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 */
/*-
@ -29,7 +29,7 @@
*/
#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
@ -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/ip.h>
#include <dev/firmload.h>
#include <dev/pci/if_ipwreg.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_load_ucode(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 int ipw_config(struct ipw_softc *);
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_sh = memh;
sc->sc_dmat = pa->pa_dmat;
strncpy(sc->sc_fwname, "ipw2100-1.2.fw", 16);
/* disable interrupts */
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);
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:
/* only super-user can do that! */
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);
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:
error = ieee80211_ioctl(&sc->sc_ic, cmd, data);
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.
*/
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_hdr hdr;
u_char *p = data;
firmware_handle_t fwh;
off_t fwsz, p;
int error;
ipw_free_firmware(sc);
if ((error = copyin(data, &hdr, sizeof hdr)) != 0)
goto fail1;
if ((error = firmware_open("if_ipw", sc->sc_fwname, &fwh)) != 0)
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->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) {
error = ENOMEM;
goto fail1;
}
fw->ucode = malloc(fw->ucode_size, M_DEVBUF, M_NOWAIT);
fw->ucode = firmware_malloc(fw->ucode_size);
if (fw->ucode == NULL) {
error = ENOMEM;
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;
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;
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;
fail3: free(fw->ucode, M_DEVBUF);
fail2: free(fw->main, M_DEVBUF);
fail1:
fail3: firmware_free(fw->ucode, 0);
fail2: firmware_free(fw->main, 0);
fail1: firmware_close(fwh);
fail0:
return error;
}
@ -2022,8 +2040,8 @@ ipw_free_firmware(struct ipw_softc *sc)
if (!(sc->flags & IPW_FLAG_FW_CACHED))
return;
free(sc->fw.main, M_DEVBUF);
free(sc->fw.ucode, M_DEVBUF);
firmware_free(sc->fw.main, 0);
firmware_free(sc->fw.ucode, 0);
sc->flags &= ~IPW_FLAG_FW_CACHED;
}
@ -2242,14 +2260,12 @@ ipw_init(struct ifnet *ifp)
struct ipw_softc *sc = ifp->if_softc;
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_WARNED))
aprint_error("%s: Please load firmware\n",
sc->sc_dev.dv_xname);
sc->flags |= IPW_FLAG_FW_WARNED;
ifp->if_flags &= ~IFF_UP;
return EIO;
if (ipw_cache_firmware(sc) != 0) {
aprint_error("%s: could not cache the firmware (%s)\n",
sc->sc_dev.dv_xname, sc->sc_fwname);
goto fail;
}
}
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
@ -93,6 +93,7 @@ struct ipw_softc {
enum ieee80211_state, int);
struct ipw_firmware fw;
char sc_fwname[16];
uint32_t flags;
#define IPW_FLAG_FW_CACHED (1 << 0)
#define IPW_FLAG_FW_INITED (1 << 1)