final fix for BCM5354 USB cores, hopefully
[openwrt.git] / target / linux / brcm-2.4 / files / arch / mips / bcm947xx / bcmsrom.c
index 1d08218..d5737d7 100644 (file)
 /*
- *  Misc useful routines to access NIC SROM/OTP .
+ *  Routines to access SPROM and to parse SROM/CIS variables.
  *
- * Copyright 2006, Broadcom Corporation
+ * Copyright 2007, Broadcom Corporation
  * All Rights Reserved.
  * 
  * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
  * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
  * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
  * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
- * $Id: bcmsrom.c,v 1.1.1.14 2006/04/15 01:28:25 michael Exp $
+ * $Id$
  */
 
 #include <typedefs.h>
 #include <bcmdefs.h>
 #include <osl.h>
-#include <bcmutils.h>
-#include <bcmsrom.h>
+#include <stdarg.h>
+#include <sbchipc.h>
 #include <bcmdevs.h>
 #include <bcmendian.h>
 #include <sbpcmcia.h>
 #include <pcicfg.h>
+#include <sbconfig.h>
 #include <sbutils.h>
+#include <bcmsrom.h>
 #include <bcmnvram.h>
+#include "utils.h"
 
 /* debug/trace */
 #if defined(WLTEST)
 #define        BS_ERROR(args)  printf args
 #else
 #define        BS_ERROR(args)
-#endif /* BCMDBG_ERR || WLTEST */
-
-#define        VARS_MAX        4096    /* should be reduced */
+#endif
 
 #define WRITE_ENABLE_DELAY     500     /* 500 ms after write enable/disable toggle */
 #define WRITE_WORD_DELAY       20      /* 20 ms between each word write */
 
-static int initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count);
-static int initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count);
-static int initvars_flash_sb(void *sbh, char **vars, uint *count);
-static int srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count);
-static int sprom_cmd_pcmcia(osl_t *osh, uint8 cmd);
-static int sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data);
-static int sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data);
-static int sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords,
-                          bool check_crc);
+typedef struct varbuf
+{
+  char *buf;                   /* pointer to current position */
+  unsigned int size;           /* current (residual) size in bytes */
+} varbuf_t;
+
+static int initvars_srom_sb (sb_t * sbh, osl_t * osh, void *curmap,
+                            char **vars, uint * count);
+static void _initvars_srom_pci (uint8 sromrev, uint16 * srom, uint off,
+                               varbuf_t * b);
+static int initvars_srom_pci (sb_t * sbh, void *curmap, char **vars,
+                             uint * count);
+static int initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars,
+                               uint * count);
+#if !defined(BCMUSBDEV) && !defined(BCMSDIODEV)
+static int initvars_flash_sb (sb_t * sbh, char **vars, uint * count);
+#endif /* !BCMUSBDEV && !BCMSDIODEV */
+static int sprom_cmd_pcmcia (osl_t * osh, uint8 cmd);
+static int sprom_read_pcmcia (osl_t * osh, uint16 addr, uint16 * data);
+static int sprom_write_pcmcia (osl_t * osh, uint16 addr, uint16 data);
+static int sprom_read_pci (osl_t * osh, uint16 * sprom, uint wordoff,
+                          uint16 * buf, uint nwords, bool check_crc);
+
+static int initvars_table (osl_t * osh, char *start, char *end, char **vars,
+                          uint * count);
+static int initvars_flash (sb_t * sbh, osl_t * osh, char **vp, uint len);
+
+#ifdef BCMUSBDEV
+static int get_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
+                              uint boff, uint16 * srom, uint bsz);
+static int set_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
+                              uint boff, uint16 * srom, uint bsz);
+static uint srom_size (sb_t * sbh, osl_t * osh);
+#endif /* def BCMUSBDEV */
+
+/* Initialization of varbuf structure */
+static void
+varbuf_init (varbuf_t * b, char *buf, uint size)
+{
+  b->size = size;
+  b->buf = buf;
+}
 
-static int initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count);
-static int initvars_flash(osl_t *osh, char **vp, uint len, char *devpath);
+/* append a null terminated var=value string */
+static int
+varbuf_append (varbuf_t * b, const char *fmt, ...)
+{
+  va_list ap;
+  int r;
+
+  if (b->size < 2)
+    return 0;
+
+  va_start (ap, fmt);
+  r = vsnprintf (b->buf, b->size, fmt, ap);
+  va_end (ap);
+
+  /* C99 snprintf behavior returns r >= size on overflow,
+   * others return -1 on overflow.
+   * All return -1 on format error.
+   * We need to leave room for 2 null terminations, one for the current var
+   * string, and one for final null of the var table. So check that the
+   * strlen written, r, leaves room for 2 chars.
+   */
+  if ((r == -1) || (r > (int) (b->size - 2)))
+    {
+      b->size = 0;
+      return 0;
+    }
+
+  /* skip over this string's null termination */
+  r++;
+  b->size -= r;
+  b->buf += r;
+
+  return r;
+}
 
 /*
  * Initialize local vars from the right source for this platform.
  * Return 0 on success, nonzero on error.
  */
 int
-srom_var_init(void *sbh, uint bustype, void *curmap, osl_t *osh, char **vars, uint *count)
+BCMINITFN (srom_var_init) (sb_t * sbh, uint bustype, void *curmap,
+                          osl_t * osh, char **vars, uint * count)
 {
-       ASSERT(bustype == BUSTYPE(bustype));
-       if (vars == NULL || count == NULL)
-               return (0);
+  ASSERT (bustype == BUSTYPE (bustype));
+  if (vars == NULL || count == NULL)
+    return (0);
 
-       switch (BUSTYPE(bustype)) {
-       case SB_BUS:
-       case JTAG_BUS:
-               return initvars_flash_sb(sbh, vars, count);
+  *vars = NULL;
+  *count = 0;
 
-       case PCI_BUS:
-               ASSERT(curmap); /* can not be NULL */
-               return initvars_srom_pci(sbh, curmap, vars, count);
+  switch (BUSTYPE (bustype))
+    {
+    case SB_BUS:
+    case JTAG_BUS:
+      return initvars_srom_sb (sbh, osh, curmap, vars, count);
 
-       case PCMCIA_BUS:
-               return initvars_cis_pcmcia(sbh, osh, vars, count);
+    case PCI_BUS:
+      ASSERT (curmap);         /* can not be NULL */
+      return initvars_srom_pci (sbh, curmap, vars, count);
 
+    case PCMCIA_BUS:
+      return initvars_cis_pcmcia (sbh, osh, vars, count);
 
-       default:
-               ASSERT(0);
-       }
-       return (-1);
+
+    default:
+      ASSERT (0);
+    }
+  return (-1);
 }
 
 /* support only 16-bit word read from srom */
 int
-srom_read(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
+srom_read (sb_t * sbh, uint bustype, void *curmap, osl_t * osh,
+          uint byteoff, uint nbytes, uint16 * buf)
 {
-       void *srom;
-       uint i, off, nw;
-
-       ASSERT(bustype == BUSTYPE(bustype));
-
-       /* check input - 16-bit access only */
-       if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
-               return 1;
-
-       off = byteoff / 2;
-       nw = nbytes / 2;
-
-       if (BUSTYPE(bustype) == PCI_BUS) {
-               if (!curmap)
-                       return 1;
-               srom = (uchar*)curmap + PCI_BAR0_SPROM_OFFSET;
-               if (sprom_read_pci(osh, srom, off, buf, nw, FALSE))
-                       return 1;
-       } else if (BUSTYPE(bustype) == PCMCIA_BUS) {
-               for (i = 0; i < nw; i++) {
-                       if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i)))
-                               return 1;
-               }
-       } else {
-               return 1;
+  void *srom;
+  uint i, off, nw;
+
+  ASSERT (bustype == BUSTYPE (bustype));
+
+  /* check input - 16-bit access only */
+  if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
+    return 1;
+
+  off = byteoff / 2;
+  nw = nbytes / 2;
+
+  if (BUSTYPE (bustype) == PCI_BUS)
+    {
+      if (!curmap)
+       return 1;
+      srom = (uchar *) curmap + PCI_BAR0_SPROM_OFFSET;
+      if (sprom_read_pci (osh, srom, off, buf, nw, FALSE))
+       return 1;
+    }
+  else if (BUSTYPE (bustype) == PCMCIA_BUS)
+    {
+      for (i = 0; i < nw; i++)
+       {
+         if (sprom_read_pcmcia
+             (osh, (uint16) (off + i), (uint16 *) (buf + i)))
+           return 1;
        }
+    }
+  else if (BUSTYPE (bustype) == SB_BUS)
+    {
+#ifdef BCMUSBDEV
+      if (SPROMBUS == PCMCIA_BUS)
+       {
+         uint origidx;
+         void *regs;
+         int rc;
+         bool wasup;
+
+         origidx = sb_coreidx (sbh);
+         regs = sb_setcore (sbh, SB_PCMCIA, 0);
+         ASSERT (regs != NULL);
+
+         if (!(wasup = sb_iscoreup (sbh)))
+           sb_core_reset (sbh, 0, 0);
+
+         rc = get_sb_pcmcia_srom (sbh, osh, regs, byteoff, buf, nbytes);
+
+         if (!wasup)
+           sb_core_disable (sbh, 0);
+
+         sb_setcoreidx (sbh, origidx);
+         return rc;
+       }
+#endif /* def BCMUSBDEV */
 
-       return 0;
+      return 1;
+    }
+  else
+    {
+      return 1;
+    }
+
+  return 0;
 }
 
 /* support only 16-bit word write into srom */
 int
-srom_write(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
+srom_write (sb_t * sbh, uint bustype, void *curmap, osl_t * osh,
+           uint byteoff, uint nbytes, uint16 * buf)
 {
-       uint16 *srom;
-       uint i, nw, crc_range;
-       uint16 image[SPROM_SIZE];
-       uint8 crc;
-       volatile uint32 val32;
-
-       ASSERT(bustype == BUSTYPE(bustype));
-
-       /* check input - 16-bit access only */
-       if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
-               return 1;
-
-       /* Are we writing the whole thing at once? */
-       if ((byteoff == 0) &&
-           ((nbytes == SPROM_SIZE) ||
-            (nbytes == (SPROM_CRC_RANGE * 2)) ||
-            (nbytes == (SROM4_WORDS * 2)))) {
-               crc_range = nbytes;
-               bcopy((void*)buf, (void*)image, nbytes);
-               nw = nbytes / 2;
-       } else {
-               if ((BUSTYPE(bustype) == PCMCIA_BUS) || (BUSTYPE(bustype) == SDIO_BUS))
-                       crc_range = SPROM_SIZE;
-               else
-                       crc_range = SPROM_CRC_RANGE * 2;        /* Tentative */
-
-               nw = crc_range / 2;
-               /* read first 64 words from srom */
-               if (srom_read(bustype, curmap, osh, 0, crc_range, image))
-                       return 1;
-               if (image[SROM4_SIGN] == SROM4_SIGNATURE) {
-                       crc_range = SROM4_WORDS;
-                       nw = crc_range / 2;
-                       if (srom_read(bustype, curmap, osh, 0, crc_range, image))
-                               return 1;
-               }
-               /* make changes */
-               bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes);
+  uint16 *srom;
+  uint i, nw, crc_range;
+  uint16 image[SPROM_SIZE];
+  uint8 crc;
+  volatile uint32 val32;
+
+  ASSERT (bustype == BUSTYPE (bustype));
+
+  /* check input - 16-bit access only */
+  if ((byteoff & 1) || (nbytes & 1))
+    return 1;
+
+  if (byteoff == 0x55aa)
+    {
+      /* Erase request */
+      crc_range = 0;
+      memset ((void *) image, 0xff, nbytes);
+      nw = nbytes / 2;
+    }
+  else if ((byteoff == 0) &&
+          ((nbytes == SPROM_SIZE * 2) ||
+           (nbytes == (SPROM_CRC_RANGE * 2)) ||
+           (nbytes == (SROM4_WORDS * 2))))
+    {
+      /* Are we writing the whole thing at once? */
+      crc_range = nbytes;
+      bcopy ((void *) buf, (void *) image, nbytes);
+      nw = nbytes / 2;
+    }
+  else
+    {
+      if ((byteoff + nbytes) > (SPROM_SIZE * 2))
+       return 1;
+
+      if (BUSTYPE (bustype) == PCMCIA_BUS)
+       {
+         crc_range = SPROM_SIZE * 2;
+       }
+      else
+       {
+         crc_range = SPROM_CRC_RANGE * 2;      /* Tentative */
        }
 
-       /* calculate crc */
-       htol16_buf(image, crc_range);
-       crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
-       ltoh16_buf(image, crc_range);
-       image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff);
-
-       if (BUSTYPE(bustype) == PCI_BUS) {
-               srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET);
-               /* enable writes to the SPROM */
-               val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
-               val32 |= SPROM_WRITEEN;
-               OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32);
-               bcm_mdelay(WRITE_ENABLE_DELAY);
-               /* write srom */
-               for (i = 0; i < nw; i++) {
-                       W_REG(osh, &srom[i], image[i]);
-                       bcm_mdelay(WRITE_WORD_DELAY);
-               }
-               /* disable writes to the SPROM */
-               OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 &
-                                    ~SPROM_WRITEEN);
-       } else if (BUSTYPE(bustype) == PCMCIA_BUS) {
-               /* enable writes to the SPROM */
-               if (sprom_cmd_pcmcia(osh, SROM_WEN))
-                       return 1;
-               bcm_mdelay(WRITE_ENABLE_DELAY);
-               /* write srom */
-               for (i = 0; i < nw; i++) {
-                       sprom_write_pcmcia(osh, (uint16)(i), image[i]);
-                       bcm_mdelay(WRITE_WORD_DELAY);
-               }
-               /* disable writes to the SPROM */
-               if (sprom_cmd_pcmcia(osh, SROM_WDS))
-                       return 1;
-       } else {
-               return 1;
+      nw = crc_range / 2;
+      /* read first 64 words from srom */
+      if (srom_read (sbh, bustype, curmap, osh, 0, crc_range, image))
+       return 1;
+      if (image[SROM4_SIGN] == SROM4_SIGNATURE)
+       {
+         nw = SROM4_WORDS;
+         crc_range = nw * 2;
+         if (srom_read (sbh, bustype, curmap, osh, 0, crc_range, image))
+           return 1;
+       }
+      /* make changes */
+      bcopy ((void *) buf, (void *) &image[byteoff / 2], nbytes);
+    }
+
+  if (crc_range)
+    {
+      /* calculate crc */
+      htol16_buf (image, crc_range);
+      crc = ~hndcrc8 ((uint8 *) image, crc_range - 1, 0xff);
+      ltoh16_buf (image, crc_range);
+      image[nw - 1] = (crc << 8) | (image[nw - 1] & 0xff);
+    }
+
+  if (BUSTYPE (bustype) == PCI_BUS)
+    {
+      srom = (uint16 *) ((uchar *) curmap + PCI_BAR0_SPROM_OFFSET);
+      /* enable writes to the SPROM */
+      val32 = OSL_PCI_READ_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32));
+      val32 |= SPROM_WRITEEN;
+      OSL_PCI_WRITE_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32), val32);
+      bcm_mdelay (WRITE_ENABLE_DELAY);
+      /* write srom */
+      for (i = 0; i < nw; i++)
+       {
+         W_REG (osh, &srom[i], image[i]);
+         bcm_mdelay (WRITE_WORD_DELAY);
+       }
+      /* disable writes to the SPROM */
+      OSL_PCI_WRITE_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32), val32 &
+                           ~SPROM_WRITEEN);
+    }
+  else if (BUSTYPE (bustype) == PCMCIA_BUS)
+    {
+      /* enable writes to the SPROM */
+      if (sprom_cmd_pcmcia (osh, SROM_WEN))
+       return 1;
+      bcm_mdelay (WRITE_ENABLE_DELAY);
+      /* write srom */
+      for (i = 0; i < nw; i++)
+       {
+         sprom_write_pcmcia (osh, (uint16) (i), image[i]);
+         bcm_mdelay (WRITE_WORD_DELAY);
        }
+      /* disable writes to the SPROM */
+      if (sprom_cmd_pcmcia (osh, SROM_WDS))
+       return 1;
+    }
+  else if (BUSTYPE (bustype) == SB_BUS)
+    {
+#ifdef BCMUSBDEV
+      if (SPROMBUS == PCMCIA_BUS)
+       {
+         uint origidx;
+         void *regs;
+         int rc;
+         bool wasup;
+
+         origidx = sb_coreidx (sbh);
+         regs = sb_setcore (sbh, SB_PCMCIA, 0);
+         ASSERT (regs != NULL);
+
+         if (!(wasup = sb_iscoreup (sbh)))
+           sb_core_reset (sbh, 0, 0);
+
+         rc = set_sb_pcmcia_srom (sbh, osh, regs, byteoff, buf, nbytes);
+
+         if (!wasup)
+           sb_core_disable (sbh, 0);
+
+         sb_setcoreidx (sbh, origidx);
+         return rc;
+       }
+#endif /* def BCMUSBDEV */
+      return 1;
+    }
+  else
+    {
+      return 1;
+    }
+
+  bcm_mdelay (WRITE_ENABLE_DELAY);
+  return 0;
+}
+
+#ifdef BCMUSBDEV
+#define SB_PCMCIA_READ(osh, regs, fcr) \
+               R_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2)
+#define SB_PCMCIA_WRITE(osh, regs, fcr, v) \
+               W_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2, v)
+
+/* set PCMCIA srom command register */
+static int
+srom_cmd_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint8 cmd)
+{
+  uint8 status = 0;
+  uint wait_cnt = 0;
+
+  /* write srom command register */
+  SB_PCMCIA_WRITE (osh, pcmregs, SROM_CS, cmd);
 
-       bcm_mdelay(WRITE_ENABLE_DELAY);
+  /* wait status */
+  while (++wait_cnt < 1000000)
+    {
+      status = SB_PCMCIA_READ (osh, pcmregs, SROM_CS);
+      if (status & SROM_DONE)
        return 0;
+      OSL_DELAY (1);
+    }
+
+  BS_ERROR (("sr_cmd: Give up after %d tries, stat = 0x%x\n", wait_cnt,
+            status));
+  return 1;
 }
 
