Index: if_ipw.c =================================================================== RCS file: /home/ncvs/src/sys/dev/ipw/if_ipw.c,v retrieving revision 1.16 diff -u -r1.16 if_ipw.c --- if_ipw.c 20 Nov 2005 16:13:00 -0000 1.16 +++ if_ipw.c 12 Dec 2005 12:59:06 -0000 @@ -46,6 +46,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -123,13 +127,12 @@ static int ipw_ioctl(struct ifnet *, u_long, caddr_t); 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 void ipw_free_firmware(struct ipw_softc *); +static int ipw_load_ucode(struct ipw_softc *, const char *); +static int ipw_load_firmware(struct ipw_softc *, const char *); static int ipw_config(struct ipw_softc *); static void ipw_init(void *); static void ipw_stop(void *); +static int ipw_read_firmware(const char *, caddr_t *, size_t *); static int ipw_sysctl_stats(SYSCTL_HANDLER_ARGS); static int ipw_sysctl_radio(SYSCTL_HANDLER_ARGS); static uint32_t ipw_read_table1(struct ipw_softc *, uint32_t); @@ -384,7 +387,6 @@ IPW_LOCK(sc); ipw_stop(sc); - ipw_free_firmware(sc); IPW_UNLOCK(sc); @@ -1555,7 +1557,6 @@ { struct ipw_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; - struct ifreq *ifr; int error = 0; IPW_LOCK(sc); @@ -1571,25 +1572,6 @@ } break; - case SIOCSLOADFW: - /* only super-user can do that! */ - if ((error = suser(curthread)) != 0) - break; - - ifr = (struct ifreq *)data; - error = ipw_cache_firmware(sc, ifr->ifr_data); - break; - - case SIOCSKILLFW: - /* only super-user can do that! */ - if ((error = suser(curthread)) != 0) - break; - - ifp->if_flags &= ~IFF_UP; - ipw_stop(sc); - ipw_free_firmware(sc); - break; - default: error = ieee80211_ioctl(ic, cmd, data); } @@ -1664,9 +1646,31 @@ * Upload the microcode to the device. */ static int -ipw_load_ucode(struct ipw_softc *sc, u_char *uc, int size) +ipw_load_ucode(struct ipw_softc *sc, const char *name) { - int ntries; + int ntries, error; + char *fw, *uc; + size_t size; + struct ipw_firmware_hdr *hdr; + + /* read firmware image from filesystem */ + IPW_UNLOCK(sc); + error = ipw_read_firmware(name, &fw, &size); + IPW_LOCK(sc); + if (error != 0) { + device_printf(sc->sc_dev, "could not read firmware image\n"); + goto fail1; + } + + if (size < sizeof (struct ipw_firmware_hdr)) { + error = EINVAL; + goto fail2; + } + + hdr = (struct ipw_firmware_hdr *)fw; + + uc = fw + sizeof (struct ipw_firmware_hdr) + le32toh(hdr->main_size); + size = le32toh(hdr->ucode_size); MEM_WRITE_4(sc, 0x3000e0, 0x80000000); CSR_WRITE_4(sc, IPW_CSR_RST, 0); @@ -1709,19 +1713,43 @@ MEM_WRITE_4(sc, 0x3000e0, 0); - return 0; +fail2: free(fw, M_DEVBUF); +fail1: + return error; } /* set of macros to handle unaligned little endian data in firmware image */ #define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24) #define GETLE16(p) ((p)[0] | (p)[1] << 8) static int -ipw_load_firmware(struct ipw_softc *sc, u_char *fw, int size) +ipw_load_firmware(struct ipw_softc *sc, const char *name) { u_char *p, *end; uint32_t dst; uint16_t len; int error; + size_t size; + struct ipw_firmware_hdr *hdr; + char *fw; + + /* read firmware image from filesystem */ + IPW_UNLOCK(sc); + error = ipw_read_firmware(name, &fw, &size); + IPW_LOCK(sc); + if (error != 0) { + device_printf(sc->sc_dev, "could not read firmware image\n"); + goto fail1; + } + + if (size < sizeof (struct ipw_firmware_hdr)) { + error = EINVAL; + goto fail2; + } + + hdr = (struct ipw_firmware_hdr *)fw; + fw += sizeof (struct ipw_firmware_hdr); + + size = le32toh(hdr->main_size); p = fw; end = fw + size; @@ -1755,77 +1783,9 @@ CSR_WRITE_4(sc, IPW_CSR_IO, CSR_READ_4(sc, IPW_CSR_IO) | IPW_IO_GPIO1_MASK | IPW_IO_GPIO3_MASK); - return 0; -} - -/* - * Store firmware into kernel memory so we can download it when we need to, - * e.g when the adapter wakes up from suspend mode. - */ -static int -ipw_cache_firmware(struct ipw_softc *sc, void *data) -{ - struct ipw_firmware *fw = &sc->fw; - struct ipw_firmware_hdr hdr; - u_char *p = data; - int error; - - ipw_free_firmware(sc); - - IPW_UNLOCK(sc); - - if ((error = copyin(data, &hdr, sizeof hdr)) != 0) - goto fail1; - - 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); - if (fw->main == NULL) { - error = ENOMEM; - goto fail1; - } - - fw->ucode = malloc(fw->ucode_size, M_DEVBUF, M_NOWAIT); - if (fw->ucode == NULL) { - error = ENOMEM; - goto fail2; - } - - if ((error = copyin(p, fw->main, fw->main_size)) != 0) - goto fail3; - - p += fw->main_size; - if ((error = copyin(p, fw->ucode, fw->ucode_size)) != 0) - goto fail3; - - DPRINTF(("Firmware cached: main %u, ucode %u\n", fw->main_size, - fw->ucode_size)); - - IPW_LOCK(sc); - - sc->flags |= IPW_FLAG_FW_CACHED; - - return 0; - -fail3: free(fw->ucode, M_DEVBUF); -fail2: free(fw->main, M_DEVBUF); -fail1: IPW_LOCK(sc); - - return error; -} - -static void -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); - - sc->flags &= ~IPW_FLAG_FW_CACHED; +fail2: free(fw, M_DEVBUF); +fail1: + return error; } static int @@ -2041,15 +2001,24 @@ struct ipw_softc *sc = priv; struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = ic->ic_ifp; - struct ipw_firmware *fw = &sc->fw; + const char *fw; - /* exit immediately if firmware has not been ioctl'd */ - if (!(sc->flags & IPW_FLAG_FW_CACHED)) { - if (!(sc->flags & IPW_FLAG_FW_WARNED)) - device_printf(sc->sc_dev, "Please load firmware\n"); - sc->flags |= IPW_FLAG_FW_WARNED; - ifp->if_flags &= ~IFF_UP; - return; + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + fw = "ipw"; + break; + + case IEEE80211_M_IBSS: + fw = "ipw-i"; + break; + + case IEEE80211_M_MONITOR: + fw = "ipw-p"; + break; + + default: + fw = NULL; /* should not get there */ + break; } ipw_stop(sc); @@ -2059,7 +2028,7 @@ goto fail; } - if (ipw_load_ucode(sc, fw->ucode, fw->ucode_size) != 0) { + if (ipw_load_ucode(sc, fw) != 0) { device_printf(sc->sc_dev, "could not load microcode\n"); goto fail; } @@ -2086,7 +2055,7 @@ CSR_WRITE_4(sc, IPW_CSR_STATUS_BASE, sc->status_phys); - if (ipw_load_firmware(sc, fw->main, fw->main_size) != 0) { + if (ipw_load_firmware(sc, fw) != 0) { device_printf(sc->sc_dev, "could not load firmware\n"); goto fail; } @@ -2138,6 +2107,74 @@ ieee80211_new_state(ic, IEEE80211_S_INIT, -1); } +/* + * Read firmware image from the filesystem and load it into kernel memory. + * Must be called from a process context. + */ +static int +ipw_read_firmware(const char *name, caddr_t *bufp, size_t *len) +{ + char path[64]; + struct thread *td = curthread; + struct nameidata nd; + struct vattr va; + struct iovec iov; + struct uio uio; + caddr_t buf; + int vfslocked, error; + + snprintf(path, sizeof path, "/boot/firmware/%s.fw", name); + + NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | MPSAFE, UIO_SYSSPACE, path, + td); + if ((error = namei(&nd)) != 0) + goto fail1; + + vfslocked = NDHASGIANT(&nd); + + if ((error = VOP_GETATTR(nd.ni_vp, &va, td->td_ucred, td)) != 0) + goto fail2; + + /* limit firmware size to 256KB */ + if (va.va_size > 256 * 1024) { + error = E2BIG; + goto fail2; + } + + if ((buf = malloc(va.va_size, M_DEVBUF, M_NOWAIT)) == NULL) { + error = ENOMEM; + goto fail2; + } + + /* read the whole image at once */ + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + iov.iov_base = buf; + iov.iov_len = va.va_size; + uio.uio_offset = 0; + uio.uio_resid = va.va_size; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_td = td; + + if ((error = VOP_READ(nd.ni_vp, &uio, 0, NOCRED)) != 0) + goto fail3; + + *bufp = buf; + *len = va.va_size; + + vput(nd.ni_vp); + VFS_UNLOCK_GIANT(vfslocked); + + return 0; + +fail3: free(buf, M_DEVBUF); +fail2: vput(nd.ni_vp); + VFS_UNLOCK_GIANT(vfslocked); +fail1: + return error; +} + static int ipw_sysctl_stats(SYSCTL_HANDLER_ARGS) { Index: if_ipwvar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/ipw/if_ipwvar.h,v retrieving revision 1.3 diff -u -r1.3 if_ipwvar.h --- if_ipwvar.h 10 Jun 2005 16:49:11 -0000 1.3 +++ if_ipwvar.h 12 Dec 2005 12:59:06 -0000 @@ -94,10 +94,8 @@ struct ipw_firmware fw; uint32_t flags; -#define IPW_FLAG_FW_CACHED (1 << 0) -#define IPW_FLAG_FW_INITED (1 << 1) -#define IPW_FLAG_HAS_RADIO_SWITCH (1 << 2) -#define IPW_FLAG_FW_WARNED (1 << 3) +#define IPW_FLAG_FW_INITED (1 << 0) +#define IPW_FLAG_HAS_RADIO_SWITCH (1 << 1) int irq_rid; int mem_rid; Index: ipw.4 =================================================================== RCS file: /home/ncvs/src/share/man/man4/ipw.4,v retrieving revision 1.7 diff -u -r1.7 ipw.4 --- ipw.4 18 Nov 2005 10:52:22 -0000 1.7 +++ ipw.4 12 Dec 2005 15:26:17 -0000 @@ -64,10 +64,9 @@ .Xr ifconfig 8 . .Pp This driver requires firmware to be loaded before it will work. -You need to obtain -.Xr ipwcontrol 8 -from the IPW web page listed below to accomplish loading the firmware -before +You need to install the +.Pa ports/net/ipw-firmware +port before .Xr ifconfig 8 will work. .Sh EXAMPLES @@ -96,12 +95,13 @@ .It "ipw%d: device timeout" The driver will reset the hardware. This should not happen. -.It "ipw%d: Please load firmware" -The required firmware has not been loaded into the card, and therefore -the card cannot operate. -Load the firmware with -.Xr ipwcontrol 8 -before proceeding. +.It "ipw%d: could not read firmware image" +The required firmware could not be found in +.Pa /boot/firmware , +and therefore the card cannot operate. +Ensure +.Pa ports/net/ipw-firmware +is installed correctly. .El .Sh SEE ALSO .Xr an 4 , @@ -110,9 +110,7 @@ .Xr pci 4 , .Xr wi 4 , .Xr wlan 4 , -.Xr ifconfig 8 , -.Xr ipwcontrol 8 , -.Xr wicontrol 8 +.Xr ifconfig 8 .Rs .%T The IPW Web Page .%O http://damien.bergamini.free.fr/ipw/