Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/usb/wlan/if_zyd.c
Show First 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | |||||
static void zyd_set_multi(struct zyd_softc *); | static void zyd_set_multi(struct zyd_softc *); | ||||
static void zyd_update_mcast(struct ieee80211com *); | static void zyd_update_mcast(struct ieee80211com *); | ||||
static int zyd_set_rxfilter(struct zyd_softc *); | static int zyd_set_rxfilter(struct zyd_softc *); | ||||
static void zyd_set_chan(struct zyd_softc *, struct ieee80211_channel *); | static void zyd_set_chan(struct zyd_softc *, struct ieee80211_channel *); | ||||
static int zyd_set_beacon_interval(struct zyd_softc *, int); | static int zyd_set_beacon_interval(struct zyd_softc *, int); | ||||
static void zyd_rx_data(struct usb_xfer *, int, uint16_t); | static void zyd_rx_data(struct usb_xfer *, int, uint16_t); | ||||
static int zyd_tx_start(struct zyd_softc *, struct mbuf *, | static int zyd_tx_start(struct zyd_softc *, struct mbuf *, | ||||
struct ieee80211_node *); | struct ieee80211_node *); | ||||
static void zyd_start(struct ifnet *); | static int zyd_transmit(struct ieee80211com *, struct mbuf *); | ||||
static void zyd_start(struct zyd_softc *); | |||||
static int zyd_raw_xmit(struct ieee80211_node *, struct mbuf *, | static int zyd_raw_xmit(struct ieee80211_node *, struct mbuf *, | ||||
const struct ieee80211_bpf_params *); | const struct ieee80211_bpf_params *); | ||||
static int zyd_ioctl(struct ifnet *, u_long, caddr_t); | static void zyd_parent(struct ieee80211com *); | ||||
static void zyd_init_locked(struct zyd_softc *); | static void zyd_init_locked(struct zyd_softc *); | ||||
static void zyd_init(void *); | |||||
static void zyd_stop(struct zyd_softc *); | static void zyd_stop(struct zyd_softc *); | ||||
static int zyd_loadfirmware(struct zyd_softc *); | static int zyd_loadfirmware(struct zyd_softc *); | ||||
static void zyd_scan_start(struct ieee80211com *); | static void zyd_scan_start(struct ieee80211com *); | ||||
static void zyd_scan_end(struct ieee80211com *); | static void zyd_scan_end(struct ieee80211com *); | ||||
static void zyd_set_channel(struct ieee80211com *); | static void zyd_set_channel(struct ieee80211com *); | ||||
static int zyd_rfmd_init(struct zyd_rf *); | static int zyd_rfmd_init(struct zyd_rf *); | ||||
static int zyd_rfmd_switch_radio(struct zyd_rf *, int); | static int zyd_rfmd_switch_radio(struct zyd_rf *, int); | ||||
static int zyd_rfmd_set_channel(struct zyd_rf *, uint8_t); | static int zyd_rfmd_set_channel(struct zyd_rf *, uint8_t); | ||||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | zyd_match(device_t dev) | ||||
return (usbd_lookup_id_by_uaa(zyd_devs, sizeof(zyd_devs), uaa)); | return (usbd_lookup_id_by_uaa(zyd_devs, sizeof(zyd_devs), uaa)); | ||||
} | } | ||||
static int | static int | ||||
zyd_attach(device_t dev) | zyd_attach(device_t dev) | ||||
{ | { | ||||
struct usb_attach_arg *uaa = device_get_ivars(dev); | struct usb_attach_arg *uaa = device_get_ivars(dev); | ||||
struct zyd_softc *sc = device_get_softc(dev); | struct zyd_softc *sc = device_get_softc(dev); | ||||
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; | ||||
if (uaa->info.bcdDevice < 0x4330) { | if (uaa->info.bcdDevice < 0x4330) { | ||||
device_printf(dev, "device version mismatch: 0x%X " | device_printf(dev, "device version mismatch: 0x%X " | ||||
"(only >= 43.30 supported)\n", | "(only >= 43.30 supported)\n", | ||||
uaa->info.bcdDevice); | uaa->info.bcdDevice); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
device_set_usb_desc(dev); | device_set_usb_desc(dev); | ||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
sc->sc_udev = uaa->device; | sc->sc_udev = uaa->device; | ||||
sc->sc_macrev = USB_GET_DRIVER_INFO(uaa); | sc->sc_macrev = USB_GET_DRIVER_INFO(uaa); | ||||
mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), | mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), | ||||
MTX_NETWORK_LOCK, MTX_DEF); | MTX_NETWORK_LOCK, MTX_DEF); | ||||
STAILQ_INIT(&sc->sc_rqh); | STAILQ_INIT(&sc->sc_rqh); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | |||||
iface_index = ZYD_IFACE_INDEX; | iface_index = ZYD_IFACE_INDEX; | ||||
error = usbd_transfer_setup(uaa->device, | error = usbd_transfer_setup(uaa->device, | ||||
&iface_index, sc->sc_xfer, zyd_config, | &iface_index, sc->sc_xfer, zyd_config, | ||||
ZYD_N_TRANSFER, sc, &sc->sc_mtx); | ZYD_N_TRANSFER, sc, &sc->sc_mtx); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "could not allocate USB transfers, " | device_printf(dev, "could not allocate USB transfers, " | ||||
"err=%s\n", usbd_errstr(error)); | "err=%s\n", usbd_errstr(error)); | ||||
goto detach; | goto detach; | ||||
} | } | ||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
if ((error = zyd_get_macaddr(sc)) != 0) { | if ((error = zyd_get_macaddr(sc)) != 0) { | ||||
device_printf(sc->sc_dev, "could not read EEPROM\n"); | device_printf(sc->sc_dev, "could not read EEPROM\n"); | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
goto detach; | goto detach; | ||||
} | } | ||||
ZYD_UNLOCK(sc); | ZYD_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; | |||||
} | |||||
ifp->if_softc = sc; | |||||
if_initname(ifp, "zyd", device_get_unit(sc->sc_dev)); | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_init = zyd_init; | |||||
ifp->if_ioctl = zyd_ioctl; | |||||
ifp->if_start = zyd_start; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
ic = ifp->if_l2com; | |||||
ic->ic_ifp = ifp; | |||||
ic->ic_softc = sc; | ic->ic_softc = sc; | ||||
ic->ic_name = device_get_nameunit(dev); | ic->ic_name = device_get_nameunit(dev); | ||||
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | ||||
ic->ic_opmode = IEEE80211_M_STA; | ic->ic_opmode = IEEE80211_M_STA; | ||||
/* 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 = zyd_raw_xmit; | ic->ic_raw_xmit = zyd_raw_xmit; | ||||
ic->ic_scan_start = zyd_scan_start; | ic->ic_scan_start = zyd_scan_start; | ||||
ic->ic_scan_end = zyd_scan_end; | ic->ic_scan_end = zyd_scan_end; | ||||
ic->ic_set_channel = zyd_set_channel; | ic->ic_set_channel = zyd_set_channel; | ||||
ic->ic_vap_create = zyd_vap_create; | ic->ic_vap_create = zyd_vap_create; | ||||
ic->ic_vap_delete = zyd_vap_delete; | ic->ic_vap_delete = zyd_vap_delete; | ||||
ic->ic_update_mcast = zyd_update_mcast; | ic->ic_update_mcast = zyd_update_mcast; | ||||
ic->ic_update_promisc = zyd_update_mcast; | ic->ic_update_promisc = zyd_update_mcast; | ||||
ic->ic_parent = zyd_parent; | |||||
ic->ic_transmit = zyd_transmit; | |||||
ieee80211_radiotap_attach(ic, | ieee80211_radiotap_attach(ic, | ||||
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | ||||
ZYD_TX_RADIOTAP_PRESENT, | ZYD_TX_RADIOTAP_PRESENT, | ||||
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | ||||
ZYD_RX_RADIOTAP_PRESENT); | ZYD_RX_RADIOTAP_PRESENT); | ||||
if (bootverbose) | if (bootverbose) | ||||
ieee80211_announce(ic); | ieee80211_announce(ic); | ||||
return (0); | return (0); | ||||
detach: | detach: | ||||
zyd_detach(dev); | zyd_detach(dev); | ||||
return (ENXIO); /* failure */ | return (ENXIO); /* failure */ | ||||
} | } | ||||
static int | static int | ||||
zyd_detach(device_t dev) | zyd_detach(device_t dev) | ||||
{ | { | ||||
struct zyd_softc *sc = device_get_softc(dev); | struct zyd_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic; | |||||
unsigned int x; | unsigned int x; | ||||
/* | /* | ||||
* Prevent further allocations from RX/TX data | * Prevent further allocations from RX/TX data | ||||
* lists and ioctls: | * lists and ioctls: | ||||
*/ | */ | ||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
sc->sc_flags |= ZYD_FLAG_DETACHED; | sc->sc_flags |= ZYD_FLAG_DETACHED; | ||||
STAILQ_INIT(&sc->tx_q); | STAILQ_INIT(&sc->tx_q); | ||||
STAILQ_INIT(&sc->tx_free); | STAILQ_INIT(&sc->tx_free); | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
/* drain USB transfers */ | /* drain USB transfers */ | ||||
for (x = 0; x != ZYD_N_TRANSFER; x++) | for (x = 0; x != ZYD_N_TRANSFER; x++) | ||||
usbd_transfer_drain(sc->sc_xfer[x]); | usbd_transfer_drain(sc->sc_xfer[x]); | ||||
/* free TX list, if any */ | /* free TX list, if any */ | ||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
zyd_unsetup_tx_list(sc); | zyd_unsetup_tx_list(sc); | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
/* free USB transfers and some data buffers */ | /* free USB transfers and some data buffers */ | ||||
usbd_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); | usbd_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); | ||||
if (ifp) { | if (ic->ic_softc == sc) | ||||
ic = ifp->if_l2com; | |||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
if_free(ifp); | mbufq_drain(&sc->sc_snd); | ||||
} | |||||
mtx_destroy(&sc->sc_mtx); | mtx_destroy(&sc->sc_mtx); | ||||
return (0); | return (0); | ||||
} | } | ||||
static struct ieee80211vap * | static struct ieee80211vap * | ||||
zyd_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | zyd_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | ||||
enum ieee80211_opmode opmode, int flags, | enum ieee80211_opmode opmode, int flags, | ||||
const uint8_t bssid[IEEE80211_ADDR_LEN], | const uint8_t bssid[IEEE80211_ADDR_LEN], | ||||
const uint8_t mac[IEEE80211_ADDR_LEN]) | const uint8_t mac[IEEE80211_ADDR_LEN]) | ||||
{ | { | ||||
struct zyd_vap *zvp; | struct zyd_vap *zvp; | ||||
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); | ||||
zvp = (struct zyd_vap *) malloc(sizeof(struct zyd_vap), | zvp = malloc(sizeof(struct zyd_vap), M_80211_VAP, M_WAITOK | M_ZERO); | ||||
M_80211_VAP, M_NOWAIT | M_ZERO); | |||||
if (zvp == NULL) | |||||
return (NULL); | |||||
vap = &zvp->vap; | vap = &zvp->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(zvp, M_80211_VAP); | free(zvp, M_80211_VAP); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* override state transition machine */ | /* override state transition machine */ | ||||
zvp->newstate = vap->iv_newstate; | zvp->newstate = vap->iv_newstate; | ||||
vap->iv_newstate = zyd_newstate; | vap->iv_newstate = zyd_newstate; | ||||
ieee80211_ratectl_init(vap); | ieee80211_ratectl_init(vap); | ||||
ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); | ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); | ||||
/* 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 | ||||
zyd_vap_delete(struct ieee80211vap *vap) | zyd_vap_delete(struct ieee80211vap *vap) | ||||
{ | { | ||||
struct zyd_vap *zvp = ZYD_VAP(vap); | struct zyd_vap *zvp = ZYD_VAP(vap); | ||||
ieee80211_ratectl_deinit(vap); | ieee80211_ratectl_deinit(vap); | ||||
ieee80211_vap_detach(vap); | ieee80211_vap_detach(vap); | ||||
free(zvp, M_80211_VAP); | free(zvp, M_80211_VAP); | ||||
} | } | ||||
static void | static void | ||||
zyd_tx_free(struct zyd_tx_data *data, int txerr) | zyd_tx_free(struct zyd_tx_data *data, int txerr) | ||||
{ | { | ||||
struct zyd_softc *sc = data->sc; | struct zyd_softc *sc = data->sc; | ||||
if (data->m != NULL) { | if (data->m != NULL) { | ||||
if (data->m->m_flags & M_TXCB) | ieee80211_tx_complete(data->ni, data->m, txerr); | ||||
ieee80211_process_callback(data->ni, data->m, | |||||
txerr ? ETIMEDOUT : 0); | |||||
m_freem(data->m); | |||||
data->m = NULL; | data->m = NULL; | ||||
ieee80211_free_node(data->ni); | |||||
data->ni = NULL; | data->ni = NULL; | ||||
} | } | ||||
STAILQ_INSERT_TAIL(&sc->tx_free, data, next); | STAILQ_INSERT_TAIL(&sc->tx_free, data, next); | ||||
sc->tx_nfree++; | sc->tx_nfree++; | ||||
} | } | ||||
static void | static void | ||||
zyd_setup_tx_list(struct zyd_softc *sc) | zyd_setup_tx_list(struct zyd_softc *sc) | ||||
Show All 40 Lines | zyd_unsetup_tx_list(struct zyd_softc *sc) | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
{ | { | ||||
struct zyd_vap *zvp = ZYD_VAP(vap); | struct zyd_vap *zvp = ZYD_VAP(vap); | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct zyd_softc *sc = ic->ic_ifp->if_softc; | struct zyd_softc *sc = ic->ic_softc; | ||||
int error; | int error; | ||||
DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, | DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, | ||||
ieee80211_state_name[vap->iv_state], | ieee80211_state_name[vap->iv_state], | ||||
ieee80211_state_name[nstate]); | ieee80211_state_name[nstate]); | ||||
IEEE80211_UNLOCK(ic); | IEEE80211_UNLOCK(ic); | ||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
switch (nstate) { | switch (nstate) { | ||||
case IEEE80211_S_AUTH: | case IEEE80211_S_AUTH: | ||||
zyd_set_chan(sc, ic->ic_curchan); | zyd_set_chan(sc, ic->ic_curchan); | ||||
break; | break; | ||||
case IEEE80211_S_RUN: | case IEEE80211_S_RUN: | ||||
if (vap->iv_opmode == IEEE80211_M_MONITOR) | if (vap->iv_opmode == IEEE80211_M_MONITOR) | ||||
break; | break; | ||||
/* turn link LED on */ | /* turn link LED on */ | ||||
error = zyd_set_led(sc, ZYD_LED1, 1); | error = zyd_set_led(sc, ZYD_LED1, 1); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
/* make data LED blink upon Tx */ | /* make data LED blink upon Tx */ | ||||
zyd_write32_m(sc, sc->sc_fwbase + ZYD_FW_LINK_STATUS, 1); | zyd_write32_m(sc, sc->sc_fwbase + ZYD_FW_LINK_STATUS, 1); | ||||
IEEE80211_ADDR_COPY(sc->sc_bssid, vap->iv_bss->ni_bssid); | IEEE80211_ADDR_COPY(ic->ic_macaddr, vap->iv_bss->ni_bssid); | ||||
zyd_set_bssid(sc, sc->sc_bssid); | zyd_set_bssid(sc, ic->ic_macaddr); | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
fail: | fail: | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
IEEE80211_LOCK(ic); | IEEE80211_LOCK(ic); | ||||
return (zvp->newstate(vap, nstate, arg)); | return (zvp->newstate(vap, nstate, arg)); | ||||
} | } | ||||
/* | /* | ||||
* Callback handler for interrupt transfer | * Callback handler for interrupt transfer | ||||
*/ | */ | ||||
static void | static void | ||||
zyd_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) | zyd_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct zyd_softc *sc = usbd_xfer_softc(xfer); | struct zyd_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 ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | ||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct zyd_cmd *cmd = &sc->sc_ibuf; | struct zyd_cmd *cmd = &sc->sc_ibuf; | ||||
struct usb_page_cache *pc; | struct usb_page_cache *pc; | ||||
int datalen; | int datalen; | ||||
int actlen; | int actlen; | ||||
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | ||||
Show All 26 Lines | case ZYD_NOTIF_RETRYSTATUS: | ||||
(int)(le16toh(retry->count) & 0xff); | (int)(le16toh(retry->count) & 0xff); | ||||
ieee80211_ratectl_tx_complete(vap, ni, | ieee80211_ratectl_tx_complete(vap, ni, | ||||
IEEE80211_RATECTL_TX_FAILURE, | IEEE80211_RATECTL_TX_FAILURE, | ||||
&retrycnt, NULL); | &retrycnt, NULL); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
} | } | ||||
if (le16toh(retry->count) & 0x100) | if (le16toh(retry->count) & 0x100) | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); /* too many retries */ | /* too many retries */ | ||||
if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, | |||||
1); | |||||
break; | break; | ||||
} | } | ||||
case ZYD_NOTIF_IORD: | case ZYD_NOTIF_IORD: | ||||
{ | { | ||||
struct zyd_rq *rqp; | struct zyd_rq *rqp; | ||||
if (le16toh(*(uint16_t *)cmd->data) == ZYD_CR_INTERRUPT) | if (le16toh(*(uint16_t *)cmd->data) == ZYD_CR_INTERRUPT) | ||||
break; /* HMAC interrupt */ | break; /* HMAC interrupt */ | ||||
▲ Show 20 Lines • Show All 545 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
zyd_al2230_bandedge6(struct zyd_rf *rf, struct ieee80211_channel *c) | zyd_al2230_bandedge6(struct zyd_rf *rf, struct ieee80211_channel *c) | ||||
{ | { | ||||
#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) | #define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) | ||||
int error = 0, i; | int error = 0, i; | ||||
struct zyd_softc *sc = rf->rf_sc; | struct zyd_softc *sc = rf->rf_sc; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct zyd_phy_pair r[] = ZYD_AL2230_PHY_BANDEDGE6; | struct zyd_phy_pair r[] = ZYD_AL2230_PHY_BANDEDGE6; | ||||
int chan = ieee80211_chan2ieee(ic, c); | int chan = ieee80211_chan2ieee(ic, c); | ||||
if (chan == 1 || chan == 11) | if (chan == 1 || chan == 11) | ||||
r[0].val = 0x12; | r[0].val = 0x12; | ||||
for (i = 0; i < N(r); i++) | for (i = 0; i < N(r); i++) | ||||
zyd_write16_m(sc, r[i].reg, r[i].val); | zyd_write16_m(sc, r[i].reg, r[i].val); | ||||
▲ Show 20 Lines • Show All 671 Lines • ▼ Show 20 Lines | zyd_get_macaddr(struct zyd_softc *sc) | ||||
usb_error_t error; | usb_error_t error; | ||||
req.bmRequestType = UT_READ_VENDOR_DEVICE; | req.bmRequestType = UT_READ_VENDOR_DEVICE; | ||||
req.bRequest = ZYD_READFWDATAREQ; | req.bRequest = ZYD_READFWDATAREQ; | ||||
USETW(req.wValue, ZYD_EEPROM_MAC_ADDR_P1); | USETW(req.wValue, ZYD_EEPROM_MAC_ADDR_P1); | ||||
USETW(req.wIndex, 0); | USETW(req.wIndex, 0); | ||||
USETW(req.wLength, IEEE80211_ADDR_LEN); | USETW(req.wLength, IEEE80211_ADDR_LEN); | ||||
error = zyd_do_request(sc, &req, sc->sc_bssid); | error = zyd_do_request(sc, &req, sc->sc_ic.ic_macaddr); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "could not read EEPROM: %s\n", | device_printf(sc->sc_dev, "could not read EEPROM: %s\n", | ||||
usbd_errstr(error)); | usbd_errstr(error)); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | zyd_set_led(struct zyd_softc *sc, int which, int on) | ||||
zyd_write32_m(sc, ZYD_MAC_TX_PE_CONTROL, tmp); | zyd_write32_m(sc, ZYD_MAC_TX_PE_CONTROL, tmp); | ||||
fail: | fail: | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
zyd_set_multi(struct zyd_softc *sc) | zyd_set_multi(struct zyd_softc *sc) | ||||
{ | { | ||||
int error; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ifmultiaddr *ifma; | |||||
uint32_t low, high; | uint32_t low, high; | ||||
uint8_t v; | int error; | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((sc->sc_flags & ZYD_FLAG_RUNNING) == 0) | ||||
return; | return; | ||||
low = 0x00000000; | low = 0x00000000; | ||||
high = 0x80000000; | high = 0x80000000; | ||||
if (ic->ic_opmode == IEEE80211_M_MONITOR || | if (ic->ic_opmode == IEEE80211_M_MONITOR || ic->ic_allmulti > 0 || | ||||
(ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { | ic->ic_promisc > 0) { | ||||
low = 0xffffffff; | low = 0xffffffff; | ||||
high = 0xffffffff; | high = 0xffffffff; | ||||
} else { | } else { | ||||
struct ieee80211vap *vap; | |||||
struct ifnet *ifp; | |||||
struct ifmultiaddr *ifma; | |||||
uint8_t v; | |||||
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { | |||||
ifp = vap->iv_ifp; | |||||
if_maddr_rlock(ifp); | if_maddr_rlock(ifp); | ||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | ||||
if (ifma->ifma_addr->sa_family != AF_LINK) | if (ifma->ifma_addr->sa_family != AF_LINK) | ||||
continue; | continue; | ||||
v = ((uint8_t *)LLADDR((struct sockaddr_dl *) | v = ((uint8_t *)LLADDR((struct sockaddr_dl *) | ||||
ifma->ifma_addr))[5] >> 2; | ifma->ifma_addr))[5] >> 2; | ||||
if (v < 32) | if (v < 32) | ||||
low |= 1 << v; | low |= 1 << v; | ||||
else | else | ||||
high |= 1 << (v - 32); | high |= 1 << (v - 32); | ||||
} | } | ||||
if_maddr_runlock(ifp); | if_maddr_runlock(ifp); | ||||
} | } | ||||
} | |||||
/* reprogram multicast global hash table */ | /* reprogram multicast global hash table */ | ||||
zyd_write32_m(sc, ZYD_MAC_GHTBL, low); | zyd_write32_m(sc, ZYD_MAC_GHTBL, low); | ||||
zyd_write32_m(sc, ZYD_MAC_GHTBH, high); | zyd_write32_m(sc, ZYD_MAC_GHTBH, high); | ||||
fail: | fail: | ||||
if (error != 0) | if (error != 0) | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"could not set multicast hash table\n"); | "could not set multicast hash table\n"); | ||||
} | } | ||||
static void | static void | ||||
zyd_update_mcast(struct ieee80211com *ic) | zyd_update_mcast(struct ieee80211com *ic) | ||||
{ | { | ||||
struct zyd_softc *sc = ic->ic_softc; | struct zyd_softc *sc = ic->ic_softc; | ||||
if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | |||||
return; | |||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
zyd_set_multi(sc); | zyd_set_multi(sc); | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
} | } | ||||
static int | static int | ||||
zyd_set_rxfilter(struct zyd_softc *sc) | zyd_set_rxfilter(struct zyd_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint32_t rxfilter; | uint32_t rxfilter; | ||||
switch (ic->ic_opmode) { | switch (ic->ic_opmode) { | ||||
case IEEE80211_M_STA: | case IEEE80211_M_STA: | ||||
rxfilter = ZYD_FILTER_BSS; | rxfilter = ZYD_FILTER_BSS; | ||||
break; | break; | ||||
case IEEE80211_M_IBSS: | case IEEE80211_M_IBSS: | ||||
case IEEE80211_M_HOSTAP: | case IEEE80211_M_HOSTAP: | ||||
rxfilter = ZYD_FILTER_HOSTAP; | rxfilter = ZYD_FILTER_HOSTAP; | ||||
break; | break; | ||||
case IEEE80211_M_MONITOR: | case IEEE80211_M_MONITOR: | ||||
rxfilter = ZYD_FILTER_MONITOR; | rxfilter = ZYD_FILTER_MONITOR; | ||||
break; | break; | ||||
default: | default: | ||||
/* should not get there */ | /* should not get there */ | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
return zyd_write32(sc, ZYD_MAC_RXFILTER, rxfilter); | return zyd_write32(sc, ZYD_MAC_RXFILTER, rxfilter); | ||||
} | } | ||||
static void | static void | ||||
zyd_set_chan(struct zyd_softc *sc, struct ieee80211_channel *c) | zyd_set_chan(struct zyd_softc *sc, struct ieee80211_channel *c) | ||||
{ | { | ||||
int error; | int error; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct zyd_rf *rf = &sc->sc_rf; | struct zyd_rf *rf = &sc->sc_rf; | ||||
uint32_t tmp; | uint32_t tmp; | ||||
int chan; | int chan; | ||||
chan = ieee80211_chan2ieee(ic, c); | chan = ieee80211_chan2ieee(ic, c); | ||||
if (chan == 0 || chan == IEEE80211_CHAN_ANY) { | if (chan == 0 || chan == IEEE80211_CHAN_ANY) { | ||||
/* XXX should NEVER happen */ | /* XXX should NEVER happen */ | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
fail: | fail: | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) | zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) | ||||
{ | { | ||||
struct zyd_softc *sc = usbd_xfer_softc(xfer); | struct zyd_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 zyd_plcphdr plcp; | struct zyd_plcphdr plcp; | ||||
struct zyd_rx_stat stat; | struct zyd_rx_stat stat; | ||||
struct usb_page_cache *pc; | struct usb_page_cache *pc; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
int rlen, rssi; | int rlen, rssi; | ||||
if (len < ZYD_MIN_FRAGSZ) { | if (len < ZYD_MIN_FRAGSZ) { | ||||
DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too short (length=%d)\n", | DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too short (length=%d)\n", | ||||
device_get_nameunit(sc->sc_dev), len); | device_get_nameunit(sc->sc_dev), len); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
pc = usbd_xfer_get_frame(xfer, 0); | pc = usbd_xfer_get_frame(xfer, 0); | ||||
usbd_copy_out(pc, offset, &plcp, sizeof(plcp)); | usbd_copy_out(pc, offset, &plcp, sizeof(plcp)); | ||||
usbd_copy_out(pc, offset + len - sizeof(stat), &stat, sizeof(stat)); | usbd_copy_out(pc, offset + len - sizeof(stat), &stat, sizeof(stat)); | ||||
if (stat.flags & ZYD_RX_ERROR) { | if (stat.flags & ZYD_RX_ERROR) { | ||||
DPRINTF(sc, ZYD_DEBUG_RECV, | DPRINTF(sc, ZYD_DEBUG_RECV, | ||||
"%s: RX status indicated error (%x)\n", | "%s: RX status indicated error (%x)\n", | ||||
device_get_nameunit(sc->sc_dev), stat.flags); | device_get_nameunit(sc->sc_dev), stat.flags); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
/* compute actual frame length */ | /* compute actual frame length */ | ||||
rlen = len - sizeof(struct zyd_plcphdr) - | rlen = len - sizeof(struct zyd_plcphdr) - | ||||
sizeof(struct zyd_rx_stat) - IEEE80211_CRC_LEN; | sizeof(struct zyd_rx_stat) - IEEE80211_CRC_LEN; | ||||
/* allocate a mbuf to store the frame */ | /* allocate a mbuf to store the frame */ | ||||
if (rlen > (int)MCLBYTES) { | if (rlen > (int)MCLBYTES) { | ||||
DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too long (length=%d)\n", | DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too long (length=%d)\n", | ||||
device_get_nameunit(sc->sc_dev), rlen); | device_get_nameunit(sc->sc_dev), rlen); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} else if (rlen > (int)MHLEN) | } else if (rlen > (int)MHLEN) | ||||
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | ||||
else | else | ||||
m = m_gethdr(M_NOWAIT, MT_DATA); | m = m_gethdr(M_NOWAIT, MT_DATA); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
DPRINTF(sc, ZYD_DEBUG_RECV, "%s: could not allocate rx mbuf\n", | DPRINTF(sc, ZYD_DEBUG_RECV, "%s: could not allocate rx mbuf\n", | ||||
device_get_nameunit(sc->sc_dev)); | device_get_nameunit(sc->sc_dev)); | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | counter_u64_add(ic->ic_ierrors, 1); | ||||
return; | return; | ||||
} | } | ||||
m->m_pkthdr.rcvif = ifp; | |||||
m->m_pkthdr.len = m->m_len = rlen; | m->m_pkthdr.len = m->m_len = rlen; | ||||
usbd_copy_out(pc, offset + sizeof(plcp), mtod(m, uint8_t *), rlen); | usbd_copy_out(pc, offset + sizeof(plcp), mtod(m, uint8_t *), rlen); | ||||
if (ieee80211_radiotap_active(ic)) { | if (ieee80211_radiotap_active(ic)) { | ||||
struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap; | struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap; | ||||
tap->wr_flags = 0; | tap->wr_flags = 0; | ||||
if (stat.flags & (ZYD_RX_BADCRC16 | ZYD_RX_BADCRC32)) | if (stat.flags & (ZYD_RX_BADCRC16 | ZYD_RX_BADCRC32)) | ||||
Show All 13 Lines | zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) | ||||
sc->sc_rx_data[sc->sc_rx_count].m = m; | sc->sc_rx_data[sc->sc_rx_count].m = m; | ||||
sc->sc_rx_count++; | sc->sc_rx_count++; | ||||
} | } | ||||
static void | static void | ||||
zyd_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) | zyd_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct zyd_softc *sc = usbd_xfer_softc(xfer); | struct zyd_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_node *ni; | struct ieee80211_node *ni; | ||||
struct zyd_rx_desc desc; | struct zyd_rx_desc desc; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct usb_page_cache *pc; | struct usb_page_cache *pc; | ||||
uint32_t offset; | uint32_t offset; | ||||
uint8_t rssi; | uint8_t rssi; | ||||
int8_t nf; | int8_t nf; | ||||
int i; | int i; | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | for (i = 0; i < sc->sc_rx_count; i++) { | ||||
ni = ieee80211_find_rxnode(ic, | ni = ieee80211_find_rxnode(ic, | ||||
mtod(m, struct ieee80211_frame_min *)); | mtod(m, struct ieee80211_frame_min *)); | ||||
if (ni != NULL) { | if (ni != NULL) { | ||||
(void)ieee80211_input(ni, m, rssi, nf); | (void)ieee80211_input(ni, m, rssi, nf); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
} else | } else | ||||
(void)ieee80211_input_all(ic, m, rssi, nf); | (void)ieee80211_input_all(ic, m, rssi, nf); | ||||
} | } | ||||
if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && | |||||
!IFQ_IS_EMPTY(&ifp->if_snd)) | |||||
zyd_start(ifp); | |||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
zyd_start(sc); | |||||
break; | break; | ||||
default: /* Error */ | default: /* Error */ | ||||
DPRINTF(sc, ZYD_DEBUG_ANY, "frame error: %s\n", usbd_errstr(error)); | DPRINTF(sc, ZYD_DEBUG_ANY, "frame error: %s\n", usbd_errstr(error)); | ||||
if (error != USB_ERR_CANCELLED) { | if (error != USB_ERR_CANCELLED) { | ||||
/* try to clear stall first */ | /* try to clear stall first */ | ||||
usbd_xfer_set_stall(xfer); | usbd_xfer_set_stall(xfer); | ||||
Show All 38 Lines | zyd_plcp_signal(struct zyd_softc *sc, int rate) | ||||
device_printf(sc->sc_dev, "unsupported rate %d\n", rate); | device_printf(sc->sc_dev, "unsupported rate %d\n", rate); | ||||
return (0x0); | return (0x0); | ||||
} | } | ||||
static void | static void | ||||
zyd_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) | zyd_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct zyd_softc *sc = usbd_xfer_softc(xfer); | struct zyd_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
struct zyd_tx_data *data; | struct zyd_tx_data *data; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct usb_page_cache *pc; | struct usb_page_cache *pc; | ||||
int actlen; | int actlen; | ||||
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | ||||
switch (USB_GET_STATE(xfer)) { | switch (USB_GET_STATE(xfer)) { | ||||
case USB_ST_TRANSFERRED: | case USB_ST_TRANSFERRED: | ||||
DPRINTF(sc, ZYD_DEBUG_ANY, "transfer complete, %u bytes\n", | DPRINTF(sc, ZYD_DEBUG_ANY, "transfer complete, %u bytes\n", | ||||
actlen); | actlen); | ||||
/* free resources */ | /* free resources */ | ||||
data = usbd_xfer_get_priv(xfer); | data = usbd_xfer_get_priv(xfer); | ||||
zyd_tx_free(data, 0); | zyd_tx_free(data, 0); | ||||
usbd_xfer_set_priv(xfer, NULL); | usbd_xfer_set_priv(xfer, NULL); | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | |||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case USB_ST_SETUP: | case USB_ST_SETUP: | ||||
tr_setup: | tr_setup: | ||||
data = STAILQ_FIRST(&sc->tx_q); | data = STAILQ_FIRST(&sc->tx_q); | ||||
if (data) { | if (data) { | ||||
STAILQ_REMOVE_HEAD(&sc->tx_q, next); | STAILQ_REMOVE_HEAD(&sc->tx_q, next); | ||||
m = data->m; | m = data->m; | ||||
Show All 16 Lines | if (data) { | ||||
ieee80211_radiotap_tx(vap, m); | ieee80211_radiotap_tx(vap, m); | ||||
} | } | ||||
usbd_xfer_set_frame_len(xfer, 0, ZYD_TX_DESC_SIZE + m->m_pkthdr.len); | usbd_xfer_set_frame_len(xfer, 0, ZYD_TX_DESC_SIZE + m->m_pkthdr.len); | ||||
usbd_xfer_set_priv(xfer, data); | usbd_xfer_set_priv(xfer, data); | ||||
usbd_transfer_submit(xfer); | usbd_transfer_submit(xfer); | ||||
} | } | ||||
ZYD_UNLOCK(sc); | zyd_start(sc); | ||||
zyd_start(ifp); | |||||
ZYD_LOCK(sc); | |||||
break; | break; | ||||
default: /* Error */ | default: /* Error */ | ||||
DPRINTF(sc, ZYD_DEBUG_ANY, "transfer error, %s\n", | DPRINTF(sc, ZYD_DEBUG_ANY, "transfer error, %s\n", | ||||
usbd_errstr(error)); | usbd_errstr(error)); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | counter_u64_add(sc->sc_ic.ic_oerrors, 1); | ||||
data = usbd_xfer_get_priv(xfer); | data = usbd_xfer_get_priv(xfer); | ||||
usbd_xfer_set_priv(xfer, NULL); | usbd_xfer_set_priv(xfer, NULL); | ||||
if (data != NULL) | if (data != NULL) | ||||
zyd_tx_free(data, error); | zyd_tx_free(data, error); | ||||
if (error != USB_ERR_CANCELLED) { | if (error != USB_ERR_CANCELLED) { | ||||
if (error == USB_ERR_TIMEOUT) | if (error == USB_ERR_TIMEOUT) | ||||
device_printf(sc->sc_dev, "device timeout\n"); | device_printf(sc->sc_dev, "device timeout\n"); | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | DPRINTF(sc, ZYD_DEBUG_XMIT, | ||||
rate); | rate); | ||||
STAILQ_INSERT_TAIL(&sc->tx_q, data, next); | STAILQ_INSERT_TAIL(&sc->tx_q, data, next); | ||||
usbd_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); | usbd_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | |||||
zyd_transmit(struct ieee80211com *ic, struct mbuf *m) | |||||
{ | |||||
struct zyd_softc *sc = ic->ic_softc; | |||||
int error; | |||||
ZYD_LOCK(sc); | |||||
if ((sc->sc_flags & ZYD_FLAG_RUNNING) == 0) { | |||||
ZYD_UNLOCK(sc); | |||||
return (ENXIO); | |||||
} | |||||
error = mbufq_enqueue(&sc->sc_snd, m); | |||||
if (error) { | |||||
ZYD_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
zyd_start(sc); | |||||
ZYD_UNLOCK(sc); | |||||
return (0); | |||||
} | |||||
static void | static void | ||||
zyd_start(struct ifnet *ifp) | zyd_start(struct zyd_softc *sc) | ||||
{ | { | ||||
struct zyd_softc *sc = ifp->if_softc; | |||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
ZYD_LOCK(sc); | ZYD_LOCK_ASSERT(sc, MA_LOCKED); | ||||
for (;;) { | |||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | while (sc->tx_nfree > 0 && (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { | ||||
if (m == NULL) | |||||
break; | |||||
if (sc->tx_nfree == 0) { | |||||
IFQ_DRV_PREPEND(&ifp->if_snd, m); | |||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
break; | |||||
} | |||||
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | ||||
if (zyd_tx_start(sc, m, ni) != 0) { | if (zyd_tx_start(sc, m, ni) != 0) { | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ni->ni_vap->iv_ifp, | ||||
IFCOUNTER_OERRORS, 1); | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
ZYD_UNLOCK(sc); | |||||
} | } | ||||
static int | static int | ||||
zyd_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | zyd_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 zyd_softc *sc = ic->ic_softc; | ||||
struct zyd_softc *sc = ifp->if_softc; | |||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
/* prevent management frames from being sent if we're not ready */ | /* prevent management frames from being sent if we're not ready */ | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if (!(sc->sc_flags & ZYD_FLAG_RUNNING)) { | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return (ENETDOWN); | return (ENETDOWN); | ||||
} | } | ||||
if (sc->tx_nfree == 0) { | if (sc->tx_nfree == 0) { | ||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
m_freem(m); | m_freem(m); | ||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return (ENOBUFS); /* XXX */ | return (ENOBUFS); /* XXX */ | ||||
} | } | ||||
/* | /* | ||||
* Legacy path; interpret frame contents to decide | * Legacy path; interpret frame contents to decide | ||||
* precisely how to send the frame. | * precisely how to send the frame. | ||||
* XXX raw path | * XXX raw path | ||||
*/ | */ | ||||
if (zyd_tx_start(sc, m, ni) != 0) { | if (zyd_tx_start(sc, m, ni) != 0) { | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
ieee80211_free_node(ni); | ieee80211_free_node(ni); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static void | ||||
zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | zyd_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct zyd_softc *sc = ifp->if_softc; | struct zyd_softc *sc = ic->ic_softc; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ifreq *ifr = (struct ifreq *) data; | |||||
int error; | |||||
int startall = 0; | int startall = 0; | ||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
error = (sc->sc_flags & ZYD_FLAG_DETACHED) ? ENXIO : 0; | if (sc->sc_flags & ZYD_FLAG_DETACHED) { | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
if (error) | return; | ||||
return (error); | } | ||||
if (ic->ic_nrunning > 0) { | |||||
switch (cmd) { | if ((sc->sc_flags & ZYD_FLAG_RUNNING) == 0) { | ||||
case SIOCSIFFLAGS: | |||||
ZYD_LOCK(sc); | |||||
if (ifp->if_flags & IFF_UP) { | |||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | |||||
zyd_init_locked(sc); | zyd_init_locked(sc); | ||||
startall = 1; | startall = 1; | ||||
} else | } else | ||||
zyd_set_multi(sc); | zyd_set_multi(sc); | ||||
} else { | } else if (sc->sc_flags & ZYD_FLAG_RUNNING) | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
zyd_stop(sc); | zyd_stop(sc); | ||||
} | |||||
ZYD_UNLOCK(sc); | ZYD_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 void | static void | ||||
zyd_init_locked(struct zyd_softc *sc) | zyd_init_locked(struct zyd_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 usb_config_descriptor *cd; | struct usb_config_descriptor *cd; | ||||
int error; | int error; | ||||
uint32_t val; | uint32_t val; | ||||
ZYD_LOCK_ASSERT(sc, MA_OWNED); | ZYD_LOCK_ASSERT(sc, MA_OWNED); | ||||
if (!(sc->sc_flags & ZYD_FLAG_INITONCE)) { | if (!(sc->sc_flags & ZYD_FLAG_INITONCE)) { | ||||
error = zyd_loadfirmware(sc); | error = zyd_loadfirmware(sc); | ||||
Show All 35 Lines | if (!(sc->sc_flags & ZYD_FLAG_INITONCE)) { | ||||
/* we'll do software WEP decryption for now */ | /* we'll do software WEP decryption for now */ | ||||
DPRINTF(sc, ZYD_DEBUG_INIT, "%s: setting encryption type\n", | DPRINTF(sc, ZYD_DEBUG_INIT, "%s: setting encryption type\n", | ||||
__func__); | __func__); | ||||
zyd_write32_m(sc, ZYD_MAC_ENCRYPTION_TYPE, ZYD_ENC_SNIFFER); | zyd_write32_m(sc, ZYD_MAC_ENCRYPTION_TYPE, ZYD_ENC_SNIFFER); | ||||
sc->sc_flags |= ZYD_FLAG_INITONCE; | sc->sc_flags |= ZYD_FLAG_INITONCE; | ||||
} | } | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_flags & ZYD_FLAG_RUNNING) | ||||
zyd_stop(sc); | zyd_stop(sc); | ||||
DPRINTF(sc, ZYD_DEBUG_INIT, "setting MAC address to %6D\n", | DPRINTF(sc, ZYD_DEBUG_INIT, "setting MAC address to %6D\n", | ||||
IF_LLADDR(ifp), ":"); | IF_LLADDR(ifp), ":"); | ||||
error = zyd_set_macaddr(sc, IF_LLADDR(ifp)); | error = zyd_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); | ||||
if (error != 0) | if (error != 0) | ||||
return; | return; | ||||
/* set basic rates */ | /* set basic rates */ | ||||
if (ic->ic_curmode == IEEE80211_MODE_11B) | if (ic->ic_curmode == IEEE80211_MODE_11B) | ||||
zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0x0003); | zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0x0003); | ||||
else if (ic->ic_curmode == IEEE80211_MODE_11A) | else if (ic->ic_curmode == IEEE80211_MODE_11A) | ||||
zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0x1500); | zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0x1500); | ||||
Show All 19 Lines | zyd_init_locked(struct zyd_softc *sc) | ||||
/* | /* | ||||
* Allocate Tx and Rx xfer queues. | * Allocate Tx and Rx xfer queues. | ||||
*/ | */ | ||||
zyd_setup_tx_list(sc); | zyd_setup_tx_list(sc); | ||||
/* enable interrupts */ | /* enable interrupts */ | ||||
zyd_write32_m(sc, ZYD_CR_INTERRUPT, ZYD_HWINT_MASK); | zyd_write32_m(sc, ZYD_CR_INTERRUPT, ZYD_HWINT_MASK); | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | sc->sc_flags |= ZYD_FLAG_RUNNING; | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
usbd_xfer_set_stall(sc->sc_xfer[ZYD_BULK_WR]); | usbd_xfer_set_stall(sc->sc_xfer[ZYD_BULK_WR]); | ||||
usbd_transfer_start(sc->sc_xfer[ZYD_BULK_RD]); | usbd_transfer_start(sc->sc_xfer[ZYD_BULK_RD]); | ||||
usbd_transfer_start(sc->sc_xfer[ZYD_INTR_RD]); | usbd_transfer_start(sc->sc_xfer[ZYD_INTR_RD]); | ||||
return; | return; | ||||
fail: zyd_stop(sc); | fail: zyd_stop(sc); | ||||
return; | return; | ||||
} | } | ||||
static void | static void | ||||
zyd_init(void *priv) | |||||
{ | |||||
struct zyd_softc *sc = priv; | |||||
struct ifnet *ifp = sc->sc_ifp; | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
ZYD_LOCK(sc); | |||||
zyd_init_locked(sc); | |||||
ZYD_UNLOCK(sc); | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
ieee80211_start_all(ic); /* start all vap's */ | |||||
} | |||||
static void | |||||
zyd_stop(struct zyd_softc *sc) | zyd_stop(struct zyd_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
int error; | int error; | ||||
ZYD_LOCK_ASSERT(sc, MA_OWNED); | ZYD_LOCK_ASSERT(sc, MA_OWNED); | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | sc->sc_flags &= ~ZYD_FLAG_RUNNING; | ||||
/* | /* | ||||
* Drain all the transfers, if not already drained: | * Drain all the transfers, if not already drained: | ||||
*/ | */ | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
usbd_transfer_drain(sc->sc_xfer[ZYD_BULK_WR]); | usbd_transfer_drain(sc->sc_xfer[ZYD_BULK_WR]); | ||||
usbd_transfer_drain(sc->sc_xfer[ZYD_BULK_RD]); | usbd_transfer_drain(sc->sc_xfer[ZYD_BULK_RD]); | ||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | zyd_loadfirmware(struct zyd_softc *sc) | ||||
sc->sc_flags |= ZYD_FLAG_FWLOADED; | sc->sc_flags |= ZYD_FLAG_FWLOADED; | ||||
return (stat & 0x80) ? (EIO) : (0); | return (stat & 0x80) ? (EIO) : (0); | ||||
} | } | ||||
static void | static void | ||||
zyd_scan_start(struct ieee80211com *ic) | zyd_scan_start(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct zyd_softc *sc = ic->ic_softc; | ||||
struct zyd_softc *sc = ifp->if_softc; | |||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
/* want broadcast address while scanning */ | /* want broadcast address while scanning */ | ||||
zyd_set_bssid(sc, ifp->if_broadcastaddr); | zyd_set_bssid(sc, ieee80211broadcastaddr); | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
zyd_scan_end(struct ieee80211com *ic) | zyd_scan_end(struct ieee80211com *ic) | ||||
{ | { | ||||
struct zyd_softc *sc = ic->ic_ifp->if_softc; | struct zyd_softc *sc = ic->ic_softc; | ||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
/* restore previous bssid */ | /* restore previous bssid */ | ||||
zyd_set_bssid(sc, sc->sc_bssid); | zyd_set_bssid(sc, ic->ic_macaddr); | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
zyd_set_channel(struct ieee80211com *ic) | zyd_set_channel(struct ieee80211com *ic) | ||||
{ | { | ||||
struct zyd_softc *sc = ic->ic_ifp->if_softc; | struct zyd_softc *sc = ic->ic_softc; | ||||
ZYD_LOCK(sc); | ZYD_LOCK(sc); | ||||
zyd_set_chan(sc, ic->ic_curchan); | zyd_set_chan(sc, ic->ic_curchan); | ||||
ZYD_UNLOCK(sc); | ZYD_UNLOCK(sc); | ||||
} | } | ||||
static device_method_t zyd_methods[] = { | static device_method_t zyd_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
Show All 18 Lines |