diff --git a/sys/dev/wi/if_wavelan_ieee.h b/sys/dev/wi/if_wavelan_ieee.h index 0af03a625d64..e350c32febcb 100644 --- a/sys/dev/wi/if_wavelan_ieee.h +++ b/sys/dev/wi/if_wavelan_ieee.h @@ -75,6 +75,7 @@ struct wi_req { #define WI_RID_MGMT_XMIT 0x0200 #define WI_RID_ZERO_CACHE 0x0300 #define WI_RID_READ_CACHE 0x0400 +#define WI_RID_FWDOWNLOAD 0x0500 struct wi_80211_hdr { u_int16_t frame_ctl; @@ -147,6 +148,22 @@ struct wi_sigcache { int quality; /* quality of the packet */ }; +/* + * Firmware downloading API. We support downloading into RAM and into + * flash. We copy the entire .hex file for both the primary and secondary + * firmware into the kernel, which is minorly gross, but matches the + * format of the compiled in firmware. + */ +struct wi_fwdownload { + int type; /* What type of download. */ +#define WI_FW_RAM 1 +#define WI_FW_FLASH 2 + size_t pri_len; /* Primary firmware length */ + size_t sec_len; /* Secondary firmware length */ + caddr_t pri_data; /* Pointer (user) to primary data */ + caddr_t sec_data; /* Pointer (user) to secondary data */ +}; + #ifndef _KERNEL struct wi_counters { u_int32_t wi_tx_unicast_frames; diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index b3a3db1a6cd5..c2175644459b 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -142,6 +142,11 @@ static void wi_media_status(struct ifnet *, struct ifmediareq *); static int wi_get_debug(struct wi_softc *, struct wi_req *); static int wi_set_debug(struct wi_softc *, struct wi_req *); +/* support to download firmware for symbol CF card */ +static int wi_symbol_write_firm(struct wi_softc *, const void *, int, + const void *, int); +static int wi_symbol_set_hcr(struct wi_softc *, int); + devclass_t wi_devclass; struct wi_card_ident wi_card_ident[] = { @@ -3109,3 +3114,140 @@ wi_set_debug(sc, wreq) return (error); } + +/* + * 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)) + +int +wi_symbol_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_symbol_set_hcr(sc, WI_HCR_EEHOLD); + if (wi_symbol_write_firm(sc, primsym, primlen, NULL, 0)) + return EIO; + wi_symbol_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_symbol_write_firm(sc, secsym, seclen, ebuf + 4, GETLE16(ebuf))) + return EIO; + return 0; +} + +static int +wi_symbol_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_symbol_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; +} diff --git a/sys/dev/wi/if_wi_pccard.c b/sys/dev/wi/if_wi_pccard.c index 51550689abe5..755eb97004bd 100644 --- a/sys/dev/wi/if_wi_pccard.c +++ b/sys/dev/wi/if_wi_pccard.c @@ -82,13 +82,6 @@ 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 */ @@ -235,7 +228,7 @@ wi_pccard_attach(device_t dev) if (vendor == PCMCIA_VENDOR_SYMBOL && product == PCMCIA_PRODUCT_SYMBOL_LA4100) { #ifdef WI_SYMBOL_FIRMWARE - if (wi_pcmcia_load_firm(sc, + if (wi_symbol_load_firm(sc, spectrum24t_primsym, sizeof(spectrum24t_primsym), spectrum24t_secsym, sizeof(spectrum24t_secsym))) { device_printf(dev, "couldn't load firmware\n"); @@ -249,143 +242,3 @@ wi_pccard_attach(device_t dev) 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 diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h index 3db8acd7a993..e615e0b125f7 100644 --- a/sys/dev/wi/if_wivar.h +++ b/sys/dev/wi/if_wivar.h @@ -222,3 +222,4 @@ int wi_alloc(device_t, int); void wi_free(device_t); extern devclass_t wi_devclass; int wi_mgmt_xmit(struct wi_softc *, caddr_t, int); +int wi_symbol_load_firm(struct wi_softc *, const void *, int, const void *, int);