+/* read a word from the PCMCIA srom over SB */
+static int
+srom_read_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint16 addr, uint16 * data)
+{
+  uint8 addr_l, addr_h, data_l, data_h;
+
+  addr_l = (uint8) ((addr * 2) & 0xff);
+  addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
+
+  /* set address */
+  SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRH, addr_h);
+  SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRL, addr_l);
 
+  /* do read */
+  if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_READ))
+    return 1;
+
+  /* read data */
+  data_h = SB_PCMCIA_READ (osh, pcmregs, SROM_DATAH);
+  data_l = SB_PCMCIA_READ (osh, pcmregs, SROM_DATAL);
+  *data = ((uint16) data_h << 8) | data_l;
+
+  return 0;
+}
+
+/* write a word to the PCMCIA srom over SB */
 static int
-srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count)
+srom_write_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint16 addr, uint16 data)
 {
-       char eabuf[32];
-       char *vp, *base;
-       uint8 *cis, tup, tlen, sromrev = 1;
-       int i, j;
-       uint varsize;
-       bool ag_init = FALSE;
-       uint32 w32;
-
-       ASSERT(vars);
-       ASSERT(count);
-
-       base = vp = MALLOC(osh, VARS_MAX);
-       ASSERT(vp);
-       if (!vp)
-               return -2;
-
-       while (ciscnt--) {
-               cis = *pcis++;
-               i = 0;
-               do {
-                       tup = cis[i++];
-                       tlen = cis[i++];
-                       if ((i + tlen) >= CIS_SIZE)
-                               break;
-
-                       switch (tup) {
-                       case CISTPL_MANFID:
-                               vp += sprintf(vp, "manfid=%d", (cis[i + 1] << 8) + cis[i]);
-                               vp++;
-                               vp += sprintf(vp, "prodid=%d", (cis[i + 3] << 8) + cis[i + 2]);
-                               vp++;
-                               break;
-
-                       case CISTPL_FUNCE:
-                               switch (cis[i]) {
-                               case LAN_NID:
-                                       ASSERT(cis[i + 1] == 6);
-                                       bcm_ether_ntoa((struct ether_addr *)&cis[i + 2], eabuf);
-                                       vp += sprintf(vp, "il0macaddr=%s", eabuf);
-                                       vp++;
-                                       break;
-                               case 1:         /* SDIO Extended Data */
-                                       vp += sprintf(vp, "sdmaxblk=%d",
-                                                     (cis[i + 13] << 8) | cis[i + 12]);
-                                       vp++;
-                                       break;
-                               }
-                               break;
-
-                       case CISTPL_CFTABLE:
-                               vp += sprintf(vp, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]);
-                               vp++;
-                               break;
-
-                       case CISTPL_BRCM_HNBU:
-                               switch (cis[i]) {
-                               case HNBU_SROMREV:
-                                       sromrev = cis[i + 1];
-                                       break;
-
-                               case HNBU_CHIPID:
-                                       vp += sprintf(vp, "vendid=%d", (cis[i + 2] << 8) +
-                                                     cis[i + 1]);
-                                       vp++;
-                                       vp += sprintf(vp, "devid=%d", (cis[i + 4] << 8) +
-                                                     cis[i + 3]);
-                                       vp++;
-                                       if (tlen == 7) {
-                                               vp += sprintf(vp, "chiprev=%d",
-                                                             (cis[i + 6] << 8) + cis[i + 5]);
-                                               vp++;
-                                       }
-                                       break;
-
-                               case HNBU_BOARDREV:
-                                       vp += sprintf(vp, "boardrev=%d", cis[i + 1]);
-                                       vp++;
-                                       break;
-
-                               case HNBU_AA:
-                                       vp += sprintf(vp, "aa2g=%d", cis[i + 1]);
-                                       vp++;
-                                       break;
-
-                               case HNBU_AG:
-                                       vp += sprintf(vp, "ag0=%d", cis[i + 1]);
-                                       vp++;
-                                       ag_init = TRUE;
-                                       break;
-
-                               case HNBU_CC:
-                                       ASSERT(sromrev == 1);
-                                       vp += sprintf(vp, "cc=%d", cis[i + 1]);
-                                       vp++;
-                                       break;
-
-                               case HNBU_PAPARMS:
-                                       if (tlen == 2) {
-                                               ASSERT(sromrev == 1);
-                                               vp += sprintf(vp, "pa0maxpwr=%d", cis[i + 1]);
-                                               vp++;
-                                       } else if (tlen >= 9) {
-                                               if (tlen == 10) {
-                                                       ASSERT(sromrev == 2);
-                                                       vp += sprintf(vp, "opo=%d", cis[i + 9]);
-                                                       vp++;
-                                               } else
-                                                       ASSERT(tlen == 9);
-
-                                               for (j = 0; j < 3; j++) {
-                                                       vp += sprintf(vp, "pa0b%d=%d", j,
-                                                                     (cis[i + (j * 2) + 2] << 8) +
-                                                                     cis[i + (j * 2) + 1]);
-                                                       vp++;
-                                               }
-                                               vp += sprintf(vp, "pa0itssit=%d", cis[i + 7]);
-                                               vp++;
-                                               vp += sprintf(vp, "pa0maxpwr=%d", cis[i + 8]);
-                                               vp++;
-                                       } else
-                                               ASSERT(tlen >= 9);
-                                       break;
-
-                               case HNBU_OEM:
-                                       ASSERT(sromrev == 1);
-                                       vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
-                                                     cis[i + 1], cis[i + 2],
-                                                     cis[i + 3], cis[i + 4],
-                                                     cis[i + 5], cis[i + 6],
-                                                     cis[i + 7], cis[i + 8]);
-                                       vp++;
-                                       break;
-
-                               case HNBU_BOARDFLAGS:
-                                       w32 = (cis[i + 2] << 8) + cis[i + 1];
-                                       if (tlen == 5)
-                                               w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16);
-                                       vp += sprintf(vp, "boardflags=0x%x", w32);
-                                       vp++;
-                                       break;
-
-                               case HNBU_LEDS:
-                                       if (cis[i + 1] != 0xff) {
-                                               vp += sprintf(vp, "ledbh0=%d", cis[i + 1]);
-                                               vp++;
-                                       }
-                                       if (cis[i + 2] != 0xff) {
-                                               vp += sprintf(vp, "ledbh1=%d", cis[i + 2]);
-                                               vp++;
-                                       }
-                                       if (cis[i + 3] != 0xff) {
-                                               vp += sprintf(vp, "ledbh2=%d", cis[i + 3]);
-                                               vp++;
-                                       }
-                                       if (cis[i + 4] != 0xff) {
-                                               vp += sprintf(vp, "ledbh3=%d", cis[i + 4]);
-                                               vp++;
-                                       }
-                                       break;
-
-                               case HNBU_CCODE:
-                               {
-                                       char str[3];
-                                       ASSERT(sromrev > 1);
-                                       str[0] = cis[i + 1];
-                                       str[1] = cis[i + 2];
-                                       str[2] = 0;
-                                       vp += sprintf(vp, "ccode=%s", str);
-                                       vp++;
-                                       vp += sprintf(vp, "cctl=0x%x", cis[i + 3]);
-                                       vp++;
-                                       break;
-                               }
-
-                               case HNBU_CCKPO:
-                                       ASSERT(sromrev > 2);
-                                       vp += sprintf(vp, "cckpo=0x%x",
-                                                     (cis[i + 2] << 8) | cis[i + 1]);
-                                       vp++;
-                                       break;
-
-                               case HNBU_OFDMPO:
-                                       ASSERT(sromrev > 2);
-                                       vp += sprintf(vp, "ofdmpo=0x%x",
-                                                     (cis[i + 4] << 24) |
-                                                     (cis[i + 3] << 16) |
-                                                     (cis[i + 2] << 8) |
-                                                     cis[i + 1]);
-                                       vp++;
-                                       break;
-                               }
-                               break;
+  uint8 addr_l, addr_h, data_l, data_h;
+  int rc;
 
-                       }
-                       i += tlen;
-               } while (tup != 0xff);
+  addr_l = (uint8) ((addr * 2) & 0xff);
+  addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
+
+  /* set address */
+  SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRH, addr_h);
+  SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRL, addr_l);
+
+  data_l = (uint8) (data & 0xff);
+  data_h = (uint8) ((data >> 8) & 0xff);
+
+  /* write data */
+  SB_PCMCIA_WRITE (osh, pcmregs, SROM_DATAH, data_h);
+  SB_PCMCIA_WRITE (osh, pcmregs, SROM_DATAL, data_l);
+
+  /* do write */
+  rc = srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WRITE);
+  OSL_DELAY (20000);
+  return rc;
+}
+
+/*
+ * Read the srom for the pcmcia-srom over sb case.
+ * Return 0 on success, nonzero on error.
+ */
+static int
+get_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
+                   uint boff, uint16 * srom, uint bsz)
+{
+  uint i, nw, woff, wsz;
+  int err = 0;
+
+  /* read must be at word boundary */
+  ASSERT ((boff & 1) == 0 && (bsz & 1) == 0);
+
+  /* read sprom size and validate the parms */
+  if ((nw = srom_size (sbh, osh)) == 0)
+    {
+      BS_ERROR (("get_sb_pcmcia_srom: sprom size unknown\n"));
+      err = -1;
+      goto out;
+    }
+  if (boff + bsz > 2 * nw)
+    {
+      BS_ERROR (("get_sb_pcmcia_srom: sprom size exceeded\n"));
+      err = -2;
+      goto out;
+    }
+
+  /* read in sprom contents */
+  for (woff = boff / 2, wsz = bsz / 2, i = 0;
+       woff < nw && i < wsz; woff++, i++)
+    {
+      if (srom_read_sb_pcmcia (osh, pcmregs, (uint16) woff, &srom[i]))
+       {
+         BS_ERROR (("get_sb_pcmcia_srom: sprom read failed\n"));
+         err = -3;
+         goto out;
        }
+    }
 
-       /* Set the srom version */
-       vp += sprintf(vp, "sromrev=%d", sromrev);
-       vp++;
+out:
+  return err;
+}
 
