Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_rsu.c
Context not available. | |||||
static void rsu_txeof(struct usb_xfer *, struct rsu_data *); | static void rsu_txeof(struct usb_xfer *, struct rsu_data *); | ||||
static int rsu_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int rsu_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static void rsu_init(void *); | static void rsu_init(struct rsu_softc *); | ||||
static void rsu_init_locked(struct rsu_softc *); | |||||
static int rsu_tx_start(struct rsu_softc *, struct ieee80211_node *, | static int rsu_tx_start(struct rsu_softc *, struct ieee80211_node *, | ||||
struct mbuf *, struct rsu_data *); | struct mbuf *, struct rsu_data *); | ||||
static void rsu_start(struct ifnet *); | static int rsu_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void rsu_start_locked(struct ifnet *); | static void rsu_start(struct rsu_softc *); | ||||
static int rsu_ioctl(struct ifnet *, u_long, caddr_t); | static void rsu_parent(struct ieee80211com *); | ||||
static void rsu_stop(struct ifnet *, int); | static void rsu_stop(struct rsu_softc *); | ||||
static void rsu_stop_locked(struct ifnet *, int); | |||||
static void rsu_ms_delay(struct rsu_softc *); | static void rsu_ms_delay(struct rsu_softc *); | ||||
static device_method_t rsu_methods[] = { | static device_method_t rsu_methods[] = { | ||||
Context not available. | |||||
{ | { | ||||
struct usb_attach_arg *uaa = device_get_ivars(self); | struct usb_attach_arg *uaa = device_get_ivars(self); | ||||
struct rsu_softc *sc = device_get_softc(self); | struct rsu_softc *sc = device_get_softc(self); | ||||
struct ifnet *ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic; | |||||
int error; | int error; | ||||
uint8_t iface_index, bands; | uint8_t iface_index, bands; | ||||
Context not available. | |||||
MTX_DEF); | MTX_DEF); | ||||
TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0, | TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0, | ||||
rsu_calib_task, sc); | rsu_calib_task, sc); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
/* Allocate Tx/Rx buffers. */ | /* Allocate Tx/Rx buffers. */ | ||||
error = rsu_alloc_rx_list(sc); | error = rsu_alloc_rx_list(sc); | ||||
Context not available. | |||||
device_printf(self, "could not read ROM\n"); | device_printf(self, "could not read ROM\n"); | ||||
goto fail_rom; | goto fail_rom; | ||||
} | } | ||||
IEEE80211_ADDR_COPY(sc->sc_bssid, &sc->rom[0x12]); | IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->rom[0x12]); | ||||
device_printf(self, "MAC/BB RTL8712 cut %d\n", sc->cut); | device_printf(self, "MAC/BB RTL8712 cut %d\n", sc->cut); | ||||
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | |||||
if (ifp == NULL) { | |||||
device_printf(self, "cannot allocate interface\n"); | |||||
goto fail_ifalloc; | |||||
} | |||||
ic = ifp->if_l2com; | |||||
ifp->if_softc = sc; | |||||
if_initname(ifp, "rsu", device_get_unit(self)); | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = rsu_init; | |||||
ifp->if_ioctl = rsu_ioctl; | |||||
ifp->if_start = rsu_start; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
ifp->if_capabilities |= IFCAP_RXCSUM; | |||||
ifp->if_capenable |= IFCAP_RXCSUM; | |||||
ifp->if_hwassist = CSUM_TCP; | |||||
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 = rsu_raw_xmit; | ic->ic_raw_xmit = rsu_raw_xmit; | ||||
ic->ic_scan_start = rsu_scan_start; | ic->ic_scan_start = rsu_scan_start; | ||||
ic->ic_scan_end = rsu_scan_end; | ic->ic_scan_end = rsu_scan_end; | ||||
Context not available. | |||||
ic->ic_vap_create = rsu_vap_create; | ic->ic_vap_create = rsu_vap_create; | ||||
ic->ic_vap_delete = rsu_vap_delete; | ic->ic_vap_delete = rsu_vap_delete; | ||||
ic->ic_update_mcast = rsu_update_mcast; | ic->ic_update_mcast = rsu_update_mcast; | ||||
ic->ic_parent = rsu_parent; | |||||
ic->ic_transmit = rsu_transmit; | |||||
ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, | ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, | ||||
sizeof(sc->sc_txtap), RSU_TX_RADIOTAP_PRESENT, | sizeof(sc->sc_txtap), RSU_TX_RADIOTAP_PRESENT, | ||||
Context not available. | |||||
return (0); | return (0); | ||||
fail_ifalloc: | |||||
fail_rom: | fail_rom: | ||||
usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); | usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); | ||||
fail_usb: | fail_usb: | ||||
Context not available. | |||||
rsu_detach(device_t self) | rsu_detach(device_t self) | ||||
{ | { | ||||
struct rsu_softc *sc = device_get_softc(self); | struct rsu_softc *sc = device_get_softc(self); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
rsu_stop(ifp, 1); | RSU_LOCK(sc); | ||||
rsu_stop(sc); | |||||
RSU_UNLOCK(sc); | |||||
usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); | usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
Context not available. | |||||
rsu_free_tx_list(sc); | rsu_free_tx_list(sc); | ||||
rsu_free_rx_list(sc); | rsu_free_rx_list(sc); | ||||
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. | |||||
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 rsu_vap *) malloc(sizeof(struct rsu_vap), | uvp = malloc(sizeof(struct rsu_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; | ||||
if (ieee80211_vap_setup(ic, vap, name, unit, opmode, | if (ieee80211_vap_setup(ic, vap, name, unit, opmode, | ||||
flags, bssid, mac) != 0) { | flags, 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 void | static void | ||||
rsu_scan_start(struct ieee80211com *ic) | rsu_scan_start(struct ieee80211com *ic) | ||||
{ | { | ||||
struct rsu_softc *sc = ic->ic_softc; | |||||
int error; | int error; | ||||
struct ifnet *ifp = ic->ic_ifp; | |||||
struct rsu_softc *sc = ifp->if_softc; | |||||
/* Scanning is done by the firmware. */ | /* Scanning is done by the firmware. */ | ||||
RSU_LOCK(sc); | RSU_LOCK(sc); | ||||
Context not available. | |||||
RSU_ASSERT_LOCKED(sc); | RSU_ASSERT_LOCKED(sc); | ||||
bf = _rsu_getbuf(sc); | bf = _rsu_getbuf(sc); | ||||
if (bf == NULL) { | if (bf == NULL) | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
DPRINTF("stop queue\n"); | DPRINTF("stop queue\n"); | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
} | |||||
return (bf); | return (bf); | ||||
} | } | ||||
Context not available. | |||||
{ | { | ||||
struct rsu_vap *uvp = RSU_VAP(vap); | struct rsu_vap *uvp = RSU_VAP(vap); | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct rsu_softc *sc = ic->ic_ifp->if_softc; | struct rsu_softc *sc = ic->ic_softc; | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct ieee80211_rateset *rs; | struct ieee80211_rateset *rs; | ||||
enum ieee80211_state ostate; | enum ieee80211_state ostate; | ||||
Context not available. | |||||
rsu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap) | rsu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap) | ||||
{ | { | ||||
struct r92s_fw_cmd_sitesurvey cmd; | struct r92s_fw_cmd_sitesurvey cmd; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
memset(&cmd, 0, sizeof(cmd)); | memset(&cmd, 0, sizeof(cmd)); | ||||
if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->scan_pass == 1) | if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->sc_scan_pass == 1) | ||||
cmd.active = htole32(1); | cmd.active = htole32(1); | ||||
cmd.limit = htole32(48); | cmd.limit = htole32(48); | ||||
if (sc->scan_pass == 1 && vap->iv_des_nssid > 0) { | if (sc->sc_scan_pass == 1 && vap->iv_des_nssid > 0) { | ||||
/* Do a directed scan for second pass. */ | /* Do a directed scan for second pass. */ | ||||
cmd.ssidlen = htole32(vap->iv_des_ssid[0].len); | cmd.ssidlen = htole32(vap->iv_des_ssid[0].len); | ||||
memcpy(cmd.ssid, vap->iv_des_ssid[0].ssid, | memcpy(cmd.ssid, vap->iv_des_ssid[0].ssid, | ||||
Context not available. | |||||
vap->iv_des_ssid[0].len); | vap->iv_des_ssid[0].len); | ||||
} | } | ||||
DPRINTF("sending site survey command, pass=%d\n", sc->scan_pass); | DPRINTF("sending site survey command, pass=%d\n", sc->sc_scan_pass); | ||||
return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd))); | return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd))); | ||||
} | } | ||||
Context not available. | |||||
static int | static int | ||||
rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) | rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ndis_wlan_bssid_ex *bss; | struct ndis_wlan_bssid_ex *bss; | ||||
struct ndis_802_11_fixed_ies *fixed; | struct ndis_802_11_fixed_ies *fixed; | ||||
Context not available. | |||||
static void | static void | ||||
rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) | rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) | ||||
{ | { | ||||
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_channel *c; | struct ieee80211_channel *c; | ||||
struct ndis_wlan_bssid_ex *bss; | struct ndis_wlan_bssid_ex *bss; | ||||
Context not available. | |||||
IEEE80211_FC0_SUBTYPE_BEACON; | IEEE80211_FC0_SUBTYPE_BEACON; | ||||
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; | wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; | ||||
USETW(wh->i_dur, 0); | USETW(wh->i_dur, 0); | ||||
IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); | IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr); | ||||
IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr); | IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr); | ||||
IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr); | IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr); | ||||
*(uint16_t *)wh->i_seq = 0; | *(uint16_t *)wh->i_seq = 0; | ||||
Context not available. | |||||
/* Finalize mbuf. */ | /* Finalize mbuf. */ | ||||
m->m_pkthdr.len = m->m_len = pktlen; | m->m_pkthdr.len = m->m_len = pktlen; | ||||
m->m_pkthdr.rcvif = ifp; | |||||
/* Fix the channel. */ | /* Fix the channel. */ | ||||
c = ieee80211_find_channel_byieee(ic, | c = ieee80211_find_channel_byieee(ic, | ||||
le32toh(bss->config.dsconfig), | le32toh(bss->config.dsconfig), | ||||
Context not available. | |||||
static void | static void | ||||
rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len) | rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len) | ||||
{ | { | ||||
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; | ||||
struct r92s_event_join_bss *rsp; | struct r92s_event_join_bss *rsp; | ||||
Context not available. | |||||
static void | static void | ||||
rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) | rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) | ||||
{ | { | ||||
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); | ||||
DPRINTFN(4, "Rx event code=%d len=%d\n", code, len); | DPRINTFN(4, "Rx event code=%d len=%d\n", code, len); | ||||
Context not available. | |||||
break; | break; | ||||
case R92S_EVT_SURVEY_DONE: | case R92S_EVT_SURVEY_DONE: | ||||
DPRINTF("site survey pass %d done, found %d BSS\n", | DPRINTF("site survey pass %d done, found %d BSS\n", | ||||
sc->scan_pass, le32toh(*(uint32_t *)buf)); | sc->sc_scan_pass, le32toh(*(uint32_t *)buf)); | ||||
if (vap->iv_state != IEEE80211_S_SCAN) | if (vap->iv_state != IEEE80211_S_SCAN) | ||||
break; /* Ignore if not scanning. */ | break; /* Ignore if not scanning. */ | ||||
if (sc->scan_pass == 0 && vap->iv_des_nssid != 0) { | if (sc->sc_scan_pass == 0 && vap->iv_des_nssid != 0) { | ||||
/* Schedule a directed scan for hidden APs. */ | /* Schedule a directed scan for hidden APs. */ | ||||
sc->scan_pass = 1; | sc->sc_scan_pass = 1; | ||||
RSU_UNLOCK(sc); | RSU_UNLOCK(sc); | ||||
ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); | ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); | ||||
RSU_LOCK(sc); | RSU_LOCK(sc); | ||||
break; | break; | ||||
} | } | ||||
sc->scan_pass = 0; | sc->sc_scan_pass = 0; | ||||
break; | break; | ||||
case R92S_EVT_JOIN_BSS: | case R92S_EVT_JOIN_BSS: | ||||
if (vap->iv_state == IEEE80211_S_AUTH) | if (vap->iv_state == IEEE80211_S_AUTH) | ||||
Context not available. | |||||
DPRINTF("WPS PBC pushed.\n"); | DPRINTF("WPS PBC pushed.\n"); | ||||
break; | break; | ||||
case R92S_EVT_FWDBG: | case R92S_EVT_FWDBG: | ||||
if (ifp->if_flags & IFF_DEBUG) { | if (vap->iv_ifp->if_flags & IFF_DEBUG) { | ||||
buf[60] = '\0'; | buf[60] = '\0'; | ||||
printf("FWDBG: %s\n", (char *)buf); | printf("FWDBG: %s\n", (char *)buf); | ||||
} | } | ||||
Context not available. | |||||
static struct mbuf * | static struct mbuf * | ||||
rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) | rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) | ||||
{ | { | ||||
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 r92s_rx_stat *stat; | struct r92s_rx_stat *stat; | ||||
uint32_t rxdw0, rxdw3; | uint32_t rxdw0, rxdw3; | ||||
Context not available. | |||||
rxdw3 = le32toh(stat->rxdw3); | rxdw3 = le32toh(stat->rxdw3); | ||||
if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) { | if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) { | if (__predict_false(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. | |||||
m = m_get2(pktlen, M_NOWAIT, MT_DATA, M_PKTHDR); | m = m_get2(pktlen, M_NOWAIT, MT_DATA, M_PKTHDR); | ||||
if (__predict_false(m == NULL)) { | if (__predict_false(m == NULL)) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
/* Finalize mbuf. */ | |||||
m->m_pkthdr.rcvif = ifp; | |||||
/* Hardware does Rx TCP checksum offload. */ | /* Hardware does Rx TCP checksum offload. */ | ||||
if (rxdw3 & R92S_RXDW3_TCPCHKVALID) { | if (rxdw3 & R92S_RXDW3_TCPCHKVALID) { | ||||
if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT)) | if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT)) | ||||
Context not available. | |||||
rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data, int *rssi) | rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data, int *rssi) | ||||
{ | { | ||||
struct rsu_softc *sc = data->sc; | struct rsu_softc *sc = data->sc; | ||||
struct ieee80211com *ic = &sc->sc_ic; | |||||
struct r92s_rx_stat *stat; | struct r92s_rx_stat *stat; | ||||
int len; | int len; | ||||
Context not available. | |||||
if (__predict_false(len < sizeof(*stat))) { | if (__predict_false(len < sizeof(*stat))) { | ||||
DPRINTF("xfer too short %d\n", len); | DPRINTF("xfer too short %d\n", len); | ||||
if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* Determine if it is a firmware C2H event or an 802.11 frame. */ | /* Determine if it is a firmware C2H event or an 802.11 frame. */ | ||||
Context not available. | |||||
rsu_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) | rsu_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct rsu_softc *sc = usbd_xfer_softc(xfer); | struct rsu_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. | |||||
} | } | ||||
static void | static void | ||||
rsu_txeof(struct usb_xfer *xfer, struct rsu_data *data) | rsu_txeof(struct usb_xfer *xfer, struct rsu_data *data) | ||||
{ | { | ||||
struct rsu_softc *sc = usbd_xfer_softc(xfer); | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct mbuf *m; | |||||
RSU_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); | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
uint8_t which) | uint8_t which) | ||||
{ | { | ||||
struct rsu_softc *sc = usbd_xfer_softc(xfer); | struct rsu_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct rsu_data *data; | struct rsu_data *data; | ||||
RSU_ASSERT_LOCKED(sc); | RSU_ASSERT_LOCKED(sc); | ||||
Context not available. | |||||
rsu_txeof(xfer, data); | rsu_txeof(xfer, data); | ||||
STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); | STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | counter_u64_add(ic->ic_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. | |||||
rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, | rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, | ||||
struct mbuf *m0, struct rsu_data *data) | struct mbuf *m0, struct rsu_data *data) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211_frame *wh; | struct ieee80211_frame *wh; | ||||
struct ieee80211_key *k = NULL; | struct ieee80211_key *k = NULL; | ||||
Context not available. | |||||
return (0); | return (0); | ||||
} | } | ||||
static void | static int | ||||
rsu_start(struct ifnet *ifp) | rsu_transmit(struct ieee80211com *ic, struct mbuf *m) | ||||
{ | { | ||||
struct rsu_softc *sc = ifp->if_softc; | struct rsu_softc *sc = ic->ic_softc; | ||||
int error; | |||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | |||||
return; | |||||
RSU_LOCK(sc); | RSU_LOCK(sc); | ||||
rsu_start_locked(ifp); | if (!sc->sc_running) { | ||||
RSU_UNLOCK(sc); | |||||
return (ENXIO); | |||||
} | |||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
RSU_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
rsu_start(sc); | |||||
RSU_UNLOCK(sc); | RSU_UNLOCK(sc); | ||||
return (0); | |||||
} | } | ||||
static void | static void | ||||
rsu_start_locked(struct ifnet *ifp) | rsu_start(struct rsu_softc *sc) | ||||
{ | { | ||||
struct rsu_softc *sc = ifp->if_softc; | |||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct rsu_data *bf; | struct rsu_data *bf; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
Context not available. | |||||
RSU_ASSERT_LOCKED(sc); | RSU_ASSERT_LOCKED(sc); | ||||
for (;;) { | while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | bf = rsu_getbuf(sc); | ||||
if (m == NULL) | if (bf == NULL) { | ||||
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; | ||||
bf = rsu_getbuf(sc); | if (rsu_tx_start(sc, ni, m, bf) != 0) { | ||||
if (bf == NULL) { | if_inc_counter(ni->ni_vap->iv_ifp, | ||||
if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); | IFCOUNTER_OERRORS, 1); | ||||
m_freem(m); | |||||
ieee80211_free_node(ni); | |||||
} else if (rsu_tx_start(sc, ni, m, bf) != 0) { | |||||
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); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
break; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
static int | static void | ||||
rsu_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | rsu_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ieee80211com *ic = ifp->if_l2com; | struct rsu_softc *sc = ic->ic_softc; | ||||
struct ifreq *ifr = (struct ifreq *) data; | int startall = 0; | ||||
int error = 0, startall = 0; | |||||
switch (cmd) { | RSU_LOCK(sc); | ||||
case SIOCSIFFLAGS: | if (ic->ic_nrunning > 0) { | ||||
if (ifp->if_flags & IFF_UP) { | if (!sc->sc_running) { | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | rsu_init(sc); | ||||
rsu_init(ifp->if_softc); | startall = 1; | ||||
startall = 1; | |||||
} | |||||
} else { | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
rsu_stop(ifp, 1); | |||||
} | } | ||||
if (startall) | } else if (sc->sc_running) | ||||
ieee80211_start_all(ic); | rsu_stop(sc); | ||||
break; | RSU_UNLOCK(sc); | ||||
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); | if (startall) | ||||
ieee80211_start_all(ic); | |||||
} | } | ||||
/* | /* | ||||
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 rsu_softc *sc = ic->ic_softc; | ||||
struct rsu_softc *sc = ifp->if_softc; | |||||
struct rsu_data *bf; | struct rsu_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_running) { | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return (ENETDOWN); | return (ENETDOWN); | ||||
Context not available. | |||||
RSU_UNLOCK(sc); | RSU_UNLOCK(sc); | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
if (rsu_tx_start(sc, ni, m, bf) != 0) { | if (rsu_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); | ||||
RSU_UNLOCK(sc); | RSU_UNLOCK(sc); | ||||
return (EIO); | return (EIO); | ||||
Context not available. | |||||
} | } | ||||
static void | static void | ||||
rsu_init(void *arg) | rsu_init(struct rsu_softc *sc) | ||||
{ | { | ||||
struct rsu_softc *sc = arg; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | |||||
RSU_LOCK(sc); | uint8_t macaddr[IEEE80211_ADDR_LEN]; | ||||
rsu_init_locked(arg); | |||||
RSU_UNLOCK(sc); | |||||
} | |||||
static void | |||||
rsu_init_locked(struct rsu_softc *sc) | |||||
{ | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct r92s_set_pwr_mode cmd; | struct r92s_set_pwr_mode cmd; | ||||
int error; | int error; | ||||
int i; | int i; | ||||
RSU_ASSERT_LOCKED(sc); | |||||
/* Init host async commands ring. */ | /* Init host async commands ring. */ | ||||
sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0; | sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0; | ||||
Context not available. | |||||
rsu_read_1(sc, 0xfe5c) | 0x80); | rsu_read_1(sc, 0xfe5c) | 0x80); | ||||
/* Set MAC address. */ | /* Set MAC address. */ | ||||
rsu_write_region_1(sc, R92S_MACID, IF_LLADDR(ifp), | IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); | ||||
IEEE80211_ADDR_LEN); | rsu_write_region_1(sc, R92S_MACID, macaddr, IEEE80211_ADDR_LEN); | ||||
/* It really takes 1.5 seconds for the firmware to boot: */ | /* It really takes 1.5 seconds for the firmware to boot: */ | ||||
usb_pause_mtx(&sc->sc_mtx, (3 * hz) / 2); | usb_pause_mtx(&sc->sc_mtx, (3 * hz) / 2); | ||||
DPRINTF("setting MAC address to %s\n", ether_sprintf(IF_LLADDR(ifp))); | DPRINTF("setting MAC address to %s\n", ether_sprintf(IF_LLADDR(ifp))); | ||||
error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, IF_LLADDR(ifp), | error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, macaddr, | ||||
IEEE80211_ADDR_LEN); | IEEE80211_ADDR_LEN); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "could not set MAC address\n"); | device_printf(sc->sc_dev, "could not set MAC address\n"); | ||||
Context not available. | |||||
/* Set default channel. */ | /* Set default channel. */ | ||||
ic->ic_bss->ni_chan = ic->ic_ibss_chan; | ic->ic_bss->ni_chan = ic->ic_ibss_chan; | ||||
#endif | #endif | ||||
sc->scan_pass = 0; | sc->sc_scan_pass = 0; | ||||
usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]); | usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]); | ||||
/* We're ready to go. */ | /* We're ready to go. */ | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | sc->sc_running = 1; | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
return; | return; | ||||
fail: | fail: | ||||
/* Need to stop all failed transfers, if any */ | /* Need to stop all failed transfers, if any */ | ||||
Context not available. | |||||
} | } | ||||
static void | static void | ||||
rsu_stop(struct ifnet *ifp, int disable) | rsu_stop(struct rsu_softc *sc) | ||||
{ | { | ||||
struct rsu_softc *sc = ifp->if_softc; | |||||
RSU_LOCK(sc); | |||||
rsu_stop_locked(ifp, disable); | |||||
RSU_UNLOCK(sc); | |||||
} | |||||
static void | |||||
rsu_stop_locked(struct ifnet *ifp, int disable __unused) | |||||
{ | |||||
struct rsu_softc *sc = ifp->if_softc; | |||||
int i; | int i; | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | sc->sc_running = 0; | ||||
sc->sc_calibrating = 0; | sc->sc_calibrating = 0; | ||||
taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL); | taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL); | ||||
Context not available. |