|
|
|
@@ -1,5 +1,3 @@
|
|
|
|
|
/* $FreeBSD$ */
|
|
|
|
|
|
|
|
|
|
/*-
|
|
|
|
|
* Copyright (c) 2004-2006
|
|
|
|
|
* Damien Bergamini <[email protected]>. All rights reserved.
|
|
|
|
@@ -30,7 +28,7 @@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
__FBSDID("$FreeBSD: releng/11.1/sys/dev/ipw/if_ipw.c 300239 2016-05-19 22:19:35Z avos $");
|
|
|
|
|
|
|
|
|
|
/*-
|
|
|
|
|
* Intel(R) PRO/Wireless 2100 MiniPCI driver
|
|
|
|
@@ -62,6 +60,7 @@ __FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
|
|
#include <net/bpf.h>
|
|
|
|
|
#include <net/if.h>
|
|
|
|
|
#include <net/if_var.h>
|
|
|
|
|
#include <net/if_arp.h>
|
|
|
|
|
#include <net/ethernet.h>
|
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
@@ -117,6 +116,7 @@ static void ipw_release(struct ipw_softc *);
|
|
|
|
|
static void ipw_media_status(struct ifnet *, struct ifmediareq *);
|
|
|
|
|
static int ipw_newstate(struct ieee80211vap *, enum ieee80211_state, int);
|
|
|
|
|
static uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_t);
|
|
|
|
|
static uint16_t ipw_read_chanmask(struct ipw_softc *);
|
|
|
|
|
static void ipw_rx_cmd_intr(struct ipw_softc *, struct ipw_soft_buf *);
|
|
|
|
|
static void ipw_rx_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
|
|
|
|
|
static void ipw_rx_data_intr(struct ipw_softc *, struct ipw_status *,
|
|
|
|
@@ -128,14 +128,14 @@ static void ipw_intr(void *);
|
|
|
|
|
static void ipw_dma_map_addr(void *, bus_dma_segment_t *, int, int);
|
|
|
|
|
static const char * ipw_cmdname(int);
|
|
|
|
|
static int ipw_cmd(struct ipw_softc *, uint32_t, void *, uint32_t);
|
|
|
|
|
static int ipw_tx_start(struct ifnet *, struct mbuf *,
|
|
|
|
|
static int ipw_tx_start(struct ipw_softc *, struct mbuf *,
|
|
|
|
|
struct ieee80211_node *);
|
|
|
|
|
static int ipw_raw_xmit(struct ieee80211_node *, struct mbuf *,
|
|
|
|
|
const struct ieee80211_bpf_params *);
|
|
|
|
|
static void ipw_start(struct ifnet *);
|
|
|
|
|
static void ipw_start_locked(struct ifnet *);
|
|
|
|
|
static int ipw_transmit(struct ieee80211com *, struct mbuf *);
|
|
|
|
|
static void ipw_start(struct ipw_softc *);
|
|
|
|
|
static void ipw_watchdog(void *);
|
|
|
|
|
static int ipw_ioctl(struct ifnet *, u_long, caddr_t);
|
|
|
|
|
static void ipw_parent(struct ieee80211com *);
|
|
|
|
|
static void ipw_stop_master(struct ipw_softc *);
|
|
|
|
|
static int ipw_enable(struct ipw_softc *);
|
|
|
|
|
static int ipw_disable(struct ipw_softc *);
|
|
|
|
@@ -165,6 +165,8 @@ static void ipw_write_mem_1(struct ipw_softc *, bus_size_t,
|
|
|
|
|
static int ipw_scan(struct ipw_softc *);
|
|
|
|
|
static void ipw_scan_start(struct ieee80211com *);
|
|
|
|
|
static void ipw_scan_end(struct ieee80211com *);
|
|
|
|
|
static void ipw_getradiocaps(struct ieee80211com *, int, int *,
|
|
|
|
|
struct ieee80211_channel[]);
|
|
|
|
|
static void ipw_set_channel(struct ieee80211com *);
|
|
|
|
|
static void ipw_scan_curchan(struct ieee80211_scan_state *,
|
|
|
|
|
unsigned long maxdwell);
|
|
|
|
@@ -186,7 +188,7 @@ static device_method_t ipw_methods[] = {
|
|
|
|
|
DEVMETHOD(device_suspend, ipw_suspend),
|
|
|
|
|
DEVMETHOD(device_resume, ipw_resume),
|
|
|
|
|
|
|
|
|
|
{ 0, 0 }
|
|
|
|
|
DEVMETHOD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static driver_t ipw_driver = {
|
|
|
|
@@ -197,7 +199,7 @@ static driver_t ipw_driver = {
|
|
|
|
|
|
|
|
|
|
static devclass_t ipw_devclass;
|
|
|
|
|
|
|
|
|
|
DRIVER_MODULE(ipw, pci, ipw_driver, ipw_devclass, 0, 0);
|
|
|
|
|
DRIVER_MODULE(ipw, pci, ipw_driver, ipw_devclass, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
MODULE_VERSION(ipw, 1);
|
|
|
|
|
|
|
|
|
@@ -210,48 +212,36 @@ ipw_probe(device_t dev)
|
|
|
|
|
if (pci_get_vendor(dev) == ident->vendor &&
|
|
|
|
|
pci_get_device(dev) == ident->device) {
|
|
|
|
|
device_set_desc(dev, ident->name);
|
|
|
|
|
return 0;
|
|
|
|
|
return (BUS_PROBE_DEFAULT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ENXIO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Base Address Register */
|
|
|
|
|
#define IPW_PCI_BAR0 0x10
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ipw_attach(device_t dev)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = device_get_softc(dev);
|
|
|
|
|
struct ifnet *ifp;
|
|
|
|
|
struct ieee80211com *ic;
|
|
|
|
|
struct ieee80211_channel *c;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
uint16_t val;
|
|
|
|
|
int error, i;
|
|
|
|
|
uint8_t macaddr[IEEE80211_ADDR_LEN];
|
|
|
|
|
|
|
|
|
|
sc->sc_dev = dev;
|
|
|
|
|
|
|
|
|
|
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
|
|
|
|
|
MTX_DEF | MTX_RECURSE);
|
|
|
|
|
|
|
|
|
|
mbufq_init(&sc->sc_snd, ifqmaxlen);
|
|
|
|
|
TASK_INIT(&sc->sc_init_task, 0, ipw_init_task, sc);
|
|
|
|
|
callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0);
|
|
|
|
|
|
|
|
|
|
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
|
|
|
|
|
device_printf(dev, "chip is in D%d power mode "
|
|
|
|
|
"-- setting to D0\n", pci_get_powerstate(dev));
|
|
|
|
|
pci_set_powerstate(dev, PCI_POWERSTATE_D0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pci_write_config(dev, 0x41, 0, 1);
|
|
|
|
|
|
|
|
|
|
/* enable bus-mastering */
|
|
|
|
|
pci_enable_busmaster(dev);
|
|
|
|
|
|
|
|
|
|
sc->mem_rid = IPW_PCI_BAR0;
|
|
|
|
|
sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
|
|
|
|
|
RF_ACTIVE);
|
|
|
|
|
i = PCIR_BAR(0);
|
|
|
|
|
sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE);
|
|
|
|
|
if (sc->mem == NULL) {
|
|
|
|
|
device_printf(dev, "could not allocate memory resource\n");
|
|
|
|
|
goto fail;
|
|
|
|
@@ -260,8 +250,8 @@ ipw_attach(device_t dev)
|
|
|
|
|
sc->sc_st = rman_get_bustag(sc->mem);
|
|
|
|
|
sc->sc_sh = rman_get_bushandle(sc->mem);
|
|
|
|
|
|
|
|
|
|
sc->irq_rid = 0;
|
|
|
|
|
sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
|
|
|
|
|
i = 0;
|
|
|
|
|
sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i,
|
|
|
|
|
RF_ACTIVE | RF_SHAREABLE);
|
|
|
|
|
if (sc->irq == NULL) {
|
|
|
|
|
device_printf(dev, "could not allocate interrupt resource\n");
|
|
|
|
@@ -278,24 +268,8 @@ ipw_attach(device_t dev)
|
|
|
|
|
goto fail2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
|
|
|
|
|
if (ifp == NULL) {
|
|
|
|
|
device_printf(dev, "can not if_alloc()\n");
|
|
|
|
|
goto fail3;
|
|
|
|
|
}
|
|
|
|
|
ic = ifp->if_l2com;
|
|
|
|
|
|
|
|
|
|
ifp->if_softc = sc;
|
|
|
|
|
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
|
|
|
|
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
|
|
|
|
ifp->if_init = ipw_init;
|
|
|
|
|
ifp->if_ioctl = ipw_ioctl;
|
|
|
|
|
ifp->if_start = ipw_start;
|
|
|
|
|
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
|
|
|
|
|
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
|
|
|
|
|
IFQ_SET_READY(&ifp->if_snd);
|
|
|
|
|
|
|
|
|
|
ic->ic_ifp = ifp;
|
|
|
|
|
ic->ic_softc = sc;
|
|
|
|
|
ic->ic_name = device_get_nameunit(dev);
|
|
|
|
|
ic->ic_opmode = IEEE80211_M_STA;
|
|
|
|
|
ic->ic_phytype = IEEE80211_T_DS;
|
|
|
|
|
|
|
|
|
@@ -311,42 +285,35 @@ ipw_attach(device_t dev)
|
|
|
|
|
|
|
|
|
|
/* read MAC address from EEPROM */
|
|
|
|
|
val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 0);
|
|
|
|
|
macaddr[0] = val >> 8;
|
|
|
|
|
macaddr[1] = val & 0xff;
|
|
|
|
|
ic->ic_macaddr[0] = val >> 8;
|
|
|
|
|
ic->ic_macaddr[1] = val & 0xff;
|
|
|
|
|
val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 1);
|
|
|
|
|
macaddr[2] = val >> 8;
|
|
|
|
|
macaddr[3] = val & 0xff;
|
|
|
|
|
ic->ic_macaddr[2] = val >> 8;
|
|
|
|
|
ic->ic_macaddr[3] = val & 0xff;
|
|
|
|
|
val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 2);
|
|
|
|
|
macaddr[4] = val >> 8;
|
|
|
|
|
macaddr[5] = val & 0xff;
|
|
|
|
|
ic->ic_macaddr[4] = val >> 8;
|
|
|
|
|
ic->ic_macaddr[5] = val & 0xff;
|
|
|
|
|
|
|
|
|
|
/* set supported .11b channels (read from EEPROM) */
|
|
|
|
|
if ((val = ipw_read_prom_word(sc, IPW_EEPROM_CHANNEL_LIST)) == 0)
|
|
|
|
|
val = 0x7ff; /* default to channels 1-11 */
|
|
|
|
|
val <<= 1;
|
|
|
|
|
for (i = 1; i < 16; i++) {
|
|
|
|
|
if (val & (1 << i)) {
|
|
|
|
|
c = &ic->ic_channels[ic->ic_nchans++];
|
|
|
|
|
c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
|
|
|
|
|
c->ic_flags = IEEE80211_CHAN_B;
|
|
|
|
|
c->ic_ieee = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sc->chanmask = ipw_read_chanmask(sc);
|
|
|
|
|
ipw_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,
|
|
|
|
|
ic->ic_channels);
|
|
|
|
|
|
|
|
|
|
/* check support for radio transmitter switch in EEPROM */
|
|
|
|
|
if (!(ipw_read_prom_word(sc, IPW_EEPROM_RADIO) & 8))
|
|
|
|
|
sc->flags |= IPW_FLAG_HAS_RADIO_SWITCH;
|
|
|
|
|
|
|
|
|
|
ieee80211_ifattach(ic, macaddr);
|
|
|
|
|
ieee80211_ifattach(ic);
|
|
|
|
|
ic->ic_scan_start = ipw_scan_start;
|
|
|
|
|
ic->ic_scan_end = ipw_scan_end;
|
|
|
|
|
ic->ic_getradiocaps = ipw_getradiocaps;
|
|
|
|
|
ic->ic_set_channel = ipw_set_channel;
|
|
|
|
|
ic->ic_scan_curchan = ipw_scan_curchan;
|
|
|
|
|
ic->ic_scan_mindwell = ipw_scan_mindwell;
|
|
|
|
|
ic->ic_raw_xmit = ipw_raw_xmit;
|
|
|
|
|
|
|
|
|
|
ic->ic_vap_create = ipw_vap_create;
|
|
|
|
|
ic->ic_vap_delete = ipw_vap_delete;
|
|
|
|
|
ic->ic_transmit = ipw_transmit;
|
|
|
|
|
ic->ic_parent = ipw_parent;
|
|
|
|
|
|
|
|
|
|
ieee80211_radiotap_attach(ic,
|
|
|
|
|
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
|
|
|
|
@@ -374,21 +341,20 @@ ipw_attach(device_t dev)
|
|
|
|
|
NULL, ipw_intr, sc, &sc->sc_ih);
|
|
|
|
|
if (error != 0) {
|
|
|
|
|
device_printf(dev, "could not set up interrupt\n");
|
|
|
|
|
goto fail4;
|
|
|
|
|
goto fail3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bootverbose)
|
|
|
|
|
ieee80211_announce(ic);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
fail4:
|
|
|
|
|
if_free(ifp);
|
|
|
|
|
fail3:
|
|
|
|
|
ipw_release(sc);
|
|
|
|
|
fail2:
|
|
|
|
|
bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
|
|
|
|
|
bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), sc->irq);
|
|
|
|
|
fail1:
|
|
|
|
|
bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
|
|
|
|
|
bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem),
|
|
|
|
|
sc->mem);
|
|
|
|
|
fail:
|
|
|
|
|
mtx_destroy(&sc->sc_mtx);
|
|
|
|
|
return ENXIO;
|
|
|
|
@@ -398,8 +364,9 @@ static int
|
|
|
|
|
ipw_detach(device_t dev)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = device_get_softc(dev);
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
|
|
|
|
|
bus_teardown_intr(dev, sc->irq, sc->sc_ih);
|
|
|
|
|
|
|
|
|
|
ieee80211_draintask(ic, &sc->sc_init_task);
|
|
|
|
|
ipw_stop(sc);
|
|
|
|
@@ -407,15 +374,14 @@ ipw_detach(device_t dev)
|
|
|
|
|
ieee80211_ifdetach(ic);
|
|
|
|
|
|
|
|
|
|
callout_drain(&sc->sc_wdtimer);
|
|
|
|
|
mbufq_drain(&sc->sc_snd);
|
|
|
|
|
|
|
|
|
|
ipw_release(sc);
|
|
|
|
|
|
|
|
|
|
bus_teardown_intr(dev, sc->irq, sc->sc_ih);
|
|
|
|
|
bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
|
|
|
|
|
bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), sc->irq);
|
|
|
|
|
|
|
|
|
|
bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
|
|
|
|
|
|
|
|
|
|
if_free(ifp);
|
|
|
|
|
bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem),
|
|
|
|
|
sc->mem);
|
|
|
|
|
|
|
|
|
|
if (sc->sc_firmware != NULL) {
|
|
|
|
|
firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
|
|
|
|
@@ -433,8 +399,7 @@ ipw_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
|
|
|
|
|
const uint8_t bssid[IEEE80211_ADDR_LEN],
|
|
|
|
|
const uint8_t mac[IEEE80211_ADDR_LEN])
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = ic->ic_ifp;
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
struct ipw_vap *ivp;
|
|
|
|
|
struct ieee80211vap *vap;
|
|
|
|
|
const struct firmware *fp;
|
|
|
|
@@ -492,19 +457,17 @@ ipw_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ivp = (struct ipw_vap *) malloc(sizeof(struct ipw_vap),
|
|
|
|
|
M_80211_VAP, M_NOWAIT | M_ZERO);
|
|
|
|
|
if (ivp == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
ivp = malloc(sizeof(struct ipw_vap), M_80211_VAP, M_WAITOK | M_ZERO);
|
|
|
|
|
vap = &ivp->vap;
|
|
|
|
|
|
|
|
|
|
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
|
|
|
|
|
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
|
|
|
|
|
/* override with driver methods */
|
|
|
|
|
ivp->newstate = vap->iv_newstate;
|
|
|
|
|
vap->iv_newstate = ipw_newstate;
|
|
|
|
|
|
|
|
|
|
/* complete setup */
|
|
|
|
|
ieee80211_vap_attach(vap, ieee80211_media_change, ipw_media_status);
|
|
|
|
|
ieee80211_vap_attach(vap, ieee80211_media_change, ipw_media_status,
|
|
|
|
|
mac);
|
|
|
|
|
ic->ic_opmode = opmode;
|
|
|
|
|
return vap;
|
|
|
|
|
}
|
|
|
|
@@ -758,11 +721,8 @@ ipw_release(struct ipw_softc *sc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sc->tbd_dmat != NULL) {
|
|
|
|
|
if (sc->stbd_list != NULL) {
|
|
|
|
|
bus_dmamap_unload(sc->tbd_dmat, sc->tbd_map);
|
|
|
|
|
bus_dmamem_free(sc->tbd_dmat, sc->tbd_list,
|
|
|
|
|
sc->tbd_map);
|
|
|
|
|
}
|
|
|
|
|
bus_dmamap_unload(sc->tbd_dmat, sc->tbd_map);
|
|
|
|
|
bus_dmamem_free(sc->tbd_dmat, sc->tbd_list, sc->tbd_map);
|
|
|
|
|
bus_dma_tag_destroy(sc->tbd_dmat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -835,7 +795,7 @@ static int
|
|
|
|
|
ipw_suspend(device_t dev)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = device_get_softc(dev);
|
|
|
|
|
struct ieee80211com *ic = sc->sc_ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
|
|
|
|
|
ieee80211_suspend_all(ic);
|
|
|
|
|
return 0;
|
|
|
|
@@ -845,7 +805,7 @@ static int
|
|
|
|
|
ipw_resume(device_t dev)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = device_get_softc(dev);
|
|
|
|
|
struct ieee80211com *ic = sc->sc_ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
|
|
|
|
|
pci_write_config(dev, 0x41, 0, 1);
|
|
|
|
|
|
|
|
|
@@ -874,7 +834,7 @@ ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
|
|
|
|
|
{
|
|
|
|
|
struct ieee80211vap *vap = ifp->if_softc;
|
|
|
|
|
struct ieee80211com *ic = vap->iv_ic;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
|
|
|
|
|
/* read current transmission rate from adapter */
|
|
|
|
|
vap->iv_bss->ni_txrate = ipw_cvtrate(
|
|
|
|
@@ -887,8 +847,7 @@ ipw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_vap *ivp = IPW_VAP(vap);
|
|
|
|
|
struct ieee80211com *ic = vap->iv_ic;
|
|
|
|
|
struct ifnet *ifp = ic->ic_ifp;
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
enum ieee80211_state ostate;
|
|
|
|
|
|
|
|
|
|
DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__,
|
|
|
|
@@ -1001,6 +960,19 @@ ipw_read_prom_word(struct ipw_softc *sc, uint8_t addr)
|
|
|
|
|
return le16toh(val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
|
ipw_read_chanmask(struct ipw_softc *sc)
|
|
|
|
|
{
|
|
|
|
|
uint16_t val;
|
|
|
|
|
|
|
|
|
|
/* set supported .11b channels (read from EEPROM) */
|
|
|
|
|
if ((val = ipw_read_prom_word(sc, IPW_EEPROM_CHANNEL_LIST)) == 0)
|
|
|
|
|
val = 0x7ff; /* default to channels 1-11 */
|
|
|
|
|
val <<= 1;
|
|
|
|
|
|
|
|
|
|
return (val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ipw_rx_cmd_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
|
|
|
|
|
{
|
|
|
|
@@ -1023,8 +995,7 @@ static void
|
|
|
|
|
ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
|
|
|
|
|
{
|
|
|
|
|
#define IEEESTATE(vap) ieee80211_state_name[vap->iv_state]
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
|
uint32_t state;
|
|
|
|
|
|
|
|
|
@@ -1126,8 +1097,7 @@ ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
|
|
|
|
|
static void
|
|
|
|
|
ipw_setcurchan(struct ipw_softc *sc, struct ieee80211_channel *chan)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
|
|
|
|
|
ic->ic_curchan = chan;
|
|
|
|
|
ieee80211_radiotap_chan_change(ic);
|
|
|
|
@@ -1140,8 +1110,7 @@ ipw_setcurchan(struct ipw_softc *sc, struct ieee80211_channel *chan)
|
|
|
|
|
static void
|
|
|
|
|
ipw_fix_channel(struct ipw_softc *sc, struct mbuf *m)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
struct ieee80211_channel *c;
|
|
|
|
|
struct ieee80211_frame *wh;
|
|
|
|
|
uint8_t subtype;
|
|
|
|
@@ -1186,8 +1155,7 @@ static void
|
|
|
|
|
ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status,
|
|
|
|
|
struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
struct mbuf *mnew, *m;
|
|
|
|
|
struct ieee80211_node *ni;
|
|
|
|
|
bus_addr_t physaddr;
|
|
|
|
@@ -1209,7 +1177,7 @@ ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status,
|
|
|
|
|
*/
|
|
|
|
|
mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
|
|
|
|
|
if (mnew == NULL) {
|
|
|
|
|
ifp->if_ierrors++;
|
|
|
|
|
counter_u64_add(ic->ic_ierrors, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1230,7 +1198,7 @@ ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status,
|
|
|
|
|
panic("%s: could not load old rx mbuf",
|
|
|
|
|
device_get_name(sc->sc_dev));
|
|
|
|
|
}
|
|
|
|
|
ifp->if_ierrors++;
|
|
|
|
|
counter_u64_add(ic->ic_ierrors, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1241,9 +1209,6 @@ ipw_rx_data_intr(struct ipw_softc *sc, struct ipw_status *status,
|
|
|
|
|
m = sbuf->m;
|
|
|
|
|
sbuf->m = mnew;
|
|
|
|
|
sbd->bd->physaddr = htole32(physaddr);
|
|
|
|
|
|
|
|
|
|
/* finalize mbuf */
|
|
|
|
|
m->m_pkthdr.rcvif = ifp;
|
|
|
|
|
m->m_pkthdr.len = m->m_len = le32toh(status->len);
|
|
|
|
|
|
|
|
|
|
rssi = status->rssi + IPW_RSSI_TO_DBM;
|
|
|
|
@@ -1372,7 +1337,6 @@ ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd)
|
|
|
|
|
static void
|
|
|
|
|
ipw_tx_intr(struct ipw_softc *sc)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ipw_soft_bd *sbd;
|
|
|
|
|
uint32_t r, i;
|
|
|
|
|
|
|
|
|
@@ -1383,10 +1347,6 @@ ipw_tx_intr(struct ipw_softc *sc)
|
|
|
|
|
|
|
|
|
|
for (i = (sc->txold + 1) % IPW_NTBD; i != r; i = (i + 1) % IPW_NTBD) {
|
|
|
|
|
sbd = &sc->stbd_list[i];
|
|
|
|
|
|
|
|
|
|
if (sbd->type == IPW_SBD_TYPE_DATA)
|
|
|
|
|
ifp->if_opackets++;
|
|
|
|
|
|
|
|
|
|
ipw_release_sbd(sc, sbd);
|
|
|
|
|
sc->txfree++;
|
|
|
|
|
}
|
|
|
|
@@ -1394,15 +1354,13 @@ ipw_tx_intr(struct ipw_softc *sc)
|
|
|
|
|
/* remember what the firmware has processed */
|
|
|
|
|
sc->txold = (r == 0) ? IPW_NTBD - 1 : r - 1;
|
|
|
|
|
|
|
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
|
|
|
|
ipw_start_locked(ifp);
|
|
|
|
|
ipw_start(sc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ipw_fatal_error_intr(struct ipw_softc *sc)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
|
|
|
|
|
|
device_printf(sc->sc_dev, "firmware error\n");
|
|
|
|
@@ -1470,7 +1428,6 @@ ipw_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
|
|
|
|
static const char *
|
|
|
|
|
ipw_cmdname(int cmd)
|
|
|
|
|
{
|
|
|
|
|
#define N(a) (sizeof(a) / sizeof(a[0]))
|
|
|
|
|
static const struct {
|
|
|
|
|
int cmd;
|
|
|
|
|
const char *name;
|
|
|
|
@@ -1507,12 +1464,11 @@ ipw_cmdname(int cmd)
|
|
|
|
|
static char buf[12];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < N(cmds); i++)
|
|
|
|
|
for (i = 0; i < nitems(cmds); i++)
|
|
|
|
|
if (cmds[i].cmd == cmd)
|
|
|
|
|
return cmds[i].name;
|
|
|
|
|
snprintf(buf, sizeof(buf), "%u", cmd);
|
|
|
|
|
return buf;
|
|
|
|
|
#undef N
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -1566,14 +1522,9 @@ ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len)
|
|
|
|
|
0, 0, len);
|
|
|
|
|
/* Print the data buffer in the higher debug level */
|
|
|
|
|
if (ipw_debug >= 9 && len > 0) {
|
|
|
|
|
#ifdef __HAIKU__
|
|
|
|
|
int i;
|
|
|
|
|
printf(" data: 0x");
|
|
|
|
|
for (i = 1; i <= len; i++)
|
|
|
|
|
#else
|
|
|
|
|
printf(" data: 0x");
|
|
|
|
|
for (int i = 1; i <= len; i++)
|
|
|
|
|
#endif
|
|
|
|
|
printf("%1D", (u_char *)data + len - i, "");
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
|
|
|
@@ -1597,10 +1548,9 @@ ipw_cmd(struct ipw_softc *sc, uint32_t type, void *data, uint32_t len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ipw_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
|
|
|
|
|
ipw_tx_start(struct ipw_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
struct ieee80211vap *vap = ni->ni_vap;
|
|
|
|
|
struct ieee80211_frame *wh;
|
|
|
|
|
struct ipw_soft_bd *sbd;
|
|
|
|
@@ -1614,7 +1564,7 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
|
|
|
|
|
|
|
|
|
|
wh = mtod(m0, struct ieee80211_frame *);
|
|
|
|
|
|
|
|
|
|
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
|
|
|
|
|
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
|
|
|
|
|
k = ieee80211_crypto_encap(ni, m0);
|
|
|
|
|
if (k == NULL) {
|
|
|
|
|
m_freem(m0);
|
|
|
|
@@ -1638,7 +1588,7 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
|
|
|
|
|
|
|
|
|
|
shdr->hdr.type = htole32(IPW_HDR_TYPE_SEND);
|
|
|
|
|
shdr->hdr.subtype = 0;
|
|
|
|
|
shdr->hdr.encrypted = (wh->i_fc[1] & IEEE80211_FC1_WEP) ? 1 : 0;
|
|
|
|
|
shdr->hdr.encrypted = (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) ? 1 : 0;
|
|
|
|
|
shdr->hdr.encrypt = 0;
|
|
|
|
|
shdr->hdr.keyidx = 0;
|
|
|
|
|
shdr->hdr.keysz = 0;
|
|
|
|
@@ -1754,38 +1704,42 @@ ipw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ipw_start(struct ifnet *ifp)
|
|
|
|
|
static int
|
|
|
|
|
ipw_transmit(struct ieee80211com *ic, struct mbuf *m)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK(sc);
|
|
|
|
|
ipw_start_locked(ifp);
|
|
|
|
|
if ((sc->flags & IPW_FLAG_RUNNING) == 0) {
|
|
|
|
|
IPW_UNLOCK(sc);
|
|
|
|
|
return (ENXIO);
|
|
|
|
|
}
|
|
|
|
|
error = mbufq_enqueue(&sc->sc_snd, m);
|
|
|
|
|
if (error) {
|
|
|
|
|
IPW_UNLOCK(sc);
|
|
|
|
|
return (error);
|
|
|
|
|
}
|
|
|
|
|
ipw_start(sc);
|
|
|
|
|
IPW_UNLOCK(sc);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ipw_start_locked(struct ifnet *ifp)
|
|
|
|
|
ipw_start(struct ipw_softc *sc)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ieee80211_node *ni;
|
|
|
|
|
struct mbuf *m;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK_ASSERT(sc);
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
|
|
|
|
|
if (m == NULL)
|
|
|
|
|
break;
|
|
|
|
|
if (sc->txfree < 1 + IPW_MAX_NSEG) {
|
|
|
|
|
IFQ_DRV_PREPEND(&ifp->if_snd, m);
|
|
|
|
|
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
while (sc->txfree < 1 + IPW_MAX_NSEG &&
|
|
|
|
|
(m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
|
|
|
|
|
ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
|
|
|
|
|
if (ipw_tx_start(ifp, m, ni) != 0) {
|
|
|
|
|
if (ipw_tx_start(sc, m, ni) != 0) {
|
|
|
|
|
if_inc_counter(ni->ni_vap->iv_ifp,
|
|
|
|
|
IFCOUNTER_OERRORS, 1);
|
|
|
|
|
ieee80211_free_node(ni);
|
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* start watchdog timer */
|
|
|
|
@@ -1797,15 +1751,14 @@ static void
|
|
|
|
|
ipw_watchdog(void *arg)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = arg;
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK_ASSERT(sc);
|
|
|
|
|
|
|
|
|
|
if (sc->sc_tx_timer > 0) {
|
|
|
|
|
if (--sc->sc_tx_timer == 0) {
|
|
|
|
|
if_printf(ifp, "device timeout\n");
|
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
|
device_printf(sc->sc_dev, "device timeout\n");
|
|
|
|
|
counter_u64_add(ic->ic_oerrors, 1);
|
|
|
|
|
taskqueue_enqueue(taskqueue_swi, &sc->sc_init_task);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -1821,45 +1774,27 @@ ipw_watchdog(void *arg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
|
|
|
|
|
if (sc->flags & IPW_FLAG_RUNNING)
|
|
|
|
|
callout_reset(&sc->sc_wdtimer, hz, ipw_watchdog, sc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
|
|
|
|
static void
|
|
|
|
|
ipw_parent(struct ieee80211com *ic)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ifreq *ifr = (struct ifreq *) data;
|
|
|
|
|
int error = 0, startall = 0;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
int startall = 0;
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case SIOCSIFFLAGS:
|
|
|
|
|
IPW_LOCK(sc);
|
|
|
|
|
if (ifp->if_flags & IFF_UP) {
|
|
|
|
|
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
|
|
|
|
|
ipw_init_locked(sc);
|
|
|
|
|
startall = 1;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
|
|
|
|
|
ipw_stop_locked(sc);
|
|
|
|
|
IPW_LOCK(sc);
|
|
|
|
|
if (ic->ic_nrunning > 0) {
|
|
|
|
|
if (!(sc->flags & IPW_FLAG_RUNNING)) {
|
|
|
|
|
ipw_init_locked(sc);
|
|
|
|
|
startall = 1;
|
|
|
|
|
}
|
|
|
|
|
IPW_UNLOCK(sc);
|
|
|
|
|
if (startall)
|
|
|
|
|
ieee80211_start_all(ic);
|
|
|
|
|
break;
|
|
|
|
|
case SIOCGIFMEDIA:
|
|
|
|
|
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
|
|
|
|
|
break;
|
|
|
|
|
case SIOCGIFADDR:
|
|
|
|
|
error = ether_ioctl(ifp, cmd, data);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
error = EINVAL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
} else if (sc->flags & IPW_FLAG_RUNNING)
|
|
|
|
|
ipw_stop_locked(sc);
|
|
|
|
|
IPW_UNLOCK(sc);
|
|
|
|
|
if (startall)
|
|
|
|
|
ieee80211_start_all(ic);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
@@ -2075,8 +2010,7 @@ ipw_load_firmware(struct ipw_softc *sc, const char *fw, int size)
|
|
|
|
|
static int
|
|
|
|
|
ipw_setwepkeys(struct ipw_softc *sc)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
|
struct ipw_wep_key wepkey;
|
|
|
|
|
struct ieee80211_key *wk;
|
|
|
|
@@ -2219,8 +2153,7 @@ done:
|
|
|
|
|
static int
|
|
|
|
|
ipw_setchannel(struct ipw_softc *sc, struct ieee80211_channel *chan)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
uint32_t data;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
@@ -2235,8 +2168,7 @@ ipw_setchannel(struct ipw_softc *sc, struct ieee80211_channel *chan)
|
|
|
|
|
static void
|
|
|
|
|
ipw_assoc(struct ieee80211com *ic, struct ieee80211vap *vap)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = vap->iv_ic->ic_ifp;
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
struct ieee80211_node *ni = vap->iv_bss;
|
|
|
|
|
struct ipw_security security;
|
|
|
|
|
uint32_t data;
|
|
|
|
@@ -2327,9 +2259,8 @@ done:
|
|
|
|
|
static void
|
|
|
|
|
ipw_disassoc(struct ieee80211com *ic, struct ieee80211vap *vap)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = vap->iv_ic->ic_ifp;
|
|
|
|
|
struct ieee80211_node *ni = vap->iv_bss;
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK(sc);
|
|
|
|
|
DPRINTF(("Disassociate from %6D\n", ni->ni_bssid, ":"));
|
|
|
|
@@ -2363,22 +2294,20 @@ static void
|
|
|
|
|
ipw_init(void *priv)
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = priv;
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK(sc);
|
|
|
|
|
ipw_init_locked(sc);
|
|
|
|
|
IPW_UNLOCK(sc);
|
|
|
|
|
|
|
|
|
|
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
|
|
|
|
|
if (sc->flags & IPW_FLAG_RUNNING)
|
|
|
|
|
ieee80211_start_all(ic); /* start all vap's */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ipw_init_locked(struct ipw_softc *sc)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
|
const struct firmware *fp;
|
|
|
|
|
const struct ipw_firmware_hdr *hdr;
|
|
|
|
@@ -2462,22 +2391,19 @@ ipw_init_locked(struct ipw_softc *sc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callout_reset(&sc->sc_wdtimer, hz, ipw_watchdog, sc);
|
|
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
|
|
|
|
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
|
|
|
|
|
|
|
|
|
sc->flags &=~ IPW_FLAG_INIT_LOCKED;
|
|
|
|
|
sc->flags |= IPW_FLAG_RUNNING;
|
|
|
|
|
sc->flags &= ~IPW_FLAG_INIT_LOCKED;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
ipw_stop_locked(sc);
|
|
|
|
|
sc->flags &=~ IPW_FLAG_INIT_LOCKED;
|
|
|
|
|
sc->flags &= ~IPW_FLAG_INIT_LOCKED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ipw_config(struct ipw_softc *sc)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
struct ieee80211com *ic = ifp->if_l2com;
|
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
struct ipw_configuration config;
|
|
|
|
|
uint32_t data;
|
|
|
|
|
int error;
|
|
|
|
@@ -2522,7 +2448,7 @@ ipw_config(struct ipw_softc *sc)
|
|
|
|
|
IPW_CFG_PREAMBLE_AUTO | IPW_CFG_802_1x_ENABLE);
|
|
|
|
|
if (ic->ic_opmode == IEEE80211_M_IBSS)
|
|
|
|
|
config.flags |= htole32(IPW_CFG_IBSS_AUTO_START);
|
|
|
|
|
if (ifp->if_flags & IFF_PROMISC)
|
|
|
|
|
if (ic->ic_promisc > 0)
|
|
|
|
|
config.flags |= htole32(IPW_CFG_PROMISCUOUS);
|
|
|
|
|
config.bss_chan = htole32(0x3fff); /* channels 1-14 */
|
|
|
|
|
config.ibss_chan = htole32(0x7ff); /* channels 1-11 */
|
|
|
|
@@ -2580,7 +2506,6 @@ ipw_stop(void *priv)
|
|
|
|
|
static void
|
|
|
|
|
ipw_stop_locked(struct ipw_softc *sc)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = sc->sc_ifp;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK_ASSERT(sc);
|
|
|
|
@@ -2597,7 +2522,7 @@ ipw_stop_locked(struct ipw_softc *sc)
|
|
|
|
|
ipw_release_sbd(sc, &sc->stbd_list[i]);
|
|
|
|
|
|
|
|
|
|
sc->sc_tx_timer = 0;
|
|
|
|
|
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
|
|
|
|
|
sc->flags &= ~IPW_FLAG_RUNNING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
@@ -2695,19 +2620,37 @@ ipw_write_mem_1(struct ipw_softc *sc, bus_size_t offset, const uint8_t *datap,
|
|
|
|
|
static void
|
|
|
|
|
ipw_scan_start(struct ieee80211com *ic)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = ic->ic_ifp;
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK(sc);
|
|
|
|
|
ipw_scan(sc);
|
|
|
|
|
IPW_UNLOCK(sc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ipw_getradiocaps(struct ieee80211com *ic,
|
|
|
|
|
int maxchans, int *nchans, struct ieee80211_channel chans[])
|
|
|
|
|
{
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
uint8_t bands[IEEE80211_MODE_BYTES];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
memset(bands, 0, sizeof(bands));
|
|
|
|
|
setbit(bands, IEEE80211_MODE_11B);
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < 16; i++) {
|
|
|
|
|
if (sc->chanmask & (1 << i)) {
|
|
|
|
|
ieee80211_add_channel(chans, maxchans, nchans,
|
|
|
|
|
i, 0, 0, 0, bands);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ipw_set_channel(struct ieee80211com *ic)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = ic->ic_ifp;
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK(sc);
|
|
|
|
|
if (ic->ic_opmode == IEEE80211_M_MONITOR) {
|
|
|
|
@@ -2733,8 +2676,7 @@ ipw_scan_mindwell(struct ieee80211_scan_state *ss)
|
|
|
|
|
static void
|
|
|
|
|
ipw_scan_end(struct ieee80211com *ic)
|
|
|
|
|
{
|
|
|
|
|
struct ifnet *ifp = ic->ic_ifp;
|
|
|
|
|
struct ipw_softc *sc = ifp->if_softc;
|
|
|
|
|
struct ipw_softc *sc = ic->ic_softc;
|
|
|
|
|
|
|
|
|
|
IPW_LOCK(sc);
|
|
|
|
|
sc->flags &= ~IPW_FLAG_SCANNING;
|
|
|
|
|