mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-20 14:27:31 +02:00
1214 lines
29 KiB
C
1214 lines
29 KiB
C
|
/*
|
||
|
* Misc useful routines to access NIC SROM/OTP .
|
||
|
*
|
||
|
* Copyright 2006, 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 $
|
||
|
*/
|
||
|
|
||
|
#include <typedefs.h>
|
||
|
#include <bcmdefs.h>
|
||
|
#include <osl.h>
|
||
|
#include <bcmutils.h>
|
||
|
#include <bcmsrom.h>
|
||
|
#include <bcmdevs.h>
|
||
|
#include <bcmendian.h>
|
||
|
#include <sbpcmcia.h>
|
||
|
#include <pcicfg.h>
|
||
|
#include <sbutils.h>
|
||
|
#include <bcmnvram.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 */
|
||
|
|
||
|
#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);
|
||
|
|
||
|
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);
|
||
|
|
||
|
/*
|
||
|
* 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)
|
||
|
{
|
||
|
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);
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/* support only 16-bit word read from srom */
|
||
|
int
|
||
|
srom_read(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;
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/* 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;
|
||
|
}
|
||
|
|
||
|
bcm_mdelay(WRITE_ENABLE_DELAY);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int
|
||
|
srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count)
|
||
|
{
|
||
|
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;
|
||
|
|
||
|
}
|
||
|
i += tlen;
|
||
|
} while (tup != 0xff);
|
||
|
}
|
||
|
|
||
|
/* Set the srom version */
|
||
|
vp += sprintf(vp, "sromrev=%d", sromrev);
|
||
|
vp++;
|
||
|
|
||
|
/* if there is no antenna gain field, set default */
|
||
|
if (ag_init == FALSE) {
|
||
|
ASSERT(sromrev == 1);
|
||
|
vp += sprintf(vp, "ag0=%d", 0xff);
|
||
|
vp++;
|
||
|
}
|
||
|
|
||
|
/* 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;
|
||
|
}
|
||
|
}
|
||
|
*count = varsize;
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* set PCMCIA sprom command register */
|
||
|
static int
|
||
|
sprom_cmd_pcmcia(osl_t *osh, uint8 cmd)
|
||
|
{
|
||
|
uint8 status = 0;
|
||
|
uint wait_cnt = 1000;
|
||
|
|
||
|
/* 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;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* read a word from the PCMCIA srom */
|
||
|
static int
|
||
|
sprom_read_pcmcia(osl_t *osh, 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 */
|
||
|
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;
|
||
|
|
||
|
/* 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;
|
||
|
}
|
||
|
|
||
|
/* write a word to the PCMCIA srom */
|
||
|
static int
|
||
|
sprom_write_pcmcia(osl_t *osh, 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);
|
||
|
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);
|
||
|
|
||
|
/* 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);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Read in and validate sprom.
|
||
|
* 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)
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Create variable table from memory.
|
||
|
* Return 0 on success, nonzero on error.
|
||
|
*/
|
||
|
static int
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Find variables with <devpath> from flash. 'base' points to the beginning
|
||
|
* of the table upon enter and to the end of the table upon exit when success.
|
||
|
* Return 0 on success, nonzero on error.
|
||
|
*/
|
||
|
static int
|
||
|
initvars_flash(osl_t *osh, char **base, uint len, char *devpath)
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/* add null string as terminator */
|
||
|
if (len < 1) {
|
||
|
err = BCME_BUFTOOSHORT;
|
||
|
goto exit;
|
||
|
}
|
||
|
*vp++ = '\0';
|
||
|
|
||
|
*base = vp;
|
||
|
|
||
|
exit: MFREE(osh, flash, NVRAM_SPACE);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Initialize nonvolatile variable table from flash.
|
||
|
* Return 0 on success, nonzero on error.
|
||
|
*/
|
||
|
static int
|
||
|
initvars_flash_sb(void *sbh, char **vars, uint *count)
|
||
|
{
|
||
|
osl_t *osh = sb_osh(sbh);
|
||
|
char devpath[SB_DEVPATH_BUFSZ];
|
||
|
char *vp, *base;
|
||
|
int err;
|
||
|
|
||
|
ASSERT(vars);
|
||
|
ASSERT(count);
|
||
|
|
||
|
if ((err = sb_devpath(sbh, devpath, sizeof(devpath))))
|
||
|
return err;
|
||
|
|
||
|
base = vp = MALLOC(osh, VARS_MAX);
|
||
|
ASSERT(vp);
|
||
|
if (!vp)
|
||
|
return BCME_NOMEM;
|
||
|
|
||
|
if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath)))
|
||
|
goto err;
|
||
|
|
||
|
err = initvars_table(osh, base, vp, vars, count);
|
||
|
|
||
|
err: MFREE(osh, base, VARS_MAX);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
#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 */
|
||
|
#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++;
|
||
|
}
|
||
|
|
||
|
/* 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++;
|
||
|
}
|
||
|
|
||
|
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++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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++;
|
||
|
}
|
||
|
|
||
|
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++;
|
||
|
|
||
|
goto done;
|
||
|
}
|
||
|
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++;
|
||
|
}
|
||
|
|
||
|
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++;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* 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++;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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++;
|
||
|
}
|
||
|
|
||
|
/* 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;
|
||
|
}
|
||
|
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++;
|
||
|
}
|
||
|
|
||
|
/* final nullbyte terminator */
|
||
|
done: *vp++ = '\0';
|
||
|
|
||
|
ASSERT((vp - base) <= VARS_MAX);
|
||
|
|
||
|
varsdone:
|
||
|
err = initvars_table(osh, base, vp, vars, count);
|
||
|
|
||
|
err:
|
||
|
#ifdef WLTEST
|
||
|
if (base != mfgsromvars)
|
||
|
#endif
|
||
|
MFREE(osh, base, VARS_MAX);
|
||
|
MFREE(osh, b, SROM_MAX);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Read the cis and call parsecis to initialize the vars.
|
||
|
* Return 0 on success, nonzero on error.
|
||
|
*/
|
||
|
static int
|
||
|
initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count)
|
||
|
{
|
||
|
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(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 */
|
||
|
ltoh16_buf((uint16 *)cis, data_sz);
|
||
|
} else
|
||
|
OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz);
|
||
|
|
||
|
rc = srom_parsecis(osh, &cis, 1, vars, count);
|
||
|
|
||
|
MFREE(osh, cis, data_sz);
|
||
|
|
||
|
return (rc);
|
||
|
}
|
||
|
|