-       /* if there is no antenna gain field, set default */
-       if (ag_init == FALSE) {
-               ASSERT(sromrev == 1);
-               vp += sprintf(vp, "ag0=%d", 0xff);
-               vp++;
+/*
+ * Write the srom for the pcmcia-srom over sb case.
+ * Return 0 on success, nonzero on error.
+ */
+static int
+set_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs,
+                   uint boff, uint16 * srom, uint bsz)
+{
+  uint i, nw, woff, wsz;
+  uint16 word;
+  uint8 crc;
+  int err = 0;
+
+  /* write must be at word boundary */
+  ASSERT ((boff & 1) == 0 && (bsz & 1) == 0);
+
+  /* read sprom size and validate the parms */
+  if ((nw = srom_size (sbh, osh)) == 0)
+    {
+      BS_ERROR (("set_sb_pcmcia_srom: sprom size unknown\n"));
+      err = -1;
+      goto out;
+    }
+  if (boff + bsz > 2 * nw)
+    {
+      BS_ERROR (("set_sb_pcmcia_srom: sprom size exceeded\n"));
+      err = -2;
+      goto out;
+    }
+
+  /* enable write */
+  if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WEN))
+    {
+      BS_ERROR (("set_sb_pcmcia_srom: sprom wen failed\n"));
+      err = -3;
+      goto out;
+    }
+
+  /* write buffer to sprom */
+  for (woff = boff / 2, wsz = bsz / 2, i = 0;
+       woff < nw && i < wsz; woff++, i++)
+    {
+      if (srom_write_sb_pcmcia (osh, pcmregs, (uint16) woff, srom[i]))
+       {
+         BS_ERROR (("set_sb_pcmcia_srom: sprom write failed\n"));
+         err = -4;
+         goto out;
+       }
+    }
+
+  /* fix crc */
+  crc = 0xff;
+  for (woff = 0; woff < nw; woff++)
+    {
+      if (srom_read_sb_pcmcia (osh, pcmregs, (uint16) woff, &word))
+       {
+         BS_ERROR (("set_sb_pcmcia_srom: sprom fix crc read failed\n"));
+         err = -5;
+         goto out;
        }
+      word = htol16 (word);
+      crc = hndcrc8 ((uint8 *) & word, woff != nw - 1 ? 2 : 1, crc);
+    }
+  word = (~crc << 8) + (ltoh16 (word) & 0xff);
+  if (srom_write_sb_pcmcia (osh, pcmregs, (uint16) (woff - 1), word))
+    {
+      BS_ERROR (("set_sb_pcmcia_srom: sprom fix crc write failed\n"));
+      err = -6;
+      goto out;
+    }
+
+  /* disable write */
+  if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WDS))
+    {
+      BS_ERROR (("set_sb_pcmcia_srom: sprom wds failed\n"));
+      err = -7;
+      goto out;
+    }
+
+out:
+  return err;
+}
+#endif /* def BCMUSBDEV */
 
-       /* final nullbyte terminator */
-       *vp++ = '\0';
-       varsize = (uint)(vp - base);
-
-       ASSERT((vp - base) < VARS_MAX);
-
-       if (varsize == VARS_MAX) {
-               *vars = base;
-       } else {
-               vp = MALLOC(osh, varsize);
-               ASSERT(vp);
-               if (vp)
-                       bcopy(base, vp, varsize);
-               MFREE(osh, base, VARS_MAX);
-               *vars = vp;
-               if (!vp) {
-                       *count = 0;
-                       return -2;
+int
+srom_parsecis (osl_t * osh, uint8 * pcis[], uint ciscnt, char **vars,
+              uint * count)
+{
+  char eabuf[32];
+  char *base;
+  varbuf_t b;
+  uint8 *cis, tup, tlen, sromrev = 1;
+  int i, j;
+  uint varsize;
+  bool ag_init = FALSE;
+  uint32 w32;
+  uint funcid;
+  uint cisnum;
+  int32 boardnum = -1;
+
+  ASSERT (vars);
+  ASSERT (count);
+
+  base = MALLOC (osh, MAXSZ_NVRAM_VARS);
+  ASSERT (base);
+  if (!base)
+    return -2;
+
+  varbuf_init (&b, base, MAXSZ_NVRAM_VARS);
+
+  eabuf[0] = '\0';
+  for (cisnum = 0; cisnum < ciscnt; cisnum++)
+    {
+      cis = *pcis++;
+      i = 0;
+      funcid = 0;
+      do
+       {
+         tup = cis[i++];
+         tlen = cis[i++];
+         if ((i + tlen) >= CIS_SIZE)
+           break;
+
+         switch (tup)
+           {
+           case CISTPL_VERS_1:
+             /* assume the strings are good if the version field checks out */
+             if (((cis[i + 1] << 8) + cis[i]) >= 0x0008)
+               {
+                 varbuf_append (&b, "manf=%s", &cis[i + 2]);
+                 varbuf_append (&b, "productname=%s",
+                                &cis[i + 3 + strlen ((char *) &cis[i + 2])]);
+                 break;
                }
+
+           case CISTPL_MANFID:
+             varbuf_append (&b, "manfid=0x%x", (cis[i + 1] << 8) + cis[i]);
+             varbuf_append (&b, "prodid=0x%x",
+                            (cis[i + 3] << 8) + cis[i + 2]);
+             break;
+
+           case CISTPL_FUNCID:
+             funcid = cis[i];
+             break;
+
+           case CISTPL_FUNCE:
+             switch (funcid)
+               {
+               default:
+                 /* set macaddr if HNBU_MACADDR not seen yet */
+                 if (eabuf[0] == '\0' && cis[i] == LAN_NID)
+                   {
+                     ASSERT (cis[i + 1] == ETHER_ADDR_LEN);
+                     bcm_ether_ntoa ((struct ether_addr *) &cis[i + 2],
+                                     eabuf);
+                   }
+                 /* set boardnum if HNBU_BOARDNUM not seen yet */
+                 if (boardnum == -1)
+                   boardnum = (cis[i + 6] << 8) + cis[i + 7];
+                 break;
+               }
+             break;
+
+           case CISTPL_CFTABLE:
+             varbuf_append (&b, "regwindowsz=%d",
+                            (cis[i + 7] << 8) | cis[i + 6]);
+             break;
+
+           case CISTPL_BRCM_HNBU:
+             switch (cis[i])
+               {
+               case HNBU_SROMREV:
+                 sromrev = cis[i + 1];
+                 varbuf_append (&b, "sromrev=%d", sromrev);
+                 break;
+
+               case HNBU_CHIPID:
+                 varbuf_append (&b, "vendid=0x%x", (cis[i + 2] << 8) +
+                                cis[i + 1]);
+                 varbuf_append (&b, "devid=0x%x", (cis[i + 4] << 8) +
+                                cis[i + 3]);
+                 if (tlen >= 7)
+                   {
+                     varbuf_append (&b, "chiprev=%d",
+                                    (cis[i + 6] << 8) + cis[i + 5]);
+                   }
+                 if (tlen >= 9)
+                   {
+                     varbuf_append (&b, "subvendid=0x%x",
+                                    (cis[i + 8] << 8) + cis[i + 7]);
+                   }
+                 if (tlen >= 11)
+                   {
+                     varbuf_append (&b, "subdevid=0x%x",
+                                    (cis[i + 10] << 8) + cis[i + 9]);
+                     /* subdevid doubles for boardtype */
+                     varbuf_append (&b, "boardtype=0x%x",
+                                    (cis[i + 10] << 8) + cis[i + 9]);
+                   }
+                 break;
+
+               case HNBU_BOARDREV:
+                 varbuf_append (&b, "boardrev=0x%x", cis[i + 1]);
+                 break;
+
+               case HNBU_AA:
+                 varbuf_append (&b, "aa2g=%d", cis[i + 1]);
+                 break;
+
+               case HNBU_AG:
+                 varbuf_append (&b, "ag0=%d", cis[i + 1]);
+                 ag_init = TRUE;
+                 break;
+
+               case HNBU_ANT5G:
+                 varbuf_append (&b, "aa5g=%d", cis[i + 1]);
+                 varbuf_append (&b, "ag1=%d", cis[i + 2]);
+                 break;
+
+               case HNBU_CC:
+                 ASSERT (sromrev == 1);
+                 varbuf_append (&b, "cc=%d", cis[i + 1]);
+                 break;
+
+               case HNBU_PAPARMS:
+                 if (tlen == 2)
+                   {
+                     ASSERT (sromrev == 1);
+                     varbuf_append (&b, "pa0maxpwr=%d", cis[i + 1]);
+                   }
+                 else if (tlen >= 9)
+                   {
+                     if (tlen == 10)
+                       {
+                         ASSERT (sromrev >= 2);
+                         varbuf_append (&b, "opo=%d", cis[i + 9]);
+                       }
+                     else
+                       ASSERT (tlen == 9);
+
+                     for (j = 0; j < 3; j++)
+                       {
+                         varbuf_append (&b, "pa0b%d=%d", j,
+                                        (cis[i + (j * 2) + 2] << 8) +
+                                        cis[i + (j * 2) + 1]);
+                       }
+                     varbuf_append (&b, "pa0itssit=%d", cis[i + 7]);
+                     varbuf_append (&b, "pa0maxpwr=%d", cis[i + 8]);
+                   }
+                 else
+                   ASSERT (tlen >= 9);
+                 break;
+
+               case HNBU_PAPARMS5G:
+                 ASSERT ((sromrev == 2) || (sromrev == 3));
+                 for (j = 0; j < 3; j++)
+                   {
+                     varbuf_append (&b, "pa1b%d=%d", j,
+                                    (cis[i + (j * 2) + 2] << 8) +
+                                    cis[i + (j * 2) + 1]);
+                   }
+                 for (j = 3; j < 6; j++)
+                   {
+                     varbuf_append (&b, "pa1lob%d=%d", j - 3,
+                                    (cis[i + (j * 2) + 2] << 8) +
+                                    cis[i + (j * 2) + 1]);
+                   }
+                 for (j = 6; j < 9; j++)
+                   {
+                     varbuf_append (&b, "pa1hib%d=%d", j - 6,
+                                    (cis[i + (j * 2) + 2] << 8) +
+                                    cis[i + (j * 2) + 1]);
+                   }
+                 varbuf_append (&b, "pa1itssit=%d", cis[i + 19]);
+                 varbuf_append (&b, "pa1maxpwr=%d", cis[i + 20]);
+                 varbuf_append (&b, "pa1lomaxpwr=%d", cis[i + 21]);
+                 varbuf_append (&b, "pa1himaxpwr=%d", cis[i + 22]);
+                 break;
+
+               case HNBU_OEM:
+                 ASSERT (sromrev == 1);
+                 varbuf_append (&b, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
+                                cis[i + 1], cis[i + 2],
+                                cis[i + 3], cis[i + 4],
+                                cis[i + 5], cis[i + 6],
+                                cis[i + 7], cis[i + 8]);
+                 break;
+
+               case HNBU_BOARDFLAGS:
+                 w32 = (cis[i + 2] << 8) + cis[i + 1];
+                 if (tlen == 5)
+                   w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16);
+                 varbuf_append (&b, "boardflags=0x%x", w32);
+                 break;
+
+               case HNBU_LEDS:
+                 if (cis[i + 1] != 0xff)
+                   {
+                     varbuf_append (&b, "ledbh0=%d", cis[i + 1]);
+                   }
+                 if (cis[i + 2] != 0xff)
+                   {
+                     varbuf_append (&b, "ledbh1=%d", cis[i + 2]);
+                   }
+                 if (cis[i + 3] != 0xff)
+                   {
+                     varbuf_append (&b, "ledbh2=%d", cis[i + 3]);
+                   }
+                 if (cis[i + 4] != 0xff)
+                   {
+                     varbuf_append (&b, "ledbh3=%d", cis[i + 4]);
+                   }
+                 break;
+
+               case HNBU_CCODE:
+                 ASSERT (sromrev > 1);
+                 if ((cis[i + 1] == 0) || (cis[i + 2] == 0))
+                   varbuf_append (&b, "ccode=");
+                 else
+                   varbuf_append (&b, "ccode=%c%c", cis[i + 1], cis[i + 2]);
+                 varbuf_append (&b, "cctl=0x%x", cis[i + 3]);
+                 break;
+
+               case HNBU_CCKPO:
+                 ASSERT (sromrev > 2);
+                 varbuf_append (&b, "cckpo=0x%x",
+                                (cis[i + 2] << 8) | cis[i + 1]);
+                 break;
+
+               case HNBU_OFDMPO:
+                 ASSERT (sromrev > 2);
+                 varbuf_append (&b, "ofdmpo=0x%x",
+                                (cis[i + 4] << 24) |
+                                (cis[i + 3] << 16) |
+                                (cis[i + 2] << 8) | cis[i + 1]);
+                 break;
+
+               case HNBU_RDLID:
+                 varbuf_append (&b, "rdlid=0x%x",
+                                (cis[i + 2] << 8) | cis[i + 1]);
+                 break;
+
+               case HNBU_RDLRNDIS:
+                 varbuf_append (&b, "rdlrndis=%d", cis[i + 1]);
+                 break;
+
+               case HNBU_RDLRWU:
+                 varbuf_append (&b, "rdlrwu=%d", cis[i + 1]);
+                 break;
+
+               case HNBU_RDLSN:
+                 varbuf_append (&b, "rdlsn=%d",
+                                (cis[i + 2] << 8) | cis[i + 1]);
+                 break;
+
+               case HNBU_XTALFREQ:
+                 varbuf_append (&b, "xtalfreq=%d",
+                                (cis[i + 4] << 24) |
+                                (cis[i + 3] << 16) |
+                                (cis[i + 2] << 8) | cis[i + 1]);
+                 break;
+
+               case HNBU_RSSISMBXA2G:
+                 ASSERT (sromrev == 3);
+                 varbuf_append (&b, "rssismf2g=%d", cis[i + 1] & 0xf);
+                 varbuf_append (&b, "rssismc2g=%d", (cis[i + 1] >> 4) & 0xf);
+                 varbuf_append (&b, "rssisav2g=%d", cis[i + 2] & 0x7);
+                 varbuf_append (&b, "bxa2g=%d", (cis[i + 2] >> 3) & 0x3);
+                 break;
+
+               case HNBU_RSSISMBXA5G:
+                 ASSERT (sromrev == 3);
+                 varbuf_append (&b, "rssismf5g=%d", cis[i + 1] & 0xf);
+                 varbuf_append (&b, "rssismc5g=%d", (cis[i + 1] >> 4) & 0xf);
+                 varbuf_append (&b, "rssisav5g=%d", cis[i + 2] & 0x7);
+                 varbuf_append (&b, "bxa5g=%d", (cis[i + 2] >> 3) & 0x3);
+                 break;
+
+               case HNBU_TRI2G:
+                 ASSERT (sromrev == 3);
+                 varbuf_append (&b, "tri2g=%d", cis[i + 1]);
+                 break;
+
+               case HNBU_TRI5G:
+                 ASSERT (sromrev == 3);
+                 varbuf_append (&b, "tri5gl=%d", cis[i + 1]);
+                 varbuf_append (&b, "tri5g=%d", cis[i + 2]);
+                 varbuf_append (&b, "tri5gh=%d", cis[i + 3]);
+                 break;
+
+               case HNBU_RXPO2G:
+                 ASSERT (sromrev == 3);
+                 varbuf_append (&b, "rxpo2g=%d", cis[i + 1]);
+                 break;
+
+               case HNBU_RXPO5G:
+                 ASSERT (sromrev == 3);
+                 varbuf_append (&b, "rxpo5g=%d", cis[i + 1]);
+                 break;
+
+               case HNBU_BOARDNUM:
+                 boardnum = (cis[i + 2] << 8) + cis[i + 1];
+                 break;
+
+               case HNBU_MACADDR:
+                 bcm_ether_ntoa ((struct ether_addr *) &cis[i + 1], eabuf);
+                 break;
+
+               case HNBU_BOARDTYPE:
+                 varbuf_append (&b, "boardtype=0x%x",
+                                (cis[i + 2] << 8) + cis[i + 1]);
+                 break;
+
+#if defined(BCMCCISSR3)
+               case HNBU_SROM3SWRGN:
+                 {
+                   uint16 srom[35];
+                   uint8 srev = cis[i + 1 + 70];
+                   ASSERT (srev == 3);
+                   /* make tuple value 16-bit aligned and parse it */
+                   bcopy (&cis[i + 1], srom, sizeof (srom));
+                   _initvars_srom_pci (srev, srom, SROM3_SWRGN_OFF, &b);
+                   /* create extra variables */
+                   varbuf_append (&b, "vendid=0x%x",
+                                  (cis[i + 1 + 73] << 8) + cis[i + 1 + 72]);
+                   varbuf_append (&b, "devid=0x%x",
+                                  (cis[i + 1 + 75] << 8) + cis[i + 1 + 74]);
+                   varbuf_append (&b, "xtalfreq=%d",
+                                  (cis[i + 1 + 77] << 8) + cis[i + 1 + 76]);
+                   /* 2.4G antenna gain is included in SROM */
+                   ag_init = TRUE;
+                   /* Ethernet MAC address is included in SROM */
+                   eabuf[0] = 0;
+                   boardnum = -1;
+                   break;
+                 }
+#endif
+               }
+             break;
+           }
+         i += tlen;
        }
-       *count = varsize;
+      while (tup != CISTPL_END);
+    }
+
+  if (boardnum != -1)
+    {
+      varbuf_append (&b, "boardnum=%d", boardnum);
+    }
+
+  if (eabuf[0])
+    {
+      varbuf_append (&b, "macaddr=%s", eabuf);
+    }
+
+  /* if there is no antenna gain field, set default */
+  if (ag_init == FALSE)
+    {
+      varbuf_append (&b, "ag0=%d", 0xff);
+    }
+
+  /* final nullbyte terminator */
+  ASSERT (b.size >= 1);
+  *b.buf++ = '\0';
+  varsize = (uint) (b.buf - base);
+  ASSERT (varsize < MAXSZ_NVRAM_VARS);
+  if (varsize < MAXSZ_NVRAM_VARS)
+    {
+      char *new_buf;
+      new_buf = (char *) MALLOC (osh, varsize);
+      ASSERT (new_buf);
+      if (new_buf)
+       {
+         bcopy (base, new_buf, varsize);
+         MFREE (osh, base, MAXSZ_NVRAM_VARS);
+         base = new_buf;
+       }
+    }
+
+  *vars = base;
+  *count = varsize;
 
-       return (0);
+  return (0);
 }
 
 
 /* set PCMCIA sprom command register */
 static int
-sprom_cmd_pcmcia(osl_t *osh, uint8 cmd)
+sprom_cmd_pcmcia (osl_t * osh, uint8 cmd)
 {
-       uint8 status = 0;
-       uint wait_cnt = 1000;
+  uint8 status = 0;
+  uint wait_cnt = 1000;
 
-       /* write sprom command register */
-       OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1);
+  /* write sprom command register */
+  OSL_PCMCIA_WRITE_ATTR (osh, SROM_CS, &cmd, 1);
 
-       /* wait status */
-       while (wait_cnt--) {
-               OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1);
-               if (status & SROM_DONE)
-                       return 0;
-       }
+  /* wait status */
+  while (wait_cnt--)
+    {
+      OSL_PCMCIA_READ_ATTR (osh, SROM_CS, &status, 1);
+      if (status & SROM_DONE)
+       return 0;
+    }
 
