Add code that will download firmware to a Symbol LA4100-series of CF

cards.  Since the firmware is hard coded into the kernel, I've made it
a kernel option (WI_SYMBOL_FIRMWARE).

Note: This only downloads into the RAM of these cards.  It doesn't
download into FLASH, and is somewhat limited.  There needs to be a
better way to deal, but this works for now.  My Symbol LA4132 CF card
works now.

Obtained from: NetBSD
This commit is contained in:
Warner Losh 2002-08-03 00:19:58 +00:00
parent b8182b24d7
commit 073eef8ca2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=101245
4 changed files with 4537 additions and 1 deletions

View file

@ -553,8 +553,12 @@ DEV_BPF opt_bpf.h
# ed driver
ED_NO_MIIBUS opt_ed.h
# wi driver
WI_SYMBOL_FIRMWARE opt_wi.h
# Polling device handling
DEVICE_POLLING opt_global.h
# Mutex profiling
MUTEX_PROFILING opt_global.h

View file

@ -38,6 +38,8 @@
* Columbia University, New York City
*/
#include "opt_wi.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/socket.h>
@ -66,6 +68,9 @@
#include <dev/wi/wi_hostap.h>
#include <dev/wi/if_wivar.h>
#include <dev/wi/if_wireg.h>
#ifdef WI_SYMBOL_FIRMWARE
#include <dev/wi/spectrum24t_cf.h>
#endif
#include "card_if.h"
@ -77,6 +82,13 @@ static const char rcsid[] =
static int wi_pccard_probe(device_t);
static int wi_pccard_attach(device_t);
#ifdef WI_SYMBOL_FIRMWARE
/* support to download firmware for symbol CF card */
static int wi_pcmcia_load_firm(struct wi_softc *, const void *, int, const void *, int);
static int wi_pcmcia_write_firm(struct wi_softc *, const void *, int, const void *, int);
static int wi_pcmcia_set_hcr(struct wi_softc *, int);
#endif
#if __FreeBSD_version < 500000
static device_method_t wi_pccard_methods[] = {
/* Device interface */
@ -203,6 +215,8 @@ wi_pccard_attach(device_t dev)
{
struct wi_softc *sc;
int error;
uint32_t vendor;
uint32_t product;
sc = device_get_softc(dev);
@ -211,5 +225,167 @@ wi_pccard_attach(device_t dev)
device_printf(dev, "wi_alloc() failed! (%d)\n", error);
return (error);
}
/*
* The cute little Symbol LA4100-series CF cards need to have
* code downloaded to them.
*/
pccard_get_vendor(dev, &vendor);
pccard_get_product(dev, &product);
if (vendor == PCMCIA_VENDOR_SYMBOL &&
product == PCMCIA_PRODUCT_SYMBOL_LA4100) {
#ifdef WI_SYMBOL_FIRMWARE
if (wi_pcmcia_load_firm(sc,
spectrum24t_primsym, sizeof(spectrum24t_primsym),
spectrum24t_secsym, sizeof(spectrum24t_secsym))) {
device_printf(dev, "couldn't load firmware\n");
}
#else
device_printf(dev,
"Symbol LA4100 needs 'option WI_SYMBOL_FIRMWARE'\n");
return (ENXIO);
#endif
}
return (wi_generic_attach(dev));
}
#ifdef WI_SYMBOL_FIRMWARE
/*
* Special routines to download firmware for Symbol CF card.
* XXX: This should be modified generic into any PRISM-2 based card.
*/
#define WI_SBCF_PDIADDR 0x3100
/* unaligned load little endian */
#define GETLE32(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
#define GETLE16(p) ((p)[0] | ((p)[1]<<8))
static int
wi_pcmcia_load_firm(struct wi_softc *sc, const void *primsym, int primlen,
const void *secsym, int seclen)
{
uint8_t ebuf[256];
int i;
/* load primary code and run it */
wi_pcmcia_set_hcr(sc, WI_HCR_EEHOLD);
if (wi_pcmcia_write_firm(sc, primsym, primlen, NULL, 0))
return EIO;
wi_pcmcia_set_hcr(sc, WI_HCR_RUN);
for (i = 0; ; i++) {
if (i == 10)
return ETIMEDOUT;
tsleep(sc, PWAIT, "wiinit", 1);
if (CSR_READ_2(sc, WI_CNTL) == WI_CNTL_AUX_ENA_STAT)
break;
/* write the magic key value to unlock aux port */
CSR_WRITE_2(sc, WI_PARAM0, WI_AUX_KEY0);
CSR_WRITE_2(sc, WI_PARAM1, WI_AUX_KEY1);
CSR_WRITE_2(sc, WI_PARAM2, WI_AUX_KEY2);
CSR_WRITE_2(sc, WI_CNTL, WI_CNTL_AUX_ENA_CNTL);
}
/* issue read EEPROM command: XXX copied from wi_cmd() */
CSR_WRITE_2(sc, WI_PARAM0, 0);
CSR_WRITE_2(sc, WI_PARAM1, 0);
CSR_WRITE_2(sc, WI_PARAM2, 0);
CSR_WRITE_2(sc, WI_COMMAND, WI_CMD_READEE);
for (i = 0; i < WI_TIMEOUT; i++) {
if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
break;
DELAY(1);
}
CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
CSR_WRITE_2(sc, WI_AUX_PAGE, WI_SBCF_PDIADDR / WI_AUX_PGSZ);
CSR_WRITE_2(sc, WI_AUX_OFFSET, WI_SBCF_PDIADDR % WI_AUX_PGSZ);
CSR_READ_MULTI_STREAM_2(sc, WI_AUX_DATA,
(uint16_t *)ebuf, sizeof(ebuf) / 2);
if (GETLE16(ebuf) > sizeof(ebuf))
return EIO;
if (wi_pcmcia_write_firm(sc, secsym, seclen, ebuf + 4, GETLE16(ebuf)))
return EIO;
return 0;
}
static int
wi_pcmcia_write_firm(struct wi_softc *sc, const void *buf, int buflen,
const void *ebuf, int ebuflen)
{
const uint8_t *p, *ep, *q, *eq;
char *tp;
uint32_t addr, id, eid;
int i, len, elen, nblk, pdrlen;
/*
* Parse the header of the firmware image.
*/
p = buf;
ep = p + buflen;
while (p < ep && *p++ != ' '); /* FILE: */
while (p < ep && *p++ != ' '); /* filename */
while (p < ep && *p++ != ' '); /* type of the firmware */
nblk = strtoul(p, &tp, 10);
p = tp;
pdrlen = strtoul(p + 1, &tp, 10);
p = tp;
while (p < ep && *p++ != 0x1a); /* skip rest of header */
/*
* Block records: address[4], length[2], data[length];
*/
for (i = 0; i < nblk; i++) {
addr = GETLE32(p); p += 4;
len = GETLE16(p); p += 2;
CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
(const uint16_t *)p, len / 2);
p += len;
}
/*
* PDR: id[4], address[4], length[4];
*/
for (i = 0; i < pdrlen; ) {
id = GETLE32(p); p += 4; i += 4;
addr = GETLE32(p); p += 4; i += 4;
len = GETLE32(p); p += 4; i += 4;
/* replace PDR entry with the values from EEPROM, if any */
for (q = ebuf, eq = q + ebuflen; q < eq; q += elen * 2) {
elen = GETLE16(q); q += 2;
eid = GETLE16(q); q += 2;
elen--; /* elen includes eid */
if (eid == 0)
break;
if (eid != id)
continue;
CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
(const uint16_t *)q, len / 2);
break;
}
}
return 0;
}
static int
wi_pcmcia_set_hcr(struct wi_softc *sc, int mode)
{
uint16_t hcr;
CSR_WRITE_2(sc, WI_COR, WI_COR_RESET);
tsleep(sc, PWAIT, "wiinit", 1);
hcr = CSR_READ_2(sc, WI_HCR);
hcr = (hcr & WI_HCR_4WIRE) | (mode & ~WI_HCR_4WIRE);
CSR_WRITE_2(sc, WI_HCR, hcr);
tsleep(sc, PWAIT, "wiinit", 1);
CSR_WRITE_2(sc, WI_COR, WI_COR_IOMODE);
tsleep(sc, PWAIT, "wiinit", 1);
return 0;
}
#endif

