Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_urtwn.c
Show First 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | |||||
static device_probe_t urtwn_match; | static device_probe_t urtwn_match; | ||||
static device_attach_t urtwn_attach; | static device_attach_t urtwn_attach; | ||||
static device_detach_t urtwn_detach; | static device_detach_t urtwn_detach; | ||||
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], | ||||
const uint8_t [IEEE80211_ADDR_LEN]); | const uint8_t [IEEE80211_ADDR_LEN]); | ||||
static void urtwn_vap_delete(struct ieee80211vap *); | static void urtwn_vap_delete(struct ieee80211vap *); | ||||
static struct mbuf * urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int, | static struct mbuf * urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int, | ||||
int *); | int *); | ||||
static struct mbuf * urtwn_rxeof(struct usb_xfer *, struct urtwn_data *, | static struct mbuf * urtwn_rxeof(struct usb_xfer *, struct urtwn_data *, | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | static int urtwn_newstate(struct ieee80211vap *, | ||||
enum ieee80211_state, int); | enum ieee80211_state, int); | ||||
static void urtwn_watchdog(void *); | static void urtwn_watchdog(void *); | ||||
static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); | static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); | ||||
static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); | static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); | ||||
static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); | static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); | ||||
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 *); | ||||
static void urtwn_fw_reset(struct urtwn_softc *); | static void urtwn_fw_reset(struct urtwn_softc *); | ||||
static void urtwn_r88e_fw_reset(struct urtwn_softc *); | static void urtwn_r88e_fw_reset(struct urtwn_softc *); | ||||
static int urtwn_fw_loadpage(struct urtwn_softc *, int, | static int urtwn_fw_loadpage(struct urtwn_softc *, int, | ||||
const uint8_t *, int); | const uint8_t *, int); | ||||
static int urtwn_load_firmware(struct urtwn_softc *); | static int urtwn_load_firmware(struct urtwn_softc *); | ||||
Show All 21 Lines | |||||
static void urtwn_scan_end(struct ieee80211com *); | static void urtwn_scan_end(struct ieee80211com *); | ||||
static void urtwn_set_channel(struct ieee80211com *); | static void urtwn_set_channel(struct ieee80211com *); | ||||
static void urtwn_set_chan(struct urtwn_softc *, | static void urtwn_set_chan(struct urtwn_softc *, | ||||
struct ieee80211_channel *, | struct ieee80211_channel *, | ||||
struct ieee80211_channel *); | struct ieee80211_channel *); | ||||
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 *); | ||||
static void urtwn_ms_delay(struct urtwn_softc *); | static void urtwn_ms_delay(struct urtwn_softc *); | ||||
/* Aliases. */ | /* Aliases. */ | ||||
#define urtwn_bb_write urtwn_write_4 | #define urtwn_bb_write urtwn_write_4 | ||||
#define urtwn_bb_read urtwn_read_4 | #define urtwn_bb_read urtwn_read_4 | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | urtwn_match(device_t self) | ||||
return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa)); | return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa)); | ||||
} | } | ||||
static int | static int | ||||
urtwn_attach(device_t self) | urtwn_attach(device_t self) | ||||
{ | { | ||||
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; | ||||
device_set_usb_desc(self); | device_set_usb_desc(self); | ||||
sc->sc_udev = uaa->device; | sc->sc_udev = uaa->device; | ||||
sc->sc_dev = self; | sc->sc_dev = self; | ||||
if (USB_GET_DRIVER_INFO(uaa) == URTWN_RTL8188E) | if (USB_GET_DRIVER_INFO(uaa) == URTWN_RTL8188E) | ||||
sc->chip |= URTWN_CHIP_88E; | sc->chip |= URTWN_CHIP_88E; | ||||
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, | ||||
urtwn_config, URTWN_N_TRANSFER, sc, &sc->sc_mtx); | urtwn_config, URTWN_N_TRANSFER, sc, &sc->sc_mtx); | ||||
if (error) { | if (error) { | ||||
device_printf(self, "could not allocate USB transfers, " | device_printf(self, "could not allocate USB transfers, " | ||||
"err=%s\n", usbd_errstr(error)); | "err=%s\n", usbd_errstr(error)); | ||||
goto detach; | goto detach; | ||||
Show All 26 Lines | device_printf(sc->sc_dev, "MAC/BB RTL%s, RF 6052 %dT%dR\n", | ||||
(sc->chip & URTWN_CHIP_92C) ? "8192CU" : | (sc->chip & URTWN_CHIP_92C) ? "8192CU" : | ||||
(sc->chip & URTWN_CHIP_88E) ? "8188EU" : | (sc->chip & URTWN_CHIP_88E) ? "8188EU" : | ||||
(sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : | (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : | ||||
(sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : | (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : | ||||
"8188CUS", sc->ntxchains, sc->nrxchains); | "8188CUS", sc->ntxchains, sc->nrxchains); | ||||
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 */ | ||||
ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ | ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ | ||||
/* set device capabilities */ | /* set device capabilities */ | ||||
ic->ic_caps = | ic->ic_caps = | ||||
IEEE80211_C_STA /* station mode */ | IEEE80211_C_STA /* station mode */ | ||||
| IEEE80211_C_MONITOR /* monitor mode */ | | IEEE80211_C_MONITOR /* monitor mode */ | ||||
| IEEE80211_C_SHPREAMBLE /* short preamble supported */ | | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | ||||
| IEEE80211_C_SHSLOT /* short slot time supported */ | | IEEE80211_C_SHSLOT /* short slot time supported */ | ||||
| IEEE80211_C_BGSCAN /* capable of bg scanning */ | | IEEE80211_C_BGSCAN /* capable of bg scanning */ | ||||
| IEEE80211_C_WPA /* 802.11i */ | | IEEE80211_C_WPA /* 802.11i */ | ||||
; | ; | ||||
bands = 0; | bands = 0; | ||||
setbit(&bands, IEEE80211_MODE_11B); | setbit(&bands, IEEE80211_MODE_11B); | ||||
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; | ||||
ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, | ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, | ||||
sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT, | sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT, | ||||
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | ||||
URTWN_RX_RADIOTAP_PRESENT); | URTWN_RX_RADIOTAP_PRESENT); | ||||
if (bootverbose) | if (bootverbose) | ||||
ieee80211_announce(ic); | ieee80211_announce(ic); | ||||
return (0); | return (0); | ||||
detach: | detach: | ||||
urtwn_detach(self); | urtwn_detach(self); | ||||
return (ENXIO); /* failure */ | return (ENXIO); /* failure */ | ||||
} | } | ||||
static int | static int | ||||
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. */ | ||||
URTWN_LOCK(sc); | URTWN_LOCK(sc); | ||||
STAILQ_INIT(&sc->sc_tx_active); | STAILQ_INIT(&sc->sc_tx_active); | ||||
STAILQ_INIT(&sc->sc_tx_inactive); | STAILQ_INIT(&sc->sc_tx_inactive); | ||||
STAILQ_INIT(&sc->sc_tx_pending); | STAILQ_INIT(&sc->sc_tx_pending); | ||||
Show All 9 Lines | urtwn_detach(device_t self) | ||||
URTWN_LOCK(sc); | URTWN_LOCK(sc); | ||||
urtwn_free_tx_list(sc); | urtwn_free_tx_list(sc); | ||||
urtwn_free_rx_list(sc); | urtwn_free_rx_list(sc); | ||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
/* 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); | ||||
} | } | ||||
static void | static void | ||||
urtwn_free_tx_list(struct urtwn_softc *sc) | urtwn_free_tx_list(struct urtwn_softc *sc) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | urtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | ||||
const uint8_t mac[IEEE80211_ADDR_LEN]) | const uint8_t mac[IEEE80211_ADDR_LEN]) | ||||
{ | { | ||||
struct urtwn_vap *uvp; | struct urtwn_vap *uvp; | ||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
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); | ||||
} | } | ||||
/* override state transition machine */ | /* override state transition machine */ | ||||
uvp->newstate = vap->iv_newstate; | uvp->newstate = vap->iv_newstate; | ||||
vap->iv_newstate = urtwn_newstate; | vap->iv_newstate = urtwn_newstate; | ||||
/* 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); | ||||
} | } | ||||
static void | static void | ||||
urtwn_vap_delete(struct ieee80211vap *vap) | urtwn_vap_delete(struct ieee80211vap *vap) | ||||
{ | { | ||||
struct urtwn_vap *uvp = URTWN_VAP(vap); | struct urtwn_vap *uvp = URTWN_VAP(vap); | ||||
ieee80211_vap_detach(vap); | ieee80211_vap_detach(vap); | ||||
free(uvp, M_80211_VAP); | free(uvp, M_80211_VAP); | ||||
} | } | ||||
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; | ||||
uint32_t rxdw0, rxdw3; | uint32_t rxdw0, rxdw3; | ||||
uint8_t rate; | uint8_t rate; | ||||
int8_t rssi = 0; | int8_t rssi = 0; | ||||
int infosz; | int infosz; | ||||
/* | /* | ||||
* 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; | ||||
rxdw0 = le32toh(stat->rxdw0); | rxdw0 = le32toh(stat->rxdw0); | ||||
rxdw3 = le32toh(stat->rxdw3); | rxdw3 = le32toh(stat->rxdw3); | ||||
if (rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR)) { | if (rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR)) { | ||||
/* | /* | ||||
* 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); | ||||
} | } | ||||
rate = MS(rxdw3, R92C_RXDW3_RATE); | rate = MS(rxdw3, R92C_RXDW3_RATE); | ||||
infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; | ||||
/* Get RSSI from PHY status descriptor if present. */ | /* Get RSSI from PHY status descriptor if present. */ | ||||
if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { | if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { | ||||
Show All 12 Lines | urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) | ||||
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
device_printf(sc->sc_dev, "could not create RX mbuf\n"); | device_printf(sc->sc_dev, "could not create RX mbuf\n"); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* 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; | ||||
if (ieee80211_radiotap_active(ic)) { | if (ieee80211_radiotap_active(ic)) { | ||||
struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap; | struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap; | ||||
tap->wr_flags = 0; | tap->wr_flags = 0; | ||||
Show All 29 Lines | urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) | ||||
return (m); | return (m); | ||||
} | } | ||||
static struct mbuf * | static struct mbuf * | ||||
urtwn_rxeof(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, | urtwn_rxeof(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, | ||||
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; | ||||
uint8_t *buf; | uint8_t *buf; | ||||
int len, totlen, pktlen, infosz, npkts; | int len, totlen, pktlen, infosz, npkts; | ||||
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); | ||||
} | } | ||||
buf = data->buf; | buf = data->buf; | ||||
/* Get the number of encapsulated frames. */ | /* Get the number of encapsulated frames. */ | ||||
stat = (struct r92c_rx_stat *)buf; | stat = (struct r92c_rx_stat *)buf; | ||||
npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT); | npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT); | ||||
DPRINTFN(6, "Rx %d frames in one chunk\n", npkts); | DPRINTFN(6, "Rx %d frames in one chunk\n", npkts); | ||||
Show All 34 Lines | urtwn_rxeof(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, | ||||
return (m0); | return (m0); | ||||
} | } | ||||
static void | static void | ||||
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; | ||||
struct urtwn_data *data; | struct urtwn_data *data; | ||||
int8_t nf; | int8_t nf; | ||||
int rssi = 1; | int rssi = 1; | ||||
URTWN_ASSERT_LOCKED(sc); | URTWN_ASSERT_LOCKED(sc); | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | default: | ||||
/* needs it to the inactive queue due to a error. */ | /* needs it to the inactive queue due to a error. */ | ||||
data = STAILQ_FIRST(&sc->sc_rx_active); | data = STAILQ_FIRST(&sc->sc_rx_active); | ||||
if (data != NULL) { | if (data != NULL) { | ||||
STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); | STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); | ||||
STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); | STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); | ||||
} | } | ||||
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; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
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); | ||||
/* | |||||
* Do any tx complete callback. Note this must be done before releasing | |||||
* the node reference. | |||||
*/ | |||||
if (data->m) { | |||||
m = data->m; | |||||
if (m->m_flags & M_TXCB) { | |||||
/* XXX status? */ | /* XXX status? */ | ||||
ieee80211_process_callback(data->ni, m, 0); | ieee80211_tx_complete(data->ni, data->m, 0); | ||||
} | |||||
m_freem(m); | |||||
data->m = NULL; | |||||
} | |||||
if (data->ni) { | |||||
ieee80211_free_node(data->ni); | |||||
data->ni = NULL; | data->ni = NULL; | ||||
} | data->m = 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 | ||||
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); | ||||
switch (USB_GET_STATE(xfer)){ | switch (USB_GET_STATE(xfer)){ | ||||
case USB_ST_TRANSFERRED: | case USB_ST_TRANSFERRED: | ||||
data = STAILQ_FIRST(&sc->sc_tx_active); | data = STAILQ_FIRST(&sc->sc_tx_active); | ||||
if (data == NULL) | if (data == NULL) | ||||
goto tr_setup; | goto tr_setup; | ||||
STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); | STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); | ||||
urtwn_txeof(xfer, data); | urtwn_txeof(xfer, data); | ||||
STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); | STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case USB_ST_SETUP: | case USB_ST_SETUP: | ||||
tr_setup: | tr_setup: | ||||
data = STAILQ_FIRST(&sc->sc_tx_pending); | data = STAILQ_FIRST(&sc->sc_tx_pending); | ||||
if (data == NULL) { | if (data == NULL) { | ||||
DPRINTF("%s: empty pending queue\n", __func__); | DPRINTF("%s: empty pending queue\n", __func__); | ||||
return; | return; | ||||
} | } | ||||
STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); | STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); | ||||
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); | ||||
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); | ||||
goto tr_setup; | goto tr_setup; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
Show All 16 Lines | |||||
static struct urtwn_data * | static struct urtwn_data * | ||||
urtwn_getbuf(struct urtwn_softc *sc) | urtwn_getbuf(struct urtwn_softc *sc) | ||||
{ | { | ||||
struct urtwn_data *bf; | struct urtwn_data *bf; | ||||
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); | ||||
} | } | ||||
static int | static int | ||||
urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, | urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, | ||||
int len) | int len) | ||||
{ | { | ||||
usb_device_request_t req; | usb_device_request_t req; | ||||
▲ Show 20 Lines • Show All 306 Lines • ▼ Show 20 Lines | urtwn_read_rom(struct urtwn_softc *sc) | ||||
/* XXX Weird but this is what the vendor driver does. */ | /* XXX Weird but this is what the vendor driver does. */ | ||||
sc->pa_setting = urtwn_efuse_read_1(sc, 0x1fa); | sc->pa_setting = urtwn_efuse_read_1(sc, 0x1fa); | ||||
DPRINTF("PA setting=0x%x\n", sc->pa_setting); | DPRINTF("PA setting=0x%x\n", sc->pa_setting); | ||||
sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); | sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); | ||||
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; | ||||
sc->sc_dma_init = urtwn_r92c_dma_init; | sc->sc_dma_init = urtwn_r92c_dma_init; | ||||
} | } | ||||
static void | static void | ||||
urtwn_r88e_read_rom(struct urtwn_softc *sc) | urtwn_r88e_read_rom(struct urtwn_softc *sc) | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | for (i = 0; i < 5; i++) | ||||
sc->ht40_tx_pwr[i] = sc->r88e_rom[addr++]; | sc->ht40_tx_pwr[i] = sc->r88e_rom[addr++]; | ||||
sc->bw20_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf0) >> 4; | sc->bw20_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf0) >> 4; | ||||
if (sc->bw20_tx_pwr_diff & 0x08) | if (sc->bw20_tx_pwr_diff & 0x08) | ||||
sc->bw20_tx_pwr_diff |= 0xf0; | sc->bw20_tx_pwr_diff |= 0xf0; | ||||
sc->ofdm_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf); | sc->ofdm_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf); | ||||
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; | ||||
sc->sc_dma_init = urtwn_r88e_dma_init; | sc->sc_dma_init = urtwn_r88e_dma_init; | ||||
} | } | ||||
/* | /* | ||||
* Initialize rate adaptation in firmware. | * Initialize rate adaptation in firmware. | ||||
*/ | */ | ||||
static int | static int | ||||
urtwn_ra_init(struct urtwn_softc *sc) | urtwn_ra_init(struct urtwn_softc *sc) | ||||
{ | { | ||||
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; | ||||
struct r92c_fw_cmd_macid_cfg cmd; | struct r92c_fw_cmd_macid_cfg cmd; | ||||
uint32_t rates, basicrates; | uint32_t rates, basicrates; | ||||
uint8_t mode; | uint8_t mode; | ||||
int maxrate, maxbasicrate, error, i, j; | int maxrate, maxbasicrate, error, i, j; | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | urtwn_ra_init(struct urtwn_softc *sc) | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return (0); | return (0); | ||||
} | } | ||||
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; | ||||
uint64_t tsf; | uint64_t tsf; | ||||
/* Enable TSF synchronization. */ | /* Enable TSF synchronization. */ | ||||
urtwn_write_1(sc, R92C_BCN_CTRL, | urtwn_write_1(sc, R92C_BCN_CTRL, | ||||
urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0); | urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0); | ||||
Show All 40 Lines | urtwn_set_led(struct urtwn_softc *sc, int led, int on) | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
{ | { | ||||
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; | ||||
ostate = vap->iv_state; | ostate = vap->iv_state; | ||||
DPRINTF("%s -> %s\n", ieee80211_state_name[ostate], | DPRINTF("%s -> %s\n", ieee80211_state_name[ostate], | ||||
ieee80211_state_name[nstate]); | ieee80211_state_name[nstate]); | ||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
IEEE80211_LOCK(ic); | IEEE80211_LOCK(ic); | ||||
return(uvp->newstate(vap, nstate, arg)); | return(uvp->newstate(vap, nstate, arg)); | ||||
} | } | ||||
static void | static void | ||||
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); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi) | urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi) | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt) | ||||
return (rssi); | return (rssi); | ||||
} | } | ||||
static int | static int | ||||
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; | ||||
uint8_t raid, type; | uint8_t raid, type; | ||||
uint16_t sum; | uint16_t sum; | ||||
int i, hasqos, xferlen; | int i, hasqos, xferlen; | ||||
struct usb_xfer *urtwn_pipes[4] = { | struct usb_xfer *urtwn_pipes[4] = { | ||||
sc->sc_xfer[URTWN_BULK_TX_BE], | sc->sc_xfer[URTWN_BULK_TX_BE], | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni, | ||||
data->ni = ni; | data->ni = ni; | ||||
data->m = m0; | data->m = m0; | ||||
STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); | STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); | ||||
usbd_transfer_start(xfer); | usbd_transfer_start(xfer); | ||||
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); | 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); | |||||
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; | ||||
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); | URTWN_UNLOCK(sc); | ||||
if (error != 0) | return; | ||||
return (error); | } | ||||
if (ic->ic_nrunning > 0) { | |||||
switch (cmd) { | if ((sc->sc_flags & URTWN_RUNNING) == 0) { | ||||
case SIOCSIFFLAGS: | urtwn_init(sc); | ||||
if (ifp->if_flags & IFF_UP) { | |||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | |||||
urtwn_init(ifp->if_softc); | |||||
startall = 1; | startall = 1; | ||||
} | } | ||||
} else { | } else if (sc->sc_flags & URTWN_RUNNING) | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | urtwn_stop(sc); | ||||
urtwn_stop(ifp); | URTWN_UNLOCK(sc); | ||||
} | |||||
if (startall) | if (startall) | ||||
ieee80211_start_all(ic); | 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 | ||||
urtwn_alloc_list(struct urtwn_softc *sc, struct urtwn_data data[], | urtwn_alloc_list(struct urtwn_softc *sc, struct urtwn_data data[], | ||||
int ndata, int maxsz) | int ndata, int maxsz) | ||||
{ | { | ||||
int i, error; | int i, error; | ||||
for (i = 0; i < ndata; i++) { | for (i = 0; i < ndata; i++) { | ||||
▲ Show 20 Lines • Show All 896 Lines • ▼ Show 20 Lines | urtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), | ||||
SM(R92C_TXAGC_MCS15, power[27])); | SM(R92C_TXAGC_MCS15, power[27])); | ||||
} | } | ||||
void | void | ||||
urtwn_get_txpower(struct urtwn_softc *sc, int chain, | urtwn_get_txpower(struct urtwn_softc *sc, int chain, | ||||
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; | ||||
int ridx, chan, group; | int ridx, chan, group; | ||||
/* Determine channel group. */ | /* Determine channel group. */ | ||||
chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ | chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ | ||||
if (chan <= 3) | if (chan <= 3) | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
} | } | ||||
void | void | ||||
urtwn_r88e_get_txpower(struct urtwn_softc *sc, int chain, | urtwn_r88e_get_txpower(struct urtwn_softc *sc, int chain, | ||||
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; | ||||
/* Determine channel group. */ | /* Determine channel group. */ | ||||
chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ | chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ | ||||
if (chan <= 2) | if (chan <= 2) | ||||
group = 0; | group = 0; | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
urtwn_scan_end(struct ieee80211com *ic) | urtwn_scan_end(struct ieee80211com *ic) | ||||
{ | { | ||||
/* XXX do nothing? */ | /* XXX do nothing? */ | ||||
} | } | ||||
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); | ||||
if (vap->iv_state == IEEE80211_S_SCAN) { | if (vap->iv_state == IEEE80211_S_SCAN) { | ||||
/* Make link LED blink during scan. */ | /* Make link LED blink during scan. */ | ||||
urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink); | urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink); | ||||
} | } | ||||
urtwn_set_chan(sc, ic->ic_curchan, NULL); | urtwn_set_chan(sc, ic->ic_curchan, NULL); | ||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
urtwn_update_mcast(struct ieee80211com *ic) | urtwn_update_mcast(struct ieee80211com *ic) | ||||
{ | { | ||||
/* XXX do nothing? */ | /* XXX do nothing? */ | ||||
} | } | ||||
static void | static void | ||||
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; | ||||
chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ | chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ | ||||
if (chan == 0 || chan == IEEE80211_CHAN_ANY) { | if (chan == 0 || chan == IEEE80211_CHAN_ANY) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: invalid channel %x\n", __func__, chan); | "%s: invalid channel %x\n", __func__, chan); | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | for (i = 0; i < sc->nrxchains; i++) | ||||
urtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); | urtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); | ||||
} else { | } else { | ||||
/* Unblock all Tx queues. */ | /* Unblock all Tx queues. */ | ||||
urtwn_write_1(sc, R92C_TXPAUSE, 0x00); | urtwn_write_1(sc, R92C_TXPAUSE, 0x00); | ||||
} | } | ||||
} | } | ||||
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; | ||||
/* Allocate Tx/Rx buffers. */ | /* Allocate Tx/Rx buffers. */ | ||||
error = urtwn_alloc_rx_list(sc); | error = urtwn_alloc_rx_list(sc); | ||||
if (error != 0) | if (error != 0) | ||||
goto fail; | goto fail; | ||||
Show All 26 Lines | urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION, | ||||
urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | | urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | | ||||
R92C_USB_SPECIAL_OPTION_INT_BULK_SEL); | R92C_USB_SPECIAL_OPTION_INT_BULK_SEL); | ||||
} else { | } else { | ||||
urtwn_write_4(sc, R92C_HISR, 0xffffffff); | urtwn_write_4(sc, R92C_HISR, 0xffffffff); | ||||
urtwn_write_4(sc, R92C_HIMR, 0xffffffff); | urtwn_write_4(sc, R92C_HIMR, 0xffffffff); | ||||
} | } | ||||
/* 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); | ||||
reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA); | reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA); | ||||
urtwn_write_4(sc, R92C_CR, reg); | urtwn_write_4(sc, R92C_CR, reg); | ||||
urtwn_rxfilter_init(sc); | urtwn_rxfilter_init(sc); | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | urtwn_write_1(sc, R92C_GPIO_MUXCFG, | ||||
urtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT); | urtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT); | ||||
/* Fix for lower temperature. */ | /* Fix for lower temperature. */ | ||||
if (!(sc->chip & URTWN_CHIP_88E)) | if (!(sc->chip & URTWN_CHIP_88E)) | ||||
urtwn_write_1(sc, 0x15, 0xe9); | urtwn_write_1(sc, 0x15, 0xe9); | ||||
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: | ||||
return; | return; | ||||
} | } | ||||
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; | ||||
URTWN_ASSERT_LOCKED(sc); | URTWN_ASSERT_LOCKED(sc); | ||||
/* abort any pending transfers */ | /* abort any pending transfers */ | ||||
for (i = 0; i < URTWN_N_TRANSFER; i++) | for (i = 0; i < URTWN_N_TRANSFER; i++) | ||||
usbd_transfer_stop(sc->sc_xfer[i]); | usbd_transfer_stop(sc->sc_xfer[i]); | ||||
} | } | ||||
static int | static int | ||||
urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | ||||
const struct ieee80211_bpf_params *params) | const struct ieee80211_bpf_params *params) | ||||
{ | { | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
struct ifnet *ifp = ic->ic_ifp; | struct 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); | ||||
} | } | ||||
URTWN_LOCK(sc); | URTWN_LOCK(sc); | ||||
bf = urtwn_getbuf(sc); | bf = urtwn_getbuf(sc); | ||||
if (bf == NULL) { | if (bf == NULL) { | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
m_freem(m); | m_freem(m); | ||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
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); | ||||
} | } | ||||
URTWN_UNLOCK(sc); | URTWN_UNLOCK(sc); | ||||
sc->sc_txtimer = 5; | sc->sc_txtimer = 5; | ||||
return (0); | return (0); | ||||
Show All 30 Lines |