-       return 1;
+  return 1;
 }
 
 /* read a word from the PCMCIA srom */
 static int
-sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data)
+sprom_read_pcmcia (osl_t * osh, uint16 addr, uint16 * data)
 {
-       uint8 addr_l, addr_h, data_l, data_h;
+  uint8 addr_l, addr_h, data_l, data_h;
 
-       addr_l = (uint8)((addr * 2) & 0xff);
-       addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
+  addr_l = (uint8) ((addr * 2) & 0xff);
+  addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
 
-       /* set address */
-       OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
-       OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
+  /* set address */
+  OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRH, &addr_h, 1);
+  OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRL, &addr_l, 1);
 
-       /* do read */
-       if (sprom_cmd_pcmcia(osh, SROM_READ))
-               return 1;
+  /* do read */
+  if (sprom_cmd_pcmcia (osh, SROM_READ))
+    return 1;
 
-       /* read data */
-       data_h = data_l = 0;
-       OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1);
-       OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1);
+  /* read data */
+  data_h = data_l = 0;
+  OSL_PCMCIA_READ_ATTR (osh, SROM_DATAH, &data_h, 1);
+  OSL_PCMCIA_READ_ATTR (osh, SROM_DATAL, &data_l, 1);
 
-       *data = (data_h << 8) | data_l;
-       return 0;
+  *data = (data_h << 8) | data_l;
+  return 0;
 }
 
 /* write a word to the PCMCIA srom */
 static int
-sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data)
+sprom_write_pcmcia (osl_t * osh, uint16 addr, uint16 data)
 {
-       uint8 addr_l, addr_h, data_l, data_h;
+  uint8 addr_l, addr_h, data_l, data_h;
 
-       addr_l = (uint8)((addr * 2) & 0xff);
-       addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
-       data_l = (uint8)(data & 0xff);
-       data_h = (uint8)((data >> 8) & 0xff);
+  addr_l = (uint8) ((addr * 2) & 0xff);
+  addr_h = (uint8) (((addr * 2) >> 8) & 0xff);
+  data_l = (uint8) (data & 0xff);
+  data_h = (uint8) ((data >> 8) & 0xff);
 
-       /* set address */
-       OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
-       OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
+  /* set address */
+  OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRH, &addr_h, 1);
+  OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRL, &addr_l, 1);
 
-       /* write data */
-       OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1);
-       OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1);
+  /* write data */
+  OSL_PCMCIA_WRITE_ATTR (osh, SROM_DATAH, &data_h, 1);
+  OSL_PCMCIA_WRITE_ATTR (osh, SROM_DATAL, &data_l, 1);
 
-       /* do write */
-       return sprom_cmd_pcmcia(osh, SROM_WRITE);
+  /* do write */
+  return sprom_cmd_pcmcia (osh, SROM_WRITE);
 }
 
 /*
@@ -511,25 +1050,43 @@ sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data)
  * Return 0 on success, nonzero on error.
  */
 static int
-sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc)
+sprom_read_pci (osl_t * osh, uint16 * sprom, uint wordoff, uint16 * buf,
+               uint nwords, bool check_crc)
 {
-       int err = 0;
-       uint i;
-
-       /* read the sprom */
-       for (i = 0; i < nwords; i++)
-               buf[i] = R_REG(osh, &sprom[wordoff + i]);
-
-       if (check_crc) {
-               /* fixup the endianness so crc8 will pass */
-               htol16_buf(buf, nwords * 2);
-               if (hndcrc8((uint8*)buf, nwords * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE)
-                       err = 1;
-               /* now correct the endianness of the byte array */
-               ltoh16_buf(buf, nwords * 2);
+  int err = 0;
+  uint i;
+
+  /* read the sprom */
+  for (i = 0; i < nwords; i++)
+    {
+#ifdef BCMQT
+      buf[i] = R_REG (osh, &sprom[wordoff + i]);
+#endif
+      buf[i] = R_REG (osh, &sprom[wordoff + i]);
+    }
+
+  if (check_crc)
+    {
+      if (buf[0] == 0xffff)
+       {
+         /* The hardware thinks that an srom that starts with 0xffff
+          * is blank, regardless of the rest of the content, so declare
+          * it bad.
+          */
+         BS_ERROR (("%s: buf[0] = 0x%x, returning bad-crc\n", __FUNCTION__,
+                    buf[0]));
+         return 1;
        }
 
-       return err;
+      /* fixup the endianness so crc8 will pass */
+      htol16_buf (buf, nwords * 2);
+      if (hndcrc8 ((uint8 *) buf, nwords * 2, 0xff) != 0x9f)
+       err = 1;
+      /* now correct the endianness of the byte array */
+      ltoh16_buf (buf, nwords * 2);
+    }
+
+  return err;
 }
 
 /*
@@ -537,26 +1094,29 @@ sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords
 * Return 0 on success, nonzero on error.
 */
 static int
-initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count)
+BCMINITFN (initvars_table) (osl_t * osh, char *start, char *end, char **vars,
+                           uint * count)
 {
-       int c = (int)(end - start);
-
-       /* do it only when there is more than just the null string */
-       if (c > 1) {
-               char *vp = MALLOC(osh, c);
-               ASSERT(vp);
-               if (!vp)
-                       return BCME_NOMEM;
-               bcopy(start, vp, c);
-               *vars = vp;
-               *count = c;
-       }
-       else {
-               *vars = NULL;
-               *count = 0;
-       }
-
-       return 0;
+  int c = (int) (end - start);
+
+  /* do it only when there is more than just the null string */
+  if (c > 1)
+    {
+      char *vp = MALLOC (osh, c);
+      ASSERT (vp);
+      if (!vp)
+       return BCME_NOMEM;
+      bcopy (start, vp, c);
+      *vars = vp;
+      *count = c;
+    }
+  else
+    {
+      *vars = NULL;
+      *count = 0;
+    }
+
+  return 0;
 }
 
 /*
@@ -565,617 +1125,763 @@ initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count)
  * Return 0 on success, nonzero on error.
  */
 static int
-initvars_flash(osl_t *osh, char **base, uint len, char *devpath)
+initvars_flash (sb_t * sbh, osl_t * osh, char **base, uint len)
 {
-       char *vp = *base;
-       char *flash;
-       int err;
-       char *s;
-       uint l, dl, copy_len;
-
-       /* allocate memory and read in flash */
-       if (!(flash = MALLOC(osh, NVRAM_SPACE)))
-               return BCME_NOMEM;
-       if ((err = nvram_getall(flash, NVRAM_SPACE)))
-               goto exit;
-
-       /* grab vars with the <devpath> prefix in name */
-       dl = strlen(devpath);
-       for (s = flash; s && *s; s += l + 1) {
-               l = strlen(s);
-
-               /* skip non-matching variable */
-               if (strncmp(s, devpath, dl))
-                       continue;
-
-               /* is there enough room to copy? */
-               copy_len = l - dl + 1;
-               if (len < copy_len) {
-                       err = BCME_BUFTOOSHORT;
-                       goto exit;
-               }
-
-               /* no prefix, just the name=value */
-               strcpy(vp, &s[dl]);
-               vp += copy_len;
-               len -= copy_len;
+  char *vp = *base;
+  char *flash;
+  int err;
+  char *s;
+  uint l, dl, copy_len;
+  char devpath[SB_DEVPATH_BUFSZ];
+
+  /* allocate memory and read in flash */
+  if (!(flash = MALLOC (osh, NVRAM_SPACE)))
+    return BCME_NOMEM;
+  if ((err = nvram_getall (flash, NVRAM_SPACE)))
+    goto exit;
+
+  sb_devpath (sbh, devpath, sizeof (devpath));
+
+  /* grab vars with the <devpath> prefix in name */
+  dl = strlen (devpath);
+  for (s = flash; s && *s; s += l + 1)
+    {
+      l = strlen (s);
+
+      /* skip non-matching variable */
+      if (strncmp (s, devpath, dl))
+       continue;
+
+      /* is there enough room to copy? */
+      copy_len = l - dl + 1;
+      if (len < copy_len)
+       {
+         err = BCME_BUFTOOSHORT;
+         goto exit;
        }
 
-       /* add null string as terminator */
-       if (len < 1) {
-               err = BCME_BUFTOOSHORT;
-               goto exit;
-       }
-       *vp++ = '\0';
+      /* no prefix, just the name=value */
+      strncpy (vp, &s[dl], copy_len);
+      vp += copy_len;
+      len -= copy_len;
+    }
+
+  /* add null string as terminator */
+  if (len < 1)
+    {
+      err = BCME_BUFTOOSHORT;
+      goto exit;
+    }
+  *vp++ = '\0';
 
-       *base = vp;
+  *base = vp;
 
-exit:  MFREE(osh, flash, NVRAM_SPACE);
-       return err;
+exit:MFREE (osh, flash, NVRAM_SPACE);
+  return err;
 }
 
+#if !defined(BCMUSBDEV) && !defined(BCMSDIODEV)
 /*
  * Initialize nonvolatile variable table from flash.
  * Return 0 on success, nonzero on error.
  */
 static int
-initvars_flash_sb(void *sbh, char **vars, uint *count)
+initvars_flash_sb (sb_t * sbh, char **vars, uint * count)
 {
-       osl_t *osh = sb_osh(sbh);
-       char devpath[SB_DEVPATH_BUFSZ];
-       char *vp, *base;
-       int err;
+  osl_t *osh = sb_osh (sbh);
+  char *vp, *base;
+  int err;
 
-       ASSERT(vars);
-       ASSERT(count);
+  ASSERT (vars);
+  ASSERT (count);
 
-       if ((err = sb_devpath(sbh, devpath, sizeof(devpath))))
-               return err;
+  base = vp = MALLOC (osh, MAXSZ_NVRAM_VARS);
+  ASSERT (vp);
+  if (!vp)
+    return BCME_NOMEM;
 
-       base = vp = MALLOC(osh, VARS_MAX);
-       ASSERT(vp);
-       if (!vp)
-               return BCME_NOMEM;
+  if ((err = initvars_flash (sbh, osh, &vp, MAXSZ_NVRAM_VARS)) == 0)
+    err = initvars_table (osh, base, vp, vars, count);
 
-       if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath)))
-               goto err;
+  MFREE (osh, base, MAXSZ_NVRAM_VARS);
 
