Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_upgt.c
Context not available. | |||||
static void upgt_eeprom_parse_freq6(struct upgt_softc *, uint8_t *, int); | static void upgt_eeprom_parse_freq6(struct upgt_softc *, uint8_t *, int); | ||||
static uint32_t upgt_chksum_le(const uint32_t *, size_t); | static uint32_t upgt_chksum_le(const uint32_t *, size_t); | ||||
static void upgt_tx_done(struct upgt_softc *, uint8_t *); | static void upgt_tx_done(struct upgt_softc *, uint8_t *); | ||||
static void upgt_init(void *); | static void upgt_init(struct upgt_softc *); | ||||
static void upgt_init_locked(struct upgt_softc *); | static void upgt_parent(struct ieee80211com *); | ||||
static int upgt_ioctl(struct ifnet *, u_long, caddr_t); | static int upgt_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void upgt_start(struct ifnet *); | static void upgt_start(struct upgt_softc *); | ||||
static int upgt_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int upgt_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static void upgt_scan_start(struct ieee80211com *); | static void upgt_scan_start(struct ieee80211com *); | ||||
Context not available. | |||||
static int | static int | ||||
upgt_attach(device_t dev) | upgt_attach(device_t dev) | ||||
{ | { | ||||
int error; | |||||
struct ieee80211com *ic; | |||||
struct ifnet *ifp; | |||||
struct upgt_softc *sc = device_get_softc(dev); | struct upgt_softc *sc = device_get_softc(dev); | ||||
struct ieee80211com *ic = &sc->sc_ic; | |||||
struct usb_attach_arg *uaa = device_get_ivars(dev); | struct usb_attach_arg *uaa = device_get_ivars(dev); | ||||
uint8_t bands, iface_index = UPGT_IFACE_INDEX; | uint8_t bands, iface_index = UPGT_IFACE_INDEX; | ||||
int error; | |||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
sc->sc_udev = uaa->device; | sc->sc_udev = uaa->device; | ||||
Context not available. | |||||
MTX_DEF); | MTX_DEF); | ||||
callout_init(&sc->sc_led_ch, 0); | callout_init(&sc->sc_led_ch, 0); | ||||
callout_init(&sc->sc_watchdog_ch, 0); | callout_init(&sc->sc_watchdog_ch, 0); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, | error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, | ||||
upgt_config, UPGT_N_XFERS, sc, &sc->sc_mtx); | upgt_config, UPGT_N_XFERS, sc, &sc->sc_mtx); | ||||
Context not available. | |||||
if (error) | if (error) | ||||
goto fail3; | goto fail3; | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | |||||
if (ifp == NULL) { | |||||
device_printf(dev, "can not if_alloc()\n"); | |||||
goto fail4; | |||||
} | |||||
/* Initialize the device. */ | /* Initialize the device. */ | ||||
error = upgt_device_reset(sc); | error = upgt_device_reset(sc); | ||||
if (error) | if (error) | ||||
goto fail5; | goto fail4; | ||||
/* Verify the firmware. */ | /* Verify the firmware. */ | ||||
error = upgt_fw_verify(sc); | error = upgt_fw_verify(sc); | ||||
if (error) | if (error) | ||||
goto fail5; | goto fail4; | ||||
/* Calculate device memory space. */ | /* Calculate device memory space. */ | ||||
if (sc->sc_memaddr_frame_start == 0 || sc->sc_memaddr_frame_end == 0) { | if (sc->sc_memaddr_frame_start == 0 || sc->sc_memaddr_frame_end == 0) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"could not find memory space addresses on FW\n"); | "could not find memory space addresses on FW\n"); | ||||
error = EIO; | error = EIO; | ||||
goto fail5; | goto fail4; | ||||
} | } | ||||
sc->sc_memaddr_frame_end -= UPGT_MEMSIZE_RX + 1; | sc->sc_memaddr_frame_end -= UPGT_MEMSIZE_RX + 1; | ||||
sc->sc_memaddr_rx_start = sc->sc_memaddr_frame_end + 1; | sc->sc_memaddr_rx_start = sc->sc_memaddr_frame_end + 1; | ||||
Context not available. | |||||
/* Load the firmware. */ | /* Load the firmware. */ | ||||
error = upgt_fw_load(sc); | error = upgt_fw_load(sc); | ||||
if (error) | if (error) | ||||
goto fail5; | goto fail4; | ||||
/* Read the whole EEPROM content and parse it. */ | /* Read the whole EEPROM content and parse it. */ | ||||
error = upgt_eeprom_read(sc); | error = upgt_eeprom_read(sc); | ||||
if (error) | if (error) | ||||
goto fail5; | goto fail4; | ||||
error = upgt_eeprom_parse(sc); | error = upgt_eeprom_parse(sc); | ||||
if (error) | if (error) | ||||
goto fail5; | goto fail4; | ||||
/* all works related with the device have done here. */ | /* all works related with the device have done here. */ | ||||
upgt_abort_xfers(sc); | upgt_abort_xfers(sc); | ||||
/* Setup the 802.11 device. */ | |||||
ifp->if_softc = sc; | |||||
if_initname(ifp, "upgt", device_get_unit(sc->sc_dev)); | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = upgt_init; | |||||
ifp->if_ioctl = upgt_ioctl; | |||||
ifp->if_start = upgt_start; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
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. | |||||
setbit(&bands, IEEE80211_MODE_11G); | setbit(&bands, IEEE80211_MODE_11G); | ||||
ieee80211_init_channels(ic, NULL, &bands); | ieee80211_init_channels(ic, NULL, &bands); | ||||
ieee80211_ifattach(ic, sc->sc_myaddr); | ieee80211_ifattach(ic); | ||||
ic->ic_raw_xmit = upgt_raw_xmit; | ic->ic_raw_xmit = upgt_raw_xmit; | ||||
ic->ic_scan_start = upgt_scan_start; | ic->ic_scan_start = upgt_scan_start; | ||||
ic->ic_scan_end = upgt_scan_end; | ic->ic_scan_end = upgt_scan_end; | ||||
ic->ic_set_channel = upgt_set_channel; | ic->ic_set_channel = upgt_set_channel; | ||||
ic->ic_vap_create = upgt_vap_create; | ic->ic_vap_create = upgt_vap_create; | ||||
ic->ic_vap_delete = upgt_vap_delete; | ic->ic_vap_delete = upgt_vap_delete; | ||||
ic->ic_update_mcast = upgt_update_mcast; | ic->ic_update_mcast = upgt_update_mcast; | ||||
ic->ic_transmit = upgt_transmit; | |||||
ic->ic_parent = upgt_parent; | |||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(ic, | ||||
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | ||||
Context not available. | |||||
return (0); | return (0); | ||||
fail5: if_free(ifp); | |||||
fail4: upgt_free_rx(sc); | fail4: upgt_free_rx(sc); | ||||
fail3: upgt_free_tx(sc); | fail3: upgt_free_tx(sc); | ||||
fail2: usbd_transfer_unsetup(sc->sc_xfer, UPGT_N_XFERS); | fail2: usbd_transfer_unsetup(sc->sc_xfer, UPGT_N_XFERS); | ||||
Context not available. | |||||
static void | static void | ||||
upgt_txeof(struct usb_xfer *xfer, struct upgt_data *data) | upgt_txeof(struct usb_xfer *xfer, struct upgt_data *data) | ||||
{ | { | ||||
struct upgt_softc *sc = usbd_xfer_softc(xfer); | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct mbuf *m; | |||||
UPGT_ASSERT_LOCKED(sc); | |||||
/* | |||||
* Do any tx complete callback. Note this must be done before releasing | |||||
* the node reference. | |||||
*/ | |||||
if (data->m) { | if (data->m) { | ||||
m = data->m; | /* XXX status? */ | ||||
if (m->m_flags & M_TXCB) { | ieee80211_tx_complete(data->ni, data->m, 0); | ||||
/* XXX status? */ | |||||
ieee80211_process_callback(data->ni, m, 0); | |||||
} | |||||
m_freem(m); | |||||
data->m = NULL; | data->m = NULL; | ||||
} | |||||
if (data->ni) { | |||||
ieee80211_free_node(data->ni); | |||||
data->ni = NULL; | data->ni = NULL; | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
upgt_bulk_tx(sc, data_cmd); | upgt_bulk_tx(sc, data_cmd); | ||||
} | } | ||||
static int | static void | ||||
upgt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | upgt_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct upgt_softc *sc = ifp->if_softc; | struct upgt_softc *sc = ic->ic_softc; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
int error; | |||||
int startall = 0; | int startall = 0; | ||||
UPGT_LOCK(sc); | UPGT_LOCK(sc); | ||||
error = (sc->sc_flags & UPGT_FLAG_DETACHED) ? ENXIO : 0; | if (sc->sc_flags & UPGT_FLAG_DETACHED) { | ||||
UPGT_UNLOCK(sc); | UPGT_UNLOCK(sc); | ||||
if (error) | return; | ||||
return (error); | } | ||||
if (ic->ic_nrunning > 0) { | |||||
switch (cmd) { | if (sc->sc_flags & UPGT_FLAG_INITDONE) { | ||||
case SIOCSIFFLAGS: | if (ic->ic_allmulti > 0 || ic->ic_promisc > 0) | ||||
if (ifp->if_flags & IFF_UP) { | upgt_set_multi(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | |||||
if ((ifp->if_flags ^ sc->sc_if_flags) & | |||||
(IFF_ALLMULTI | IFF_PROMISC)) | |||||
upgt_set_multi(sc); | |||||
} else { | |||||
upgt_init(sc); | |||||
startall = 1; | |||||
} | |||||
} else { | } else { | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | upgt_init(sc); | ||||
upgt_stop(sc); | startall = 1; | ||||
} | } | ||||
sc->sc_if_flags = ifp->if_flags; | } else if (sc->sc_flags & UPGT_FLAG_INITDONE) | ||||
if (startall) | upgt_stop(sc); | ||||
ieee80211_start_all(ic); | UPGT_UNLOCK(sc); | ||||
break; | if (startall) | ||||
case SIOCGIFMEDIA: | ieee80211_start_all(ic); | ||||
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; | |||||
} | } | ||||
static void | static void | ||||
upgt_stop_locked(struct upgt_softc *sc) | upgt_stop(struct upgt_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
UPGT_ASSERT_LOCKED(sc); | UPGT_ASSERT_LOCKED(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_flags & UPGT_FLAG_INITDONE) | ||||
upgt_set_macfilter(sc, IEEE80211_S_INIT); | upgt_set_macfilter(sc, IEEE80211_S_INIT); | ||||
upgt_abort_xfers_locked(sc); | upgt_abort_xfers_locked(sc); | ||||
} | |||||
static void | |||||
upgt_stop(struct upgt_softc *sc) | |||||
{ | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
UPGT_LOCK(sc); | |||||
upgt_stop_locked(sc); | |||||
UPGT_UNLOCK(sc); | |||||
/* device down */ | /* device down */ | ||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | |||||
sc->sc_flags &= ~UPGT_FLAG_INITDONE; | sc->sc_flags &= ~UPGT_FLAG_INITDONE; | ||||
} | } | ||||
Context not available. | |||||
} | } | ||||
static void | static void | ||||
upgt_init(void *priv) | upgt_init(struct upgt_softc *sc) | ||||
{ | { | ||||
struct upgt_softc *sc = priv; | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
UPGT_LOCK(sc); | |||||
upgt_init_locked(sc); | |||||
UPGT_UNLOCK(sc); | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
ieee80211_start_all(ic); /* start all vap's */ | |||||
} | |||||
static void | |||||
upgt_init_locked(struct upgt_softc *sc) | |||||
{ | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
UPGT_ASSERT_LOCKED(sc); | UPGT_ASSERT_LOCKED(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_flags & UPGT_FLAG_INITDONE) | ||||
upgt_stop_locked(sc); | upgt_stop(sc); | ||||
usbd_transfer_start(sc->sc_xfer[UPGT_BULK_RX]); | usbd_transfer_start(sc->sc_xfer[UPGT_BULK_RX]); | ||||
(void)upgt_set_macfilter(sc, IEEE80211_S_SCAN); | (void)upgt_set_macfilter(sc, IEEE80211_S_SCAN); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
sc->sc_flags |= UPGT_FLAG_INITDONE; | sc->sc_flags |= UPGT_FLAG_INITDONE; | ||||
callout_reset(&sc->sc_watchdog_ch, hz, upgt_watchdog, sc); | callout_reset(&sc->sc_watchdog_ch, hz, upgt_watchdog, sc); | ||||
Context not available. | |||||
static int | static int | ||||
upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) | upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) | ||||
{ | { | ||||
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_node *ni; | struct ieee80211_node *ni; | ||||
struct upgt_data *data_cmd; | struct upgt_data *data_cmd; | ||||
struct upgt_lmac_mem *mem; | struct upgt_lmac_mem *mem; | ||||
struct upgt_lmac_filter *filter; | struct upgt_lmac_filter *filter; | ||||
uint8_t broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | |||||
UPGT_ASSERT_LOCKED(sc); | UPGT_ASSERT_LOCKED(sc); | ||||
Context not available. | |||||
case IEEE80211_S_SCAN: | case IEEE80211_S_SCAN: | ||||
DPRINTF(sc, UPGT_DEBUG_STATE, | DPRINTF(sc, UPGT_DEBUG_STATE, | ||||
"set MAC filter to SCAN (bssid %s)\n", | "set MAC filter to SCAN (bssid %s)\n", | ||||
ether_sprintf(broadcast)); | ether_sprintf(ieee80211broadcastaddr)); | ||||
filter->type = htole16(UPGT_FILTER_TYPE_NONE); | filter->type = htole16(UPGT_FILTER_TYPE_NONE); | ||||
IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); | IEEE80211_ADDR_COPY(filter->dst, | ||||
IEEE80211_ADDR_COPY(filter->src, broadcast); | vap ? vap->iv_myaddr : ic->ic_macaddr); | ||||
IEEE80211_ADDR_COPY(filter->src, ieee80211broadcastaddr); | |||||
filter->unknown1 = htole16(UPGT_FILTER_UNKNOWN1); | filter->unknown1 = htole16(UPGT_FILTER_UNKNOWN1); | ||||
filter->rxaddr = htole32(sc->sc_memaddr_rx_start); | filter->rxaddr = htole32(sc->sc_memaddr_rx_start); | ||||
filter->unknown2 = htole16(UPGT_FILTER_UNKNOWN2); | filter->unknown2 = htole16(UPGT_FILTER_UNKNOWN2); | ||||
Context not available. | |||||
/* XXX monitor mode isn't tested yet. */ | /* XXX monitor mode isn't tested yet. */ | ||||
if (vap->iv_opmode == IEEE80211_M_MONITOR) { | if (vap->iv_opmode == IEEE80211_M_MONITOR) { | ||||
filter->type = htole16(UPGT_FILTER_TYPE_MONITOR); | filter->type = htole16(UPGT_FILTER_TYPE_MONITOR); | ||||
IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); | IEEE80211_ADDR_COPY(filter->dst, | ||||
vap ? vap->iv_myaddr : ic->ic_macaddr); | |||||
IEEE80211_ADDR_COPY(filter->src, ni->ni_bssid); | IEEE80211_ADDR_COPY(filter->src, ni->ni_bssid); | ||||
filter->unknown1 = htole16(UPGT_FILTER_MONITOR_UNKNOWN1); | filter->unknown1 = htole16(UPGT_FILTER_MONITOR_UNKNOWN1); | ||||
filter->rxaddr = htole32(sc->sc_memaddr_rx_start); | filter->rxaddr = htole32(sc->sc_memaddr_rx_start); | ||||
Context not available. | |||||
"set MAC filter to RUN (bssid %s)\n", | "set MAC filter to RUN (bssid %s)\n", | ||||
ether_sprintf(ni->ni_bssid)); | ether_sprintf(ni->ni_bssid)); | ||||
filter->type = htole16(UPGT_FILTER_TYPE_STA); | filter->type = htole16(UPGT_FILTER_TYPE_STA); | ||||
IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); | IEEE80211_ADDR_COPY(filter->dst, | ||||
vap ? vap->iv_myaddr : ic->ic_macaddr); | |||||
IEEE80211_ADDR_COPY(filter->src, ni->ni_bssid); | IEEE80211_ADDR_COPY(filter->src, ni->ni_bssid); | ||||
filter->unknown1 = htole16(UPGT_FILTER_UNKNOWN1); | filter->unknown1 = htole16(UPGT_FILTER_UNKNOWN1); | ||||
filter->rxaddr = htole32(sc->sc_memaddr_rx_start); | filter->rxaddr = htole32(sc->sc_memaddr_rx_start); | ||||
Context not available. | |||||
static void | static void | ||||
upgt_setup_rates(struct ieee80211vap *vap, struct ieee80211com *ic) | upgt_setup_rates(struct ieee80211vap *vap, struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct upgt_softc *sc = ic->ic_softc; | ||||
struct upgt_softc *sc = ifp->if_softc; | |||||
const struct ieee80211_txparam *tp; | const struct ieee80211_txparam *tp; | ||||
/* | /* | ||||
Context not available. | |||||
static void | static void | ||||
upgt_set_multi(void *arg) | upgt_set_multi(void *arg) | ||||
{ | { | ||||
struct upgt_softc *sc = arg; | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
if (!(ifp->if_flags & IFF_UP)) | /* XXX don't know how to set a device. Lack of docs. */ | ||||
return; | } | ||||
/* | static int | ||||
* XXX don't know how to set a device. Lack of docs. Just try to set | upgt_transmit(struct ieee80211com *ic, struct mbuf *m) | ||||
* IFF_ALLMULTI flag here. | { | ||||
*/ | struct upgt_softc *sc = ic->ic_softc; | ||||
ifp->if_flags |= IFF_ALLMULTI; | int error; | ||||
UPGT_LOCK(sc); | |||||
if ((sc->sc_flags & UPGT_FLAG_INITDONE) == 0) { | |||||
UPGT_UNLOCK(sc); | |||||
return (ENXIO); | |||||
} | |||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
UPGT_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
upgt_start(sc); | |||||
UPGT_UNLOCK(sc); | |||||
return (0); | |||||
} | } | ||||
static void | static void | ||||
upgt_start(struct ifnet *ifp) | upgt_start(struct upgt_softc *sc) | ||||
{ | { | ||||
struct upgt_softc *sc = ifp->if_softc; | |||||
struct upgt_data *data_tx; | struct upgt_data *data_tx; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | UPGT_ASSERT_LOCKED(sc); | ||||
if ((sc->sc_flags & UPGT_FLAG_INITDONE) == 0) | |||||
return; | return; | ||||
UPGT_LOCK(sc); | while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
for (;;) { | |||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | |||||
if (m == NULL) | |||||
break; | |||||
data_tx = upgt_gettxbuf(sc); | data_tx = upgt_gettxbuf(sc); | ||||
if (data_tx == NULL) { | if (data_tx == NULL) { | ||||
IFQ_DRV_PREPEND(&ifp->if_snd, m); | mbufq_prepend(&sc->sc_snd, m); | ||||
break; | break; | ||||
} | } | ||||
Context not available. | |||||
m->m_pkthdr.rcvif = NULL; | m->m_pkthdr.rcvif = NULL; | ||||
if (upgt_tx_start(sc, m, ni, data_tx) != 0) { | if (upgt_tx_start(sc, m, ni, data_tx) != 0) { | ||||
if_inc_counter(ni->ni_vap->iv_ifp, | |||||
IFCOUNTER_OERRORS, 1); | |||||
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, data_tx, next); | STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, data_tx, next); | ||||
UPGT_STAT_INC(sc, st_tx_inactive); | UPGT_STAT_INC(sc, st_tx_inactive); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
continue; | continue; | ||||
} | } | ||||
sc->sc_tx_timer = 5; | sc->sc_tx_timer = 5; | ||||
} | } | ||||
UPGT_UNLOCK(sc); | |||||
} | } | ||||
static int | static int | ||||
Context not available. | |||||
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 upgt_softc *sc = ic->ic_softc; | ||||
struct upgt_softc *sc = ifp->if_softc; | |||||
struct upgt_data *data_tx = NULL; | struct upgt_data *data_tx = NULL; | ||||
UPGT_LOCK(sc); | |||||
/* prevent management frames from being sent if we're not ready */ | /* prevent management frames from being sent if we're not ready */ | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if (!(sc->sc_flags & UPGT_FLAG_INITDONE)) { | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
UPGT_UNLOCK(sc); | |||||
return ENETDOWN; | return ENETDOWN; | ||||
} | } | ||||
UPGT_LOCK(sc); | |||||
data_tx = upgt_gettxbuf(sc); | data_tx = upgt_gettxbuf(sc); | ||||
if (data_tx == NULL) { | if (data_tx == NULL) { | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
Context not available. | |||||
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, data_tx, next); | STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, data_tx, next); | ||||
UPGT_STAT_INC(sc, st_tx_inactive); | UPGT_STAT_INC(sc, st_tx_inactive); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
UPGT_UNLOCK(sc); | UPGT_UNLOCK(sc); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
Context not available. | |||||
upgt_watchdog(void *arg) | upgt_watchdog(void *arg) | ||||
{ | { | ||||
struct upgt_softc *sc = arg; | struct upgt_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
if (sc->sc_tx_timer > 0) { | if (sc->sc_tx_timer > 0) { | ||||
if (--sc->sc_tx_timer == 0) { | if (--sc->sc_tx_timer == 0) { | ||||
device_printf(sc->sc_dev, "watchdog timeout\n"); | device_printf(sc->sc_dev, "watchdog timeout\n"); | ||||
/* upgt_init(ifp); XXX needs a process context ? */ | /* upgt_init(sc); XXX needs a process context ? */ | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | counter_u64_add(ic->ic_oerrors, 1); | ||||
return; | return; | ||||
} | } | ||||
callout_reset(&sc->sc_watchdog_ch, hz, upgt_watchdog, sc); | callout_reset(&sc->sc_watchdog_ch, hz, upgt_watchdog, sc); | ||||
Context not available. | |||||
static void | static void | ||||
upgt_set_channel(struct ieee80211com *ic) | upgt_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
struct upgt_softc *sc = ic->ic_ifp->if_softc; | struct upgt_softc *sc = ic->ic_softc; | ||||
UPGT_LOCK(sc); | UPGT_LOCK(sc); | ||||
upgt_set_chan(sc, ic->ic_curchan); | upgt_set_chan(sc, ic->ic_curchan); | ||||
Context not available. | |||||
static void | static void | ||||
upgt_set_chan(struct upgt_softc *sc, struct ieee80211_channel *c) | upgt_set_chan(struct upgt_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 upgt_data *data_cmd; | struct upgt_data *data_cmd; | ||||
struct upgt_lmac_mem *mem; | struct upgt_lmac_mem *mem; | ||||
struct upgt_lmac_channel *chan; | struct upgt_lmac_channel *chan; | ||||
Context not available. | |||||
/* enable s/w bmiss handling for sta mode */ | /* enable s/w bmiss handling for sta mode */ | ||||
if (ieee80211_vap_setup(ic, vap, name, unit, opmode, | if (ieee80211_vap_setup(ic, vap, name, unit, opmode, | ||||
flags | IEEE80211_CLONE_NOBEACONS, bssid, mac) != 0) { | flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { | ||||
/* out of memory */ | /* out of memory */ | ||||
free(uvp, M_80211_VAP); | free(uvp, M_80211_VAP); | ||||
return (NULL); | return (NULL); | ||||
Context not available. | |||||
/* 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. | |||||
{ | { | ||||
struct upgt_vap *uvp = UPGT_VAP(vap); | struct upgt_vap *uvp = UPGT_VAP(vap); | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct upgt_softc *sc = ic->ic_ifp->if_softc; | struct upgt_softc *sc = ic->ic_softc; | ||||
/* do it in a process context */ | /* do it in a process context */ | ||||
sc->sc_state = nstate; | sc->sc_state = nstate; | ||||
Context not available. | |||||
static int | static int | ||||
upgt_eeprom_parse(struct upgt_softc *sc) | upgt_eeprom_parse(struct upgt_softc *sc) | ||||
{ | { | ||||
struct ieee80211com *ic = &sc->sc_ic; | |||||
struct upgt_eeprom_header *eeprom_header; | struct upgt_eeprom_header *eeprom_header; | ||||
struct upgt_eeprom_option *eeprom_option; | struct upgt_eeprom_option *eeprom_option; | ||||
uint16_t option_len; | uint16_t option_len; | ||||
Context not available. | |||||
DPRINTF(sc, UPGT_DEBUG_FW, | DPRINTF(sc, UPGT_DEBUG_FW, | ||||
"EEPROM mac len=%d\n", option_len); | "EEPROM mac len=%d\n", option_len); | ||||
IEEE80211_ADDR_COPY(sc->sc_myaddr, eeprom_option->data); | IEEE80211_ADDR_COPY(ic->ic_macaddr, | ||||
eeprom_option->data); | |||||
break; | break; | ||||
case UPGT_EEPROM_TYPE_HWRX: | case UPGT_EEPROM_TYPE_HWRX: | ||||
DPRINTF(sc, UPGT_DEBUG_FW, | DPRINTF(sc, UPGT_DEBUG_FW, | ||||
Context not available. | |||||
static struct mbuf * | static struct mbuf * | ||||
upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) | upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct upgt_lmac_rx_desc *rxdesc; | struct upgt_lmac_rx_desc *rxdesc; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
Context not available. | |||||
* don't pass packets to the ieee80211 framework if the driver isn't | * don't pass packets to the ieee80211 framework if the driver isn't | ||||
* RUNNING. | * RUNNING. | ||||
*/ | */ | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) | if (!(sc->sc_flags & UPGT_FLAG_INITDONE)) | ||||
return (NULL); | return (NULL); | ||||
/* access RX packet descriptor */ | /* access RX packet descriptor */ | ||||
Context not available. | |||||
memcpy(mtod(m, char *), rxdesc->data, pkglen); | memcpy(mtod(m, char *), rxdesc->data, pkglen); | ||||
/* trim FCS */ | /* trim FCS */ | ||||
m->m_len = m->m_pkthdr.len = pkglen - IEEE80211_CRC_LEN; | m->m_len = m->m_pkthdr.len = pkglen - IEEE80211_CRC_LEN; | ||||
m->m_pkthdr.rcvif = ifp; | |||||
if (ieee80211_radiotap_active(ic)) { | if (ieee80211_radiotap_active(ic)) { | ||||
struct upgt_rx_radiotap_header *tap = &sc->sc_rxtap; | struct upgt_rx_radiotap_header *tap = &sc->sc_rxtap; | ||||
Context not available. | |||||
tap->wr_rate = upgt_rx_rate(sc, rxdesc->rate); | tap->wr_rate = upgt_rx_rate(sc, rxdesc->rate); | ||||
tap->wr_antsignal = rxdesc->rssi; | tap->wr_antsignal = rxdesc->rssi; | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | |||||
DPRINTF(sc, UPGT_DEBUG_RX_PROC, "%s: RX done\n", __func__); | DPRINTF(sc, UPGT_DEBUG_RX_PROC, "%s: RX done\n", __func__); | ||||
*rssi = rxdesc->rssi; | *rssi = rxdesc->rssi; | ||||
Context not available. | |||||
static uint8_t | static uint8_t | ||||
upgt_rx_rate(struct upgt_softc *sc, const int rate) | upgt_rx_rate(struct upgt_softc *sc, const int rate) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
static const uint8_t cck_upgt2rate[4] = { 2, 4, 11, 22 }; | static const uint8_t cck_upgt2rate[4] = { 2, 4, 11, 22 }; | ||||
static const uint8_t ofdm_upgt2rate[12] = | static const uint8_t ofdm_upgt2rate[12] = | ||||
{ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; | { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; | ||||
Context not available. | |||||
static void | static void | ||||
upgt_tx_done(struct upgt_softc *sc, uint8_t *data) | upgt_tx_done(struct upgt_softc *sc, uint8_t *data) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct upgt_lmac_tx_done_desc *desc; | struct upgt_lmac_tx_done_desc *desc; | ||||
int i, freed = 0; | int i, freed = 0; | ||||
Context not available. | |||||
} | } | ||||
if (freed != 0) { | if (freed != 0) { | ||||
UPGT_UNLOCK(sc); | |||||
sc->sc_tx_timer = 0; | sc->sc_tx_timer = 0; | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | upgt_start(sc); | ||||
UPGT_UNLOCK(sc); | |||||
upgt_start(ifp); | |||||
UPGT_LOCK(sc); | UPGT_LOCK(sc); | ||||
} | } | ||||
} | } | ||||
Context not available. | |||||
upgt_detach(device_t dev) | upgt_detach(device_t dev) | ||||
{ | { | ||||
struct upgt_softc *sc = device_get_softc(dev); | struct upgt_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
unsigned int x; | unsigned int x; | ||||
/* | /* | ||||
Context not available. | |||||
STAILQ_INIT(&sc->sc_rx_active); | STAILQ_INIT(&sc->sc_rx_active); | ||||
STAILQ_INIT(&sc->sc_rx_inactive); | STAILQ_INIT(&sc->sc_rx_inactive); | ||||
UPGT_UNLOCK(sc); | |||||
upgt_stop(sc); | upgt_stop(sc); | ||||
UPGT_UNLOCK(sc); | |||||
callout_drain(&sc->sc_led_ch); | callout_drain(&sc->sc_led_ch); | ||||
callout_drain(&sc->sc_watchdog_ch); | callout_drain(&sc->sc_watchdog_ch); | ||||
Context not available. | |||||
usbd_transfer_unsetup(sc->sc_xfer, UPGT_N_XFERS); | usbd_transfer_unsetup(sc->sc_xfer, UPGT_N_XFERS); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
if_free(ifp); | mbufq_drain(&sc->sc_snd); | ||||
mtx_destroy(&sc->sc_mtx); | mtx_destroy(&sc->sc_mtx); | ||||
return (0); | return (0); | ||||
Context not available. | |||||
UPGT_ASSERT_LOCKED(sc); | UPGT_ASSERT_LOCKED(sc); | ||||
bf = _upgt_getbuf(sc); | bf = _upgt_getbuf(sc); | ||||
if (bf == NULL) { | if (bf == NULL) | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: stop queue\n", __func__); | DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: stop queue\n", __func__); | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
} | |||||
return (bf); | return (bf); | ||||
} | } | ||||
Context not available. | |||||
bf->addr = upgt_mem_alloc(sc); | bf->addr = upgt_mem_alloc(sc); | ||||
if (bf->addr == 0) { | if (bf->addr == 0) { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: no free prism memory!\n", | DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: no free prism memory!\n", | ||||
__func__); | __func__); | ||||
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | ||||
UPGT_STAT_INC(sc, st_tx_inactive); | UPGT_STAT_INC(sc, st_tx_inactive); | ||||
if (!(ifp->if_drv_flags & IFF_DRV_OACTIVE)) | |||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
return (NULL); | return (NULL); | ||||
} | } | ||||
return (bf); | return (bf); | ||||
Context not available. | |||||
int error = 0, len; | int error = 0, len; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k; | struct ieee80211_key *k; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct upgt_lmac_mem *mem; | struct upgt_lmac_mem *mem; | ||||
struct upgt_lmac_tx_desc *txdesc; | struct upgt_lmac_tx_desc *txdesc; | ||||
Context not available. | |||||
* will stall. It's strange, but it works, so we keep reading | * will stall. It's strange, but it works, so we keep reading | ||||
* the statistics here. *shrug* | * the statistics here. *shrug* | ||||
*/ | */ | ||||
if (!(ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS) % | if (!(vap->iv_ifp->if_get_counter(vap->iv_ifp, IFCOUNTER_OPACKETS) % | ||||
UPGT_TX_STAT_INTERVAL)) | UPGT_TX_STAT_INTERVAL)) | ||||
upgt_get_stats(sc); | upgt_get_stats(sc); | ||||
Context not available. | |||||
upgt_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) | upgt_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct upgt_softc *sc = usbd_xfer_softc(xfer); | struct upgt_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m = NULL; | struct mbuf *m = NULL; | ||||
Context not available. | |||||
(void) ieee80211_input_all(ic, m, rssi, nf); | (void) ieee80211_input_all(ic, m, rssi, nf); | ||||
m = NULL; | m = NULL; | ||||
} | } | ||||
if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && | |||||
!IFQ_IS_EMPTY(&ifp->if_snd)) | |||||
upgt_start(ifp); | |||||
UPGT_LOCK(sc); | UPGT_LOCK(sc); | ||||
upgt_start(sc); | |||||
break; | break; | ||||
default: | default: | ||||
/* needs it to the inactive queue due to a error. */ | /* needs it to the inactive queue due to a error. */ | ||||
Context not available. | |||||
} | } | ||||
if (error != USB_ERR_CANCELLED) { | if (error != USB_ERR_CANCELLED) { | ||||
usbd_xfer_set_stall(xfer); | usbd_xfer_set_stall(xfer); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
goto setup; | goto setup; | ||||
} | } | ||||
break; | break; | ||||
Context not available. | |||||
upgt_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) | upgt_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct upgt_softc *sc = usbd_xfer_softc(xfer); | struct upgt_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct upgt_data *data; | struct upgt_data *data; | ||||
UPGT_ASSERT_LOCKED(sc); | UPGT_ASSERT_LOCKED(sc); | ||||
Context not available. | |||||
usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); | usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); | ||||
usbd_transfer_submit(xfer); | usbd_transfer_submit(xfer); | ||||
UPGT_UNLOCK(sc); | upgt_start(sc); | ||||
upgt_start(ifp); | |||||
UPGT_LOCK(sc); | |||||
break; | break; | ||||
default: | default: | ||||
data = STAILQ_FIRST(&sc->sc_tx_active); | data = STAILQ_FIRST(&sc->sc_tx_active); | ||||
Context not available. | |||||
if (data == NULL) | if (data == NULL) | ||||
goto setup; | goto setup; | ||||
if (data->ni != NULL) { | if (data->ni != NULL) { | ||||
if_inc_counter(data->ni->ni_vap->iv_ifp, | |||||
IFCOUNTER_OERRORS, 1); | |||||
ieee80211_free_node(data->ni); | ieee80211_free_node(data->ni); | ||||
data->ni = NULL; | data->ni = NULL; | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
} | } | ||||
if (error != USB_ERR_CANCELLED) { | if (error != USB_ERR_CANCELLED) { | ||||
usbd_xfer_set_stall(xfer); | usbd_xfer_set_stall(xfer); | ||||
Context not available. |