Use the firmload API to retrive the firmware from the filesystem.

This commit is contained in:
rpaulo 2006-04-17 17:29:08 +00:00
parent e82413c3cf
commit f32518359d
2 changed files with 50 additions and 33 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_ipw.c,v 1.16 2005/12/24 20:27:42 perry Exp $ */ /* $NetBSD: if_ipw.c,v 1.17 2006/04/17 17:29:08 rpaulo Exp $ */
/* FreeBSD: src/sys/dev/ipw/if_ipw.c,v 1.15 2005/11/13 17:17:40 damien Exp */ /* FreeBSD: src/sys/dev/ipw/if_ipw.c,v 1.15 2005/11/13 17:17:40 damien Exp */
/*- /*-
@ -29,7 +29,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_ipw.c,v 1.16 2005/12/24 20:27:42 perry Exp $"); __KERNEL_RCSID(0, "$NetBSD: if_ipw.c,v 1.17 2006/04/17 17:29:08 rpaulo Exp $");
/*- /*-
* Intel(R) PRO/Wireless 2100 MiniPCI driver * Intel(R) PRO/Wireless 2100 MiniPCI driver
@ -74,6 +74,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_ipw.c,v 1.16 2005/12/24 20:27:42 perry Exp $");
#include <netinet/in_var.h> #include <netinet/in_var.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <dev/firmload.h>
#include <dev/pci/if_ipwreg.h> #include <dev/pci/if_ipwreg.h>
#include <dev/pci/if_ipwvar.h> #include <dev/pci/if_ipwvar.h>
@ -121,7 +123,7 @@ static void ipw_stop_master(struct ipw_softc *);
static int ipw_reset(struct ipw_softc *); static int ipw_reset(struct ipw_softc *);
static int ipw_load_ucode(struct ipw_softc *, u_char *, int); static int ipw_load_ucode(struct ipw_softc *, u_char *, int);
static int ipw_load_firmware(struct ipw_softc *, u_char *, int); static int ipw_load_firmware(struct ipw_softc *, u_char *, int);
static int ipw_cache_firmware(struct ipw_softc *, void *); static int ipw_cache_firmware(struct ipw_softc *);
static void ipw_free_firmware(struct ipw_softc *); static void ipw_free_firmware(struct ipw_softc *);
static int ipw_config(struct ipw_softc *); static int ipw_config(struct ipw_softc *);
static int ipw_init(struct ifnet *); static int ipw_init(struct ifnet *);
@ -218,6 +220,7 @@ ipw_attach(struct device *parent, struct device *self, void *aux)
sc->sc_st = memt; sc->sc_st = memt;
sc->sc_sh = memh; sc->sc_sh = memh;
sc->sc_dmat = pa->pa_dmat; sc->sc_dmat = pa->pa_dmat;
strncpy(sc->sc_fwname, "ipw2100-1.2.fw", 16);
/* disable interrupts */ /* disable interrupts */
CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0); CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
@ -1737,14 +1740,6 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = ipw_get_radio(sc, (int *)ifr->ifr_data); error = ipw_get_radio(sc, (int *)ifr->ifr_data);
break; break;
case SIOCSLOADFW:
/* only super-user can do that! */
if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0)
break;
error = ipw_cache_firmware(sc, ifr->ifr_data);
break;
case SIOCSKILLFW: case SIOCSKILLFW:
/* only super-user can do that! */ /* only super-user can do that! */
if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0) if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0)
@ -1753,6 +1748,16 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ipw_reset(sc); ipw_reset(sc);
break; break;
case SIOCSIFMEDIA:
if (ifr->ifr_media & IFM_IEEE80211_ADHOC)
strncpy(sc->sc_fwname, "ipw2100-1.2-i.fw", 16);
else if (ifr->ifr_media & IFM_IEEE80211_MONITOR)
strncpy(sc->sc_fwname, "ipw2100-1.2-p.fw", 16);
else
strncpy(sc->sc_fwname, "ipw2100-1.2.fw", 16);
ipw_free_firmware(sc);
/* FALLTRHOUGH */
default: default:
error = ieee80211_ioctl(&sc->sc_ic, cmd, data); error = ieee80211_ioctl(&sc->sc_ic, cmd, data);
if (error != ENETRESET) if (error != ENETRESET)
@ -1968,39 +1973,51 @@ ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size)
* e.g when the adapter wakes up from suspend mode. * e.g when the adapter wakes up from suspend mode.
*/ */
static int static int
ipw_cache_firmware(struct ipw_softc *sc, void *data) ipw_cache_firmware(struct ipw_softc *sc)
{ {
struct ipw_firmware *fw = &sc->fw; struct ipw_firmware *fw = &sc->fw;
struct ipw_firmware_hdr hdr; struct ipw_firmware_hdr hdr;
u_char *p = data; firmware_handle_t fwh;
off_t fwsz, p;
int error; int error;
ipw_free_firmware(sc); ipw_free_firmware(sc);
if ((error = copyin(data, &hdr, sizeof hdr)) != 0) if ((error = firmware_open("if_ipw", sc->sc_fwname, &fwh)) != 0)
goto fail1; goto fail0;
fwsz = firmware_get_size(fwh);
if (fwsz < sizeof(hdr))
goto fail2;
if ((error = firmware_read(fwh, 0, &hdr, sizeof(hdr))) != 0)
goto fail2;
fw->main_size = le32toh(hdr.main_size); fw->main_size = le32toh(hdr.main_size);
fw->ucode_size = le32toh(hdr.ucode_size); fw->ucode_size = le32toh(hdr.ucode_size);
p += sizeof hdr;
fw->main = malloc(fw->main_size, M_DEVBUF, M_NOWAIT); fw->main = firmware_malloc(fw->main_size);
if (fw->main == NULL) { if (fw->main == NULL) {
error = ENOMEM; error = ENOMEM;
goto fail1; goto fail1;
} }
fw->ucode = malloc(fw->ucode_size, M_DEVBUF, M_NOWAIT); fw->ucode = firmware_malloc(fw->ucode_size);
if (fw->ucode == NULL) { if (fw->ucode == NULL) {
error = ENOMEM; error = ENOMEM;
goto fail2; goto fail2;
} }
if ((error = copyin(p, fw->main, fw->main_size)) != 0) p = sizeof(hdr);
if ((error = firmware_read(fwh, p, fw->main, fw->main_size)) != 0)
goto fail3;
if ((error = firmware_read(fwh, p, fw->main, fw->main_size)) != 0)
goto fail3; goto fail3;
p += fw->main_size; p += fw->main_size;
if ((error = copyin(p, fw->ucode, fw->ucode_size)) != 0) if ((error = firmware_read(fwh, p, fw->ucode, fw->ucode_size)) != 0)
goto fail3; goto fail3;
DPRINTF(("Firmware cached: main %u, ucode %u\n", fw->main_size, DPRINTF(("Firmware cached: main %u, ucode %u\n", fw->main_size,
@ -2010,9 +2027,10 @@ ipw_cache_firmware(struct ipw_softc *sc, void *data)
return 0; return 0;
fail3: free(fw->ucode, M_DEVBUF); fail3: firmware_free(fw->ucode, 0);
fail2: free(fw->main, M_DEVBUF); fail2: firmware_free(fw->main, 0);
fail1: fail1: firmware_close(fwh);
fail0:
return error; return error;
} }
@ -2022,8 +2040,8 @@ ipw_free_firmware(struct ipw_softc *sc)
if (!(sc->flags & IPW_FLAG_FW_CACHED)) if (!(sc->flags & IPW_FLAG_FW_CACHED))
return; return;
free(sc->fw.main, M_DEVBUF); firmware_free(sc->fw.main, 0);
free(sc->fw.ucode, M_DEVBUF); firmware_free(sc->fw.ucode, 0);
sc->flags &= ~IPW_FLAG_FW_CACHED; sc->flags &= ~IPW_FLAG_FW_CACHED;
} }
@ -2242,14 +2260,12 @@ ipw_init(struct ifnet *ifp)
struct ipw_softc *sc = ifp->if_softc; struct ipw_softc *sc = ifp->if_softc;
struct ipw_firmware *fw = &sc->fw; struct ipw_firmware *fw = &sc->fw;
/* exit immediately if firmware has not been ioctl'd */
if (!(sc->flags & IPW_FLAG_FW_CACHED)) { if (!(sc->flags & IPW_FLAG_FW_CACHED)) {
if (!(sc->flags & IPW_FLAG_FW_WARNED)) if (ipw_cache_firmware(sc) != 0) {
aprint_error("%s: Please load firmware\n", aprint_error("%s: could not cache the firmware (%s)\n",
sc->sc_dev.dv_xname); sc->sc_dev.dv_xname, sc->sc_fwname);
sc->flags |= IPW_FLAG_FW_WARNED; goto fail;
ifp->if_flags &= ~IFF_UP; }
return EIO;
} }
ipw_stop(ifp, 0); ipw_stop(ifp, 0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_ipwvar.h,v 1.8 2005/12/20 07:51:38 skrll Exp $ */ /* $NetBSD: if_ipwvar.h,v 1.9 2006/04/17 17:29:08 rpaulo Exp $ */
/*- /*-
* Copyright (c) 2004 * Copyright (c) 2004
@ -93,6 +93,7 @@ struct ipw_softc {
enum ieee80211_state, int); enum ieee80211_state, int);
struct ipw_firmware fw; struct ipw_firmware fw;
char sc_fwname[16];
uint32_t flags; uint32_t flags;
#define IPW_FLAG_FW_CACHED (1 << 0) #define IPW_FLAG_FW_CACHED (1 << 0)
#define IPW_FLAG_FW_INITED (1 << 1) #define IPW_FLAG_FW_INITED (1 << 1)