-       err = initvars_table(osh, base, vp, vars, count);
-
-err:   MFREE(osh, base, VARS_MAX);
-       return err;
+  return err;
 }
+#endif /* !BCMUSBDEV && !BCMSDIODEV */
 
 #ifdef WLTEST
 char mfgsromvars[256];
 char *defaultsromvars = "il0macaddr=00:11:22:33:44:51\0"
-               "et0macaddr=00:11:22:33:44:52\0"
-               "et1macaddr=00:11:22:33:44:53\0"
-               "boardtype=0xffff\0"
-               "boardrev=0x10\0"
-               "boardflags=8\0"
-               "sromrev=2\0"
-               "aa2g=3";
-#define        MFGSROM_DEFVARSLEN      147 /* default srom len */
+  "et0macaddr=00:11:22:33:44:52\0"
+  "et1macaddr=00:11:22:33:44:53\0"
+  "boardtype=0xffff\0"
+  "boardrev=0x10\0" "boardflags=8\0" "sromrev=2\0" "aa2g=3\0" "\0";
+#define        MFGSROM_DEFVARSLEN      149     /* default srom len */
 #endif /* WL_TEST */
 
 /*
  * Initialize nonvolatile variable table from sprom.
  * Return 0 on success, nonzero on error.
  */
-static int
-initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count)
-{
-       uint16 w, *b;
-       uint8 sromrev = 0;
-       struct ether_addr ea;
-       char eabuf[32];
-       uint32 w32;
-       int woff, i;
-       char *vp, *base;
-       osl_t *osh = sb_osh(sbh);
-       bool flash = FALSE;
-       char name[SB_DEVPATH_BUFSZ+16], *value;
-       char devpath[SB_DEVPATH_BUFSZ];
-       int err;
-
-       /*
-        * Apply CRC over SROM content regardless SROM is present or not,
-        * and use variable <devpath>sromrev's existance in flash to decide
-        * if we should return an error when CRC fails or read SROM variables
-        * from flash.
-        */
-       b = MALLOC(osh, SROM_MAX);
-       ASSERT(b);
-       if (!b)
-               return -2;
-
-       err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b,
-                            64, TRUE);
-       if (b[SROM4_SIGN] == SROM4_SIGNATURE) {
-               /* sromrev >= 4, read more */
-               err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, SROM4_WORDS, TRUE);
-               sromrev = b[SROM4_WORDS - 1] & 0xff;
-       } else if (err == 0) {
-               /* srom is good and is rev < 4 */
-               /* top word of sprom contains version and crc8 */
-               sromrev = b[63] & 0xff;
-               /* bcm4401 sroms misprogrammed */
-               if (sromrev == 0x10)
-                       sromrev = 1;
-       }
-
-       if (err) {
-#ifdef WLTEST
-               BS_ERROR(("SROM Crc Error, so see if we could use a default\n"));
-               w32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
-               if (w32 & SPROM_OTPIN_USE) {
-                       BS_ERROR(("srom crc failed with OTP, use default vars....\n"));
-                       vp = base =  mfgsromvars;
-                       if (sb_chip(sbh) == BCM4311_CHIP_ID) {
-                               BS_ERROR(("setting the devid to be 4311\n"));
-                               vp += sprintf(vp, "devid=0x4311");
-                               vp++;
-                       }
-                       bcopy(defaultsromvars,  vp, MFGSROM_DEFVARSLEN);
-                       vp += MFGSROM_DEFVARSLEN;
-                       goto varsdone;
-               } else {
-                       BS_ERROR(("srom crc failed with SPROM....\n"));
-#endif /* WLTEST */
-                       if ((err = sb_devpath(sbh, devpath, sizeof(devpath))))
-                               return err;
-                       sprintf(name, "%ssromrev", devpath);
-                       if (!(value = getvar(NULL, name)))
-                               return (-1);
-                       sromrev = (uint8)bcm_strtoul(value, NULL, 0);
-                       flash = TRUE;
-#ifdef WLTEST
-               }
-#endif /* WLTEST */
-       }
 
