diff options
Diffstat (limited to 'sys/dev/ic/bcw.c')
-rw-r--r-- | sys/dev/ic/bcw.c | 81 |
1 files changed, 62 insertions, 19 deletions
diff --git a/sys/dev/ic/bcw.c b/sys/dev/ic/bcw.c index 9b16bb32875..22750160a24 100644 --- a/sys/dev/ic/bcw.c +++ b/sys/dev/ic/bcw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bcw.c,v 1.25 2007/01/03 18:54:29 mglocker Exp $ */ +/* $OpenBSD: bcw.c,v 1.26 2007/01/05 07:09:15 mglocker Exp $ */ /* * Copyright (c) 2006 Jon Simola <jsimola@gmail.com> @@ -98,6 +98,7 @@ void bcw_powercontrol_crystal_off(struct bcw_softc *); int bcw_change_core(struct bcw_softc *, int); void bcw_radio_off(struct bcw_softc *); int bcw_reset_core(struct bcw_softc *, uint32_t); +int bcw_get_firmware(const char *, const uint8_t *, size_t *, size_t *); int bcw_load_firmware(struct bcw_softc *); int bcw_write_initvals(struct bcw_softc *, const struct bcw_initval *, const unsigned int); @@ -1149,6 +1150,8 @@ bcw_init(struct ifnet *ifp) return (1); } + return (0); + /* load init values */ if ((error = bcw_load_initvals(sc))) return (error); @@ -2248,19 +2251,50 @@ disabled: } int +bcw_get_firmware(const char *name, const uint8_t *ucode, size_t *size, + size_t *offset) +{ + int i, nfiles, off = 0, ret = 1; + struct fwheader *h; + + if ((h = malloc(sizeof(struct fwheader), M_DEVBUF, M_NOWAIT)) == NULL) + return (ret); + + /* get number of firmware files */ + bcopy(ucode, &nfiles, sizeof(nfiles)); + off += sizeof(nfiles); + + /* parse header and search the firmware */ + for (i = 0; i < nfiles; i++) { + bzero(h, sizeof(struct fwheader)); + bcopy(ucode + off, h, sizeof(struct fwheader)); + off += sizeof(struct fwheader); + + if (strcmp(name, h->filename) == 0) { + ret = 0; + *size = h->filesize; + *offset = h->fileoffset; + break; + } + } + + free(h, M_DEVBUF); + + return (ret); +} + +int bcw_load_firmware(struct bcw_softc *sc) { int rev = sc->sc_core[sc->sc_currentcore].rev; int error, len, i; uint32_t *data; - uint8_t *ucode, *pcm; - size_t size_ucode, size_pcm; - char name[32]; - - /* read microcode file */ - snprintf(name, sizeof(name), "bcm43xx_microcode%d.fw", - rev >= 5 ? 5 : rev); + uint8_t *ucode; + size_t size_ucode, size_micro, size_pcm, off_micro, off_pcm; + char *name = "bcw-bcm43xx"; + char filename[64]; + /* load firmware */ if ((error = loadfirmware(name, &ucode, &size_ucode)) != 0) { printf("%s: error %d, could not read microcode %s!\n", sc->sc_dev.dv_xname, error, name); @@ -2268,30 +2302,38 @@ bcw_load_firmware(struct bcw_softc *sc) } DPRINTF(("%s: successfully read %s\n", sc->sc_dev.dv_xname, name)); - /* read pcm file */ - snprintf(name, sizeof(name), "bcm43xx_pcm%d.fw", + /* get microcode file offset */ + snprintf(filename, sizeof(filename), "bcm43xx_microcode%d.fw", + rev >= 5 ? 5 : rev); + + if (bcw_get_firmware(filename, ucode, &size_micro, &off_micro) != 0) { + printf("%s: getting firmware file %s failed!\n", + sc->sc_dev.dv_xname, name); + return (EIO); + } + + /* get pcm file offset */ + snprintf(filename, sizeof(filename), "bcm43xx_pcm%d.fw", rev < 5 ? 4 : 5); - if ((error = loadfirmware(name, &pcm, &size_pcm)) != 0) { - printf("%s: error %d, could not read pcm %s!\n", - sc->sc_dev.dv_xname, error, name); + if (bcw_get_firmware(filename, ucode, &size_pcm, &off_pcm) != 0) { + printf("%s: getting firmware file %s failed!\n", + sc->sc_dev.dv_xname, name); return (EIO); } - DPRINTF(("%s: successfully read %s\n", sc->sc_dev.dv_xname, name)); /* upload microcode */ - data = (uint32_t *)ucode; - len = size_ucode / sizeof(uint32_t); + data = (uint32_t *)(ucode + off_micro); + len = size_micro / sizeof(uint32_t); bcw_shm_ctl_word(sc, BCW_SHM_CONTROL_MCODE, 0); for (i = 0; i < len; i++) { BCW_WRITE(sc, BCW_SHM_DATA, betoh32(data[i])); delay(10); } DPRINTF(("%s: uploaded microcode\n", sc->sc_dev.dv_xname)); - free(ucode, M_DEVBUF); /* upload pcm */ - data = (uint32_t *)pcm; + data = (uint32_t *)(ucode + off_pcm); len = size_pcm / sizeof(uint32_t); bcw_shm_ctl_word(sc, BCW_SHM_CONTROL_PCM, 0x01ea); BCW_WRITE(sc, BCW_SHM_DATA, 0x00004000); @@ -2301,7 +2343,8 @@ bcw_load_firmware(struct bcw_softc *sc) delay(10); } DPRINTF(("%s: uploaded pcm\n", sc->sc_dev.dv_xname)); - free(pcm, M_DEVBUF); + + free(ucode, M_DEVBUF); return (0); } |