View file

@ -132,6 +132,19 @@
#define CSM_READ_1(sc, off) \
bus_space_read_1((sc)->wi_bmemtag, (sc)->wi_bmemhandle, off)
#define CSR_WRITE_STREAM_2(sc, reg, val) \
bus_space_write_stream_2(sc->wi_btag, sc->wi_bhandle, \
(sc->wi_bus_type == WI_BUS_PCI_NATIVE ? (reg) * 2 : (reg)), val)
#define CSR_WRITE_MULTI_STREAM_2(sc, reg, val, count) \
bus_space_write_multi_stream_2(sc->wi_btag, sc->wi_bhandle, \
(sc->wi_bus_type == WI_BUS_PCI_NATIVE ? (reg) * 2 : (reg)), val, count)
#define CSR_READ_STREAM_2(sc, reg) \
bus_space_read_stream_2(sc->wi_btag, sc->wi_bhandle, \
(sc->wi_bus_type == WI_BUS_PCI_NATIVE ? (reg) * 2 : (reg)))
#define CSR_READ_MULTI_STREAM_2(sc, reg, buf, count) \
bus_space_read_multi_stream_2(sc->wi_btag, sc->wi_bhandle, \
(sc->wi_bus_type == WI_BUS_PCI_NATIVE ? (reg) * 2 : (reg)), buf, count)
/*
* The WaveLAN/IEEE cards contain an 802.11 MAC controller which Lucent
* calls 'Hermes.' In typical fashion, getting documentation about this
@ -202,6 +215,7 @@
#define WI_CMD_INQUIRE 0x0011
#define WI_CMD_ACCESS 0x0021
#define WI_CMD_PROGRAM 0x0022
#define WI_CMD_READEE 0x0030 /* symbol only */
#define WI_CMD_CODE_MASK 0x003F
@ -297,7 +311,22 @@
#define WI_AUX_OFFSET 0x3C
#define WI_AUX_DATA 0x3E
#define WI_COR_OFFSET 0x3e0
#define WI_AUX_PGSZ 128
#define WI_AUX_KEY0 0xfe01
#define WI_AUX_KEY1 0xdc23
#define WI_AUX_KEY2 0xba45
#define WI_COR 0x40 /* only for Symbol */
#define WI_COR_RESET 0x0080
#define WI_COR_IOMODE 0x0041
#define WI_HCR 0x42 /* only for Symbol */
#define WI_HCR_4WIRE 0x0010
#define WI_HCR_RUN 0x0007
#define WI_HCR_HOLD 0x000f
#define WI_HCR_EEHOLD 0x00ce
#define WI_COR_OFFSET 0x3e0 /* Bogus for sure! */
#define WI_COR_VALUE 0x41
/*

4327
sys/dev/wi/spectrum24t_cf.h Normal file

File diff suppressed because it is too large Load diff