summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/bcw.c81
-rw-r--r--sys/dev/ic/bcwvar.h8
2 files changed, 69 insertions, 20 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);
}
diff --git a/sys/dev/ic/bcwvar.h b/sys/dev/ic/bcwvar.h
index 1784c34e0d5..52c19db35eb 100644
--- a/sys/dev/ic/bcwvar.h
+++ b/sys/dev/ic/bcwvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bcwvar.h,v 1.11 2007/01/03 06:31:54 mglocker Exp $ */
+/* $OpenBSD: bcwvar.h,v 1.12 2007/01/05 07:09:15 mglocker Exp $ */
/*
* Copyright (c) 2006 Jon Simola <jsimola@gmail.com>
@@ -23,6 +23,12 @@
* Cliff Wright cliff@snipe444.org
*/
+struct fwheader {
+ char filename[64];
+ int filesize;
+ int fileoffset;
+};
+
struct bcw_initval {
uint16_t offset;
uint16_t size;