Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/wpi/if_wpi.c
Context not available. | |||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static void wpi_start(struct ifnet *); | static int wpi_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void wpi_start_task(void *, int); | static void wpi_start(void *, int); | ||||
static void wpi_watchdog_rfkill(void *); | static void wpi_watchdog_rfkill(void *); | ||||
static void wpi_scan_timeout(void *); | static void wpi_scan_timeout(void *); | ||||
static void wpi_tx_timeout(void *); | static void wpi_tx_timeout(void *); | ||||
static int wpi_ioctl(struct ifnet *, u_long, caddr_t); | static void wpi_parent(struct ieee80211com *); | ||||
static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); | static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); | ||||
static int wpi_mrr_setup(struct wpi_softc *); | static int wpi_mrr_setup(struct wpi_softc *); | ||||
static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); | static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); | ||||
Context not available. | |||||
static void wpi_hw_stop(struct wpi_softc *); | static void wpi_hw_stop(struct wpi_softc *); | ||||
static void wpi_radio_on(void *, int); | static void wpi_radio_on(void *, int); | ||||
static void wpi_radio_off(void *, int); | static void wpi_radio_off(void *, int); | ||||
static void wpi_init(void *); | static int wpi_init(struct wpi_softc *); | ||||
static void wpi_stop_locked(struct wpi_softc *); | static void wpi_stop_locked(struct wpi_softc *); | ||||
static void wpi_stop(struct wpi_softc *); | static void wpi_stop(struct wpi_softc *); | ||||
static void wpi_scan_start(struct ieee80211com *); | static void wpi_scan_start(struct ieee80211com *); | ||||
Context not available. | |||||
{ | { | ||||
struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); | struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); | ||||
struct ieee80211com *ic; | struct ieee80211com *ic; | ||||
struct ifnet *ifp; | |||||
int i, error, rid; | int i, error, rid; | ||||
#ifdef WPI_DEBUG | #ifdef WPI_DEBUG | ||||
int supportsa = 1; | int supportsa = 1; | ||||
const struct wpi_ident *ident; | const struct wpi_ident *ident; | ||||
#endif | #endif | ||||
uint8_t macaddr[IEEE80211_ADDR_LEN]; | |||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
Context not available. | |||||
/* Clear pending interrupts. */ | /* Clear pending interrupts. */ | ||||
WPI_WRITE(sc, WPI_INT, 0xffffffff); | WPI_WRITE(sc, WPI_INT, 0xffffffff); | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | ic = &sc->sc_ic; | ||||
if (ifp == NULL) { | |||||
device_printf(dev, "can not allocate ifnet structure\n"); | |||||
goto fail; | |||||
} | |||||
ic = ifp->if_l2com; | |||||
ic->ic_ifp = ifp; | |||||
ic->ic_softc = sc; | ic->ic_softc = sc; | ||||
ic->ic_name = device_get_nameunit(dev); | ic->ic_name = device_get_nameunit(dev); | ||||
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ||||
Context not available. | |||||
* Read in the eeprom and also setup the channels for | * Read in the eeprom and also setup the channels for | ||||
* net80211. We don't set the rates as net80211 does this for us | * net80211. We don't set the rates as net80211 does this for us | ||||
*/ | */ | ||||
if ((error = wpi_read_eeprom(sc, macaddr)) != 0) { | if ((error = wpi_read_eeprom(sc, ic->ic_macaddr)) != 0) { | ||||
device_printf(dev, "could not read EEPROM, error %d\n", | device_printf(dev, "could not read EEPROM, error %d\n", | ||||
error); | error); | ||||
goto fail; | goto fail; | ||||
Context not available. | |||||
} | } | ||||
#endif | #endif | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ieee80211_ifattach(ic); | ||||
ifp->if_softc = sc; | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = wpi_init; | |||||
ifp->if_ioctl = wpi_ioctl; | |||||
ifp->if_start = wpi_start; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
ieee80211_ifattach(ic, macaddr); | |||||
ic->ic_vap_create = wpi_vap_create; | ic->ic_vap_create = wpi_vap_create; | ||||
ic->ic_vap_delete = wpi_vap_delete; | ic->ic_vap_delete = wpi_vap_delete; | ||||
ic->ic_parent = wpi_parent; | |||||
ic->ic_raw_xmit = wpi_raw_xmit; | ic->ic_raw_xmit = wpi_raw_xmit; | ||||
ic->ic_transmit = wpi_transmit; | |||||
ic->ic_node_alloc = wpi_node_alloc; | ic->ic_node_alloc = wpi_node_alloc; | ||||
sc->sc_node_free = ic->ic_node_free; | sc->sc_node_free = ic->ic_node_free; | ||||
ic->ic_node_free = wpi_node_free; | ic->ic_node_free = wpi_node_free; | ||||
Context not available. | |||||
TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); | TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); | ||||
TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); | TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); | ||||
TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); | TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); | ||||
TASK_INIT(&sc->sc_start_task, 0, wpi_start_task, sc); | TASK_INIT(&sc->sc_start_task, 0, wpi_start, sc); | ||||
sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK, | sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK, | ||||
taskqueue_thread_enqueue, &sc->sc_tq); | taskqueue_thread_enqueue, &sc->sc_tq); | ||||
Context not available. | |||||
static void | static void | ||||
wpi_radiotap_attach(struct wpi_softc *sc) | wpi_radiotap_attach(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct wpi_rx_radiotap_header *rxtap = &sc->sc_rxtap; | ||||
struct ieee80211com *ic = ifp->if_l2com; | struct wpi_tx_radiotap_header *txtap = &sc->sc_txtap; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(&sc->sc_ic, | ||||
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | &txtap->wt_ihdr, sizeof(*txtap), WPI_TX_RADIOTAP_PRESENT, | ||||
WPI_TX_RADIOTAP_PRESENT, | &rxtap->wr_ihdr, sizeof(*rxtap), WPI_RX_RADIOTAP_PRESENT); | ||||
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | |||||
WPI_RX_RADIOTAP_PRESENT); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
} | } | ||||
Context not available. | |||||
if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ | if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ | ||||
return NULL; | return NULL; | ||||
wvp = (struct wpi_vap *) malloc(sizeof(struct wpi_vap), | wvp = malloc(sizeof(struct wpi_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
M_80211_VAP, M_NOWAIT | M_ZERO); | |||||
if (wvp == NULL) | |||||
return NULL; | |||||
vap = &wvp->wv_vap; | vap = &wvp->wv_vap; | ||||
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); | ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); | ||||
if (opmode == IEEE80211_M_IBSS || opmode == IEEE80211_M_HOSTAP) { | if (opmode == IEEE80211_M_IBSS || opmode == IEEE80211_M_HOSTAP) { | ||||
WPI_VAP_LOCK_INIT(wvp); | WPI_VAP_LOCK_INIT(wvp); | ||||
Context not available. | |||||
ieee80211_ratectl_init(vap); | ieee80211_ratectl_init(vap); | ||||
/* Complete setup. */ | /* Complete setup. */ | ||||
ieee80211_vap_attach(vap, ieee80211_media_change, | ieee80211_vap_attach(vap, ieee80211_media_change, | ||||
ieee80211_media_status); | ieee80211_media_status, mac); | ||||
ic->ic_opmode = opmode; | ic->ic_opmode = opmode; | ||||
return vap; | return vap; | ||||
} | } | ||||
Context not available. | |||||
wpi_detach(device_t dev) | wpi_detach(device_t dev) | ||||
{ | { | ||||
struct wpi_softc *sc = device_get_softc(dev); | struct wpi_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic; | |||||
int qid; | int qid; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if (ifp != NULL) { | if (ic->ic_vap_create == wpi_vap_create) { | ||||
ic = ifp->if_l2com; | |||||
ieee80211_draintask(ic, &sc->sc_radioon_task); | ieee80211_draintask(ic, &sc->sc_radioon_task); | ||||
ieee80211_draintask(ic, &sc->sc_start_task); | ieee80211_draintask(ic, &sc->sc_start_task); | ||||
wpi_stop(sc); | wpi_stop(sc); | ||||
taskqueue_drain_all(sc->sc_tq); | if (sc->sc_tq != NULL) { | ||||
taskqueue_free(sc->sc_tq); | taskqueue_drain_all(sc->sc_tq); | ||||
taskqueue_free(sc->sc_tq); | |||||
} | |||||
callout_drain(&sc->watchdog_rfkill); | callout_drain(&sc->watchdog_rfkill); | ||||
callout_drain(&sc->tx_timeout); | callout_drain(&sc->tx_timeout); | ||||
Context not available. | |||||
bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, | ||||
rman_get_rid(sc->mem), sc->mem); | rman_get_rid(sc->mem), sc->mem); | ||||
if (ifp != NULL) | |||||
if_free(ifp); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
WPI_TXQ_STATE_LOCK_DESTROY(sc); | WPI_TXQ_STATE_LOCK_DESTROY(sc); | ||||
WPI_TXQ_LOCK_DESTROY(sc); | WPI_TXQ_LOCK_DESTROY(sc); | ||||
Context not available. | |||||
wpi_suspend(device_t dev) | wpi_suspend(device_t dev) | ||||
{ | { | ||||
struct wpi_softc *sc = device_get_softc(dev); | struct wpi_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
ieee80211_suspend_all(ic); | ieee80211_suspend_all(ic); | ||||
return 0; | return 0; | ||||
Context not available. | |||||
wpi_resume(device_t dev) | wpi_resume(device_t dev) | ||||
{ | { | ||||
struct wpi_softc *sc = device_get_softc(dev); | struct wpi_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
/* Clear device-specific "PCI retry timeout" register (41h). */ | /* Clear device-specific "PCI retry timeout" register (41h). */ | ||||
pci_write_config(dev, 0x41, 0, 1); | pci_write_config(dev, 0x41, 0, 1); | ||||
Context not available. | |||||
ring->queued = 0; | ring->queued = 0; | ||||
ring->cur = 0; | ring->cur = 0; | ||||
ring->update = 0; | ring->update = 0; | ||||
mbufq_init(&ring->snd, ifqmaxlen); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
Context not available. | |||||
memset(ring->desc, 0, ring->desc_dma.size); | memset(ring->desc, 0, ring->desc_dma.size); | ||||
bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, | bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
mbufq_drain(&ring->snd); | |||||
sc->qfullmsk &= ~(1 << ring->qid); | sc->qfullmsk &= ~(1 << ring->qid); | ||||
ring->queued = 0; | ring->queued = 0; | ||||
ring->cur = 0; | ring->cur = 0; | ||||
Context not available. | |||||
static void | static void | ||||
wpi_read_eeprom_band(struct wpi_softc *sc, int n) | wpi_read_eeprom_band(struct wpi_softc *sc, int n) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; | struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; | ||||
const struct wpi_chan_band *band = &wpi_bands[n]; | const struct wpi_chan_band *band = &wpi_bands[n]; | ||||
struct ieee80211_channel *c; | struct ieee80211_channel *c; | ||||
Context not available. | |||||
static int | static int | ||||
wpi_read_eeprom_channels(struct wpi_softc *sc, int n) | wpi_read_eeprom_channels(struct wpi_softc *sc, int n) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
const struct wpi_chan_band *band = &wpi_bands[n]; | const struct wpi_chan_band *band = &wpi_bands[n]; | ||||
int error; | int error; | ||||
Context not available. | |||||
wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, | wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, | ||||
int nchan, struct ieee80211_channel chans[]) | int nchan, struct ieee80211_channel chans[]) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | |||||
int i; | int i; | ||||
for (i = 0; i < nchan; i++) { | for (i = 0; i < nchan; i++) { | ||||
Context not available. | |||||
channel = wpi_find_eeprom_channel(sc, c); | channel = wpi_find_eeprom_channel(sc, c); | ||||
if (channel == NULL) { | if (channel == NULL) { | ||||
if_printf(ic->ic_ifp, | ic_printf(ic, "%s: invalid channel %u freq %u/0x%x\n", | ||||
"%s: invalid channel %u freq %u/0x%x\n", | |||||
__func__, c->ic_ieee, c->ic_freq, c->ic_flags); | __func__, c->ic_ieee, c->ic_freq, c->ic_flags); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
Context not available. | |||||
static void | static void | ||||
wpi_node_free(struct ieee80211_node *ni) | wpi_node_free(struct ieee80211_node *ni) | ||||
{ | { | ||||
struct ieee80211com *ic = ni->ni_ic; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | |||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
if (wn->id != WPI_ID_UNDEFINED) { | if (wn->id != WPI_ID_UNDEFINED) { | ||||
Context not available. | |||||
int rssi, int nf) | int rssi, int nf) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; | struct wpi_softc *sc = vap->iv_ic->ic_softc; | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
uint64_t ni_tstamp, rx_tstamp; | uint64_t ni_tstamp, rx_tstamp; | ||||
Context not available. | |||||
static void | static void | ||||
wpi_restore_node_table(struct wpi_softc *sc, struct wpi_vap *wvp) | wpi_restore_node_table(struct wpi_softc *sc, struct wpi_vap *wvp) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
/* Set group keys once. */ | /* Set group keys once. */ | ||||
WPI_NT_LOCK(sc); | WPI_NT_LOCK(sc); | ||||
Context not available. | |||||
{ | { | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | |||||
int error = 0; | int error = 0; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
WPI_TXQ_LOCK(sc); | |||||
if (nstate > IEEE80211_S_INIT && sc->sc_running == 0) { | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | |||||
WPI_TXQ_UNLOCK(sc); | |||||
return ENXIO; | |||||
} | |||||
WPI_TXQ_UNLOCK(sc); | |||||
DPRINTF(sc, WPI_DEBUG_STATE, "%s: %s -> %s\n", __func__, | DPRINTF(sc, WPI_DEBUG_STATE, "%s: %s -> %s\n", __func__, | ||||
ieee80211_state_name[vap->iv_state], | ieee80211_state_name[vap->iv_state], | ||||
ieee80211_state_name[nstate]); | ieee80211_state_name[nstate]); | ||||
Context not available. | |||||
wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, | wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, | ||||
struct wpi_rx_data *data) | struct wpi_rx_data *data) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct wpi_rx_ring *ring = &sc->rxq; | struct wpi_rx_ring *ring = &sc->rxq; | ||||
struct wpi_rx_stat *stat; | struct wpi_rx_stat *stat; | ||||
struct wpi_rx_head *head; | struct wpi_rx_head *head; | ||||
Context not available. | |||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
/* Finalize mbuf. */ | /* Finalize mbuf. */ | ||||
m->m_pkthdr.rcvif = ifp; | |||||
m->m_data = (caddr_t)(head + 1); | m->m_data = (caddr_t)(head + 1); | ||||
m->m_pkthdr.len = m->m_len = len; | m->m_pkthdr.len = m->m_len = len; | ||||
Context not available. | |||||
fail2: m_freem(m); | fail2: m_freem(m); | ||||
fail1: if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | fail1: counter_u64_add(ic->ic_ierrors, 1); | ||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
static void | static void | ||||
wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) | wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; | struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; | ||||
struct wpi_tx_data *data = &ring->data[desc->idx]; | struct wpi_tx_data *data = &ring->data[desc->idx]; | ||||
struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); | struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); | ||||
Context not available. | |||||
* Update rate control statistics for the node. | * Update rate control statistics for the node. | ||||
*/ | */ | ||||
if (status & WPI_TX_STATUS_FAIL) { | if (status & WPI_TX_STATUS_FAIL) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); | IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); | ||||
} else { | } else | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); | IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); | ||||
} | |||||
ieee80211_tx_complete(ni, m, (status & WPI_TX_STATUS_FAIL) != 0); | ieee80211_tx_complete(ni, m, (status & WPI_TX_STATUS_FAIL) != 0); | ||||
Context not available. | |||||
if (ring->queued > 0) { | if (ring->queued > 0) { | ||||
callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | ||||
if (sc->qfullmsk != 0 && | if ((sc->qfullmsk & (1 << ring->qid)) != 0 && | ||||
ring->queued < WPI_TX_RING_LOMARK) { | ring->queued < WPI_TX_RING_LOMARK) { | ||||
sc->qfullmsk &= ~(1 << ring->qid); | sc->qfullmsk &= ~(1 << ring->qid); | ||||
IF_LOCK(&ifp->if_snd); | ieee80211_runtask(ic, &sc->sc_start_task); | ||||
if (sc->qfullmsk == 0 && | |||||
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) { | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
ieee80211_runtask(ic, &sc->sc_start_task); | |||||
} else | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
} | } | ||||
} else | } else | ||||
callout_stop(&sc->tx_timeout); | callout_stop(&sc->tx_timeout); | ||||
Context not available. | |||||
static void | static void | ||||
wpi_notif_intr(struct wpi_softc *sc) | wpi_notif_intr(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
uint32_t hw; | uint32_t hw; | ||||
Context not available. | |||||
/* An 802.11 frame has been received. */ | /* An 802.11 frame has been received. */ | ||||
wpi_rx_done(sc, desc, data); | wpi_rx_done(sc, desc, data); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | if (sc->sc_running == 0) { | ||||
/* wpi_stop() was called. */ | /* wpi_stop() was called. */ | ||||
return; | return; | ||||
} | } | ||||
Context not available. | |||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"microcontroller initialization failed\n"); | "microcontroller initialization failed\n"); | ||||
wpi_stop_locked(sc); | wpi_stop_locked(sc); | ||||
return; | |||||
} | } | ||||
/* Save the address of the error log in SRAM. */ | /* Save the address of the error log in SRAM. */ | ||||
sc->errptr = le32toh(uc->errptr); | sc->errptr = le32toh(uc->errptr); | ||||
Context not available. | |||||
wpi_intr(void *arg) | wpi_intr(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
uint32_t r1, r2; | uint32_t r1, r2; | ||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
Context not available. | |||||
done: | done: | ||||
/* Re-enable interrupts. */ | /* Re-enable interrupts. */ | ||||
if (ifp->if_flags & IFF_UP) | if (sc->sc_running) | ||||
WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); | WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); | ||||
end: WPI_UNLOCK(sc); | end: WPI_UNLOCK(sc); | ||||
Context not available. | |||||
static int | static int | ||||
wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) | wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct wpi_tx_cmd *cmd; | struct wpi_tx_cmd *cmd; | ||||
struct wpi_tx_data *data; | struct wpi_tx_data *data; | ||||
Context not available. | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if (sc->txq_active == 0) { | if (sc->sc_running == 0) { | ||||
/* wpi_stop() was called */ | /* wpi_stop() was called */ | ||||
error = ENETDOWN; | error = ENETDOWN; | ||||
goto fail; | goto fail; | ||||
Context not available. | |||||
if (ring->qid < WPI_CMD_QUEUE_NUM) { | if (ring->qid < WPI_CMD_QUEUE_NUM) { | ||||
/* Mark TX ring as full if we reach a certain threshold. */ | /* Mark TX ring as full if we reach a certain threshold. */ | ||||
WPI_TXQ_STATE_LOCK(sc); | WPI_TXQ_STATE_LOCK(sc); | ||||
if (++ring->queued > WPI_TX_RING_HIMARK) { | if (++ring->queued > WPI_TX_RING_HIMARK) | ||||
sc->qfullmsk |= 1 << ring->qid; | sc->qfullmsk |= 1 << ring->qid; | ||||
IF_LOCK(&ifp->if_snd); | |||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
} | |||||
callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | callout_reset(&sc->tx_timeout, 5*hz, wpi_tx_timeout, sc); | ||||
WPI_TXQ_STATE_UNLOCK(sc); | WPI_TXQ_STATE_UNLOCK(sc); | ||||
} | } | ||||
Context not available. | |||||
return wpi_cmd2(sc, &tx_data); | return wpi_cmd2(sc, &tx_data); | ||||
} | } | ||||
static __inline int | |||||
wpi_tx_ring_is_full(struct wpi_softc *sc, int ac) | |||||
{ | |||||
struct wpi_tx_ring *ring = &sc->txq[ac]; | |||||
int retval; | |||||
WPI_TXQ_STATE_LOCK(sc); | |||||
retval = (ring->queued > WPI_TX_RING_HIMARK); | |||||
WPI_TXQ_STATE_UNLOCK(sc); | |||||
return retval; | |||||
} | |||||
static __inline void | |||||
wpi_handle_tx_failure(struct ieee80211_node *ni) | |||||
{ | |||||
/* NB: m is reclaimed on tx failure */ | |||||
if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); | |||||
ieee80211_free_node(ni); | |||||
} | |||||
static int | static int | ||||
wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | ||||
const struct ieee80211_bpf_params *params) | const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | int ac, error = 0; | ||||
int error = 0; | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | ac = M_WME_GETAC(m); | ||||
ieee80211_free_node(ni); | |||||
WPI_TX_LOCK(sc); | |||||
if (sc->sc_running == 0 || wpi_tx_ring_is_full(sc, ac)) { | |||||
m_freem(m); | m_freem(m); | ||||
return ENETDOWN; | error = sc->sc_running ? ENOBUFS : ENETDOWN; | ||||
goto unlock; | |||||
} | } | ||||
WPI_TX_LOCK(sc); | |||||
if (params == NULL) { | if (params == NULL) { | ||||
/* | /* | ||||
* Legacy path; interpret frame contents to decide | * Legacy path; interpret frame contents to decide | ||||
Context not available. | |||||
*/ | */ | ||||
error = wpi_tx_data_raw(sc, m, ni, params); | error = wpi_tx_data_raw(sc, m, ni, params); | ||||
} | } | ||||
WPI_TX_UNLOCK(sc); | |||||
unlock: WPI_TX_UNLOCK(sc); | |||||
if (error != 0) { | if (error != 0) { | ||||
/* NB: m is reclaimed on tx failure */ | wpi_handle_tx_failure(ni); | ||||
ieee80211_free_node(ni); | |||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | ||||
return error; | return error; | ||||
Context not available. | |||||
return 0; | return 0; | ||||
} | } | ||||
/** | static int | ||||
* Process data waiting to be sent on the IFNET output queue | wpi_transmit(struct ieee80211com *ic, struct mbuf *m) | ||||
*/ | |||||
static void | |||||
wpi_start(struct ifnet *ifp) | |||||
{ | { | ||||
struct wpi_softc *sc = ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | struct mbufq *sndq; | ||||
int ac, error; | |||||
WPI_TX_LOCK(sc); | WPI_TX_LOCK(sc); | ||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); | DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); | ||||
for (;;) { | /* Check if interface is up & running. */ | ||||
IF_LOCK(&ifp->if_snd); | if (sc->sc_running == 0) { | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || | error = ENXIO; | ||||
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) { | goto unlock; | ||||
IF_UNLOCK(&ifp->if_snd); | } | ||||
break; | |||||
} | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | /* Check for available space. */ | ||||
if (m == NULL) | ac = M_WME_GETAC(m); | ||||
break; | sndq = &sc->txq[ac].snd; | ||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | if (wpi_tx_ring_is_full(sc, ac) || mbufq_len(sndq) != 0) { | ||||
if (wpi_tx_data(sc, m, ni) != 0) { | /* wpi_tx_done() will dequeue it. */ | ||||
ieee80211_free_node(ni); | error = mbufq_enqueue(sndq, m); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | goto unlock; | ||||
} | |||||
} | } | ||||
error = 0; | |||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | |||||
if (wpi_tx_data(sc, m, ni) != 0) { | |||||
wpi_handle_tx_failure(ni); | |||||
} | |||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); | DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); | ||||
WPI_TX_UNLOCK(sc); | |||||
unlock: WPI_TX_UNLOCK(sc); | |||||
return (error); | |||||
} | } | ||||
/** | |||||
* Process data waiting to be sent on the output queue | |||||
*/ | |||||
static void | static void | ||||
wpi_start_task(void *arg0, int pending) | wpi_start(void *arg0, int pending) | ||||
{ | { | ||||
struct wpi_softc *sc = arg0; | struct wpi_softc *sc = arg0; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | |||||
uint8_t i; | |||||
wpi_start(ifp); | WPI_TX_LOCK(sc); | ||||
if (sc->sc_running == 0) | |||||
goto unlock; | |||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); | |||||
for (i = 0; i < WPI_CMD_QUEUE_NUM; i++) { | |||||
struct mbufq *sndq = &sc->txq[i].snd; | |||||
for (;;) { | |||||
if (wpi_tx_ring_is_full(sc, i)) | |||||
break; | |||||
if ((m = mbufq_dequeue(sndq)) == NULL) | |||||
break; | |||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | |||||
if (wpi_tx_data(sc, m, ni) != 0) { | |||||
wpi_handle_tx_failure(ni); | |||||
} | |||||
} | |||||
} | |||||
DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); | |||||
unlock: WPI_TX_UNLOCK(sc); | |||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
wpi_watchdog_rfkill(void *arg) | wpi_watchdog_rfkill(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
DPRINTF(sc, WPI_DEBUG_WATCHDOG, "RFkill Watchdog: tick\n"); | DPRINTF(sc, WPI_DEBUG_WATCHDOG, "RFkill Watchdog: tick\n"); | ||||
Context not available. | |||||
wpi_scan_timeout(void *arg) | wpi_scan_timeout(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
if_printf(ifp, "scan timeout\n"); | ic_printf(ic, "scan timeout\n"); | ||||
taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); | taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); | ||||
} | } | ||||
Context not available. | |||||
wpi_tx_timeout(void *arg) | wpi_tx_timeout(void *arg) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
if_printf(ifp, "device timeout\n"); | ic_printf(ic, "device timeout\n"); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); | taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask); | ||||
} | } | ||||
static int | static void | ||||
wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | wpi_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct wpi_softc *sc = ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
int error = 0; | |||||
switch (cmd) { | if (ic->ic_nrunning > 0) { | ||||
case SIOCGIFADDR: | if (wpi_init(sc) == 0) { | ||||
error = ether_ioctl(ifp, cmd, data); | ieee80211_notify_radio(ic, 1); | ||||
break; | ieee80211_start_all(ic); | ||||
case SIOCSIFFLAGS: | } else { | ||||
if (ifp->if_flags & IFF_UP) { | ieee80211_notify_radio(ic, 0); | ||||
wpi_init(sc); | ieee80211_stop(vap); | ||||
} | |||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 && | } else | ||||
vap != NULL) | wpi_stop(sc); | ||||
ieee80211_stop(vap); | |||||
} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) | |||||
wpi_stop(sc); | |||||
break; | |||||
case SIOCGIFMEDIA: | |||||
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); | |||||
break; | |||||
default: | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
return error; | |||||
} | } | ||||
/* | /* | ||||
Context not available. | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if (sc->txq_active == 0) { | if (sc->sc_running == 0) { | ||||
/* wpi_stop() was called */ | /* wpi_stop() was called */ | ||||
error = 0; | if (code == WPI_CMD_SCAN) | ||||
error = ENETDOWN; | |||||
else | |||||
error = 0; | |||||
goto fail; | goto fail; | ||||
} | } | ||||
Context not available. | |||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
if (async) | return async ? 0 : mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); | ||||
return 0; | |||||
return mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); | |||||
fail: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | fail: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
Context not available. | |||||
static int | static int | ||||
wpi_mrr_setup(struct wpi_softc *sc) | wpi_mrr_setup(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct wpi_mrr_setup mrr; | struct wpi_mrr_setup mrr; | ||||
int i, error; | int i, error; | ||||
Context not available. | |||||
static int | static int | ||||
wpi_add_broadcast_node(struct wpi_softc *sc, int async) | wpi_add_broadcast_node(struct wpi_softc *sc, int async) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct wpi_node_info node; | struct wpi_node_info node; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
memset(&node, 0, sizeof node); | memset(&node, 0, sizeof node); | ||||
IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); | IEEE80211_ADDR_COPY(node.macaddr, ieee80211broadcastaddr); | ||||
node.id = WPI_ID_BROADCAST; | node.id = WPI_ID_BROADCAST; | ||||
node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? | node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? | ||||
wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; | wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; | ||||
Context not available. | |||||
wpi_updateedca(struct ieee80211com *ic) | wpi_updateedca(struct ieee80211com *ic) | ||||
{ | { | ||||
#define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ | #define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_edca_params cmd; | struct wpi_edca_params cmd; | ||||
int aci, error; | int aci, error; | ||||
Context not available. | |||||
static void | static void | ||||
wpi_set_promisc(struct wpi_softc *sc) | wpi_set_promisc(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
uint32_t promisc_filter; | uint32_t promisc_filter; | ||||
Context not available. | |||||
if (vap != NULL && vap->iv_opmode != IEEE80211_M_HOSTAP) | if (vap != NULL && vap->iv_opmode != IEEE80211_M_HOSTAP) | ||||
promisc_filter |= WPI_FILTER_PROMISC; | promisc_filter |= WPI_FILTER_PROMISC; | ||||
if (ifp->if_flags & IFF_PROMISC) | if (ic->ic_promisc > 0) | ||||
sc->rxon.filter |= htole32(promisc_filter); | sc->rxon.filter |= htole32(promisc_filter); | ||||
else | else | ||||
sc->rxon.filter &= ~htole32(promisc_filter); | sc->rxon.filter &= ~htole32(promisc_filter); | ||||
Context not available. | |||||
static int | static int | ||||
wpi_config(struct wpi_softc *sc) | wpi_config(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
struct ieee80211_channel *c = ic->ic_curchan; | struct ieee80211_channel *c = ic->ic_curchan; | ||||
int error; | int error; | ||||
Context not available. | |||||
static uint16_t | static uint16_t | ||||
wpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) | wpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
int bintval = 0; | int bintval = 0; | ||||
Context not available. | |||||
static int | static int | ||||
wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) | wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211_scan_state *ss = ic->ic_scan; | struct ieee80211_scan_state *ss = ic->ic_scan; | ||||
struct ieee80211vap *vap = ss->ss_vap; | struct ieee80211vap *vap = ss->ss_vap; | ||||
struct wpi_scan_hdr *hdr; | struct wpi_scan_hdr *hdr; | ||||
Context not available. | |||||
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | | wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | | ||||
IEEE80211_FC0_SUBTYPE_PROBE_REQ; | IEEE80211_FC0_SUBTYPE_PROBE_REQ; | ||||
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; | wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; | ||||
IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); | IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr); | ||||
IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); | IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); | ||||
IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); | IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr); | ||||
*(uint16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ | |||||
*(uint16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ | |||||
frm = (uint8_t *)(wh + 1); | frm = (uint8_t *)(wh + 1); | ||||
frm = ieee80211_add_ssid(frm, NULL, 0); | frm = ieee80211_add_ssid(frm, NULL, 0); | ||||
Context not available. | |||||
/* | /* | ||||
* Calculate the active/passive dwell times. | * Calculate the active/passive dwell times. | ||||
*/ | */ | ||||
dwell_active = wpi_get_active_dwell_time(sc, c, nssid); | dwell_active = wpi_get_active_dwell_time(sc, c, nssid); | ||||
dwell_passive = wpi_get_passive_dwell_time(sc, c); | dwell_passive = wpi_get_passive_dwell_time(sc, c); | ||||
Context not available. | |||||
struct ieee80211com *ic = wvp->wv_vap.iv_ic; | struct ieee80211com *ic = wvp->wv_vap.iv_ic; | ||||
struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; | struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; | ||||
struct wpi_buf *bcn = &wvp->wv_bcbuf; | struct wpi_buf *bcn = &wvp->wv_bcbuf; | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; | struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; | ||||
struct ieee80211_tim_ie *tie; | struct ieee80211_tim_ie *tie; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
Context not available. | |||||
static void | static void | ||||
wpi_update_beacon(struct ieee80211vap *vap, int item) | wpi_update_beacon(struct ieee80211vap *vap, int item) | ||||
{ | { | ||||
struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; | struct wpi_softc *sc = vap->iv_ic->ic_softc; | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
struct wpi_buf *bcn = &wvp->wv_bcbuf; | struct wpi_buf *bcn = &wvp->wv_bcbuf; | ||||
struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; | struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; | ||||
Context not available. | |||||
wpi_newassoc(struct ieee80211_node *ni, int isnew) | wpi_newassoc(struct ieee80211_node *ni, int isnew) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
int error; | int error; | ||||
Context not available. | |||||
{ | { | ||||
const struct ieee80211_cipher *cip = k->wk_cipher; | const struct ieee80211_cipher *cip = k->wk_cipher; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
struct wpi_node_info node; | struct wpi_node_info node; | ||||
uint16_t kflags; | uint16_t kflags; | ||||
Context not available. | |||||
{ | { | ||||
const struct ieee80211_key *k = arg; | const struct ieee80211_key *k = arg; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
int error; | int error; | ||||
Context not available. | |||||
wpi_del_key(struct ieee80211_node *ni, const struct ieee80211_key *k) | wpi_del_key(struct ieee80211_node *ni, const struct ieee80211_key *k) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
struct wpi_node_info node; | struct wpi_node_info node; | ||||
uint16_t kflags; | uint16_t kflags; | ||||
Context not available. | |||||
{ | { | ||||
const struct ieee80211_key *k = arg; | const struct ieee80211_key *k = arg; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | struct wpi_softc *sc = ni->ni_ic->ic_softc; | ||||
struct wpi_node *wn = WPI_NODE(ni); | struct wpi_node *wn = WPI_NODE(ni); | ||||
int error; | int error; | ||||
Context not available. | |||||
int set) | int set) | ||||
{ | { | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_vap *wvp = WPI_VAP(vap); | struct wpi_vap *wvp = WPI_VAP(vap); | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
int error, ni_ref = 0; | int error, ni_ref = 0; | ||||
Context not available. | |||||
wpi_radio_on(void *arg0, int pending) | wpi_radio_on(void *arg0, int pending) | ||||
{ | { | ||||
struct wpi_softc *sc = arg0; | struct wpi_softc *sc = arg0; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
device_printf(sc->sc_dev, "RF switch: radio enabled\n"); | device_printf(sc->sc_dev, "RF switch: radio enabled\n"); | ||||
if (vap != NULL) { | WPI_LOCK(sc); | ||||
wpi_init(sc); | callout_stop(&sc->watchdog_rfkill); | ||||
WPI_UNLOCK(sc); | |||||
if (vap != NULL) | |||||
ieee80211_init(vap); | ieee80211_init(vap); | ||||
} | |||||
if (WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL) { | |||||
WPI_LOCK(sc); | |||||
callout_stop(&sc->watchdog_rfkill); | |||||
WPI_UNLOCK(sc); | |||||
} | |||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
wpi_radio_off(void *arg0, int pending) | wpi_radio_off(void *arg0, int pending) | ||||
{ | { | ||||
struct wpi_softc *sc = arg0; | struct wpi_softc *sc = arg0; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
device_printf(sc->sc_dev, "RF switch: radio disabled\n"); | device_printf(sc->sc_dev, "RF switch: radio disabled\n"); | ||||
ieee80211_notify_radio(ic, 0); | |||||
wpi_stop(sc); | wpi_stop(sc); | ||||
if (vap != NULL) | if (vap != NULL) | ||||
ieee80211_stop(vap); | ieee80211_stop(vap); | ||||
Context not available. | |||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
} | } | ||||
static void | static int | ||||
wpi_init(void *arg) | wpi_init(struct wpi_softc *sc) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | int error = 0; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
int error; | |||||
WPI_LOCK(sc); | WPI_LOCK(sc); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) | if (sc->sc_running != 0) | ||||
goto end; | goto end; | ||||
/* Check that the radio is not disabled by hardware switch. */ | /* Check that the radio is not disabled by hardware switch. */ | ||||
Context not available. | |||||
"RF switch: radio disabled (%s)\n", __func__); | "RF switch: radio disabled (%s)\n", __func__); | ||||
callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, | callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, | ||||
sc); | sc); | ||||
error = EINPROGRESS; | |||||
goto end; | goto end; | ||||
} | } | ||||
Context not available. | |||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: could not read firmware, error %d\n", __func__, | "%s: could not read firmware, error %d\n", __func__, | ||||
error); | error); | ||||
goto fail; | goto end; | ||||
} | } | ||||
sc->sc_running = 1; | |||||
/* Initialize hardware and upload firmware. */ | /* Initialize hardware and upload firmware. */ | ||||
error = wpi_hw_init(sc); | error = wpi_hw_init(sc); | ||||
wpi_unload_firmware(sc); | wpi_unload_firmware(sc); | ||||
Context not available. | |||||
} | } | ||||
/* Configure adapter now that it is ready. */ | /* Configure adapter now that it is ready. */ | ||||
sc->txq_active = 1; | |||||
if ((error = wpi_config(sc)) != 0) { | if ((error = wpi_config(sc)) != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: could not configure device, error %d\n", __func__, | "%s: could not configure device, error %d\n", __func__, | ||||
Context not available. | |||||
goto fail; | goto fail; | ||||
} | } | ||||
IF_LOCK(&ifp->if_snd); | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); | ||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
ieee80211_start_all(ic); | return 0; | ||||
return; | fail: wpi_stop_locked(sc); | ||||
fail: wpi_stop_locked(sc); | |||||
end: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | end: DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); | ||||
WPI_UNLOCK(sc); | WPI_UNLOCK(sc); | ||||
return error; | |||||
} | } | ||||
static void | static void | ||||
wpi_stop_locked(struct wpi_softc *sc) | wpi_stop_locked(struct wpi_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
WPI_LOCK_ASSERT(sc); | WPI_LOCK_ASSERT(sc); | ||||
if (sc->sc_running == 0) | |||||
return; | |||||
WPI_TX_LOCK(sc); | |||||
WPI_TXQ_LOCK(sc); | WPI_TXQ_LOCK(sc); | ||||
sc->txq_active = 0; | sc->sc_running = 0; | ||||
WPI_TXQ_UNLOCK(sc); | WPI_TXQ_UNLOCK(sc); | ||||
WPI_TX_UNLOCK(sc); | |||||
WPI_TXQ_STATE_LOCK(sc); | WPI_TXQ_STATE_LOCK(sc); | ||||
callout_stop(&sc->tx_timeout); | callout_stop(&sc->tx_timeout); | ||||
Context not available. | |||||
callout_stop(&sc->calib_to); | callout_stop(&sc->calib_to); | ||||
WPI_RXON_UNLOCK(sc); | WPI_RXON_UNLOCK(sc); | ||||
IF_LOCK(&ifp->if_snd); | |||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | |||||
IF_UNLOCK(&ifp->if_snd); | |||||
/* Power OFF hardware. */ | /* Power OFF hardware. */ | ||||
wpi_hw_stop(sc); | wpi_hw_stop(sc); | ||||
} | } | ||||
Context not available. | |||||
static void | static void | ||||
wpi_scan_start(struct ieee80211com *ic) | wpi_scan_start(struct ieee80211com *ic) | ||||
{ | { | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
wpi_set_led(sc, WPI_LED_LINK, 20, 2); | wpi_set_led(sc, WPI_LED_LINK, 20, 2); | ||||
} | } | ||||
Context not available. | |||||
static void | static void | ||||
wpi_scan_end(struct ieee80211com *ic) | wpi_scan_end(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
if (vap->iv_state == IEEE80211_S_RUN) | if (vap->iv_state == IEEE80211_S_RUN) | ||||
Context not available. | |||||
wpi_set_channel(struct ieee80211com *ic) | wpi_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
const struct ieee80211_channel *c = ic->ic_curchan; | const struct ieee80211_channel *c = ic->ic_curchan; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct wpi_softc *sc = ic->ic_softc; | ||||
struct wpi_softc *sc = ifp->if_softc; | |||||
int error; | int error; | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
Context not available. | |||||
{ | { | ||||
struct ieee80211vap *vap = ss->ss_vap; | struct ieee80211vap *vap = ss->ss_vap; | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct wpi_softc *sc = ic->ic_ifp->if_softc; | struct wpi_softc *sc = ic->ic_softc; | ||||
int error; | int error; | ||||
WPI_RXON_LOCK(sc); | WPI_RXON_LOCK(sc); | ||||
Context not available. | |||||
wpi_hw_reset(void *arg, int pending) | wpi_hw_reset(void *arg, int pending) | ||||
{ | { | ||||
struct wpi_softc *sc = arg; | struct wpi_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); | ||||
ieee80211_notify_radio(ic, 0); | |||||
if (vap != NULL && (ic->ic_flags & IEEE80211_F_SCAN)) | if (vap != NULL && (ic->ic_flags & IEEE80211_F_SCAN)) | ||||
ieee80211_cancel_scan(vap); | ieee80211_cancel_scan(vap); | ||||
wpi_stop(sc); | wpi_stop(sc); | ||||
if (vap != NULL) | if (vap != NULL) { | ||||
ieee80211_stop(vap); | ieee80211_stop(vap); | ||||
wpi_init(sc); | |||||
if (vap != NULL) | |||||
ieee80211_init(vap); | ieee80211_init(vap); | ||||
} | |||||
} | } | ||||
Context not available. |