-       /* srom version check */
-       if (sromrev > 4)
-               return (-2);
-
-       ASSERT(vars);
-       ASSERT(count);
-
-       base = vp = MALLOC(osh, VARS_MAX);
-       ASSERT(vp);
-       if (!vp)
-               return -2;
-
-       /* read variables from flash */
-       if (flash) {
-               if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath)))
-                       goto err;
-               goto varsdone;
-       }
-
-       vp += sprintf(vp, "sromrev=%d", sromrev);
-       vp++;
-
-       if (sromrev >= 4) {
-               uint path, pathbase;
-               const uint pathbases[MAX_PATH] = {SROM4_PATH0, SROM4_PATH1,
-                                                 SROM4_PATH2, SROM4_PATH3};
-
-               vp += sprintf(vp, "boardrev=%d", b[SROM4_BREV]);
-               vp++;
-
-               vp += sprintf(vp, "boardflags=%d", (b[SROM4_BFL1] << 16) | b[SROM4_BFL0]);
-               vp++;
-
-               vp += sprintf(vp, "boardflags2=%d", (b[SROM4_BFL3] << 16) | b[SROM4_BFL2]);
-               vp++;
-
-               /* The macaddr */
-               ea.octet[0] = (b[SROM4_MACHI] >> 8) & 0xff;
-               ea.octet[1] = b[SROM4_MACHI] & 0xff;
-               ea.octet[2] = (b[SROM4_MACMID] >> 8) & 0xff;
-               ea.octet[3] = b[SROM4_MACMID] & 0xff;
-               ea.octet[4] = (b[SROM4_MACLO] >> 8) & 0xff;
-               ea.octet[5] = b[SROM4_MACLO] & 0xff;
-               bcm_ether_ntoa(&ea, eabuf);
-               vp += sprintf(vp, "macaddr=%s", eabuf);
-               vp++;
-
-               w = b[SROM4_CCODE];
-               if (w == 0)
-                       vp += sprintf(vp, "ccode=");
-               else
-                       vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
-               vp++;
-               vp += sprintf(vp, "regrev=%d", b[SROM4_REGREV]);
-               vp++;
-
-               w = b[SROM4_LEDBH10];
-               if ((w != 0) && (w != 0xffff)) {
-                       /* ledbh0 */
-                       vp += sprintf(vp, "ledbh0=%d", (w & 0xff));
-                       vp++;
-
-                       /* ledbh1 */
-                       vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff);
-                       vp++;
-               }
-               w = b[SROM4_LEDBH32];
-               if ((w != 0) && (w != 0xffff)) {
-                       /* ledbh2 */
-                       vp += sprintf(vp, "ledbh2=%d", w & 0xff);
-                       vp++;
-
-                       /* ledbh3 */
-                       vp += sprintf(vp, "ledbh3=%d", (w >> 8) & 0xff);
-                       vp++;
-               }
-               /* LED Powersave duty cycle (oncount >> 24) (offcount >> 8) */
-               if (w != 0xffff) {
-                       w = b[SROM4_LEDDC];
-                       w32 = ((uint32)((unsigned char)(w >> 8) & 0xff) << 24) |  /* oncount */
-                               ((uint32)((unsigned char)(w & 0xff)) << 8); /* offcount */
-                       vp += sprintf(vp, "leddc=%d", w32);
-                       vp++;
-               }
-
-               w = b[SROM4_AA];
-               vp += sprintf(vp, "aa2g=%d", w & SROM4_AA2G_MASK);
-               vp++;
-               vp += sprintf(vp, "aa5g=%d", w >> SROM4_AA5G_SHIFT);
-               vp++;
-
-               w = b[SROM4_AG10];
-               vp += sprintf(vp, "ag0=%d", w & 0xff);
-               vp++;
-               vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
-               vp++;
-               w = b[SROM4_AG32];
-               vp += sprintf(vp, "ag2=%d", w & 0xff);
-               vp++;
-               vp += sprintf(vp, "ag3=%d", (w >> 8) & 0xff);
-               vp++;
-
-               /* Fixed power indices when power control is disabled */
-               for (i = 0; i < 2; i++) {
-                       w = b[SROM4_TXPID2G + i];
-                       vp += sprintf(vp, "txpid2ga%d=%d", 2 * i, w & 0xff);
-                       vp++;
-                       vp += sprintf(vp, "txpid2ga%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
-                       vp++;
-                       w = b[SROM4_TXPID5G + i];
-                       vp += sprintf(vp, "txpid5ga%d=%d", 2 * i, w & 0xff);
-                       vp++;
-                       vp += sprintf(vp, "txpid5ga%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
-                       vp++;
-                       w = b[SROM4_TXPID5GL + i];
-                       vp += sprintf(vp, "txpid5gla%d=%d", 2 * i, w & 0xff);
-                       vp++;
-                       vp += sprintf(vp, "txpid5gla%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
-                       vp++;
-                       w = b[SROM4_TXPID5GH + i];
-                       vp += sprintf(vp, "txpid5gha%d=%d", 2 * i, w & 0xff);
-                       vp++;
-                       vp += sprintf(vp, "txpid5gha%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
-                       vp++;
-               }
+typedef struct
+{
+  const char *name;
+  uint32 revmask;
+  uint32 flags;
+  uint16 off;
+  uint16 mask;
+} sromvar_t;
+
+#define SRFL_MORE      1       /* value continues as described by the next entry */
+#define        SRFL_NOFFS      2       /* value bits can't be all one's */
+#define        SRFL_PRHEX      4       /* value is in hexdecimal format */
+#define        SRFL_PRSIGN     8       /* value is in signed decimal format */
+#define        SRFL_CCODE      0x10    /* value is in country code format */
+#define        SRFL_ETHADDR    0x20    /* value is an Ethernet address */
+#define SRFL_LEDDC     0x40    /* value is an LED duty cycle */
+
+/* Assumptions:
+ * - Ethernet address spins across 3 consective words
+ *
+ * Table rules:
+ * - Add multiple entries next to each other if a value spins across multiple words
+ *   (even multiple fields in the same word) with each entry except the last having
+ *   it's SRFL_MORE bit set.
+ * - Ethernet address entry does not follow above rule and must not have SRFL_MORE
+ *   bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
+ * - The last entry's name field must be NULL to indicate the end of the table. Other
+ *   entries must have non-NULL name.
+ */
 
-               /* Per path variables */
-               for (path = 0; path < MAX_PATH; path++) {
-                       pathbase = pathbases[path];
-                       w = b[pathbase + SROM4_2G_ITT_MAXP];
-                       vp += sprintf(vp, "itt2ga%d=%d", path, w >> B2G_ITT_SHIFT);
-                       vp++;
-                       vp += sprintf(vp, "maxp2ga%d=%d", path, w & B2G_MAXP_MASK);
-                       vp++;
-
-                       for (i = 0; i < 4; i++) {
-                               vp += sprintf(vp, "pa2gw%da%d=%d", i, path,
-                                             b[pathbase + SROM4_2G_PA + i]);
-                               vp++;
-                       }
+static const sromvar_t pci_sromvars[] = {
+  {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK},
+  {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
+  {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
+  {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
+  {"boardflags", 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff},
+  {"", 0, 0, SROM_BFL2, 0xffff},
+  {"boardflags", 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff},
+  {"", 0, 0, SROM3_BFL2, 0xffff},
+  {"boardflags", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0, 0xffff},
+  {"", 0, 0, SROM4_BFL1, 0xffff},
+  {"boardflags", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0, 0xffff},
+  {"", 0, 0, SROM5_BFL1, 0xffff},
+  {"boardflags", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, 0xffff},
+  {"", 0, 0, SROM8_BFL1, 0xffff},
+  {"boardflags2", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2, 0xffff},
+  {"", 0, 0, SROM4_BFL3, 0xffff},
+  {"boardflags2", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2, 0xffff},
+  {"", 0, 0, SROM5_BFL3, 0xffff},
+  {"boardflags2", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, 0xffff},
+  {"", 0, 0, SROM8_BFL3, 0xffff},
+  {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
+  {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
+  {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff},
+  {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff},
+  {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff},
+  {"boardnum", 0xffffff00, 0, SROM8_MACLO, 0xffff},
+  {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
+  {"regrev", 0x00000008, 0, SROM_OPO, 0xff00},
+  {"regrev", 0x00000010, 0, SROM4_REGREV, 0xff},
+  {"regrev", 0x000000e0, 0, SROM5_REGREV, 0xff},
+  {"regrev", 0xffffff00, 0, SROM8_REGREV, 0xff},
+  {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff},
+  {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
+  {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff},
+  {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
+  {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff},
+  {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
+  {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff},
+  {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
+  {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff},
+  {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
+  {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff},
+  {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
+  {"ledbh0", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff},
+  {"ledbh1", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
+  {"ledbh2", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff},
+  {"ledbh3", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
+  {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
+  {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
+  {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
+  {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0xff},
+  {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff},
+  {"pa0b0", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
+  {"pa0b1", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
+  {"pa0b2", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
+  {"pa0itssit", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
+  {"pa0maxpwr", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff},
+  {"opo", 0x0000000c, 0, SROM_OPO, 0xff},
+  {"opo", 0xffffff00, 0, SROM8_2G_OFDMPO, 0xff},
+  {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
+  {"aa2g", 0x000000f0, 0, SROM4_AA, 0xff},
+  {"aa2g", 0xffffff00, 0, SROM8_AA, 0xff},
+  {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
+  {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00},
+  {"aa5g", 0xffffff00, 0, SROM8_AA, 0xff00},
+  {"ag0", 0x0000000e, 0, SROM_AG10, 0xff},
+  {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00},
+  {"ag0", 0x000000f0, 0, SROM4_AG10, 0xff},
+  {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00},
+  {"ag2", 0x000000f0, 0, SROM4_AG32, 0xff},
+  {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00},
+  {"ag0", 0xffffff00, 0, SROM8_AG10, 0xff},
+  {"ag1", 0xffffff00, 0, SROM8_AG10, 0xff00},
+  {"ag2", 0xffffff00, 0, SROM8_AG32, 0xff},
+  {"ag3", 0xffffff00, 0, SROM8_AG32, 0xff00},
+  {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
+  {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
+  {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
+  {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
+  {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
+  {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
+  {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
+  {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
+  {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
+  {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00},
+  {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
+  {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
+  {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff},
+  {"pa1b0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
+  {"pa1b1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
+  {"pa1b2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
+  {"pa1lob0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
+  {"pa1lob1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
+  {"pa1lob2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
+  {"pa1hib0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
+  {"pa1hib1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
+  {"pa1hib2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
+  {"pa1itssit", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
+  {"pa1maxpwr", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff},
+  {"pa1lomaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
+  {"pa1himaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff},
+  {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
+  {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
+  {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
+  {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
+  {"bxa2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
+  {"rssisav2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
+  {"rssismc2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
+  {"rssismf2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
+  {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
+  {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
+  {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
+  {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
+  {"bxa5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
+  {"rssisav5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
+  {"rssismc5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
+  {"rssismf5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
+  {"tri2g", 0x00000008, 0, SROM_TRI52G, 0xff},
+  {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00},
+  {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0xff},
+  {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00},
+  {"tri2g", 0xffffff00, 0, SROM8_TRI52G, 0xff},
+  {"tri5g", 0xffffff00, 0, SROM8_TRI52G, 0xff00},
+  {"tri5gl", 0xffffff00, 0, SROM8_TRI5GHL, 0xff},
+  {"tri5gh", 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
+  {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff},
+  {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
+  {"rxpo2g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff},
+  {"rxpo5g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
+  {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK},
+  {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK},
+  {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK},
+  {"txchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK},
+  {"rxchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK},
+  {"antswitch", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK},
+  {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0xff},
+  {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
+  {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff},
+  {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
+  {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0xff},
+  {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
+  {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff},
+  {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
+  {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0xff},
+  {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
+  {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff},
+  {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
+  {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0xff},
+  {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
+  {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff},
+  {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
+  {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
+  {"cck2gpo", 0xffffff00, 0, SROM8_2G_CCKPO, 0xffff},
+  {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
+  {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
+  {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
+  {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
+  {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
+  {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
+  {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
+  {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
+  {"ofdm2gpo", 0xffffff00, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
+  {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
+  {"ofdm5gpo", 0xffffff00, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
+  {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
+  {"ofdm5glpo", 0xffffff00, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
+  {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
+  {"ofdm5ghpo", 0xffffff00, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
+  {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
+  {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
+  {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
+  {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
+  {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
+  {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
+  {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
+  {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
+  {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
+  {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
+  {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
+  {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
+  {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
+  {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
+  {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
+  {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
+  {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
+  {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
+  {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
+  {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
+  {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
+  {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
+  {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
+  {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
+  {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
+  {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
+  {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
+  {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
+  {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
+  {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
+  {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
+  {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
+  {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
+  {"mcs2gpo0", 0xffffff00, 0, SROM8_2G_MCSPO, 0xffff},
+  {"mcs2gpo1", 0xffffff00, 0, SROM8_2G_MCSPO + 1, 0xffff},
+  {"mcs2gpo2", 0xffffff00, 0, SROM8_2G_MCSPO + 2, 0xffff},
+  {"mcs2gpo3", 0xffffff00, 0, SROM8_2G_MCSPO + 3, 0xffff},
+  {"mcs2gpo4", 0xffffff00, 0, SROM8_2G_MCSPO + 4, 0xffff},
+  {"mcs2gpo5", 0xffffff00, 0, SROM8_2G_MCSPO + 5, 0xffff},
+  {"mcs2gpo6", 0xffffff00, 0, SROM8_2G_MCSPO + 6, 0xffff},
+  {"mcs2gpo7", 0xffffff00, 0, SROM8_2G_MCSPO + 7, 0xffff},
+  {"mcs5gpo0", 0xffffff00, 0, SROM8_5G_MCSPO, 0xffff},
+  {"mcs5gpo1", 0xffffff00, 0, SROM8_5G_MCSPO + 1, 0xffff},
+  {"mcs5gpo2", 0xffffff00, 0, SROM8_5G_MCSPO + 2, 0xffff},
+  {"mcs5gpo3", 0xffffff00, 0, SROM8_5G_MCSPO + 3, 0xffff},
+  {"mcs5gpo4", 0xffffff00, 0, SROM8_5G_MCSPO + 4, 0xffff},
+  {"mcs5gpo5", 0xffffff00, 0, SROM8_5G_MCSPO + 5, 0xffff},
+  {"mcs5gpo6", 0xffffff00, 0, SROM8_5G_MCSPO + 6, 0xffff},
+  {"mcs5gpo7", 0xffffff00, 0, SROM8_5G_MCSPO + 7, 0xffff},
+  {"mcs5glpo0", 0xffffff00, 0, SROM8_5GL_MCSPO, 0xffff},
+  {"mcs5glpo1", 0xffffff00, 0, SROM8_5GL_MCSPO + 1, 0xffff},
+  {"mcs5glpo2", 0xffffff00, 0, SROM8_5GL_MCSPO + 2, 0xffff},
+  {"mcs5glpo3", 0xffffff00, 0, SROM8_5GL_MCSPO + 3, 0xffff},
+  {"mcs5glpo4", 0xffffff00, 0, SROM8_5GL_MCSPO + 4, 0xffff},
+  {"mcs5glpo5", 0xffffff00, 0, SROM8_5GL_MCSPO + 5, 0xffff},
+  {"mcs5glpo6", 0xffffff00, 0, SROM8_5GL_MCSPO + 6, 0xffff},
+  {"mcs5glpo7", 0xffffff00, 0, SROM8_5GL_MCSPO + 7, 0xffff},
+  {"mcs5ghpo0", 0xffffff00, 0, SROM8_5GH_MCSPO, 0xffff},
+  {"mcs5ghpo1", 0xffffff00, 0, SROM8_5GH_MCSPO + 1, 0xffff},
+  {"mcs5ghpo2", 0xffffff00, 0, SROM8_5GH_MCSPO + 2, 0xffff},
+  {"mcs5ghpo3", 0xffffff00, 0, SROM8_5GH_MCSPO + 3, 0xffff},
+  {"mcs5ghpo4", 0xffffff00, 0, SROM8_5GH_MCSPO + 4, 0xffff},
+  {"mcs5ghpo5", 0xffffff00, 0, SROM8_5GH_MCSPO + 5, 0xffff},
+  {"mcs5ghpo6", 0xffffff00, 0, SROM8_5GH_MCSPO + 6, 0xffff},
+  {"mcs5ghpo7", 0xffffff00, 0, SROM8_5GH_MCSPO + 7, 0xffff},
+  {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff},
+  {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff},
+  {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff},
+  {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
+  {"cddpo", 0xffffff00, 0, SROM8_CDDPO, 0xffff},
+  {"stbcpo", 0xffffff00, 0, SROM8_STBCPO, 0xffff},
+  {"bw40po", 0xffffff00, 0, SROM8_BW40PO, 0xffff},
+  {"bwduppo", 0xffffff00, 0, SROM8_BWDUPPO, 0xffff},
+  {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
+  {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
+  {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
+  {"ccode", 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
+  {"macaddr", 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
+  {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
+  {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
+  {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
+  {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff},
+  {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff},
+  {"leddc", 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, 0xffff},
+  {"leddc", 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC, 0xffff},
+  {"leddc", 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC, 0xffff},
+  {"leddc", 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC, 0xffff},
+  {NULL, 0, 0, 0, 0}
+};
+
+static const sromvar_t perpath_pci_sromvars[] = {
+  {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff},
+  {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
+  {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
+  {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
+  {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
+  {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
+  {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
+  {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff},
+  {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff},
+  {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
+  {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
+  {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
+  {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
+  {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
+  {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
+  {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff},
+  {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff},
+  {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff},
+  {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
+  {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff},
+  {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff},
+  {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff},
+  {"maxp2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff},
+  {"itt2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
+  {"itt5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
+  {"pa2gw0a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
+  {"pa2gw1a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
+  {"pa2gw2a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
+  {"maxp5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff},
+  {"maxp5gha", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff},
+  {"maxp5gla", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
+  {"pa5gw0a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
+  {"pa5gw1a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
+  {"pa5gw2a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
+  {"pa5glw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
+  {"pa5glw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff},
+  {"pa5glw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff},
+  {"pa5ghw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
+  {"pa5ghw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff},
+  {"pa5ghw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff},
+  {NULL, 0, 0, 0, 0}
+};
+
+/* Parse SROM and create name=value pairs. 'srom' points to
+ * the SROM word array. 'off' specifies the offset of the
+ * first word 'srom' points to, which should be either 0 or
+ * SROM3_SWRG_OFF (full SROM or software region).
+ */
 
-                       w = b[pathbase + SROM4_5G_ITT_MAXP];
-                       vp += sprintf(vp, "itt5ga%d=%d", path, w >> B5G_ITT_SHIFT);
-                       vp++;
-                       vp += sprintf(vp, "maxp5ga%d=%d", path, w & B5G_MAXP_MASK);
-                       vp++;
-
-                       w = b[pathbase + SROM4_5GLH_MAXP];
-                       vp += sprintf(vp, "maxp5lga%d=%d", path, w >> B5GL_MAXP_SHIFT);
-                       vp++;
-                       vp += sprintf(vp, "maxp5gha%d=%d", path, w & B5GH_MAXP_MASK);
-                       vp++;
-
-                       for (i = 0; i < 4; i++) {
-                               vp += sprintf(vp, "pa5gw%da%d=%d", i, path,
-                                             b[pathbase + SROM4_5G_PA + i]);
-                               vp++;
-                               vp += sprintf(vp, "pa5glw%da%d=%d", i, path,
-                                             b[pathbase + SROM4_5GL_PA + i]);
-                               vp++;
-                               vp += sprintf(vp, "pa5hgw%da%d=%d", i, path,
-                                             b[pathbase + SROM4_5GH_PA + i]);
-                               vp++;
-                       }
-               }
+static uint
+mask_shift (uint16 mask)
+{
+  uint i;
+  for (i = 0; i < (sizeof (mask) << 3); i++)
+    {
+      if (mask & (1 << i))
+       return i;
+    }
+  ASSERT (mask);
+  return 0;
+}
 
-               vp += sprintf(vp, "cck2gpo=%d", b[SROM4_2G_CCKPO]);
-               vp++;
-
-               w32 = ((uint32)b[SROM4_2G_OFDMPO + 1] << 16) | b[SROM4_2G_OFDMPO];
-               vp += sprintf(vp, "ofdm2gpo=%d", w32);
-               vp++;
-
-               w32 = ((uint32)b[SROM4_5G_OFDMPO + 1] << 16) | b[SROM4_5G_OFDMPO];
-               vp += sprintf(vp, "ofdm5gpo=%d", w32);
-               vp++;
-
-               w32 = ((uint32)b[SROM4_5GL_OFDMPO + 1] << 16) | b[SROM4_5GL_OFDMPO];
-               vp += sprintf(vp, "ofdm5glpo=%d", w32);
-               vp++;
-
-               w32 = ((uint32)b[SROM4_5GH_OFDMPO + 1] << 16) | b[SROM4_5GH_OFDMPO];
-               vp += sprintf(vp, "ofdm5ghpo=%d", w32);
-               vp++;
-
-               for (i = 0; i < 8; i++) {
-                       vp += sprintf(vp, "mcs2gpo%d=%d", i, b[SROM4_2G_MCSPO]);
-                       vp++;
-                       vp += sprintf(vp, "mcs5gpo%d=%d", i, b[SROM4_5G_MCSPO]);
-                       vp++;
-                       vp += sprintf(vp, "mcs5glpo%d=%d", i, b[SROM4_5GL_MCSPO]);
-                       vp++;
-                       vp += sprintf(vp, "mcs5ghpo%d=%d", i, b[SROM4_5GH_MCSPO]);
-                       vp++;
-               }
+static uint
+mask_width (uint16 mask)
+{
+  int i;
+  for (i = (sizeof (mask) << 3) - 1; i >= 0; i--)
+    {
+      if (mask & (1 << i))
+       return (uint) (i - mask_shift (mask) + 1);
+    }
+  ASSERT (mask);
+  return 0;
+}
 
-               vp += sprintf(vp, "ccdpo%d=%d", i, b[SROM4_CCDPO]);
-               vp++;
-               vp += sprintf(vp, "stbcpo%d=%d", i, b[SROM4_STBCPO]);
-               vp++;
-               vp += sprintf(vp, "bw40po%d=%d", i, b[SROM4_BW40PO]);
-               vp++;
-               vp += sprintf(vp, "bwduppo%d=%d", i, b[SROM4_BWDUPPO]);
-               vp++;
+#ifdef BCMDBG_ASSERT
+static bool
+mask_valid (uint16 mask)
+{
+  uint shift = mask_shift (mask);
+  uint width = mask_width (mask);
+  return mask == ((~0 << shift) & ~(~0 << (shift + width)));
+}
+#endif
 
-               goto done;
+static void
+_initvars_srom_pci (uint8 sromrev, uint16 * srom, uint off, varbuf_t * b)
+{
+  uint16 w;
+  uint32 val;
+  const sromvar_t *srv;
+  uint width;
+  uint flags;
+  uint32 sr = (1 << sromrev);
+
+  varbuf_append (b, "sromrev=%d", sromrev);
+
+  for (srv = pci_sromvars; srv->name != NULL; srv++)
+    {
+      const char *name;
+
+      if ((srv->revmask & sr) == 0)
+       continue;
+
+      if (srv->off < off)
+       continue;
+
+      flags = srv->flags;
+      name = srv->name;
+
+      if (flags & SRFL_ETHADDR)
+       {
+         char eabuf[ETHER_ADDR_STR_LEN];
+         struct ether_addr ea;
+
+         ea.octet[0] = (srom[srv->off - off] >> 8) & 0xff;
+         ea.octet[1] = srom[srv->off - off] & 0xff;
+         ea.octet[2] = (srom[srv->off + 1 - off] >> 8) & 0xff;
+         ea.octet[3] = srom[srv->off + 1 - off] & 0xff;
+         ea.octet[4] = (srom[srv->off + 2 - off] >> 8) & 0xff;
+         ea.octet[5] = srom[srv->off + 2 - off] & 0xff;
+         bcm_ether_ntoa (&ea, eabuf);
+
+         varbuf_append (b, "%s=%s", name, eabuf);
        }
-       if (sromrev >= 3) {
-               /* New section takes over the 3th hardware function space */
-
-               /* Words 22+23 are 11a (mid) ofdm power offsets */
-               w32 = ((uint32)b[23] << 16) | b[22];
-               vp += sprintf(vp, "ofdmapo=%d", w32);
-               vp++;
-
-               /* Words 24+25 are 11a (low) ofdm power offsets */
-               w32 = ((uint32)b[25] << 16) | b[24];
-               vp += sprintf(vp, "ofdmalpo=%d", w32);
-               vp++;
-
-               /* Words 26+27 are 11a (high) ofdm power offsets */
-               w32 = ((uint32)b[27] << 16) | b[26];
-               vp += sprintf(vp, "ofdmahpo=%d", w32);
-               vp++;
-
-               /* LED Powersave duty cycle (oncount >> 24) (offcount >> 8) */
-               w32 = ((uint32)((unsigned char)(b[21] >> 8) & 0xff) << 24) |  /* oncount */
-                       ((uint32)((unsigned char)(b[21] & 0xff)) << 8); /* offcount */
-               vp += sprintf(vp, "leddc=%d", w32);
-
-               vp++;
+      else
+       {
+         ASSERT (mask_valid (srv->mask));
+         ASSERT (mask_width (srv->mask));
+
+         w = srom[srv->off - off];
+         val = (w & srv->mask) >> mask_shift (srv->mask);
+         width = mask_width (srv->mask);
+
+         while (srv->flags & SRFL_MORE)
+           {
+             srv++;
+             ASSERT (srv->name);
+
+             if (srv->off == 0 || srv->off < off)
+               continue;
+
+             ASSERT (mask_valid (srv->mask));
+             ASSERT (mask_width (srv->mask));
+
+             w = srom[srv->off - off];
+             val += ((w & srv->mask) >> mask_shift (srv->mask)) << width;
+             width += mask_width (srv->mask);
+           }
+
+         if ((flags & SRFL_NOFFS) && ((int) val == (1 << width) - 1))
+           continue;
+
+         if (flags & SRFL_CCODE)
+           {
+             if (val == 0)
+               varbuf_append (b, "ccode=");
+             else
+               varbuf_append (b, "ccode=%c%c", (val >> 8), (val & 0xff));
+           }
+         /* LED Powersave duty cycle has to be scaled:
+          *(oncount >> 24) (offcount >> 8)
+          */
+         else if (flags & SRFL_LEDDC)
+           {
+             uint32 w32 = (((val >> 8) & 0xff) << 24) |        /* oncount */
+               (((val & 0xff)) << 8);  /* offcount */
+             varbuf_append (b, "leddc=%d", w32);
+           }
+         else if (flags & SRFL_PRHEX)
+           varbuf_append (b, "%s=0x%x", name, val);
+         else if ((flags & SRFL_PRSIGN) && (val & (1 << (width - 1))))
+           varbuf_append (b, "%s=%d", name, (int) (val | (~0 << width)));
+         else
+           varbuf_append (b, "%s=%u", name, val);
        }
+    }
 
-       if (sromrev >= 2) {
-               /* New section takes over the 4th hardware function space */
-
-               /* Word 29 is max power 11a high/low */
-               w = b[29];
-               vp += sprintf(vp, "pa1himaxpwr=%d", w & 0xff);
-               vp++;
-               vp += sprintf(vp, "pa1lomaxpwr=%d", (w >> 8) & 0xff);
-               vp++;
-
-               /* Words 30-32 set the 11alow pa settings,
-                * 33-35 are the 11ahigh ones.
-                */
-               for (i = 0; i < 3; i++) {
-                       vp += sprintf(vp, "pa1lob%d=%d", i, b[30 + i]);
-                       vp++;
-                       vp += sprintf(vp, "pa1hib%d=%d", i, b[33 + i]);
-                       vp++;
-               }
-               w = b[59];
-               if (w == 0)
-                       vp += sprintf(vp, "ccode=");
-               else
-                       vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
-               vp++;
+  if (sromrev >= 4)
+    {
+      /* Do per-path variables */
+      uint p, pb, psz;
 
+      if (sromrev >= 8)
+       {
+         pb = SROM8_PATH0;
+         psz = SROM8_PATH1 - SROM8_PATH0;
        }
-
-       /* parameter section of sprom starts at byte offset 72 */
-       woff = 72/2;
-
-       /* first 6 bytes are il0macaddr */
-       ea.octet[0] = (b[woff] >> 8) & 0xff;
-       ea.octet[1] = b[woff] & 0xff;
-       ea.octet[2] = (b[woff+1] >> 8) & 0xff;
-       ea.octet[3] = b[woff+1] & 0xff;
-       ea.octet[4] = (b[woff+2] >> 8) & 0xff;
-       ea.octet[5] = b[woff+2] & 0xff;
-       woff += 3;
-       bcm_ether_ntoa(&ea, eabuf);
-       vp += sprintf(vp, "il0macaddr=%s", eabuf);
-       vp++;
-
-       /* next 6 bytes are et0macaddr */
-       ea.octet[0] = (b[woff] >> 8) & 0xff;
-       ea.octet[1] = b[woff] & 0xff;
-       ea.octet[2] = (b[woff+1] >> 8) & 0xff;
-       ea.octet[3] = b[woff+1] & 0xff;
-       ea.octet[4] = (b[woff+2] >> 8) & 0xff;
-       ea.octet[5] = b[woff+2] & 0xff;
-       woff += 3;
-       bcm_ether_ntoa(&ea, eabuf);
-       vp += sprintf(vp, "et0macaddr=%s", eabuf);
-       vp++;
-
-       /* next 6 bytes are et1macaddr */
-       ea.octet[0] = (b[woff] >> 8) & 0xff;
-       ea.octet[1] = b[woff] & 0xff;
-       ea.octet[2] = (b[woff+1] >> 8) & 0xff;
-       ea.octet[3] = b[woff+1] & 0xff;
-       ea.octet[4] = (b[woff+2] >> 8) & 0xff;
-       ea.octet[5] = b[woff+2] & 0xff;
-       woff += 3;
-       bcm_ether_ntoa(&ea, eabuf);
-       vp += sprintf(vp, "et1macaddr=%s", eabuf);
-       vp++;
-
-       /*
-        * Enet phy settings one or two singles or a dual
-        * Bits 4-0 : MII address for enet0 (0x1f for not there)
-        * Bits 9-5 : MII address for enet1 (0x1f for not there)
-        * Bit 14   : Mdio for enet0
-        * Bit 15   : Mdio for enet1
-        */
-       w = b[woff];
-       vp += sprintf(vp, "et0phyaddr=%d", (w & 0x1f));
-       vp++;
-       vp += sprintf(vp, "et1phyaddr=%d", ((w >> 5) & 0x1f));
-       vp++;
-       vp += sprintf(vp, "et0mdcport=%d", ((w >> 14) & 0x1));
-       vp++;
-       vp += sprintf(vp, "et1mdcport=%d", ((w >> 15) & 0x1));
-       vp++;
-
-       /* Word 46 has board rev, antennas 0/1 & Country code/control */
-       w = b[46];
-       vp += sprintf(vp, "boardrev=%d", w & 0xff);
-       vp++;
-
-       if (sromrev > 1)
-               vp += sprintf(vp, "cctl=%d", (w >> 8) & 0xf);
-       else
-               vp += sprintf(vp, "cc=%d", (w >> 8) & 0xf);
-       vp++;
-
-       vp += sprintf(vp, "aa2g=%d", (w >> 12) & 0x3);
-       vp++;
-
-       vp += sprintf(vp, "aa5g=%d", (w >> 14) & 0x3);
-       vp++;
-
-       /* Words 47-49 set the (wl) pa settings */
-       woff = 47;
-
-       for (i = 0; i < 3; i++) {
-               vp += sprintf(vp, "pa0b%d=%d", i, b[woff+i]);
-               vp++;
-               vp += sprintf(vp, "pa1b%d=%d", i, b[woff+i+6]);
-               vp++;
+      else
+       {
+         pb = SROM4_PATH0;
+         psz = SROM4_PATH1 - SROM4_PATH0;
        }
 
-       /*
-        * Words 50-51 set the customer-configured wl led behavior.
-        * 8 bits/gpio pin.  High bit:  activehi=0, activelo=1;
-        * LED behavior values defined in wlioctl.h .
-        */
-       w = b[50];
-       if ((w != 0) && (w != 0xffff)) {
-               /* ledbh0 */
-               vp += sprintf(vp, "ledbh0=%d", (w & 0xff));
-               vp++;
-
-               /* ledbh1 */
-               vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff);
-               vp++;
-       }
-       w = b[51];
-       if ((w != 0) && (w != 0xffff)) {
-               /* ledbh2 */
-               vp += sprintf(vp, "ledbh2=%d", w & 0xff);
-               vp++;
-
-               /* ledbh */
-               vp += sprintf(vp, "ledbh3=%d", (w >> 8) & 0xff);
-               vp++;
+      for (p = 0; p < MAX_PATH; p++)
+       {
+         for (srv = perpath_pci_sromvars; srv->name != NULL; srv++)
+           {
+             if ((srv->revmask & sr) == 0)
+               continue;
+
+             if (pb + srv->off < off)
+               continue;
+
+             w = srom[pb + srv->off - off];
+             ASSERT (mask_valid (srv->mask));
+             val = (w & srv->mask) >> mask_shift (srv->mask);
+             width = mask_width (srv->mask);
+
+             /* Cheating: no per-path var is more than 1 word */
+
+             if ((srv->flags & SRFL_NOFFS)
+                 && ((int) val == (1 << width) - 1))
+               continue;
+
+             if (srv->flags & SRFL_PRHEX)
+               varbuf_append (b, "%s%d=0x%x", srv->name, p, val);
+             else
+               varbuf_append (b, "%s%d=%d", srv->name, p, val);
+           }
+         pb += psz;
        }
+    }
+}
 
-       /* Word 52 is max power 0/1 */
-       w = b[52];
-       vp += sprintf(vp, "pa0maxpwr=%d", w & 0xff);
-       vp++;
-       vp += sprintf(vp, "pa1maxpwr=%d", (w >> 8) & 0xff);
-       vp++;
-
-       /* Word 56 is idle tssi target 0/1 */
-       w = b[56];
-       vp += sprintf(vp, "pa0itssit=%d", w & 0xff);
-       vp++;
-       vp += sprintf(vp, "pa1itssit=%d", (w >> 8) & 0xff);
-       vp++;
-
-       /* Word 57 is boardflags, if not programmed make it zero */
-       w32 = (uint32)b[57];
-       if (w32 == 0xffff) w32 = 0;
-       if (sromrev > 1) {
-               /* Word 28 is the high bits of boardflags */
-               w32 |= (uint32)b[28] << 16;
+static int
+initvars_srom_pci (sb_t * sbh, void *curmap, char **vars, uint * count)
+{
+  uint16 *srom;
+  uint8 sromrev = 0;
+  uint32 sr;
+  varbuf_t b;
+  char *vp, *base = NULL;
+  osl_t *osh = sb_osh (sbh);
+  bool flash = FALSE;
+  char *value;
+  int err;
+
+  /*
+   * Apply CRC over SROM content regardless SROM is present or not,
+   * and use variable <devpath>sromrev's existance in flash to decide
+   * if we should return an error when CRC fails or read SROM variables
+   * from flash.
+   */
+  srom = MALLOC (osh, SROM_MAX);
+  ASSERT (srom);
+  if (!srom)
+    return -2;
+
+  err =
+    sprom_read_pci (osh, (void *) ((int8 *) curmap + PCI_BAR0_SPROM_OFFSET),
+                   0, srom, SROM_WORDS, TRUE);
+
+  if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
+      ((sbh->buscoretype == SB_PCIE) && (sbh->buscorerev >= 6)))
+    {
+      /* sromrev >= 4, read more */
+      err =
+       sprom_read_pci (osh,
+                       (void *) ((int8 *) curmap + PCI_BAR0_SPROM_OFFSET), 0,
+                       srom, SROM4_WORDS, TRUE);
+      sromrev = srom[SROM4_CRCREV] & 0xff;
+    }
+  else if (err == 0)
+    {
+      /* srom is good and is rev < 4 */
+      /* top word of sprom contains version and crc8 */
+      sromrev = srom[SROM_CRCREV] & 0xff;
+      /* bcm4401 sroms misprogrammed */
+      if (sromrev == 0x10)
+       sromrev = 1;
+    }
+
+  if (err)
+    {
+#ifdef WLTEST
+      uint32 val;
+
+      BS_ERROR (("SROM Crc Error, so see if we could use a default\n"));
+      val = OSL_PCI_READ_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32));
+      if (val & SPROM_OTPIN_USE)
+       {
+         BS_ERROR (("srom crc failed with OTP, use default vars....\n"));
+         vp = base = mfgsromvars;
+         if (sb_chip (sbh) == BCM4311_CHIP_ID)
+           {
+             const char *devid = "devid=0x4311";
+             const size_t devid_strlen = strlen (devid);
+             BS_ERROR (("setting the devid to be 4311\n"));
+             bcopy (devid, vp, devid_strlen + 1);
+             vp += devid_strlen + 1;
+           }
+         bcopy (defaultsromvars, vp, MFGSROM_DEFVARSLEN);
+         vp += MFGSROM_DEFVARSLEN;
+         goto varsdone;
        }
-       vp += sprintf(vp, "boardflags=%d", w32);
-       vp++;
-
-       /* Word 58 is antenna gain 0/1 */
-       w = b[58];
-       vp += sprintf(vp, "ag0=%d", w & 0xff);
-       vp++;
-
-       vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
-       vp++;
-
-       if (sromrev == 1) {
-               /* set the oem string */
-               vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
-                             ((b[59] >> 8) & 0xff), (b[59] & 0xff),
-                             ((b[60] >> 8) & 0xff), (b[60] & 0xff),
-                             ((b[61] >> 8) & 0xff), (b[61] & 0xff),
-                             ((b[62] >> 8) & 0xff), (b[62] & 0xff));
-               vp++;
-       } else if (sromrev == 2) {
-               /* Word 60 OFDM tx power offset from CCK level */
-               /* OFDM Power Offset - opo */
-               vp += sprintf(vp, "opo=%d", b[60] & 0xff);
-               vp++;
-       } else {
-               /* Word 60: cck power offsets */
-               vp += sprintf(vp, "cckpo=%d", b[60]);
-               vp++;
-
-               /* Words 61+62: 11g ofdm power offsets */
-               w32 = ((uint32)b[62] << 16) | b[61];
-               vp += sprintf(vp, "ofdmgpo=%d", w32);
-               vp++;
+      else
+       {
+#endif /* WLTEST */
+         BS_ERROR (("srom crc failed with SPROM....\n"));
+         if (!(value = sb_getdevpathvar (sbh, "sromrev")))
+           {
+             err = -1;
+             goto errout;
+           }
+         sromrev = (uint8) simple_strtoul (value, NULL, 0);
+         flash = TRUE;
+#ifdef WLTEST
        }
-
-       /* final nullbyte terminator */
-done:  *vp++ = '\0';
-
-       ASSERT((vp - base) <= VARS_MAX);
+#endif /* WLTEST */
+    }
+
+  /* Bitmask for the sromrev */
+  sr = 1 << sromrev;
+
+  /* srom version check
+   * Current valid versions: 1, 2, 3, 4, 5, 8
+   */
+  if ((sr & 0x13e) == 0)
+    {
+      err = -2;
+      goto errout;
+    }
+
+  ASSERT (vars);
+  ASSERT (count);
+
+  base = vp = MALLOC (osh, MAXSZ_NVRAM_VARS);
+  ASSERT (vp);
+  if (!vp)
+    {
+      err = -2;
+      goto errout;
+    }
+
+  /* read variables from flash */
+  if (flash)
+    {
+      if ((err = initvars_flash (sbh, osh, &vp, MAXSZ_NVRAM_VARS)))
+       goto errout;
+      goto varsdone;
+    }
+
+  varbuf_init (&b, base, MAXSZ_NVRAM_VARS);
+
+  /* parse SROM into name=value pairs. */
+  _initvars_srom_pci (sromrev, srom, 0, &b);
+
+  /* final nullbyte terminator */
+  ASSERT (b.size >= 1);
+  vp = b.buf;
+  *vp++ = '\0';
+
+  ASSERT ((vp - base) <= MAXSZ_NVRAM_VARS);
 
 varsdone:
-       err = initvars_table(osh, base, vp, vars, count);
+  err = initvars_table (osh, base, vp, vars, count);
 
-err:
+errout:
 #ifdef WLTEST
-       if (base != mfgsromvars)
+  if (base && (base != mfgsromvars))
+#else
+  if (base)
 #endif
-               MFREE(osh, base, VARS_MAX);
-       MFREE(osh, b, SROM_MAX);
-       return err;
+    MFREE (osh, base, MAXSZ_NVRAM_VARS);
+
+  MFREE (osh, srom, SROM_MAX);
+  return err;
 }
 
 /*
@@ -1183,31 +1889,217 @@ err:
  * Return 0 on success, nonzero on error.
  */
 static int
-initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count)
+initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars, uint * count)
 {
-       uint8 *cis = NULL;
-       int rc;
-       uint data_sz;
+  uint8 *cis = NULL;
+  int rc;
+  uint data_sz;
+
+  data_sz = (sb_pcmciarev (sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
+
+  if ((cis = MALLOC (osh, data_sz)) == NULL)
+    return (-2);
+
+  if (sb_pcmciarev (sbh) == 1)
+    {
+      if (srom_read
+         (sbh, PCMCIA_BUS, (void *) NULL, osh, 0, data_sz, (uint16 *) cis))
+       {
+         MFREE (osh, cis, data_sz);
+         return (-1);
+       }
+      /* fix up endianess for 16-bit data vs 8-bit parsing */
+      htol16_buf ((uint16 *) cis, data_sz);
+    }
+  else
+    OSL_PCMCIA_READ_ATTR (osh, 0, cis, data_sz);
+
+  rc = srom_parsecis (osh, &cis, 1, vars, count);
 
-       data_sz = (sb_pcmciarev(sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
+  MFREE (osh, cis, data_sz);
 
-       if ((cis = MALLOC(osh, data_sz)) == NULL)
-               return (-2);
+  return (rc);
+}
+
+
+static int
+BCMINITFN (initvars_srom_sb) (sb_t * sbh, osl_t * osh, void *curmap,
+                             char **vars, uint * varsz)
+{
+#if defined(BCMSDIODEV)
+  /* CIS is read and supplied by the host */
+  return BCME_OK;
+#elif defined(BCMUSBDEV)
+  static bool srvars = FALSE;  /* Use OTP/SPROM as global variables */
+
+  int sel = 0;                 /* where to read the srom. 0 - nowhere, 1 - otp, 2 - sprom */
+  uint sz = 0;                 /* srom size in bytes */
+  void *oh = NULL;
+  int rc = BCME_OK;
+
+  /* Bail out if we've dealt with OTP/SPROM before! */
+  if (srvars)
+    return 0;
+
+#if defined(BCM4328)
+  if (sbh->chip == BCM4328_CHIP_ID)
+    {
+      /* Access the SPROM if it is present */
+      if ((sz = srom_size (sbh, osh)) != 0)
+       {
+         sz <<= 1;
+         sel = 2;
+       }
+    }
+#endif
+#if defined(BCM4325)
+  if (sbh->chip == BCM4325_CHIP_ID)
+    {
+      uint32 cst = sbh->chipst & CST4325_SPROM_OTP_SEL_MASK;
+
+      /* Access OTP if it is present, powered on, and programmed */
+      if ((oh = otp_init (sbh)) != NULL && (otp_status (oh) & OTPS_GUP_SW))
+       {
+         sz = otp_size (oh);
+         sel = 1;
+       }
+      /* Access the SPROM if it is present and allow to be accessed */
+      else if ((cst == CST4325_OTP_PWRDN || cst == CST4325_SPROM_SEL) &&
+              (sz = srom_size (sbh, osh)) != 0)
+       {
+         sz <<= 1;
+         sel = 2;
+       }
+    }
+#endif /* BCM4325 */
+
+  /* Read CIS in OTP/SPROM */
+  if (sel != 0)
+    {
+      uint16 *srom;
+      uint8 *body = NULL;
+
+      ASSERT (sz);
+
+      /* Allocate memory */
+      if ((srom = (uint16 *) MALLOC (osh, sz)) == NULL)
+       return BCME_NOMEM;
+
+      /* Read CIS */
+      switch (sel)
+       {
+       case 1:
+         rc = otp_read_region (oh, OTP_SW_RGN, srom, sz);
+         body = (uint8 *) srom;
+         break;
+       case 2:
+         rc = srom_read (sbh, SB_BUS, curmap, osh, 0, sz, srom);
+         /* sprom has 8 byte h/w header */
+         body = (uint8 *) srom + SBSDIO_SPROM_CIS_OFFSET;
+         break;
+       default:
+         /* impossible to come here */
+         ASSERT (0);
+         break;
+       }
 
-       if (sb_pcmciarev(sbh) == 1) {
-               if (srom_read(PCMCIA_BUS, (void *)NULL, osh, 0, data_sz, (uint16 *)cis)) {
-                       MFREE(osh, cis, data_sz);
-                       return (-1);
+      /* Parse CIS */
+      if (rc == BCME_OK)
+       {
+         uint i, tpls = 0xffffffff;
+         /* # sdiod fns + common + extra */
+         uint8 *cis[SBSDIO_NUM_FUNCTION + 2];
+         uint ciss = 0;
+
+         /* each word is in host endian */
+         htol16_buf ((uint8 *) srom, sz);
+
+         ASSERT (body);
+
+         /* count cis tuple chains */
+         for (i = 0; i < sz && ciss < ARRAYSIZE (cis) && tpls != 0; i++)
+           {
+             cis[ciss++] = &body[i];
+             for (tpls = 0; i < sz - 1; tpls++)
+               {
+                 if (body[i++] == CISTPL_END)
+                   break;
+                 i += body[i] + 1;
                }
-               /* fix up endianess for 16-bit data vs 8-bit parsing */
-               ltoh16_buf((uint16 *)cis, data_sz);
-       } else
-               OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz);
+           }
 
-       rc = srom_parsecis(osh, &cis, 1, vars, count);
+         /* call parser routine only when there are tuple chains */
+         if (ciss > 1)
+           rc = srom_parsecis (osh, cis, ciss, vars, varsz);
+       }
+
+      /* Clean up */
+      MFREE (osh, srom, sz);
 
-       MFREE(osh, cis, data_sz);
+      /* Make SROM variables global */
+      if (rc == BCME_OK)
+       {
+         rc = nvram_append ((void *) sbh, *vars, *varsz);
+         srvars = TRUE;
 
-       return (rc);
+         /* Tell the caller there is no individual SROM variables */
+         *vars = NULL;
+         *varsz = 0;
+       }
+    }
+
+  return rc;
+#else /* !BCMUSBDEV && !BCMSDIODEV */
+  /* Search flash nvram section for srom variables */
+  return initvars_flash_sb (sbh, vars, varsz);
+#endif /* !BCMUSBDEV && !BCMSDIODEV */
 }
 
+#ifdef BCMUSBDEV
+/* Return sprom size in 16-bit words */
+static uint
+srom_size (sb_t * sbh, osl_t * osh)
+{
+  uint size = 0;
+  if (SPROMBUS == PCMCIA_BUS)
+    {
+      uint32 origidx;
+      sdpcmd_regs_t *pcmregs;
+      bool wasup;
+
+      origidx = sb_coreidx (sbh);
+      pcmregs = sb_setcore (sbh, SB_PCMCIA, 0);
+      ASSERT (pcmregs);
+
+      if (!(wasup = sb_iscoreup (sbh)))
+       sb_core_reset (sbh, 0, 0);
+
+      /* not worry about earlier core revs */
+      if (sb_corerev (sbh) < 8)
+       goto done;
+
+      /* SPROM is accessible only in PCMCIA mode unless there is SDIO clock */
+      if (!(R_REG (osh, &pcmregs->corestatus) & CS_PCMCIAMODE))
+       goto done;
+
+      switch (SB_PCMCIA_READ (osh, pcmregs, SROM_INFO) & SRI_SZ_MASK)
+       {
+       case 1:
+         size = 256;           /* SROM_INFO == 1 means 4kbit */
+         break;
+       case 2:
+         size = 1024;          /* SROM_INFO == 2 means 16kbit */
+         break;
+       default:
+         break;
+       }
+
+    done:
+      if (!wasup)
+       sb_core_disable (sbh, 0);
+
+      sb_setcoreidx (sbh, origidx);
+    }
+  return size;
+}
+#endif /* def BCMUSBDEV */
This page took 0.09566 seconds and 4 git commands to generate.