Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_urtwn.c
Context not available. | |||||
static usb_callback_t urtwn_bulk_tx_callback; | static usb_callback_t urtwn_bulk_tx_callback; | ||||
static usb_callback_t urtwn_bulk_rx_callback; | static usb_callback_t urtwn_bulk_rx_callback; | ||||
static usb_error_t urtwn_do_request(struct urtwn_softc *sc, | static usb_error_t urtwn_do_request(struct urtwn_softc *, | ||||
struct usb_device_request *req, void *data); | struct usb_device_request *, void *); | ||||
static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *, | static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *, | ||||
const char [IFNAMSIZ], int, enum ieee80211_opmode, int, | const char [IFNAMSIZ], int, enum ieee80211_opmode, int, | ||||
const uint8_t [IEEE80211_ADDR_LEN], | const uint8_t [IEEE80211_ADDR_LEN], | ||||
Context not available. | |||||
static int urtwn_tx_start(struct urtwn_softc *, | static int urtwn_tx_start(struct urtwn_softc *, | ||||
struct ieee80211_node *, struct mbuf *, | struct ieee80211_node *, struct mbuf *, | ||||
struct urtwn_data *); | struct urtwn_data *); | ||||
static void urtwn_start(struct ifnet *); | static int urtwn_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void urtwn_start_locked(struct ifnet *, | static void urtwn_start(struct urtwn_softc *); | ||||
struct urtwn_softc *); | static void urtwn_parent(struct ieee80211com *); | ||||
static int urtwn_ioctl(struct ifnet *, u_long, caddr_t); | |||||
static int urtwn_r92c_power_on(struct urtwn_softc *); | static int urtwn_r92c_power_on(struct urtwn_softc *); | ||||
static int urtwn_r88e_power_on(struct urtwn_softc *); | static int urtwn_r88e_power_on(struct urtwn_softc *); | ||||
static int urtwn_llt_init(struct urtwn_softc *); | static int urtwn_llt_init(struct urtwn_softc *); | ||||
Context not available. | |||||
static void urtwn_update_mcast(struct ieee80211com *); | static void urtwn_update_mcast(struct ieee80211com *); | ||||
static void urtwn_iq_calib(struct urtwn_softc *); | static void urtwn_iq_calib(struct urtwn_softc *); | ||||
static void urtwn_lc_calib(struct urtwn_softc *); | static void urtwn_lc_calib(struct urtwn_softc *); | ||||
static void urtwn_init(void *); | static void urtwn_init(struct urtwn_softc *); | ||||
static void urtwn_init_locked(void *); | static void urtwn_stop(struct urtwn_softc *); | ||||
static void urtwn_stop(struct ifnet *); | |||||
static void urtwn_stop_locked(struct ifnet *); | |||||
static void urtwn_abort_xfers(struct urtwn_softc *); | static void urtwn_abort_xfers(struct urtwn_softc *); | ||||
static int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
Context not available. | |||||
{ | { | ||||
struct usb_attach_arg *uaa = device_get_ivars(self); | struct usb_attach_arg *uaa = device_get_ivars(self); | ||||
struct urtwn_softc *sc = device_get_softc(self); | struct urtwn_softc *sc = device_get_softc(self); | ||||
struct ifnet *ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic; | |||||
uint8_t iface_index, bands; | uint8_t iface_index, bands; | ||||
int error; | int error; | ||||
Context not available. | |||||
mtx_init(&sc->sc_mtx, device_get_nameunit(self), | mtx_init(&sc->sc_mtx, device_get_nameunit(self), | ||||
MTX_NETWORK_LOCK, MTX_DEF); | MTX_NETWORK_LOCK, MTX_DEF); | ||||
callout_init(&sc->sc_watchdog_ch, 0); | callout_init(&sc->sc_watchdog_ch, 0); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
iface_index = URTWN_IFACE_INDEX; | iface_index = URTWN_IFACE_INDEX; | ||||
error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, | error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, | ||||
Context not available. | |||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | |||||
if (ifp == NULL) { | |||||
device_printf(sc->sc_dev, "can not if_alloc()\n"); | |||||
goto detach; | |||||
} | |||||
ic = ifp->if_l2com; | |||||
ifp->if_softc = sc; | |||||
if_initname(ifp, "urtwn", device_get_unit(sc->sc_dev)); | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = urtwn_init; | |||||
ifp->if_ioctl = urtwn_ioctl; | |||||
ifp->if_start = urtwn_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_softc = sc; | ||||
ic->ic_name = device_get_nameunit(self); | ic->ic_name = device_get_nameunit(self); | ||||
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_bssid); | ieee80211_ifattach(ic); | ||||
ic->ic_raw_xmit = urtwn_raw_xmit; | ic->ic_raw_xmit = urtwn_raw_xmit; | ||||
ic->ic_scan_start = urtwn_scan_start; | ic->ic_scan_start = urtwn_scan_start; | ||||
ic->ic_scan_end = urtwn_scan_end; | ic->ic_scan_end = urtwn_scan_end; | ||||
ic->ic_set_channel = urtwn_set_channel; | ic->ic_set_channel = urtwn_set_channel; | ||||
ic->ic_transmit = urtwn_transmit; | |||||
ic->ic_parent = urtwn_parent; | |||||
ic->ic_vap_create = urtwn_vap_create; | ic->ic_vap_create = urtwn_vap_create; | ||||
ic->ic_vap_delete = urtwn_vap_delete; | ic->ic_vap_delete = urtwn_vap_delete; | ||||
ic->ic_update_mcast = urtwn_update_mcast; | ic->ic_update_mcast = urtwn_update_mcast; | ||||
Context not available. | |||||
urtwn_detach(device_t self) | urtwn_detach(device_t self) | ||||
{ | { | ||||
struct urtwn_softc *sc = device_get_softc(self); | struct urtwn_softc *sc = device_get_softc(self); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
unsigned int x; | unsigned int x; | ||||
/* Prevent further ioctls. */ | /* Prevent further ioctls. */ | ||||
URTWN_LOCK(sc); | URTWN_LOCK(sc); | ||||
sc->sc_flags |= URTWN_DETACHED; | sc->sc_flags |= URTWN_DETACHED; | ||||
urtwn_stop(sc); | |||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
urtwn_stop(ifp); | |||||
callout_drain(&sc->sc_watchdog_ch); | callout_drain(&sc->sc_watchdog_ch); | ||||
/* Prevent further allocations from RX/TX data lists. */ | /* Prevent further allocations from RX/TX data lists. */ | ||||
Context not available. | |||||
/* stop all USB transfers */ | /* stop all USB transfers */ | ||||
usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER); | usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
mbufq_drain(&sc->sc_snd); | |||||
if_free(ifp); | |||||
mtx_destroy(&sc->sc_mtx); | mtx_destroy(&sc->sc_mtx); | ||||
return (0); | return (0); | ||||
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); | ||||
uvp = (struct urtwn_vap *) malloc(sizeof(struct urtwn_vap), | uvp = malloc(sizeof(struct urtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
M_80211_VAP, M_NOWAIT | M_ZERO); | |||||
if (uvp == NULL) | |||||
return (NULL); | |||||
vap = &uvp->vap; | vap = &uvp->vap; | ||||
/* 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. | |||||
static struct mbuf * | static struct mbuf * | ||||
urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) | urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) | ||||
{ | { | ||||
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 mbuf *m; | struct mbuf *m; | ||||
struct r92c_rx_stat *stat; | struct r92c_rx_stat *stat; | ||||
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 & URTWN_RUNNING)) | ||||
return (NULL); | return (NULL); | ||||
stat = (struct r92c_rx_stat *)buf; | stat = (struct r92c_rx_stat *)buf; | ||||
Context not available. | |||||
* This should not happen since we setup our Rx filter | * This should not happen since we setup our Rx filter | ||||
* to not receive these frames. | * to not receive these frames. | ||||
*/ | */ | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if (pktlen < sizeof(*wh) || pktlen > MCLBYTES) { | if (pktlen < sizeof(*wh) || pktlen > MCLBYTES) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
Context not available. | |||||
} | } | ||||
/* Finalize mbuf. */ | /* Finalize mbuf. */ | ||||
m->m_pkthdr.rcvif = ifp; | |||||
wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz); | wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz); | ||||
memcpy(mtod(m, uint8_t *), wh, pktlen); | memcpy(mtod(m, uint8_t *), wh, pktlen); | ||||
m->m_pkthdr.len = m->m_len = pktlen; | m->m_pkthdr.len = m->m_len = pktlen; | ||||
Context not available. | |||||
int8_t *nf) | int8_t *nf) | ||||
{ | { | ||||
struct urtwn_softc *sc = data->sc; | struct urtwn_softc *sc = data->sc; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct r92c_rx_stat *stat; | struct r92c_rx_stat *stat; | ||||
struct mbuf *m, *m0 = NULL, *prevm = NULL; | struct mbuf *m, *m0 = NULL, *prevm = NULL; | ||||
uint32_t rxdw0; | uint32_t rxdw0; | ||||
Context not available. | |||||
usbd_xfer_status(xfer, &len, NULL, NULL, NULL); | usbd_xfer_status(xfer, &len, NULL, NULL, NULL); | ||||
if (len < sizeof(*stat)) { | if (len < sizeof(*stat)) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
Context not available. | |||||
urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) | urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct urtwn_softc *sc = usbd_xfer_softc(xfer); | struct urtwn_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, *next; | struct mbuf *m = NULL, *next; | ||||
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 tr_setup; | goto tr_setup; | ||||
} | } | ||||
break; | break; | ||||
Context not available. | |||||
urtwn_txeof(struct usb_xfer *xfer, struct urtwn_data *data) | urtwn_txeof(struct usb_xfer *xfer, struct urtwn_data *data) | ||||
{ | { | ||||
struct urtwn_softc *sc = usbd_xfer_softc(xfer); | struct urtwn_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct mbuf *m; | |||||
URTWN_ASSERT_LOCKED(sc); | URTWN_ASSERT_LOCKED(sc); | ||||
/* XXX status? */ | |||||
/* | ieee80211_tx_complete(data->ni, data->m, 0); | ||||
* Do any tx complete callback. Note this must be done before releasing | data->ni = NULL; | ||||
* the node reference. | data->m = NULL; | ||||
*/ | |||||
if (data->m) { | |||||
m = data->m; | |||||
if (m->m_flags & M_TXCB) { | |||||
/* XXX status? */ | |||||
ieee80211_process_callback(data->ni, m, 0); | |||||
} | |||||
m_freem(m); | |||||
data->m = NULL; | |||||
} | |||||
if (data->ni) { | |||||
ieee80211_free_node(data->ni); | |||||
data->ni = NULL; | |||||
} | |||||
sc->sc_txtimer = 0; | sc->sc_txtimer = 0; | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
urtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) | urtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct urtwn_softc *sc = usbd_xfer_softc(xfer); | struct urtwn_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct urtwn_data *data; | struct urtwn_data *data; | ||||
URTWN_ASSERT_LOCKED(sc); | URTWN_ASSERT_LOCKED(sc); | ||||
Context not available. | |||||
STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); | STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); | ||||
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); | ||||
urtwn_start_locked(ifp, sc); | urtwn_start(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 tr_setup; | goto tr_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. | |||||
URTWN_ASSERT_LOCKED(sc); | URTWN_ASSERT_LOCKED(sc); | ||||
bf = _urtwn_getbuf(sc); | bf = _urtwn_getbuf(sc); | ||||
if (bf == NULL) { | if (bf == NULL) | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
DPRINTF("%s: stop queue\n", __func__); | DPRINTF("%s: stop queue\n", __func__); | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
} | |||||
return (bf); | return (bf); | ||||
} | } | ||||
Context not available. | |||||
sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); | sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); | ||||
DPRINTF("regulatory type=%d\n", sc->regulatory); | DPRINTF("regulatory type=%d\n", sc->regulatory); | ||||
IEEE80211_ADDR_COPY(sc->sc_bssid, rom->macaddr); | IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); | ||||
sc->sc_rf_write = urtwn_r92c_rf_write; | sc->sc_rf_write = urtwn_r92c_rf_write; | ||||
sc->sc_power_on = urtwn_r92c_power_on; | sc->sc_power_on = urtwn_r92c_power_on; | ||||
Context not available. | |||||
if (sc->ofdm_tx_pwr_diff & 0x08) | if (sc->ofdm_tx_pwr_diff & 0x08) | ||||
sc->ofdm_tx_pwr_diff |= 0xf0; | sc->ofdm_tx_pwr_diff |= 0xf0; | ||||
sc->regulatory = MS(sc->r88e_rom[0xc1], R92C_ROM_RF1_REGULATORY); | sc->regulatory = MS(sc->r88e_rom[0xc1], R92C_ROM_RF1_REGULATORY); | ||||
IEEE80211_ADDR_COPY(sc->sc_bssid, &sc->r88e_rom[0xd7]); | IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, &sc->r88e_rom[0xd7]); | ||||
sc->sc_rf_write = urtwn_r88e_rf_write; | sc->sc_rf_write = urtwn_r88e_rf_write; | ||||
sc->sc_power_on = urtwn_r88e_power_on; | sc->sc_power_on = urtwn_r88e_power_on; | ||||
Context not available. | |||||
{ | { | ||||
static const uint8_t map[] = | static const uint8_t map[] = | ||||
{ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; | { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; | ||||
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); | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct ieee80211_rateset *rs; | struct ieee80211_rateset *rs; | ||||
Context not available. | |||||
void | void | ||||
urtwn_tsf_sync_enable(struct urtwn_softc *sc) | urtwn_tsf_sync_enable(struct urtwn_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_node *ni = vap->iv_bss; | struct ieee80211_node *ni = vap->iv_bss; | ||||
Context not available. | |||||
{ | { | ||||
struct urtwn_vap *uvp = URTWN_VAP(vap); | struct urtwn_vap *uvp = URTWN_VAP(vap); | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct urtwn_softc *sc = ic->ic_ifp->if_softc; | struct urtwn_softc *sc = ic->ic_softc; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
enum ieee80211_state ostate; | enum ieee80211_state ostate; | ||||
uint32_t reg; | uint32_t reg; | ||||
Context not available. | |||||
urtwn_watchdog(void *arg) | urtwn_watchdog(void *arg) | ||||
{ | { | ||||
struct urtwn_softc *sc = arg; | struct urtwn_softc *sc = arg; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
if (sc->sc_txtimer > 0) { | if (sc->sc_txtimer > 0) { | ||||
if (--sc->sc_txtimer == 0) { | if (--sc->sc_txtimer == 0) { | ||||
device_printf(sc->sc_dev, "device timeout\n"); | device_printf(sc->sc_dev, "device timeout\n"); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | counter_u64_add(sc->sc_ic.ic_oerrors, 1); | ||||
return; | return; | ||||
} | } | ||||
callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); | callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); | ||||
Context not available. | |||||
urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni, | urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni, | ||||
struct mbuf *m0, struct urtwn_data *data) | struct mbuf *m0, struct urtwn_data *data) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k; | struct ieee80211_key *k; | ||||
struct ieee80211com *ic = ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct usb_xfer *xfer; | struct usb_xfer *xfer; | ||||
struct r92c_tx_desc *txd; | struct r92c_tx_desc *txd; | ||||
Context not available. | |||||
return (0); | return (0); | ||||
} | } | ||||
static void | static int | ||||
urtwn_start(struct ifnet *ifp) | urtwn_transmit(struct ieee80211com *ic, struct mbuf *m) | ||||
{ | { | ||||
struct urtwn_softc *sc = ifp->if_softc; | struct urtwn_softc *sc = ic->ic_softc; | ||||
int error; | |||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | |||||
return; | |||||
URTWN_LOCK(sc); | URTWN_LOCK(sc); | ||||
urtwn_start_locked(ifp, sc); | if ((sc->sc_flags & URTWN_RUNNING) == 0) { | ||||
URTWN_UNLOCK(sc); | |||||
return (ENXIO); | |||||
} | |||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
URTWN_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
urtwn_start(sc); | |||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
return (0); | |||||
} | } | ||||
static void | static void | ||||
urtwn_start_locked(struct ifnet *ifp, struct urtwn_softc *sc) | urtwn_start(struct urtwn_softc *sc) | ||||
{ | { | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
Context not available. | |||||
struct urtwn_data *bf; | struct urtwn_data *bf; | ||||
URTWN_ASSERT_LOCKED(sc); | URTWN_ASSERT_LOCKED(sc); | ||||
for (;;) { | while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | |||||
if (m == NULL) | |||||
break; | |||||
bf = urtwn_getbuf(sc); | bf = urtwn_getbuf(sc); | ||||
if (bf == NULL) { | if (bf == NULL) { | ||||
IFQ_DRV_PREPEND(&ifp->if_snd, m); | mbufq_prepend(&sc->sc_snd, m); | ||||
break; | break; | ||||
} | } | ||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ||||
m->m_pkthdr.rcvif = NULL; | m->m_pkthdr.rcvif = NULL; | ||||
if (urtwn_tx_start(sc, ni, m, bf) != 0) { | if (urtwn_tx_start(sc, ni, m, bf) != 0) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ni->ni_vap->iv_ifp, | ||||
IFCOUNTER_OERRORS, 1); | |||||
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
break; | break; | ||||
} | } | ||||
sc->sc_txtimer = 5; | sc->sc_txtimer = 5; | ||||
callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); | callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); | ||||
} | } | ||||
} | } | ||||
static int | static void | ||||
urtwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | urtwn_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct urtwn_softc *sc = ifp->if_softc; | struct urtwn_softc *sc = ic->ic_softc; | ||||
struct ieee80211com *ic = ifp->if_l2com; | int startall = 0; | ||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
int error = 0, startall = 0; | |||||
URTWN_LOCK(sc); | URTWN_LOCK(sc); | ||||
error = (sc->sc_flags & URTWN_DETACHED) ? ENXIO : 0; | if (sc->sc_flags & URTWN_DETACHED) { | ||||
URTWN_UNLOCK(sc); | |||||
return; | |||||
} | |||||
if (ic->ic_nrunning > 0) { | |||||
if ((sc->sc_flags & URTWN_RUNNING) == 0) { | |||||
urtwn_init(sc); | |||||
startall = 1; | |||||
} | |||||
} else if (sc->sc_flags & URTWN_RUNNING) | |||||
urtwn_stop(sc); | |||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
if (error != 0) | |||||
return (error); | |||||
switch (cmd) { | if (startall) | ||||
case SIOCSIFFLAGS: | ieee80211_start_all(ic); | ||||
if (ifp->if_flags & IFF_UP) { | |||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | |||||
urtwn_init(ifp->if_softc); | |||||
startall = 1; | |||||
} | |||||
} else { | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
urtwn_stop(ifp); | |||||
} | |||||
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); | |||||
} | } | ||||
static int | static int | ||||
Context not available. | |||||
struct ieee80211_channel *c, struct ieee80211_channel *extc, | struct ieee80211_channel *c, struct ieee80211_channel *extc, | ||||
uint16_t power[URTWN_RIDX_COUNT]) | uint16_t power[URTWN_RIDX_COUNT]) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct r92c_rom *rom = &sc->rom; | struct r92c_rom *rom = &sc->rom; | ||||
uint16_t cckpow, ofdmpow, htpow, diff, max; | uint16_t cckpow, ofdmpow, htpow, diff, max; | ||||
const struct urtwn_txpwr *base; | const struct urtwn_txpwr *base; | ||||
Context not available. | |||||
struct ieee80211_channel *c, struct ieee80211_channel *extc, | struct ieee80211_channel *c, struct ieee80211_channel *extc, | ||||
uint16_t power[URTWN_RIDX_COUNT]) | uint16_t power[URTWN_RIDX_COUNT]) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
uint16_t cckpow, ofdmpow, bw20pow, htpow; | uint16_t cckpow, ofdmpow, bw20pow, htpow; | ||||
const struct urtwn_r88e_txpwr *base; | const struct urtwn_r88e_txpwr *base; | ||||
int ridx, chan, group; | int ridx, chan, group; | ||||
Context not available. | |||||
static void | static void | ||||
urtwn_set_channel(struct ieee80211com *ic) | urtwn_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
struct urtwn_softc *sc = ic->ic_ifp->if_softc; | struct urtwn_softc *sc = ic->ic_softc; | ||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
URTWN_LOCK(sc); | URTWN_LOCK(sc); | ||||
Context not available. | |||||
urtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c, | urtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c, | ||||
struct ieee80211_channel *extc) | struct ieee80211_channel *extc) | ||||
{ | { | ||||
struct ieee80211com *ic = sc->sc_ifp->if_l2com; | struct ieee80211com *ic = &sc->sc_ic; | ||||
uint32_t reg; | uint32_t reg; | ||||
u_int chan; | u_int chan; | ||||
int i; | int i; | ||||
Context not available. | |||||
} | } | ||||
static void | static void | ||||
urtwn_init_locked(void *arg) | urtwn_init(struct urtwn_softc *sc) | ||||
{ | { | ||||
struct urtwn_softc *sc = arg; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
uint8_t macaddr[IEEE80211_ADDR_LEN]; | |||||
uint32_t reg; | uint32_t reg; | ||||
int error; | int error; | ||||
URTWN_ASSERT_LOCKED(sc); | URTWN_ASSERT_LOCKED(sc); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_flags & URTWN_RUNNING) | ||||
urtwn_stop_locked(ifp); | urtwn_stop(sc); | ||||
/* Init firmware commands ring. */ | /* Init firmware commands ring. */ | ||||
sc->fwcur = 0; | sc->fwcur = 0; | ||||
Context not available. | |||||
} | } | ||||
/* Set MAC address. */ | /* Set MAC address. */ | ||||
urtwn_write_region_1(sc, R92C_MACID, IF_LLADDR(ifp), | IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); | ||||
IEEE80211_ADDR_LEN); | urtwn_write_region_1(sc, R92C_MACID, macaddr, IEEE80211_ADDR_LEN); | ||||
/* Set initial network type. */ | /* Set initial network type. */ | ||||
reg = urtwn_read_4(sc, R92C_CR); | reg = urtwn_read_4(sc, R92C_CR); | ||||
Context not available. | |||||
usbd_transfer_start(sc->sc_xfer[URTWN_BULK_RX]); | usbd_transfer_start(sc->sc_xfer[URTWN_BULK_RX]); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | sc->sc_flags |= URTWN_RUNNING; | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); | callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); | ||||
fail: | fail: | ||||
Context not available. | |||||
} | } | ||||
static void | static void | ||||
urtwn_init(void *arg) | urtwn_stop(struct urtwn_softc *sc) | ||||
{ | { | ||||
struct urtwn_softc *sc = arg; | |||||
URTWN_LOCK(sc); | |||||
urtwn_init_locked(arg); | |||||
URTWN_UNLOCK(sc); | |||||
} | |||||
static void | |||||
urtwn_stop_locked(struct ifnet *ifp) | |||||
{ | |||||
struct urtwn_softc *sc = ifp->if_softc; | |||||
URTWN_ASSERT_LOCKED(sc); | URTWN_ASSERT_LOCKED(sc); | ||||
sc->sc_flags &= ~URTWN_RUNNING; | |||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | |||||
callout_stop(&sc->sc_watchdog_ch); | callout_stop(&sc->sc_watchdog_ch); | ||||
urtwn_abort_xfers(sc); | urtwn_abort_xfers(sc); | ||||
} | } | ||||
static void | static void | ||||
urtwn_stop(struct ifnet *ifp) | |||||
{ | |||||
struct urtwn_softc *sc = ifp->if_softc; | |||||
URTWN_LOCK(sc); | |||||
urtwn_stop_locked(ifp); | |||||
URTWN_UNLOCK(sc); | |||||
} | |||||
static void | |||||
urtwn_abort_xfers(struct urtwn_softc *sc) | urtwn_abort_xfers(struct urtwn_softc *sc) | ||||
{ | { | ||||
int i; | int i; | ||||
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 urtwn_softc *sc = ic->ic_softc; | ||||
struct urtwn_softc *sc = ifp->if_softc; | |||||
struct urtwn_data *bf; | struct urtwn_data *bf; | ||||
/* 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 & URTWN_RUNNING)) { | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return (ENETDOWN); | return (ENETDOWN); | ||||
Context not available. | |||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
if (urtwn_tx_start(sc, ni, m, bf) != 0) { | if (urtwn_tx_start(sc, ni, m, bf) != 0) { | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); | ||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
return (EIO); | return (EIO); | ||||
Context not available. |