diff options
author | thompsa <thompsa@FreeBSD.org> | 2009-02-09 22:12:47 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2009-02-09 22:12:47 +0000 |
commit | 1ef0c422a1e2b4f9a53065ae68ec459458c8f252 (patch) | |
tree | 701d8c233ad2604628b0cabf8d67a7ab2697b51a /sys/dev/usb2/wlan/if_zyd2.c | |
parent | 5adda1462b5469cbda3c872e3ff980c3e9a9e627 (diff) | |
download | FreeBSD-src-1ef0c422a1e2b4f9a53065ae68ec459458c8f252.zip FreeBSD-src-1ef0c422a1e2b4f9a53065ae68ec459458c8f252.tar.gz |
MFp4 //depot/projects/usb; 157412
Sync from svn.freebsd.org/base/user/thompsa/usb which is a minimal changeset
from oldUSB (no config_td).
This excludes the taskqueue changes (for the moment) as requested.
Diffstat (limited to 'sys/dev/usb2/wlan/if_zyd2.c')
-rw-r--r-- | sys/dev/usb2/wlan/if_zyd2.c | 4753 |
1 files changed, 2249 insertions, 2504 deletions
diff --git a/sys/dev/usb2/wlan/if_zyd2.c b/sys/dev/usb2/wlan/if_zyd2.c index 5b61f00..0195bd8 100644 --- a/sys/dev/usb2/wlan/if_zyd2.c +++ b/sys/dev/usb2/wlan/if_zyd2.c @@ -23,10 +23,7 @@ __FBSDID("$FreeBSD$"); /* - * ZyDAS ZD1211/ZD1211B USB WLAN driver - * - * NOTE: all function names beginning like "zyd_cfg_" can only - * be called from within the config thread function ! + * ZyDAS ZD1211/ZD1211B USB WLAN driver. */ #include <dev/usb2/include/usb2_devid.h> @@ -34,15 +31,9 @@ __FBSDID("$FreeBSD$"); #include <dev/usb2/include/usb2_mfunc.h> #include <dev/usb2/include/usb2_error.h> -#define usb2_config_td_cc zyd_config_copy -#define usb2_config_td_softc zyd_softc - -#define USB_DEBUG_VAR zyd_debug - #include <dev/usb2/core/usb2_core.h> #include <dev/usb2/core/usb2_lookup.h> #include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_config_td.h> #include <dev/usb2/core/usb2_debug.h> #include <dev/usb2/core/usb2_request.h> #include <dev/usb2/core/usb2_busdma.h> @@ -58,1588 +49,1503 @@ static int zyd_debug = 0; SYSCTL_NODE(_hw_usb2, OID_AUTO, zyd, CTLFLAG_RW, 0, "USB zyd"); SYSCTL_INT(_hw_usb2_zyd, OID_AUTO, debug, CTLFLAG_RW, &zyd_debug, 0, "zyd debug level"); + +enum { + ZYD_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + ZYD_DEBUG_RECV = 0x00000002, /* basic recv operation */ + ZYD_DEBUG_RESET = 0x00000004, /* reset processing */ + ZYD_DEBUG_INIT = 0x00000008, /* device init */ + ZYD_DEBUG_TX_PROC = 0x00000010, /* tx ISR proc */ + ZYD_DEBUG_RX_PROC = 0x00000020, /* rx ISR proc */ + ZYD_DEBUG_STATE = 0x00000040, /* 802.11 state transitions */ + ZYD_DEBUG_STAT = 0x00000080, /* statistic */ + ZYD_DEBUG_FW = 0x00000100, /* firmware */ + ZYD_DEBUG_CMD = 0x00000200, /* fw commands */ + ZYD_DEBUG_ANY = 0xffffffff +}; +#define DPRINTF(sc, m, fmt, ...) do { \ + if (zyd_debug & (m)) \ + printf("%s: " fmt, __func__, ## __VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(sc, m, fmt, ...) do { \ + (void) sc; \ +} while (0) #endif -#undef INDEXES -#define INDEXES(a) (sizeof(a) / sizeof((a)[0])) +#define zyd_do_request(sc,req,data) \ + usb2_do_request_proc((sc)->sc_udev, &(sc)->sc_tq, req, data, 0, NULL, 5000) -static device_probe_t zyd_probe; +static device_probe_t zyd_match; static device_attach_t zyd_attach; static device_detach_t zyd_detach; -static usb2_callback_t zyd_intr_read_clear_stall_callback; static usb2_callback_t zyd_intr_read_callback; -static usb2_callback_t zyd_intr_write_clear_stall_callback; static usb2_callback_t zyd_intr_write_callback; -static usb2_callback_t zyd_bulk_read_clear_stall_callback; static usb2_callback_t zyd_bulk_read_callback; -static usb2_callback_t zyd_bulk_write_clear_stall_callback; static usb2_callback_t zyd_bulk_write_callback; -static usb2_config_td_command_t zyd_cfg_first_time_setup; -static usb2_config_td_command_t zyd_cfg_update_promisc; -static usb2_config_td_command_t zyd_cfg_set_chan; -static usb2_config_td_command_t zyd_cfg_pre_init; -static usb2_config_td_command_t zyd_cfg_init; -static usb2_config_td_command_t zyd_cfg_pre_stop; -static usb2_config_td_command_t zyd_cfg_stop; -static usb2_config_td_command_t zyd_config_copy; -static usb2_config_td_command_t zyd_cfg_scan_start; -static usb2_config_td_command_t zyd_cfg_scan_end; -static usb2_config_td_command_t zyd_cfg_set_rxfilter; -static usb2_config_td_command_t zyd_cfg_amrr_timeout; - -static uint8_t zyd_plcp2ieee(uint8_t, uint8_t); -static void zyd_cfg_usbrequest(struct zyd_softc *, - struct usb2_device_request *, uint8_t *); -static void zyd_cfg_usb2_intr_read(struct zyd_softc *, void *, uint32_t); -static void zyd_cfg_usb2_intr_write(struct zyd_softc *, const void *, - uint16_t, uint32_t); -static void zyd_cfg_read16(struct zyd_softc *, uint16_t, uint16_t *); -static void zyd_cfg_read32(struct zyd_softc *, uint16_t, uint32_t *); -static void zyd_cfg_write16(struct zyd_softc *, uint16_t, uint16_t); -static void zyd_cfg_write32(struct zyd_softc *, uint16_t, uint32_t); -static void zyd_cfg_rfwrite(struct zyd_softc *, uint32_t); -static uint8_t zyd_cfg_uploadfirmware(struct zyd_softc *, const uint8_t *, - uint32_t); -static void zyd_cfg_lock_phy(struct zyd_softc *); -static void zyd_cfg_unlock_phy(struct zyd_softc *); -static void zyd_cfg_set_beacon_interval(struct zyd_softc *, uint32_t); -static const char *zyd_rf_name(uint8_t); -static void zyd_cfg_rf_rfmd_init(struct zyd_softc *, struct zyd_rf *); -static void zyd_cfg_rf_rfmd_switch_radio(struct zyd_softc *, uint8_t); -static void zyd_cfg_rf_rfmd_set_channel(struct zyd_softc *, - struct zyd_rf *, uint8_t); -static void zyd_cfg_rf_al2230_switch_radio(struct zyd_softc *, uint8_t); -static void zyd_cfg_rf_al2230_init(struct zyd_softc *, struct zyd_rf *); -static void zyd_cfg_rf_al2230_init_b(struct zyd_softc *, struct zyd_rf *); -static void zyd_cfg_rf_al2230_set_channel(struct zyd_softc *, - struct zyd_rf *, uint8_t); -static uint8_t zyd_cfg_rf_init_hw(struct zyd_softc *, struct zyd_rf *); -static uint8_t zyd_cfg_hw_init(struct zyd_softc *); -static void zyd_cfg_set_mac_addr(struct zyd_softc *, const uint8_t *); -static void zyd_cfg_switch_radio(struct zyd_softc *, uint8_t); -static void zyd_cfg_set_bssid(struct zyd_softc *, uint8_t *); -static void zyd_start_cb(struct ifnet *); -static void zyd_init_cb(void *); -static int zyd_ioctl_cb(struct ifnet *, u_long command, caddr_t data); -static void zyd_watchdog(void *); -static void zyd_end_of_commands(struct zyd_softc *); -static void zyd_newassoc_cb(struct ieee80211_node *, int isnew); -static void zyd_scan_start_cb(struct ieee80211com *); -static void zyd_scan_end_cb(struct ieee80211com *); -static void zyd_set_channel_cb(struct ieee80211com *); -static void zyd_cfg_set_led(struct zyd_softc *, uint32_t, uint8_t); +static usb2_proc_callback_t zyd_attach_post; +static usb2_proc_callback_t zyd_task; +static usb2_proc_callback_t zyd_scantask; +static usb2_proc_callback_t zyd_multitask; +static usb2_proc_callback_t zyd_init_task; +static usb2_proc_callback_t zyd_stop_task; + static struct ieee80211vap *zyd_vap_create(struct ieee80211com *, - const char name[IFNAMSIZ], int unit, int opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t - mac[IEEE80211_ADDR_LEN]); -static void zyd_vap_delete(struct ieee80211vap *); -static struct ieee80211_node *zyd_node_alloc_cb(struct ieee80211vap *, + const char name[IFNAMSIZ], int unit, int opmode, + int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]); -static void zyd_cfg_set_run(struct zyd_softc *, struct usb2_config_td_cc *); -static void zyd_fill_write_queue(struct zyd_softc *); -static void zyd_tx_clean_queue(struct zyd_softc *); -static void zyd_tx_freem(struct mbuf *); -static void zyd_tx_mgt(struct zyd_softc *, struct mbuf *, +static void zyd_vap_delete(struct ieee80211vap *); +static void zyd_tx_free(struct zyd_tx_data *, int); +static void zyd_setup_tx_list(struct zyd_softc *); +static void zyd_unsetup_tx_list(struct zyd_softc *); +static struct ieee80211_node *zyd_node_alloc(struct ieee80211vap *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static int zyd_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static int zyd_cmd(struct zyd_softc *, uint16_t, const void *, int, + void *, int, u_int); +static int zyd_read16(struct zyd_softc *, uint16_t, uint16_t *); +static int zyd_read32(struct zyd_softc *, uint16_t, uint32_t *); +static int zyd_write16(struct zyd_softc *, uint16_t, uint16_t); +static int zyd_write32(struct zyd_softc *, uint16_t, uint32_t); +static int zyd_rfwrite(struct zyd_softc *, uint32_t); +static int zyd_lock_phy(struct zyd_softc *); +static int zyd_unlock_phy(struct zyd_softc *); +static int zyd_rf_attach(struct zyd_softc *, uint8_t); +static const char *zyd_rf_name(uint8_t); +static int zyd_hw_init(struct zyd_softc *); +static int zyd_read_pod(struct zyd_softc *); +static int zyd_read_eeprom(struct zyd_softc *); +static int zyd_get_macaddr(struct zyd_softc *); +static int zyd_set_macaddr(struct zyd_softc *, const uint8_t *); +static int zyd_set_bssid(struct zyd_softc *, const uint8_t *); +static int zyd_switch_radio(struct zyd_softc *, int); +static int zyd_set_led(struct zyd_softc *, int, int); +static void zyd_set_multi(struct zyd_softc *); +static void zyd_update_mcast(struct ifnet *); +static int zyd_set_rxfilter(struct zyd_softc *); +static void zyd_set_chan(struct zyd_softc *, struct ieee80211_channel *); +static int zyd_set_beacon_interval(struct zyd_softc *, int); +static void zyd_rx_data(struct usb2_xfer *, int, uint16_t); +static int zyd_tx_mgt(struct zyd_softc *, struct mbuf *, struct ieee80211_node *); -static struct ieee80211vap *zyd_get_vap(struct zyd_softc *); -static void zyd_tx_data(struct zyd_softc *, struct mbuf *, +static int zyd_tx_data(struct zyd_softc *, struct mbuf *, struct ieee80211_node *); -static int zyd_raw_xmit_cb(struct ieee80211_node *, struct mbuf *, +static void zyd_start(struct ifnet *); +static int zyd_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); -static void zyd_setup_desc_and_tx(struct zyd_softc *, struct mbuf *, - uint16_t); -static int zyd_newstate_cb(struct ieee80211vap *, - enum ieee80211_state nstate, int arg); -static void zyd_cfg_amrr_start(struct zyd_softc *); -static void zyd_update_mcast_cb(struct ifnet *); -static void zyd_update_promisc_cb(struct ifnet *); -static void zyd_cfg_get_macaddr(struct zyd_softc *sc); +static int zyd_ioctl(struct ifnet *, u_long, caddr_t); +static void zyd_init(void *); +static int zyd_loadfirmware(struct zyd_softc *); +static void zyd_newassoc(struct ieee80211_node *, int); +static void zyd_scan_start(struct ieee80211com *); +static void zyd_scan_end(struct ieee80211com *); +static void zyd_set_channel(struct ieee80211com *); +static int zyd_rfmd_init(struct zyd_rf *); +static int zyd_rfmd_switch_radio(struct zyd_rf *, int); +static int zyd_rfmd_set_channel(struct zyd_rf *, uint8_t); +static int zyd_al2230_init(struct zyd_rf *); +static int zyd_al2230_switch_radio(struct zyd_rf *, int); +static int zyd_al2230_set_channel(struct zyd_rf *, uint8_t); +static int zyd_al2230_set_channel_b(struct zyd_rf *, uint8_t); +static int zyd_al2230_init_b(struct zyd_rf *); +static int zyd_al7230B_init(struct zyd_rf *); +static int zyd_al7230B_switch_radio(struct zyd_rf *, int); +static int zyd_al7230B_set_channel(struct zyd_rf *, uint8_t); +static int zyd_al2210_init(struct zyd_rf *); +static int zyd_al2210_switch_radio(struct zyd_rf *, int); +static int zyd_al2210_set_channel(struct zyd_rf *, uint8_t); +static int zyd_gct_init(struct zyd_rf *); +static int zyd_gct_switch_radio(struct zyd_rf *, int); +static int zyd_gct_set_channel(struct zyd_rf *, uint8_t); +static int zyd_maxim_init(struct zyd_rf *); +static int zyd_maxim_switch_radio(struct zyd_rf *, int); +static int zyd_maxim_set_channel(struct zyd_rf *, uint8_t); +static int zyd_maxim2_init(struct zyd_rf *); +static int zyd_maxim2_switch_radio(struct zyd_rf *, int); +static int zyd_maxim2_set_channel(struct zyd_rf *, uint8_t); +static void zyd_queue_command(struct zyd_softc *, usb2_proc_callback_t *, + struct usb2_proc_msg *, struct usb2_proc_msg *); static const struct zyd_phy_pair zyd_def_phy[] = ZYD_DEF_PHY; static const struct zyd_phy_pair zyd_def_phyB[] = ZYD_DEF_PHYB; /* various supported device vendors/products */ -#define ZYD_ZD1211 0 -#define ZYD_ZD1211B 1 +#define ZYD_ZD1211 0 +#define ZYD_ZD1211B 1 static const struct usb2_device_id zyd_devs[] = { - /* ZYD_ZD1211 */ - {USB_VPI(USB_VENDOR_3COM2, USB_PRODUCT_3COM2_3CRUSB10075, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_WL54, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_WL159G, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_CYBERTAN, USB_PRODUCT_CYBERTAN_TG54USB, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_DRAYTEK, USB_PRODUCT_DRAYTEK_VIGOR550, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54GD, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54GZL, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GWUS54GZ, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GWUS54MINI, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_XG760A, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_NUB8301, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL113, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_SWEEX, USB_PRODUCT_SWEEX_ZD1211, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_QUICKWLAN, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZD1211_1, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZD1211_2, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_TWINMOS, USB_PRODUCT_TWINMOS_G240, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_ALL0298V2, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UB_A, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UB, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_WISTRONNEWEB, USB_PRODUCT_WISTRONNEWEB_UR055G, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_ZD1211, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_ZYDAS, USB_PRODUCT_ZYDAS_ZD1211, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_AG225H, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_ZYAIRG220, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G200V2, ZYD_ZD1211)}, - {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G202, ZYD_ZD1211)}, - /* ZYD_ZD1211B */ - {USB_VPI(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SMCWUSBG, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_ZD1211B, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_A9T_WIFI, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050_V4000, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_ZD1211B, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSBF54G, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_FIBERLINE, USB_PRODUCT_FIBERLINE_WL430U, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54L, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_SNU5600, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US54GXS, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_XG76NA, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_ZD1211B, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UBC1, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_USR, USB_PRODUCT_USR_USR5423, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_VTECH, USB_PRODUCT_VTECH_ZD1211B, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_ZD1211B, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_ZYDAS, USB_PRODUCT_ZYDAS_ZD1211B, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_M202, ZYD_ZD1211B)}, - {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G220V2, ZYD_ZD1211B)}, + /* ZYD_ZD1211 */ + {USB_VPI(USB_VENDOR_3COM2, USB_PRODUCT_3COM2_3CRUSB10075, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_WL54, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_WL159G, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_CYBERTAN, USB_PRODUCT_CYBERTAN_TG54USB, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_DRAYTEK, USB_PRODUCT_DRAYTEK_VIGOR550, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54GD, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54GZL, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GWUS54GZ, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GWUS54MINI, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_XG760A, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_NUB8301, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL113, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_SWEEX, USB_PRODUCT_SWEEX_ZD1211, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_QUICKWLAN, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZD1211_1, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZD1211_2, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_TWINMOS, USB_PRODUCT_TWINMOS_G240, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_ALL0298V2, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UB_A, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UB, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_WISTRONNEWEB, USB_PRODUCT_WISTRONNEWEB_UR055G, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_ZD1211, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_ZYDAS, USB_PRODUCT_ZYDAS_ZD1211, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_AG225H, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_ZYAIRG220, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G200V2, ZYD_ZD1211)}, + {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G202, ZYD_ZD1211)}, + /* ZYD_ZD1211B */ + {USB_VPI(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SMCWUSBG, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_ZD1211B, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_A9T_WIFI, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050_V4000, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_ZD1211B, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSBF54G, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_FIBERLINE, USB_PRODUCT_FIBERLINE_WL430U, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54L, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_SNU5600, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US54GXS, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_XG76NA, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_ZD1211B, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UBC1, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_USR, USB_PRODUCT_USR_USR5423, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_VTECH, USB_PRODUCT_VTECH_ZD1211B, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_ZD1211B, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_ZYDAS, USB_PRODUCT_ZYDAS_ZD1211B, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_M202, ZYD_ZD1211B)}, + {USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G220V2, ZYD_ZD1211B)}, }; static const struct usb2_config zyd_config[ZYD_N_TRANSFER] = { - [ZYD_BULK_DT_WR] = { + [ZYD_BULK_WR] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .mh.bufsize = ZYD_MAX_TXBUFSZ, .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .mh.callback = &zyd_bulk_write_callback, + .mh.callback = zyd_bulk_write_callback, .ep_index = 0, .mh.timeout = 10000, /* 10 seconds */ }, - - [ZYD_BULK_DT_RD] = { + [ZYD_BULK_RD] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .mh.bufsize = ZYX_MAX_RXBUFSZ, .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, - .mh.callback = &zyd_bulk_read_callback, + .mh.callback = zyd_bulk_read_callback, .ep_index = 0, }, - - [ZYD_BULK_CS_WR] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.flags = {}, - .mh.callback = &zyd_bulk_write_clear_stall_callback, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ - }, - - [ZYD_BULK_CS_RD] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.flags = {}, - .mh.callback = &zyd_bulk_read_clear_stall_callback, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ - }, - - [ZYD_INTR_DT_WR] = { + [ZYD_INTR_WR] = { .type = UE_BULK_INTR, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .mh.bufsize = sizeof(struct zyd_cmd), .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .mh.callback = &zyd_intr_write_callback, + .mh.callback = zyd_intr_write_callback, .mh.timeout = 1000, /* 1 second */ .ep_index = 1, }, - - [ZYD_INTR_DT_RD] = { - .type = UE_BULK_INTR, + [ZYD_INTR_RD] = { + .type = UE_INTERRUPT, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .mh.bufsize = sizeof(struct zyd_cmd), .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, - .mh.callback = &zyd_intr_read_callback, - .ep_index = 1, - }, - - [ZYD_INTR_CS_WR] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.flags = {}, - .mh.callback = &zyd_intr_write_clear_stall_callback, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ - }, - - [ZYD_INTR_CS_RD] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.flags = {}, - .mh.callback = &zyd_intr_read_clear_stall_callback, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ + .mh.callback = zyd_intr_read_callback, }, }; +#define zyd_read16_m(sc, val, data) do { \ + error = zyd_read16(sc, val, data); \ + if (error != 0) \ + goto fail; \ +} while (0) +#define zyd_write16_m(sc, val, data) do { \ + error = zyd_write16(sc, val, data); \ + if (error != 0) \ + goto fail; \ +} while (0) +#define zyd_read32_m(sc, val, data) do { \ + error = zyd_read32(sc, val, data); \ + if (error != 0) \ + goto fail; \ +} while (0) +#define zyd_write32_m(sc, val, data) do { \ + error = zyd_write32(sc, val, data); \ + if (error != 0) \ + goto fail; \ +} while (0) -static devclass_t zyd_devclass; - -static device_method_t zyd_methods[] = { - DEVMETHOD(device_probe, zyd_probe), - DEVMETHOD(device_attach, zyd_attach), - DEVMETHOD(device_detach, zyd_detach), - {0, 0} -}; - -static driver_t zyd_driver = { - .name = "zyd", - .methods = zyd_methods, - .size = sizeof(struct zyd_softc), -}; - -DRIVER_MODULE(zyd, ushub, zyd_driver, zyd_devclass, NULL, 0); -MODULE_DEPEND(zyd, usb2_wlan, 1, 1, 1); -MODULE_DEPEND(zyd, usb2_core, 1, 1, 1); -MODULE_DEPEND(zyd, wlan, 1, 1, 1); -MODULE_DEPEND(zyd, wlan_amrr, 1, 1, 1); - -static uint8_t -zyd_plcp2ieee(uint8_t signal, uint8_t isofdm) +static int +zyd_match(device_t dev) { - if (isofdm) { - static const uint8_t ofdmrates[16] = - {0, 0, 0, 0, 0, 0, 0, 96, 48, 24, 12, 108, 72, 36, 18}; + struct usb2_attach_arg *uaa = device_get_ivars(dev); - return ofdmrates[signal & 0xf]; - } else { - static const uint8_t cckrates[16] = - {0, 0, 0, 0, 4, 0, 0, 11, 0, 0, 2, 0, 0, 0, 22, 0}; + if (uaa->usb2_mode != USB_MODE_HOST) + return (ENXIO); + if (uaa->info.bConfigIndex != ZYD_CONFIG_INDEX) + return (ENXIO); + if (uaa->info.bIfaceIndex != ZYD_IFACE_INDEX) + return (ENXIO); - return cckrates[signal & 0xf]; - } + return (usb2_lookup_id_by_uaa(zyd_devs, sizeof(zyd_devs), uaa)); } -/* - * USB request basic wrapper - */ -static void -zyd_cfg_usbrequest(struct zyd_softc *sc, struct usb2_device_request *req, uint8_t *data) +static int +zyd_attach(device_t dev) { - usb2_error_t err; - uint16_t length; + struct usb2_attach_arg *uaa = device_get_ivars(dev); + struct zyd_softc *sc = device_get_softc(dev); + int error; + uint8_t iface_index; - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - goto error; + if (uaa->info.bcdDevice < 0x4330) { + device_printf(dev, "device version mismatch: 0x%X " + "(only >= 43.30 supported)\n", + uaa->info.bcdDevice); + return (EINVAL); } - err = usb2_do_request_flags - (sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 1000); - if (err) { + device_set_usb2_desc(dev); + sc->sc_dev = dev; + sc->sc_udev = uaa->device; + sc->sc_macrev = USB_GET_DRIVER_INFO(uaa); - DPRINTFN(0, "%s: device request failed, err=%s " - "(ignored)\n", sc->sc_name, usb2_errstr(err)); + mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), + MTX_NETWORK_LOCK, MTX_DEF); -error: - length = UGETW(req->wLength); + STAILQ_INIT(&sc->sc_rqh); - if ((req->bmRequestType & UT_READ) && length) { - bzero(data, length); - } + iface_index = ZYD_IFACE_INDEX; + error = usb2_transfer_setup(uaa->device, + &iface_index, sc->sc_xfer, zyd_config, + ZYD_N_TRANSFER, sc, &sc->sc_mtx); + if (error) { + device_printf(dev, "could not allocate USB transfers, " + "err=%s\n", usb2_errstr(error)); + goto detach; + } + error = usb2_proc_create(&sc->sc_tq, &sc->sc_mtx, + device_get_nameunit(dev), USB_PRI_MED); + if (error) { + device_printf(dev, "could not setup config thread!\n"); + goto detach; } -} -static void -zyd_intr_read_clear_stall_callback(struct usb2_xfer *xfer) -{ - struct zyd_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_INTR_DT_RD]; + /* fork rest of the attach code */ + ZYD_LOCK(sc); + zyd_queue_command(sc, zyd_attach_post, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + ZYD_UNLOCK(sc); + return (0); - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~ZYD_FLAG_INTR_READ_STALL; - usb2_transfer_start(xfer_other); - } +detach: + zyd_detach(dev); + return (ENXIO); /* failure */ } -/* - * Callback handler for interrupt transfer - */ static void -zyd_intr_read_callback(struct usb2_xfer *xfer) +zyd_attach_post(struct usb2_proc_msg *pm) { - struct zyd_softc *sc = xfer->priv_sc; - struct zyd_cmd *cmd = &sc->sc_intr_ibuf; - uint32_t actlen; - - switch (USB_GET_STATE(xfer)) { - case USB_ST_TRANSFERRED: - - actlen = xfer->actlen; - - DPRINTFN(3, "length=%d\n", actlen); - - if (actlen > sizeof(sc->sc_intr_ibuf)) { - actlen = sizeof(sc->sc_intr_ibuf); - } - usb2_copy_out(xfer->frbuffers, 0, - &sc->sc_intr_ibuf, actlen); - - switch (le16toh(cmd->code)) { - case ZYD_NOTIF_RETRYSTATUS: - goto handle_notif_retrystatus; - case ZYD_NOTIF_IORD: - goto handle_notif_iord; - default: - DPRINTFN(2, "unknown indication: 0x%04x\n", - le16toh(cmd->code)); - } - - /* fallthrough */ + struct zyd_task *task = (struct zyd_task *)pm; + struct zyd_softc *sc = task->sc; + struct ifnet *ifp; + struct ieee80211com *ic; + int error; + uint8_t bands; - case USB_ST_SETUP: -tr_setup: - if (sc->sc_flags & ZYD_FLAG_INTR_READ_STALL) { - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_CS_RD]); - break; - } - xfer->frlengths[0] = xfer->max_data_length; - usb2_start_hardware(xfer); - break; + if ((error = zyd_get_macaddr(sc)) != 0) { + device_printf(sc->sc_dev, "could not read EEPROM\n"); + return; + } - default: /* Error */ - DPRINTFN(3, "error = %s\n", - usb2_errstr(xfer->error)); + ZYD_UNLOCK(sc); - if (xfer->error != USB_ERR_CANCELLED) { - /* try to clear stall first */ - sc->sc_flags |= ZYD_FLAG_INTR_READ_STALL; - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_CS_RD]); - } - break; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + ZYD_LOCK(sc); + return; } - return; + 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, IFQ_MAXLEN); + IFQ_SET_READY(&ifp->if_snd); -handle_notif_retrystatus:{ + ic = ifp->if_l2com; + ic->ic_ifp = ifp; + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; + IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_bssid); - struct zyd_notif_retry *retry = (void *)(cmd->data); - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211vap *vap; - struct ieee80211_node *ni; + /* set device capabilities */ + ic->ic_caps = + IEEE80211_C_STA /* station mode */ + | IEEE80211_C_MONITOR /* monitor mode */ + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ + | IEEE80211_C_SHSLOT /* short slot time supported */ + | IEEE80211_C_BGSCAN /* capable of bg scanning */ + | IEEE80211_C_WPA /* 802.11i */ + ; - DPRINTF("retry intr: rate=0x%x " - "addr=%02x:%02x:%02x:%02x:%02x:%02x count=%d (0x%x)\n", - le16toh(retry->rate), retry->macaddr[0], retry->macaddr[1], - retry->macaddr[2], retry->macaddr[3], retry->macaddr[4], - retry->macaddr[5], le16toh(retry->count) & 0xff, - le16toh(retry->count)); + bands = 0; + setbit(&bands, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11G); + ieee80211_init_channels(ic, NULL, &bands); - vap = zyd_get_vap(sc); - if ((vap != NULL) && (sc->sc_amrr_timer)) { - /* - * Find the node to which the packet was sent - * and update its retry statistics. In BSS - * mode, this node is the AP we're associated - * to so no lookup is actually needed. - */ - ni = ieee80211_find_txnode(vap, retry->macaddr); - if (ni != NULL) { - ieee80211_amrr_tx_complete(&ZYD_NODE(ni)->amn, - IEEE80211_AMRR_FAILURE, 1); - ieee80211_free_node(ni); - } - } - if (retry->count & htole16(0x100)) { - ifp->if_oerrors++; /* too many retries */ - } - goto tr_setup; - } + ieee80211_ifattach(ic); + ic->ic_newassoc = zyd_newassoc; + ic->ic_raw_xmit = zyd_raw_xmit; + ic->ic_node_alloc = zyd_node_alloc; + ic->ic_scan_start = zyd_scan_start; + ic->ic_scan_end = zyd_scan_end; + ic->ic_set_channel = zyd_set_channel; -handle_notif_iord: + ic->ic_vap_create = zyd_vap_create; + ic->ic_vap_delete = zyd_vap_delete; + ic->ic_update_mcast = zyd_update_mcast; - if (*(uint16_t *)cmd->data == htole16(ZYD_CR_INTERRUPT)) { - goto tr_setup; /* HMAC interrupt */ - } - if (actlen < 4) { - DPRINTFN(0, "too short, %u bytes\n", actlen); - goto tr_setup; /* too short */ - } - actlen -= 4; + bpfattach(ifp, DLT_IEEE802_11_RADIO, + sizeof(struct ieee80211_frame) + sizeof(sc->sc_txtap)); + sc->sc_rxtap_len = sizeof(sc->sc_rxtap); + sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); + sc->sc_rxtap.wr_ihdr.it_present = htole32(ZYD_RX_RADIOTAP_PRESENT); + sc->sc_txtap_len = sizeof(sc->sc_txtap); + sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); + sc->sc_txtap.wt_ihdr.it_present = htole32(ZYD_TX_RADIOTAP_PRESENT); - sc->sc_intr_ilen = actlen; + if (bootverbose) + ieee80211_announce(ic); - if (sc->sc_intr_iwakeup) { - sc->sc_intr_iwakeup = 0; - usb2_cv_signal(&sc->sc_intr_cv); - } else { - sc->sc_intr_iwakeup = 1; - } - /* - * We pause reading data from the interrupt endpoint until the - * data has been picked up! - */ + ZYD_LOCK(sc); } -/* - * Interrupt call reply transfer, read - */ -static void -zyd_cfg_usb2_intr_read(struct zyd_softc *sc, void *data, uint32_t size) +static int +zyd_detach(device_t dev) { - uint16_t actlen; - uint16_t x; - - if (size > sizeof(sc->sc_intr_ibuf.data)) { - DPRINTFN(0, "truncating transfer size!\n"); - size = sizeof(sc->sc_intr_ibuf.data); - } - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - bzero(data, size); - goto done; - } - if (sc->sc_intr_iwakeup) { - DPRINTF("got data already!\n"); - sc->sc_intr_iwakeup = 0; - goto skip0; - } -repeat: - sc->sc_intr_iwakeup = 1; + struct zyd_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - while (sc->sc_intr_iwakeup) { + /* wait for any post attach or other command to complete */ + usb2_proc_drain(&sc->sc_tq); - /* wait for data */ + /* stop all USB transfers */ + usb2_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); + usb2_proc_free(&sc->sc_tq); - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_DT_RD]); + /* free TX list, if any */ + zyd_unsetup_tx_list(sc); - if (usb2_cv_timedwait(&sc->sc_intr_cv, - &sc->sc_mtx, hz / 2)) { - /* should not happen */ - } - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - bzero(data, size); - goto done; - } - } -skip0: - if (size != sc->sc_intr_ilen) { - DPRINTFN(0, "unexpected length %u != %u\n", - size, sc->sc_intr_ilen); - goto repeat; - } - actlen = sc->sc_intr_ilen; - actlen /= 4; - - /* verify register values */ - for (x = 0; x != actlen; x++) { - if (sc->sc_intr_obuf.data[(2 * x)] != - sc->sc_intr_ibuf.data[(4 * x)]) { - /* invalid register */ - DPRINTFN(0, "Invalid register (1) at %u!\n", x); - goto repeat; - } - if (sc->sc_intr_obuf.data[(2 * x) + 1] != - sc->sc_intr_ibuf.data[(4 * x) + 1]) { - /* invalid register */ - DPRINTFN(0, "Invalid register (2) at %u!\n", x); - goto repeat; - } + if (ifp) { + bpfdetach(ifp); + ieee80211_ifdetach(ic); + if_free(ifp); } - bcopy(sc->sc_intr_ibuf.data, data, size); - - /* - * We have fetched the data from the shared buffer and it is - * safe to restart the interrupt transfer! - */ - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_DT_RD]); -done: - return; -} - -static void -zyd_intr_write_clear_stall_callback(struct usb2_xfer *xfer) -{ - struct zyd_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_INTR_DT_WR]; + mtx_destroy(&sc->sc_mtx); - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~ZYD_FLAG_INTR_WRITE_STALL; - usb2_transfer_start(xfer_other); - } + return (0); } -static void -zyd_intr_write_callback(struct usb2_xfer *xfer) +static struct ieee80211vap * +zyd_vap_create(struct ieee80211com *ic, + const char name[IFNAMSIZ], int unit, int opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct zyd_softc *sc = xfer->priv_sc; - - switch (USB_GET_STATE(xfer)) { - case USB_ST_TRANSFERRED: - DPRINTFN(3, "length=%d\n", xfer->actlen); - goto wakeup; - - case USB_ST_SETUP: - - if (sc->sc_flags & ZYD_FLAG_INTR_WRITE_STALL) { - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_CS_WR]); - goto wakeup; - } - if (sc->sc_intr_owakeup) { - usb2_copy_in(xfer->frbuffers, 0, &sc->sc_intr_obuf, - sc->sc_intr_olen); + struct zyd_vap *zvp; + struct ieee80211vap *vap; - xfer->frlengths[0] = sc->sc_intr_olen; - usb2_start_hardware(xfer); - } - break; + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + return (NULL); + zvp = (struct zyd_vap *) malloc(sizeof(struct zyd_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (zvp == NULL) + return (NULL); + vap = &zvp->vap; + /* enable s/w bmiss handling for sta mode */ + ieee80211_vap_setup(ic, vap, name, unit, opmode, + flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); - default: /* Error */ - DPRINTFN(3, "error = %s\n", - usb2_errstr(xfer->error)); + /* override state transition machine */ + zvp->newstate = vap->iv_newstate; + vap->iv_newstate = zyd_newstate; - if (xfer->error != USB_ERR_CANCELLED) { - /* try to clear stall first */ - sc->sc_flags |= ZYD_FLAG_INTR_WRITE_STALL; - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_CS_WR]); - } - goto wakeup; - } - return; + ieee80211_amrr_init(&zvp->amrr, vap, + IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, + IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, + 1000 /* 1 sec */); -wakeup: - if (sc->sc_intr_owakeup) { - sc->sc_intr_owakeup = 0; - usb2_cv_signal(&sc->sc_intr_cv); - } + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, + ieee80211_media_status); + ic->ic_opmode = opmode; + return (vap); } -/* - * Interrupt transfer, write. - * - * Not always an "interrupt transfer". If operating in - * full speed mode, EP4 is bulk out, not interrupt out. - */ static void -zyd_cfg_usb2_intr_write(struct zyd_softc *sc, const void *data, - uint16_t code, uint32_t size) +zyd_vap_delete(struct ieee80211vap *vap) { - if (size > sizeof(sc->sc_intr_obuf.data)) { - DPRINTFN(0, "truncating transfer size!\n"); - size = sizeof(sc->sc_intr_obuf.data); - } - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - goto done; - } - sc->sc_intr_olen = size + 2; - sc->sc_intr_owakeup = 1; - - sc->sc_intr_obuf.code = htole16(code); - bcopy(data, sc->sc_intr_obuf.data, size); - - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_DT_WR]); + struct zyd_vap *zvp = ZYD_VAP(vap); - while (sc->sc_intr_owakeup) { - if (usb2_cv_timedwait(&sc->sc_intr_cv, - &sc->sc_mtx, hz / 2)) { - /* should not happen */ - } - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - sc->sc_intr_owakeup = 0; - goto done; - } - } -done: - return; + ieee80211_amrr_cleanup(&zvp->amrr); + ieee80211_vap_detach(vap); + free(zvp, M_80211_VAP); } static void -zyd_cfg_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, uint16_t ilen, - void *odata, uint16_t olen, uint16_t flags) +zyd_tx_free(struct zyd_tx_data *data, int txerr) { - zyd_cfg_usb2_intr_write(sc, idata, code, ilen); + struct zyd_softc *sc = data->sc; + + if (data->m != NULL) { + if (data->m->m_flags & M_TXCB) + ieee80211_process_callback(data->ni, data->m, + txerr ? ETIMEDOUT : 0); + m_freem(data->m); + data->m = NULL; - if (flags & ZYD_CMD_FLAG_READ) { - zyd_cfg_usb2_intr_read(sc, odata, olen); + ieee80211_free_node(data->ni); + data->ni = NULL; } + STAILQ_INSERT_TAIL(&sc->tx_free, data, next); + sc->tx_nfree++; } static void -zyd_cfg_read16(struct zyd_softc *sc, uint16_t addr, uint16_t *value) +zyd_setup_tx_list(struct zyd_softc *sc) { - struct zyd_pair tmp[1]; - - addr = htole16(addr); - zyd_cfg_cmd(sc, ZYD_CMD_IORD, &addr, sizeof(addr), - tmp, sizeof(tmp), ZYD_CMD_FLAG_READ); - *value = le16toh(tmp[0].val); -} + struct zyd_tx_data *data; + int i; -static void -zyd_cfg_read32(struct zyd_softc *sc, uint16_t addr, uint32_t *value) -{ - struct zyd_pair tmp[2]; - uint16_t regs[2]; - - regs[0] = ZYD_REG32_HI(addr); - regs[1] = ZYD_REG32_LO(addr); - regs[0] = htole16(regs[0]); - regs[1] = htole16(regs[1]); - - zyd_cfg_cmd(sc, ZYD_CMD_IORD, regs, sizeof(regs), - tmp, sizeof(tmp), ZYD_CMD_FLAG_READ); - *value = (le16toh(tmp[0].val) << 16) | le16toh(tmp[1].val); -} - -static void -zyd_cfg_write16(struct zyd_softc *sc, uint16_t reg, uint16_t val) -{ - struct zyd_pair pair[1]; + sc->tx_nfree = 0; + STAILQ_INIT(&sc->tx_q); + STAILQ_INIT(&sc->tx_free); - pair[0].reg = htole16(reg); - pair[0].val = htole16(val); + for (i = 0; i < ZYD_TX_LIST_CNT; i++) { + data = &sc->tx_data[i]; - zyd_cfg_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0); + data->sc = sc; + STAILQ_INSERT_TAIL(&sc->tx_free, data, next); + sc->tx_nfree++; + } } static void -zyd_cfg_write32(struct zyd_softc *sc, uint16_t reg, uint32_t val) +zyd_unsetup_tx_list(struct zyd_softc *sc) { - struct zyd_pair pair[2]; - - pair[0].reg = htole16(ZYD_REG32_HI(reg)); - pair[0].val = htole16(val >> 16); - pair[1].reg = htole16(ZYD_REG32_LO(reg)); - pair[1].val = htole16(val & 0xffff); + struct zyd_tx_data *data; + int i; - zyd_cfg_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0); -} + /* make sure any subsequent use of the queues will fail */ + sc->tx_nfree = 0; + STAILQ_INIT(&sc->tx_q); + STAILQ_INIT(&sc->tx_free); -/*------------------------------------------------------------------------* - * zyd_cfg_rfwrite - write RF registers - *------------------------------------------------------------------------*/ -static void -zyd_cfg_rfwrite(struct zyd_softc *sc, uint32_t value) -{ - struct zyd_rf *rf = &sc->sc_rf; - struct zyd_rfwrite req; - uint16_t cr203; - uint16_t i; + /* free up all node references and mbufs */ + for (i = 0; i < ZYD_TX_LIST_CNT; i++) { + data = &sc->tx_data[i]; - zyd_cfg_read16(sc, ZYD_CR203, &cr203); - cr203 &= ~(ZYD_RF_IF_LE | ZYD_RF_CLK | ZYD_RF_DATA); - - req.code = htole16(2); - req.width = htole16(rf->width); - for (i = 0; i != rf->width; i++) { - req.bit[i] = htole16(cr203); - if (value & (1 << (rf->width - 1 - i))) - req.bit[i] |= htole16(ZYD_RF_DATA); + if (data->m != NULL) { + m_freem(data->m); + data->m = NULL; + } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; + } } - zyd_cfg_cmd(sc, ZYD_CMD_RFCFG, &req, 4 + (2 * rf->width), NULL, 0, 0); } -/*------------------------------------------------------------------------* - * zyd_cfg_rfwrite_cr - *------------------------------------------------------------------------*/ -static void -zyd_cfg_rfwrite_cr(struct zyd_softc *sc, uint32_t val) -{ - zyd_cfg_write16(sc, ZYD_CR244, (val >> 16) & 0xff); - zyd_cfg_write16(sc, ZYD_CR243, (val >> 8) & 0xff); - zyd_cfg_write16(sc, ZYD_CR242, (val >> 0) & 0xff); -} - -static void -zyd_bulk_read_clear_stall_callback(struct usb2_xfer *xfer) +/* ARGUSED */ +static struct ieee80211_node * +zyd_node_alloc(struct ieee80211vap *vap __unused, + const uint8_t mac[IEEE80211_ADDR_LEN] __unused) { - struct zyd_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_BULK_DT_RD]; + struct zyd_node *zn; - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~ZYD_FLAG_BULK_READ_STALL; - usb2_transfer_start(xfer_other); - } + zn = malloc(sizeof(struct zyd_node), M_80211_NODE, M_NOWAIT | M_ZERO); + return (zn != NULL) ? (&zn->ni) : (NULL); } static void -zyd_bulk_read_callback_sub(struct usb2_xfer *xfer, struct zyd_ifq *mq, - uint32_t offset, uint16_t len) +zyd_task(struct usb2_proc_msg *pm) { - enum { - ZYD_OVERHEAD = (ZYD_HW_PADDING + IEEE80211_CRC_LEN), - }; - struct zyd_softc *sc = xfer->priv_sc; + struct zyd_task *task = (struct zyd_task *)pm; + struct zyd_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; - struct zyd_plcphdr plcp; - struct zyd_rx_stat stat; - struct mbuf *m; - - if (len < ZYD_OVERHEAD) { - DPRINTF("frame too " - "short (length=%d)\n", len); - ifp->if_ierrors++; - return; - } - usb2_copy_out(xfer->frbuffers, offset, &plcp, sizeof(plcp)); - usb2_copy_out(xfer->frbuffers, offset + len - sizeof(stat), - &stat, sizeof(stat)); - - if (stat.flags & ZYD_RX_ERROR) { - DPRINTF("RX status indicated " - "error (0x%02x)\n", stat.flags); - ifp->if_ierrors++; - return; - } - /* compute actual frame length */ - len -= ZYD_OVERHEAD; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211_node *ni = vap->iv_bss; + struct zyd_vap *zvp = ZYD_VAP(vap); + int error; - /* allocate a mbuf to store the frame */ - if (len > MCLBYTES) { - DPRINTF("too large frame, " - "%u bytes\n", len); - return; - } else if (len > MHLEN) - m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - else - m = m_gethdr(M_DONTWAIT, MT_DATA); + switch (sc->sc_state) { + case IEEE80211_S_AUTH: + zyd_set_chan(sc, ic->ic_curchan); + break; + case IEEE80211_S_RUN: + if (vap->iv_opmode == IEEE80211_M_MONITOR) + break; - if (m == NULL) { - DPRINTF("could not allocate rx mbuf\n"); - ifp->if_ierrors++; - return; + /* turn link LED on */ + error = zyd_set_led(sc, ZYD_LED1, 1); + if (error != 0) + goto fail; + + /* make data LED blink upon Tx */ + zyd_write32_m(sc, sc->sc_fwbase + ZYD_FW_LINK_STATUS, 1); + + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); + zyd_set_bssid(sc, sc->sc_bssid); + break; + default: + break; } - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = len; - m->m_len = len; +fail: + ZYD_UNLOCK(sc); + IEEE80211_LOCK(ic); + zvp->newstate(vap, sc->sc_state, sc->sc_arg); + if (vap->iv_newstate_cb != NULL) + vap->iv_newstate_cb(vap, sc->sc_state, sc->sc_arg); + IEEE80211_UNLOCK(ic); + ZYD_LOCK(sc); +} - usb2_copy_out(xfer->frbuffers, offset + - sizeof(plcp), m->m_data, len); +static int +zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + struct zyd_vap *zvp = ZYD_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct zyd_softc *sc = ic->ic_ifp->if_softc; - if (bpf_peers_present(ifp->if_bpf)) { - struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap; + DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[nstate]); - tap->wr_flags = 0; - if (stat.flags & (ZYD_RX_BADCRC16 | ZYD_RX_BADCRC32)) - tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; - /* XXX toss, no way to express errors */ - if (stat.flags & ZYD_RX_DECRYPTERR) - tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; - tap->wr_rate = - zyd_plcp2ieee(plcp.signal, stat.flags & ZYD_RX_OFDM); - tap->wr_antsignal = stat.rssi + -95; - tap->wr_antnoise = -95; /* XXX */ + ZYD_LOCK(sc); + /* do it in a process context */ + sc->sc_state = nstate; + sc->sc_arg = arg; + ZYD_UNLOCK(sc); - bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); - } - if (sizeof(m->m_hdr.pad) > 0) { - m->m_hdr.pad[0] = stat.rssi; /* XXX hack */ + if (nstate == IEEE80211_S_INIT) { + zvp->newstate(vap, nstate, arg); + return (0); + } else { + ZYD_LOCK(sc); + zyd_queue_command(sc, zyd_task, &sc->sc_task[0].hdr, + &sc->sc_task[1].hdr); + ZYD_UNLOCK(sc); + return (EINPROGRESS); } - _IF_ENQUEUE(mq, m); } +/* + * Callback handler for interrupt transfer + */ static void -zyd_bulk_read_callback(struct usb2_xfer *xfer) +zyd_intr_read_callback(struct usb2_xfer *xfer) { struct zyd_softc *sc = xfer->priv_sc; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_node *ni; - struct zyd_rx_desc rx_desc; - struct zyd_ifq mq = {NULL, NULL, 0}; - struct mbuf *m; - uint32_t offset; - uint16_t len16; - uint8_t x; - uint8_t rssi; - int8_t nf; + struct zyd_cmd *cmd = &sc->sc_ibuf; + int datalen; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: + usb2_copy_out(xfer->frbuffers, 0, cmd, sizeof(*cmd)); - if (xfer->actlen < MAX(sizeof(rx_desc), ZYD_MIN_FRAGSZ)) { - DPRINTFN(0, "xfer too short, %d bytes\n", xfer->actlen); - ifp->if_ierrors++; - goto tr_setup; - } - usb2_copy_out(xfer->frbuffers, xfer->actlen - sizeof(rx_desc), - &rx_desc, sizeof(rx_desc)); + switch (le16toh(cmd->code)) { + case ZYD_NOTIF_RETRYSTATUS: + { + struct zyd_notif_retry *retry = + (struct zyd_notif_retry *)cmd->data; - if (UGETW(rx_desc.tag) == ZYD_TAG_MULTIFRAME) { + DPRINTF(sc, ZYD_DEBUG_TX_PROC, + "retry intr: rate=0x%x addr=%s count=%d (0x%x)\n", + le16toh(retry->rate), ether_sprintf(retry->macaddr), + le16toh(retry->count)&0xff, le16toh(retry->count)); - offset = 0; + /* + * Find the node to which the packet was sent and + * update its retry statistics. In BSS mode, this node + * is the AP we're associated to so no lookup is + * actually needed. + */ + ni = ieee80211_find_txnode(vap, retry->macaddr); + if (ni != NULL) { + ieee80211_amrr_tx_complete(&ZYD_NODE(ni)->amn, + IEEE80211_AMRR_FAILURE, 1); + ieee80211_free_node(ni); + } + if (le16toh(retry->count) & 0x100) + ifp->if_oerrors++; /* too many retries */ + break; + } + case ZYD_NOTIF_IORD: + { + struct zyd_rq *rqp; - DPRINTFN(4, "received multi-frame transfer, " - "%u bytes\n", xfer->actlen); + if (le16toh(*(uint16_t *)cmd->data) == ZYD_CR_INTERRUPT) + break; /* HMAC interrupt */ - for (x = 0; x < ZYD_MAX_RXFRAMECNT; x++) { - len16 = UGETW(rx_desc.len[x]); + datalen = xfer->actlen - sizeof(cmd->code); + datalen -= 2; /* XXX: padding? */ - if ((len16 == 0) || (len16 > xfer->actlen)) { - break; - } - zyd_bulk_read_callback_sub(xfer, &mq, offset, len16); + STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) { + int i, cnt; - /* - * next frame is aligned on a 32-bit - * boundary - */ - len16 = (len16 + 3) & ~3; - offset += len16; - if (len16 > xfer->actlen) { - break; + if (rqp->olen != datalen) + continue; + cnt = rqp->olen / sizeof(struct zyd_pair); + for (i = 0; i < cnt; i++) { + if (*(((const uint16_t *)rqp->idata) + i) != + (((struct zyd_pair *)cmd->data) + i)->reg) + break; } - xfer->actlen -= len16; + if (i != cnt) + continue; + /* copy answer into caller-supplied buffer */ + bcopy(cmd->data, rqp->odata, rqp->olen); + DPRINTF(sc, ZYD_DEBUG_CMD, + "command %p complete, data = %*D \n", + rqp, rqp->olen, rqp->odata, ":"); + wakeup(rqp); /* wakeup caller */ + break; } - } else { - DPRINTFN(4, "received single-frame transfer, " - "%u bytes\n", xfer->actlen); - zyd_bulk_read_callback_sub(xfer, &mq, 0, xfer->actlen); + if (rqp == NULL) { + device_printf(sc->sc_dev, + "unexpected IORD notification %*D\n", + datalen, cmd->data, ":"); + } + break; + } + default: + device_printf(sc->sc_dev, "unknown notification %x\n", + le16toh(cmd->code)); } + /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: - DPRINTF("setup\n"); - - if (sc->sc_flags & ZYD_FLAG_BULK_READ_STALL) { - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_CS_RD]); - } else { - xfer->frlengths[0] = xfer->max_data_length; - usb2_start_hardware(xfer); - } + xfer->frlengths[0] = xfer->max_data_length; + usb2_start_hardware(xfer); + break; - /* - * At the end of a USB callback it is always safe to unlock - * the private mutex of a device! That is why we do the - * "ieee80211_input" here, and not some lines up! - */ - if (mq.ifq_head) { + default: /* Error */ + DPRINTF(sc, ZYD_DEBUG_CMD, "error = %s\n", + usb2_errstr(xfer->error)); - mtx_unlock(&sc->sc_mtx); + if (xfer->error != USB_ERR_CANCELLED) { + /* try to clear stall first */ + xfer->flags.stall_pipe = 1; + goto tr_setup; + } + break; + } +} - while (1) { +static void +zyd_intr_write_callback(struct usb2_xfer *xfer) +{ + struct zyd_softc *sc = xfer->priv_sc; + struct zyd_rq *rqp; - _IF_DEQUEUE(&mq, m); + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + rqp = xfer->priv_fifo; + DPRINTF(sc, ZYD_DEBUG_CMD, "command %p transferred\n", rqp); + if ((rqp->flags & ZYD_CMD_FLAG_READ) == 0) + wakeup(rqp); /* wakeup caller */ - if (m == NULL) - break; + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) { + if (rqp->flags & ZYD_CMD_FLAG_SENT) + continue; - rssi = m->m_hdr.pad[0]; /* XXX hack */ - - rssi = (rssi > 63) ? 127 : 2 * rssi; - nf = -95; /* XXX */ - - ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); - if (ni != NULL) { - if (ieee80211_input(ni, m, rssi, nf, 0)) { - /* ignore */ - } - ieee80211_free_node(ni); - } else { - if (ieee80211_input_all(ic, m, rssi, nf, 0)) { - /* ignore */ - } - } - } + usb2_copy_in(xfer->frbuffers, 0, rqp->cmd, rqp->ilen); - mtx_lock(&sc->sc_mtx); + xfer->frlengths[0] = rqp->ilen; + xfer->priv_fifo = rqp; + rqp->flags |= ZYD_CMD_FLAG_SENT; + usb2_start_hardware(xfer); + break; } break; default: /* Error */ - DPRINTF("frame error: %s\n", usb2_errstr(xfer->error)); + DPRINTF(sc, ZYD_DEBUG_ANY, "error = %s\n", + usb2_errstr(xfer->error)); if (xfer->error != USB_ERR_CANCELLED) { /* try to clear stall first */ - sc->sc_flags |= ZYD_FLAG_BULK_READ_STALL; - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_CS_RD]); + xfer->flags.stall_pipe = 1; + goto tr_setup; } break; } } -/*------------------------------------------------------------------------* - * zyd_cfg_uploadfirmware - * Returns: - * 0: Success - * Else: Failure - *------------------------------------------------------------------------*/ -static uint8_t -zyd_cfg_uploadfirmware(struct zyd_softc *sc, const uint8_t *fw_ptr, - uint32_t fw_len) +static int +zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen, + void *odata, int olen, u_int flags) { - struct usb2_device_request req; - uint16_t temp; - uint16_t addr; - uint8_t stat; - - DPRINTF("firmware %p size=%u\n", fw_ptr, fw_len); - - req.bmRequestType = UT_WRITE_VENDOR_DEVICE; - req.bRequest = ZYD_DOWNLOADREQ; - USETW(req.wIndex, 0); - - temp = 64; - - addr = ZYD_FIRMWARE_START_ADDR; - while (fw_len > 0) { - - if (fw_len < 64) { - temp = fw_len; - } - DPRINTF("firmware block: fw_len=%u\n", fw_len); - - USETW(req.wValue, addr); - USETW(req.wLength, temp); - - zyd_cfg_usbrequest(sc, &req, - USB_ADD_BYTES(fw_ptr, 0)); + struct zyd_cmd cmd; + struct zyd_rq rq; + int error; - addr += (temp / 2); - fw_len -= temp; - fw_ptr += temp; - } + if (ilen > sizeof(cmd.data)) + return (EINVAL); - /* check whether the upload succeeded */ - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = ZYD_DOWNLOADSTS; - USETW(req.wValue, 0); - USETW(req.wIndex, 0); - USETW(req.wLength, sizeof(stat)); + if (usb2_proc_is_gone(&sc->sc_tq)) + return (ENXIO); - zyd_cfg_usbrequest(sc, &req, &stat); + cmd.code = htole16(code); + bcopy(idata, cmd.data, ilen); + DPRINTF(sc, ZYD_DEBUG_CMD, "sending cmd %p = %*D\n", + &rq, ilen, idata, ":"); + + rq.cmd = &cmd; + rq.idata = idata; + rq.odata = odata; + rq.ilen = sizeof(uint16_t) + ilen; + rq.olen = olen; + rq.flags = flags; + STAILQ_INSERT_TAIL(&sc->sc_rqh, &rq, rq); + usb2_transfer_start(sc->sc_xfer[ZYD_INTR_RD]); + usb2_transfer_start(sc->sc_xfer[ZYD_INTR_WR]); + + /* wait at most one second for command reply */ + error = mtx_sleep(&rq, &sc->sc_mtx, 0 , "zydcmd", hz); + if (error) + device_printf(sc->sc_dev, "command timeout\n"); + STAILQ_REMOVE(&sc->sc_rqh, &rq, zyd_rq, rq); + DPRINTF(sc, ZYD_DEBUG_CMD, "finsihed cmd %p, error = %d \n", + &rq, error); - return ((stat & 0x80) ? 1 : 0); + return (error); } -/* - * Driver OS interface - */ - -/* - * Probe for a ZD1211-containing product - */ static int -zyd_probe(device_t dev) +zyd_read16(struct zyd_softc *sc, uint16_t reg, uint16_t *val) { - struct usb2_attach_arg *uaa = device_get_ivars(dev); + struct zyd_pair tmp; + int error; - if (uaa->usb2_mode != USB_MODE_HOST) { - return (ENXIO); - } - if (uaa->info.bConfigIndex != 0) { - return (ENXIO); - } - if (uaa->info.bIfaceIndex != ZYD_IFACE_INDEX) { - return (ENXIO); - } - return (usb2_lookup_id_by_uaa(zyd_devs, sizeof(zyd_devs), uaa)); + reg = htole16(reg); + error = zyd_cmd(sc, ZYD_CMD_IORD, ®, sizeof(reg), &tmp, sizeof(tmp), + ZYD_CMD_FLAG_READ); + if (error == 0) + *val = le16toh(tmp.val); + return (error); } -/* - * Attach the interface. Allocate softc structures, do - * setup and ethernet/BPF attach. - */ static int -zyd_attach(device_t dev) +zyd_read32(struct zyd_softc *sc, uint16_t reg, uint32_t *val) { - struct usb2_attach_arg *uaa = device_get_ivars(dev); - struct zyd_softc *sc = device_get_softc(dev); + struct zyd_pair tmp[2]; + uint16_t regs[2]; int error; - uint8_t iface_index; - if (uaa->info.bcdDevice < 0x4330) { - device_printf(dev, "device version mismatch: 0x%X " - "(only >= 43.30 supported)\n", - uaa->info.bcdDevice); - return (EINVAL); - } - device_set_usb2_desc(dev); - - snprintf(sc->sc_name, sizeof(sc->sc_name), "%s", - device_get_nameunit(dev)); - - sc->sc_unit = device_get_unit(dev); - sc->sc_udev = uaa->device; - sc->sc_mac_rev = USB_GET_DRIVER_INFO(uaa); - - mtx_init(&sc->sc_mtx, "zyd lock", MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + regs[0] = htole16(ZYD_REG32_HI(reg)); + regs[1] = htole16(ZYD_REG32_LO(reg)); + error = zyd_cmd(sc, ZYD_CMD_IORD, regs, sizeof(regs), tmp, sizeof(tmp), + ZYD_CMD_FLAG_READ); + if (error == 0) + *val = le16toh(tmp[0].val) << 16 | le16toh(tmp[1].val); + return (error); +} - usb2_cv_init(&sc->sc_intr_cv, "IWAIT"); +static int +zyd_write16(struct zyd_softc *sc, uint16_t reg, uint16_t val) +{ + struct zyd_pair pair; - usb2_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); + pair.reg = htole16(reg); + pair.val = htole16(val); - /* - * Endpoint 1 = Bulk out (512b @ high speed / 64b @ full speed) - * Endpoint 2 = Bulk in (512b @ high speed / 64b @ full speed) - * Endpoint 3 = Intr in (64b) - * Endpoint 4 = Intr out @ high speed / bulk out @ full speed (64b) - */ - iface_index = ZYD_IFACE_INDEX; - error = usb2_transfer_setup(uaa->device, &iface_index, - sc->sc_xfer, zyd_config, ZYD_N_TRANSFER, sc, &sc->sc_mtx); - if (error) { - device_printf(dev, "could not allocate USB " - "transfers: %s\n", usb2_errstr(error)); - goto detach; - } - error = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_mtx, - &zyd_end_of_commands, sizeof(struct usb2_config_td_cc), 16); - if (error) { - device_printf(dev, "could not setup config " - "thread!\n"); - goto detach; - } - mtx_lock(&sc->sc_mtx); - - /* start setup */ + return zyd_cmd(sc, ZYD_CMD_IOWR, &pair, sizeof(pair), NULL, 0, 0); +} - usb2_config_td_queue_command - (&sc->sc_config_td, NULL, &zyd_cfg_first_time_setup, 0, 0); +static int +zyd_write32(struct zyd_softc *sc, uint16_t reg, uint32_t val) +{ + struct zyd_pair pair[2]; - zyd_watchdog(sc); - mtx_unlock(&sc->sc_mtx); - return (0); + pair[0].reg = htole16(ZYD_REG32_HI(reg)); + pair[0].val = htole16(val >> 16); + pair[1].reg = htole16(ZYD_REG32_LO(reg)); + pair[1].val = htole16(val & 0xffff); -detach: - zyd_detach(dev); - return (ENXIO); + return zyd_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0); } -/* - * Lock PHY registers - */ -static void -zyd_cfg_lock_phy(struct zyd_softc *sc) +static int +zyd_rfwrite(struct zyd_softc *sc, uint32_t val) { - uint32_t temp; + struct zyd_rf *rf = &sc->sc_rf; + struct zyd_rfwrite_cmd req; + uint16_t cr203; + int error, i; + + zyd_read16_m(sc, ZYD_CR203, &cr203); + cr203 &= ~(ZYD_RF_IF_LE | ZYD_RF_CLK | ZYD_RF_DATA); - zyd_cfg_read32(sc, ZYD_MAC_MISC, &temp); - temp &= ~ZYD_UNLOCK_PHY_REGS; - zyd_cfg_write32(sc, ZYD_MAC_MISC, temp); + req.code = htole16(2); + req.width = htole16(rf->width); + for (i = 0; i < rf->width; i++) { + req.bit[i] = htole16(cr203); + if (val & (1 << (rf->width - 1 - i))) + req.bit[i] |= htole16(ZYD_RF_DATA); + } + error = zyd_cmd(sc, ZYD_CMD_RFCFG, &req, 4 + 2 * rf->width, NULL, 0, 0); +fail: + return (error); } -/* - * Unlock PHY registers - */ -static void -zyd_cfg_unlock_phy(struct zyd_softc *sc) +static int +zyd_rfwrite_cr(struct zyd_softc *sc, uint32_t val) { - uint32_t temp; + int error; - zyd_cfg_read32(sc, ZYD_MAC_MISC, &temp); - temp |= ZYD_UNLOCK_PHY_REGS; - zyd_cfg_write32(sc, ZYD_MAC_MISC, temp); + zyd_write16_m(sc, ZYD_CR244, (val >> 16) & 0xff); + zyd_write16_m(sc, ZYD_CR243, (val >> 8) & 0xff); + zyd_write16_m(sc, ZYD_CR242, (val >> 0) & 0xff); +fail: + return (error); } -static void -zyd_cfg_set_beacon_interval(struct zyd_softc *sc, uint32_t bintval) +static int +zyd_lock_phy(struct zyd_softc *sc) { - uint32_t val; - - zyd_cfg_read32(sc, ZYD_CR_ATIM_WND_PERIOD, &val); - sc->sc_atim_wnd = val; - zyd_cfg_read32(sc, ZYD_CR_PRE_TBTT, &val); - sc->sc_pre_tbtt = val; - sc->sc_bcn_int = bintval; - - if (sc->sc_bcn_int <= 5) - sc->sc_bcn_int = 5; - if (sc->sc_pre_tbtt < 4 || sc->sc_pre_tbtt >= sc->sc_bcn_int) - sc->sc_pre_tbtt = sc->sc_bcn_int - 1; - if (sc->sc_atim_wnd >= sc->sc_pre_tbtt) - sc->sc_atim_wnd = sc->sc_pre_tbtt - 1; + int error; + uint32_t tmp; - zyd_cfg_write32(sc, ZYD_CR_ATIM_WND_PERIOD, sc->sc_atim_wnd); - zyd_cfg_write32(sc, ZYD_CR_PRE_TBTT, sc->sc_pre_tbtt); - zyd_cfg_write32(sc, ZYD_CR_BCN_INTERVAL, sc->sc_bcn_int); + zyd_read32_m(sc, ZYD_MAC_MISC, &tmp); + tmp &= ~ZYD_UNLOCK_PHY_REGS; + zyd_write32_m(sc, ZYD_MAC_MISC, tmp); +fail: + return (error); } -/* - * Get RF name - */ -static const char * -zyd_rf_name(uint8_t type) +static int +zyd_unlock_phy(struct zyd_softc *sc) { - static const char *const zyd_rfs[] = { - "unknown", "unknown", "UW2451", "UCHIP", "AL2230", - "AL7230B", "THETA", "AL2210", "MAXIM_NEW", "GCT", - "AL2230S", "RALINK", "INTERSIL", "RFMD", "MAXIM_NEW2", - "PHILIPS" - }; + int error; + uint32_t tmp; - return (zyd_rfs[(type > 15) ? 0 : type]); + zyd_read32_m(sc, ZYD_MAC_MISC, &tmp); + tmp |= ZYD_UNLOCK_PHY_REGS; + zyd_write32_m(sc, ZYD_MAC_MISC, tmp); +fail: + return (error); } /* - * RF driver: Init for RFMD chip + * RFMD RF methods. */ -static void -zyd_cfg_rf_rfmd_init(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_rfmd_init(struct zyd_rf *rf) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_RFMD_PHY; static const uint32_t rfini[] = ZYD_RFMD_RF; - uint32_t i; + int i, error; /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); + for (i = 0; i < N(phyini); i++) { + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); } /* init RFMD radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); + for (i = 0; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); } +fail: + return (error); +#undef N } -/* - * RF driver: Switch radio on/off for RFMD chip - */ -static void -zyd_cfg_rf_rfmd_switch_radio(struct zyd_softc *sc, uint8_t on) +static int +zyd_rfmd_switch_radio(struct zyd_rf *rf, int on) { - zyd_cfg_write16(sc, ZYD_CR10, on ? 0x89 : 0x15); - zyd_cfg_write16(sc, ZYD_CR11, on ? 0x00 : 0x81); + int error; + struct zyd_softc *sc = rf->rf_sc; + + zyd_write16_m(sc, ZYD_CR10, on ? 0x89 : 0x15); + zyd_write16_m(sc, ZYD_CR11, on ? 0x00 : 0x81); +fail: + return (error); } -/* - * RF driver: Channel setting for RFMD chip - */ -static void -zyd_cfg_rf_rfmd_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) +static int +zyd_rfmd_set_channel(struct zyd_rf *rf, uint8_t chan) { + int error; + struct zyd_softc *sc = rf->rf_sc; static const struct { - uint32_t r1, r2; - } rfprog[] = ZYD_RFMD_CHANTABLE; + uint32_t r1, r2; + } rfprog[] = ZYD_RFMD_CHANTABLE; - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2); -} + error = zyd_rfwrite(sc, rfprog[chan - 1].r1); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, rfprog[chan - 1].r2); + if (error != 0) + goto fail; -/* - * RF driver: Switch radio on/off for AL2230 chip - */ -static void -zyd_cfg_rf_al2230_switch_radio(struct zyd_softc *sc, uint8_t on) -{ - uint8_t on251 = (sc->sc_mac_rev == ZYD_ZD1211) ? 0x3f : 0x7f; - - zyd_cfg_write16(sc, ZYD_CR11, on ? 0x00 : 0x04); - zyd_cfg_write16(sc, ZYD_CR251, on ? on251 : 0x2f); +fail: + return (error); } /* - * RF driver: Init for AL2230 chip + * AL2230 RF methods. */ -static void -zyd_cfg_rf_al2230_init(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_al2230_init(struct zyd_rf *rf) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY; static const struct zyd_phy_pair phy2230s[] = ZYD_AL2230S_PHY_INIT; static const struct zyd_phy_pair phypll[] = { - {ZYD_CR251, 0x2f}, {ZYD_CR251, 0x3f}, - {ZYD_CR138, 0x28}, {ZYD_CR203, 0x06} + { ZYD_CR251, 0x2f }, { ZYD_CR251, 0x3f }, + { ZYD_CR138, 0x28 }, { ZYD_CR203, 0x06 } }; static const uint32_t rfini1[] = ZYD_AL2230_RF_PART1; static const uint32_t rfini2[] = ZYD_AL2230_RF_PART2; static const uint32_t rfini3[] = ZYD_AL2230_RF_PART3; - uint32_t i; + int i, error; /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); - if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0)) { - for (i = 0; i != INDEXES(phy2230s); i++) - zyd_cfg_write16(sc, phy2230s[i].reg, phy2230s[i].val); + if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) { + for (i = 0; i < N(phy2230s); i++) + zyd_write16_m(sc, phy2230s[i].reg, phy2230s[i].val); } + /* init AL2230 radio */ - for (i = 0; i != INDEXES(rfini1); i++) - zyd_cfg_rfwrite(sc, rfini1[i]); + for (i = 0; i < N(rfini1); i++) { + error = zyd_rfwrite(sc, rfini1[i]); + if (error != 0) + goto fail; + } - if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0)) - zyd_cfg_rfwrite(sc, 0x000824); + if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) + error = zyd_rfwrite(sc, 0x000824); else - zyd_cfg_rfwrite(sc, 0x0005a4); + error = zyd_rfwrite(sc, 0x0005a4); + if (error != 0) + goto fail; - for (i = 0; i != INDEXES(rfini2); i++) - zyd_cfg_rfwrite(sc, rfini2[i]); + for (i = 0; i < N(rfini2); i++) { + error = zyd_rfwrite(sc, rfini2[i]); + if (error != 0) + goto fail; + } - for (i = 0; i != INDEXES(phypll); i++) - zyd_cfg_write16(sc, phypll[i].reg, phypll[i].val); + for (i = 0; i < N(phypll); i++) + zyd_write16_m(sc, phypll[i].reg, phypll[i].val); - for (i = 0; i != INDEXES(rfini3); i++) - zyd_cfg_rfwrite(sc, rfini3[i]); + for (i = 0; i < N(rfini3); i++) { + error = zyd_rfwrite(sc, rfini3[i]); + if (error != 0) + goto fail; + } +fail: + return (error); +#undef N } -static void -zyd_cfg_rf_al2230_fini(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_al2230_fini(struct zyd_rf *rf) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + int error, i; + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phy[] = ZYD_AL2230_PHY_FINI_PART1; - uint32_t i; - for (i = 0; i != INDEXES(phy); i++) - zyd_cfg_write16(sc, phy[i].reg, phy[i].val); + for (i = 0; i < N(phy); i++) + zyd_write16_m(sc, phy[i].reg, phy[i].val); if (sc->sc_newphy != 0) - zyd_cfg_write16(sc, ZYD_CR9, 0xe1); - zyd_cfg_write16(sc, ZYD_CR203, 0x6); + zyd_write16_m(sc, ZYD_CR9, 0xe1); + + zyd_write16_m(sc, ZYD_CR203, 0x6); +fail: + return (error); +#undef N } -static void -zyd_cfg_rf_al2230_init_b(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_al2230_init_b(struct zyd_rf *rf) { - static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY_B; +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phy1[] = ZYD_AL2230_PHY_PART1; static const struct zyd_phy_pair phy2[] = ZYD_AL2230_PHY_PART2; static const struct zyd_phy_pair phy3[] = ZYD_AL2230_PHY_PART3; static const struct zyd_phy_pair phy2230s[] = ZYD_AL2230S_PHY_INIT; + static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY_B; static const uint32_t rfini_part1[] = ZYD_AL2230_RF_B_PART1; static const uint32_t rfini_part2[] = ZYD_AL2230_RF_B_PART2; static const uint32_t rfini_part3[] = ZYD_AL2230_RF_B_PART3; static const uint32_t zyd_al2230_chtable[][3] = ZYD_AL2230_CHANTABLE; - uint32_t i; + int i, error; - for (i = 0; i != INDEXES(phy1); i++) - zyd_cfg_write16(sc, phy1[i].reg, phy1[i].val); + for (i = 0; i < N(phy1); i++) + zyd_write16_m(sc, phy1[i].reg, phy1[i].val); /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); - if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0)) - for (i = 0; i != INDEXES(phy2230s); i++) - zyd_cfg_write16(sc, phy2230s[i].reg, phy2230s[i].val); + if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) { + for (i = 0; i < N(phy2230s); i++) + zyd_write16_m(sc, phy2230s[i].reg, phy2230s[i].val); + } - for (i = 0; i != 3; i++) - zyd_cfg_rfwrite_cr(sc, zyd_al2230_chtable[0][i]); + for (i = 0; i < 3; i++) { + error = zyd_rfwrite_cr(sc, zyd_al2230_chtable[0][i]); + if (error != 0) + return (error); + } - for (i = 0; i != INDEXES(rfini_part1); i++) - zyd_cfg_rfwrite_cr(sc, rfini_part1[i]); + for (i = 0; i < N(rfini_part1); i++) { + error = zyd_rfwrite_cr(sc, rfini_part1[i]); + if (error != 0) + return (error); + } - if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0)) - zyd_cfg_rfwrite(sc, 0x241000); + if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) + error = zyd_rfwrite(sc, 0x241000); else - zyd_cfg_rfwrite(sc, 0x25a000); + error = zyd_rfwrite(sc, 0x25a000); + if (error != 0) + goto fail; + + for (i = 0; i < N(rfini_part2); i++) { + error = zyd_rfwrite_cr(sc, rfini_part2[i]); + if (error != 0) + return (error); + } + + for (i = 0; i < N(phy2); i++) + zyd_write16_m(sc, phy2[i].reg, phy2[i].val); - for (i = 0; i != INDEXES(rfini_part2); i++) - zyd_cfg_rfwrite_cr(sc, rfini_part2[i]); + for (i = 0; i < N(rfini_part3); i++) { + error = zyd_rfwrite_cr(sc, rfini_part3[i]); + if (error != 0) + return (error); + } - for (i = 0; i != INDEXES(phy2); i++) - zyd_cfg_write16(sc, phy2[i].reg, phy2[i].val); + for (i = 0; i < N(phy3); i++) + zyd_write16_m(sc, phy3[i].reg, phy3[i].val); - for (i = 0; i != INDEXES(rfini_part3); i++) - zyd_cfg_rfwrite_cr(sc, rfini_part3[i]); + error = zyd_al2230_fini(rf); +fail: + return (error); +#undef N +} - for (i = 0; i < INDEXES(phy3); i++) - zyd_cfg_write16(sc, phy3[i].reg, phy3[i].val); +static int +zyd_al2230_switch_radio(struct zyd_rf *rf, int on) +{ + struct zyd_softc *sc = rf->rf_sc; + int error, on251 = (sc->sc_macrev == ZYD_ZD1211) ? 0x3f : 0x7f; - zyd_cfg_rf_al2230_fini(sc, rf); + zyd_write16_m(sc, ZYD_CR11, on ? 0x00 : 0x04); + zyd_write16_m(sc, ZYD_CR251, on ? on251 : 0x2f); +fail: + return (error); } -/* - * RF driver: Channel setting for AL2230 chip - */ -static void -zyd_cfg_rf_al2230_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) +static int +zyd_al2230_set_channel(struct zyd_rf *rf, uint8_t chan) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + int error, i; + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phy1[] = { - {ZYD_CR138, 0x28}, {ZYD_CR203, 0x06}, + { ZYD_CR138, 0x28 }, { ZYD_CR203, 0x06 }, }; static const struct { - uint32_t r1, r2, r3; - } rfprog[] = ZYD_AL2230_CHANTABLE; - uint32_t i; - - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r3); - - for (i = 0; i != INDEXES(phy1); i++) - zyd_cfg_write16(sc, phy1[i].reg, phy1[i].val); + uint32_t r1, r2, r3; + } rfprog[] = ZYD_AL2230_CHANTABLE; + + error = zyd_rfwrite(sc, rfprog[chan - 1].r1); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, rfprog[chan - 1].r2); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, rfprog[chan - 1].r3); + if (error != 0) + goto fail; + + for (i = 0; i < N(phy1); i++) + zyd_write16_m(sc, phy1[i].reg, phy1[i].val); +fail: + return (error); +#undef N } -static void -zyd_cfg_rf_al2230_set_channel_b(struct zyd_softc *sc, - struct zyd_rf *rf, uint8_t chan) +static int +zyd_al2230_set_channel_b(struct zyd_rf *rf, uint8_t chan) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + int error, i; + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phy1[] = ZYD_AL2230_PHY_PART1; static const struct { - uint32_t r1, r2, r3; - } rfprog[] = ZYD_AL2230_CHANTABLE_B; - uint32_t i; - - for (i = 0; i != INDEXES(phy1); i++) - zyd_cfg_write16(sc, phy1[i].reg, phy1[i].val); - - zyd_cfg_rfwrite_cr(sc, rfprog[chan - 1].r1); - zyd_cfg_rfwrite_cr(sc, rfprog[chan - 1].r2); - zyd_cfg_rfwrite_cr(sc, rfprog[chan - 1].r3); - - zyd_cfg_rf_al2230_fini(sc, rf); + uint32_t r1, r2, r3; + } rfprog[] = ZYD_AL2230_CHANTABLE_B; + + for (i = 0; i < N(phy1); i++) + zyd_write16_m(sc, phy1[i].reg, phy1[i].val); + + error = zyd_rfwrite_cr(sc, rfprog[chan - 1].r1); + if (error != 0) + goto fail; + error = zyd_rfwrite_cr(sc, rfprog[chan - 1].r2); + if (error != 0) + goto fail; + error = zyd_rfwrite_cr(sc, rfprog[chan - 1].r3); + if (error != 0) + goto fail; + error = zyd_al2230_fini(rf); +fail: + return (error); +#undef N } #define ZYD_AL2230_PHY_BANDEDGE6 \ { \ - { ZYD_CR128, 0x14 }, { ZYD_CR129, 0x12 }, { ZYD_CR130, 0x10 }, \ + { ZYD_CR128, 0x14 }, { ZYD_CR129, 0x12 }, { ZYD_CR130, 0x10 }, \ { ZYD_CR47, 0x1e } \ } -static void -zyd_cfg_rf_al2230_bandedge6(struct zyd_softc *sc, - struct zyd_rf *rf, uint8_t chan) +static int +zyd_al2230_bandedge6(struct zyd_rf *rf, struct ieee80211_channel *c) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + int error = 0, i; + struct zyd_softc *sc = rf->rf_sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct zyd_phy_pair r[] = ZYD_AL2230_PHY_BANDEDGE6; - uint32_t i; + u_int chan = ieee80211_chan2ieee(ic, c); - if ((chan == 1) || (chan == 11)) + if (chan == 1 || chan == 11) r[0].val = 0x12; - - for (i = 0; i < INDEXES(r); i++) - zyd_cfg_write16(sc, r[i].reg, r[i].val); + + for (i = 0; i < N(r); i++) + zyd_write16_m(sc, r[i].reg, r[i].val); +fail: + return (error); +#undef N } /* * AL7230B RF methods. */ -static void -zyd_cfg_rf_al7230b_switch_radio(struct zyd_softc *sc, uint8_t on) -{ - zyd_cfg_write16(sc, ZYD_CR11, on ? 0x00 : 0x04); - zyd_cfg_write16(sc, ZYD_CR251, on ? 0x3f : 0x2f); -} - -static void -zyd_cfg_rf_al7230b_init(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_al7230B_init(struct zyd_rf *rf) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini_1[] = ZYD_AL7230B_PHY_1; static const struct zyd_phy_pair phyini_2[] = ZYD_AL7230B_PHY_2; static const struct zyd_phy_pair phyini_3[] = ZYD_AL7230B_PHY_3; static const uint32_t rfini_1[] = ZYD_AL7230B_RF_1; static const uint32_t rfini_2[] = ZYD_AL7230B_RF_2; - uint32_t i; + int i, error; /* for AL7230B, PHY and RF need to be initialized in "phases" */ /* init RF-dependent PHY registers, part one */ - for (i = 0; i != INDEXES(phyini_1); i++) { - zyd_cfg_write16(sc, phyini_1[i].reg, phyini_1[i].val); - } + for (i = 0; i < N(phyini_1); i++) + zyd_write16_m(sc, phyini_1[i].reg, phyini_1[i].val); + /* init AL7230B radio, part one */ - for (i = 0; i != INDEXES(rfini_1); i++) { - zyd_cfg_rfwrite(sc, rfini_1[i]); + for (i = 0; i < N(rfini_1); i++) { + if ((error = zyd_rfwrite(sc, rfini_1[i])) != 0) + return (error); } /* init RF-dependent PHY registers, part two */ - for (i = 0; i != INDEXES(phyini_2); i++) { - zyd_cfg_write16(sc, phyini_2[i].reg, phyini_2[i].val); - } + for (i = 0; i < N(phyini_2); i++) + zyd_write16_m(sc, phyini_2[i].reg, phyini_2[i].val); + /* init AL7230B radio, part two */ - for (i = 0; i != INDEXES(rfini_2); i++) { - zyd_cfg_rfwrite(sc, rfini_2[i]); + for (i = 0; i < N(rfini_2); i++) { + if ((error = zyd_rfwrite(sc, rfini_2[i])) != 0) + return (error); } /* init RF-dependent PHY registers, part three */ - for (i = 0; i != INDEXES(phyini_3); i++) { - zyd_cfg_write16(sc, phyini_3[i].reg, phyini_3[i].val); - } + for (i = 0; i < N(phyini_3); i++) + zyd_write16_m(sc, phyini_3[i].reg, phyini_3[i].val); +fail: + return (error); +#undef N } -static void -zyd_cfg_rf_al7230b_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) +static int +zyd_al7230B_switch_radio(struct zyd_rf *rf, int on) { - static const struct { - uint32_t r1, r2; - } rfprog[] = ZYD_AL7230B_CHANTABLE; - static const uint32_t rfsc[] = ZYD_AL7230B_RF_SETCHANNEL; - uint32_t i; - - zyd_cfg_write16(sc, ZYD_CR240, 0x57); - zyd_cfg_write16(sc, ZYD_CR251, 0x2f); - - for (i = 0; i != INDEXES(rfsc); i++) { - zyd_cfg_rfwrite(sc, rfsc[i]); - } - - zyd_cfg_write16(sc, ZYD_CR128, 0x14); - zyd_cfg_write16(sc, ZYD_CR129, 0x12); - zyd_cfg_write16(sc, ZYD_CR130, 0x10); - zyd_cfg_write16(sc, ZYD_CR38, 0x38); - zyd_cfg_write16(sc, ZYD_CR136, 0xdf); - - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2); - zyd_cfg_rfwrite(sc, 0x3c9000); + int error; + struct zyd_softc *sc = rf->rf_sc; - zyd_cfg_write16(sc, ZYD_CR251, 0x3f); - zyd_cfg_write16(sc, ZYD_CR203, 0x06); - zyd_cfg_write16(sc, ZYD_CR240, 0x08); + zyd_write16_m(sc, ZYD_CR11, on ? 0x00 : 0x04); + zyd_write16_m(sc, ZYD_CR251, on ? 0x3f : 0x2f); +fail: + return (error); +} +static int +zyd_al7230B_set_channel(struct zyd_rf *rf, uint8_t chan) +{ +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; + static const struct { + uint32_t r1, r2; + } rfprog[] = ZYD_AL7230B_CHANTABLE; + static const uint32_t rfsc[] = ZYD_AL7230B_RF_SETCHANNEL; + int i, error; + + zyd_write16_m(sc, ZYD_CR240, 0x57); + zyd_write16_m(sc, ZYD_CR251, 0x2f); + + for (i = 0; i < N(rfsc); i++) { + if ((error = zyd_rfwrite(sc, rfsc[i])) != 0) + return (error); + } + + zyd_write16_m(sc, ZYD_CR128, 0x14); + zyd_write16_m(sc, ZYD_CR129, 0x12); + zyd_write16_m(sc, ZYD_CR130, 0x10); + zyd_write16_m(sc, ZYD_CR38, 0x38); + zyd_write16_m(sc, ZYD_CR136, 0xdf); + + error = zyd_rfwrite(sc, rfprog[chan - 1].r1); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, rfprog[chan - 1].r2); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, 0x3c9000); + if (error != 0) + goto fail; + + zyd_write16_m(sc, ZYD_CR251, 0x3f); + zyd_write16_m(sc, ZYD_CR203, 0x06); + zyd_write16_m(sc, ZYD_CR240, 0x08); +fail: + return (error); +#undef N } /* * AL2210 RF methods. */ -static void -zyd_cfg_rf_al2210_switch_radio(struct zyd_softc *sc, uint8_t on) -{ - -} - -static void -zyd_cfg_rf_al2210_init(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_al2210_init(struct zyd_rf *rf) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_AL2210_PHY; static const uint32_t rfini[] = ZYD_AL2210_RF; uint32_t tmp; - uint32_t i; + int i, error; - zyd_cfg_write32(sc, ZYD_CR18, 2); + zyd_write32_m(sc, ZYD_CR18, 2); /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); - } + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + /* init AL2210 radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); - } - zyd_cfg_write16(sc, ZYD_CR47, 0x1e); - zyd_cfg_read32(sc, ZYD_CR_RADIO_PD, &tmp); - zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp & ~1); - zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp | 1); - zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x05); - zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x00); - zyd_cfg_write16(sc, ZYD_CR47, 0x1e); - zyd_cfg_write32(sc, ZYD_CR18, 3); + for (i = 0; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); + } + zyd_write16_m(sc, ZYD_CR47, 0x1e); + zyd_read32_m(sc, ZYD_CR_RADIO_PD, &tmp); + zyd_write32_m(sc, ZYD_CR_RADIO_PD, tmp & ~1); + zyd_write32_m(sc, ZYD_CR_RADIO_PD, tmp | 1); + zyd_write32_m(sc, ZYD_CR_RFCFG, 0x05); + zyd_write32_m(sc, ZYD_CR_RFCFG, 0x00); + zyd_write16_m(sc, ZYD_CR47, 0x1e); + zyd_write32_m(sc, ZYD_CR18, 3); +fail: + return (error); +#undef N } -static void -zyd_cfg_rf_al2210_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) +static int +zyd_al2210_switch_radio(struct zyd_rf *rf, int on) { + /* vendor driver does nothing for this RF chip */ + + return (0); +} + +static int +zyd_al2210_set_channel(struct zyd_rf *rf, uint8_t chan) +{ + int error; + struct zyd_softc *sc = rf->rf_sc; static const uint32_t rfprog[] = ZYD_AL2210_CHANTABLE; uint32_t tmp; - zyd_cfg_write32(sc, ZYD_CR18, 2); - zyd_cfg_write16(sc, ZYD_CR47, 0x1e); - zyd_cfg_read32(sc, ZYD_CR_RADIO_PD, &tmp); - zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp & ~1); - zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp | 1); - zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x05); - zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x00); - zyd_cfg_write16(sc, ZYD_CR47, 0x1e); + zyd_write32_m(sc, ZYD_CR18, 2); + zyd_write16_m(sc, ZYD_CR47, 0x1e); + zyd_read32_m(sc, ZYD_CR_RADIO_PD, &tmp); + zyd_write32_m(sc, ZYD_CR_RADIO_PD, tmp & ~1); + zyd_write32_m(sc, ZYD_CR_RADIO_PD, tmp | 1); + zyd_write32_m(sc, ZYD_CR_RFCFG, 0x05); + zyd_write32_m(sc, ZYD_CR_RFCFG, 0x00); + zyd_write16_m(sc, ZYD_CR47, 0x1e); /* actually set the channel */ - zyd_cfg_rfwrite(sc, rfprog[channel - 1]); + error = zyd_rfwrite(sc, rfprog[chan - 1]); + if (error != 0) + goto fail; - zyd_cfg_write32(sc, ZYD_CR18, 3); + zyd_write32_m(sc, ZYD_CR18, 3); +fail: + return (error); } /* * GCT RF methods. */ -static void -zyd_cfg_rf_gct_switch_radio(struct zyd_softc *sc, uint8_t on) -{ - /* vendor driver does nothing for this RF chip */ -} - -static void -zyd_cfg_rf_gct_init(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_gct_init(struct zyd_rf *rf) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_GCT_PHY; static const uint32_t rfini[] = ZYD_GCT_RF; - uint32_t i; + int i, error; /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); - } + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + /* init cgt radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); + for (i = 0; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); } +fail: + return (error); +#undef N } -static void -zyd_cfg_rf_gct_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) +static int +zyd_gct_switch_radio(struct zyd_rf *rf, int on) { - static const uint32_t rfprog[] = ZYD_GCT_CHANTABLE; + /* vendor driver does nothing for this RF chip */ - zyd_cfg_rfwrite(sc, 0x1c0000); - zyd_cfg_rfwrite(sc, rfprog[channel - 1]); - zyd_cfg_rfwrite(sc, 0x1c0008); + return (0); } -/* - * Maxim RF methods. - */ -static void -zyd_cfg_rf_maxim_switch_radio(struct zyd_softc *sc, uint8_t on) +static int +zyd_gct_set_channel(struct zyd_rf *rf, uint8_t chan) { - /* vendor driver does nothing for this RF chip */ + int error; + struct zyd_softc *sc = rf->rf_sc; + static const uint32_t rfprog[] = ZYD_GCT_CHANTABLE; + error = zyd_rfwrite(sc, 0x1c0000); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, rfprog[chan - 1]); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, 0x1c0008); +fail: + return (error); } -static void -zyd_cfg_rf_maxim_init(struct zyd_softc *sc, struct zyd_rf *rf) +/* + * Maxim RF methods. + */ +static int +zyd_maxim_init(struct zyd_rf *rf) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_MAXIM_PHY; static const uint32_t rfini[] = ZYD_MAXIM_RF; uint16_t tmp; - uint32_t i; + int i, error; /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); - } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp & ~(1 << 4)); + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp & ~(1 << 4)); /* init maxim radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); + for (i = 0; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4)); + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); +fail: + return (error); +#undef N } -static void -zyd_cfg_rf_maxim_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) +static int +zyd_maxim_switch_radio(struct zyd_rf *rf, int on) { + + /* vendor driver does nothing for this RF chip */ + return (0); +} + +static int +zyd_maxim_set_channel(struct zyd_rf *rf, uint8_t chan) +{ +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_MAXIM_PHY; static const uint32_t rfini[] = ZYD_MAXIM_RF; static const struct { - uint32_t r1, r2; - } rfprog[] = ZYD_MAXIM_CHANTABLE; + uint32_t r1, r2; + } rfprog[] = ZYD_MAXIM_CHANTABLE; uint16_t tmp; - uint32_t i; + int i, error; /* * Do the same as we do when initializing it, except for the channel @@ -1647,69 +1553,84 @@ zyd_cfg_rf_maxim_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, */ /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); - } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp & ~(1 << 4)); + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp & ~(1 << 4)); /* first two values taken from the chantables */ - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2); + error = zyd_rfwrite(sc, rfprog[chan - 1].r1); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, rfprog[chan - 1].r2); + if (error != 0) + goto fail; /* init maxim radio - skipping the two first values */ - if (INDEXES(rfini) > 2) { - for (i = 2; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); - } + for (i = 2; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4)); + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); +fail: + return (error); +#undef N } /* * Maxim2 RF methods. */ -static void -zyd_cfg_rf_maxim2_switch_radio(struct zyd_softc *sc, uint8_t on) -{ - /* vendor driver does nothing for this RF chip */ -} - -static void -zyd_cfg_rf_maxim2_init(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_maxim2_init(struct zyd_rf *rf) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY; static const uint32_t rfini[] = ZYD_MAXIM2_RF; uint16_t tmp; - uint32_t i; + int i, error; /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); - } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp & ~(1 << 4)); + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp & ~(1 << 4)); /* init maxim2 radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); + for (i = 0; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4)); + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); +fail: + return (error); +#undef N } -static void -zyd_cfg_rf_maxim2_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) +static int +zyd_maxim2_switch_radio(struct zyd_rf *rf, int on) +{ + + /* vendor driver does nothing for this RF chip */ + return (0); +} + +static int +zyd_maxim2_set_channel(struct zyd_rf *rf, uint8_t chan) { +#define N(a) (sizeof(a) / sizeof((a)[0])) + struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY; static const uint32_t rfini[] = ZYD_MAXIM2_RF; static const struct { - uint32_t r1, r2; - } rfprog[] = ZYD_MAXIM2_CHANTABLE; + uint32_t r1, r2; + } rfprog[] = ZYD_MAXIM2_CHANTABLE; uint16_t tmp; - uint32_t i; + int i, error; /* * Do the same as we do when initializing it, except for the channel @@ -1717,237 +1638,277 @@ zyd_cfg_rf_maxim2_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, */ /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); - } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp & ~(1 << 4)); + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp & ~(1 << 4)); /* first two values taken from the chantables */ - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2); + error = zyd_rfwrite(sc, rfprog[chan - 1].r1); + if (error != 0) + goto fail; + error = zyd_rfwrite(sc, rfprog[chan - 1].r2); + if (error != 0) + goto fail; /* init maxim2 radio - skipping the two first values */ - if (INDEXES(rfini) > 2) { - for (i = 2; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); - } + for (i = 2; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4)); + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); +fail: + return (error); +#undef N } -/* - * Assign drivers and init the RF - */ -static uint8_t -zyd_cfg_rf_init_hw(struct zyd_softc *sc, struct zyd_rf *rf) +static int +zyd_rf_attach(struct zyd_softc *sc, uint8_t type) { - ; /* fix for indent */ + struct zyd_rf *rf = &sc->sc_rf; - switch (sc->sc_rf_rev) { + rf->rf_sc = sc; + + switch (type) { case ZYD_RF_RFMD: - rf->cfg_init_hw = zyd_cfg_rf_rfmd_init; - rf->cfg_switch_radio = zyd_cfg_rf_rfmd_switch_radio; - rf->cfg_set_channel = zyd_cfg_rf_rfmd_set_channel; - rf->width = 24; /* 24-bit RF values */ + rf->init = zyd_rfmd_init; + rf->switch_radio = zyd_rfmd_switch_radio; + rf->set_channel = zyd_rfmd_set_channel; + rf->width = 24; /* 24-bit RF values */ break; case ZYD_RF_AL2230: case ZYD_RF_AL2230S: - if (sc->sc_mac_rev == ZYD_ZD1211B) { - rf->cfg_init_hw = zyd_cfg_rf_al2230_init_b; - rf->cfg_set_channel = zyd_cfg_rf_al2230_set_channel_b; + if (sc->sc_macrev == ZYD_ZD1211B) { + rf->init = zyd_al2230_init_b; + rf->set_channel = zyd_al2230_set_channel_b; } else { - rf->cfg_init_hw = zyd_cfg_rf_al2230_init; - rf->cfg_set_channel = zyd_cfg_rf_al2230_set_channel; + rf->init = zyd_al2230_init; + rf->set_channel = zyd_al2230_set_channel; } - rf->cfg_switch_radio = zyd_cfg_rf_al2230_switch_radio; - rf->cfg_bandedge6 = zyd_cfg_rf_al2230_bandedge6; - rf->width = 24; /* 24-bit RF values */ + rf->switch_radio = zyd_al2230_switch_radio; + rf->bandedge6 = zyd_al2230_bandedge6; + rf->width = 24; /* 24-bit RF values */ break; case ZYD_RF_AL7230B: - rf->cfg_init_hw = zyd_cfg_rf_al7230b_init; - rf->cfg_switch_radio = zyd_cfg_rf_al7230b_switch_radio; - rf->cfg_set_channel = zyd_cfg_rf_al7230b_set_channel; - rf->width = 24; /* 24-bit RF values */ + rf->init = zyd_al7230B_init; + rf->switch_radio = zyd_al7230B_switch_radio; + rf->set_channel = zyd_al7230B_set_channel; + rf->width = 24; /* 24-bit RF values */ break; case ZYD_RF_AL2210: - rf->cfg_init_hw = zyd_cfg_rf_al2210_init; - rf->cfg_switch_radio = zyd_cfg_rf_al2210_switch_radio; - rf->cfg_set_channel = zyd_cfg_rf_al2210_set_channel; - rf->width = 24; /* 24-bit RF values */ + rf->init = zyd_al2210_init; + rf->switch_radio = zyd_al2210_switch_radio; + rf->set_channel = zyd_al2210_set_channel; + rf->width = 24; /* 24-bit RF values */ break; case ZYD_RF_GCT: - rf->cfg_init_hw = zyd_cfg_rf_gct_init; - rf->cfg_switch_radio = zyd_cfg_rf_gct_switch_radio; - rf->cfg_set_channel = zyd_cfg_rf_gct_set_channel; - rf->width = 21; /* 21-bit RF values */ + rf->init = zyd_gct_init; + rf->switch_radio = zyd_gct_switch_radio; + rf->set_channel = zyd_gct_set_channel; + rf->width = 21; /* 21-bit RF values */ break; case ZYD_RF_MAXIM_NEW: - rf->cfg_init_hw = zyd_cfg_rf_maxim_init; - rf->cfg_switch_radio = zyd_cfg_rf_maxim_switch_radio; - rf->cfg_set_channel = zyd_cfg_rf_maxim_set_channel; - rf->width = 18; /* 18-bit RF values */ + rf->init = zyd_maxim_init; + rf->switch_radio = zyd_maxim_switch_radio; + rf->set_channel = zyd_maxim_set_channel; + rf->width = 18; /* 18-bit RF values */ break; case ZYD_RF_MAXIM_NEW2: - rf->cfg_init_hw = zyd_cfg_rf_maxim2_init; - rf->cfg_switch_radio = zyd_cfg_rf_maxim2_switch_radio; - rf->cfg_set_channel = zyd_cfg_rf_maxim2_set_channel; - rf->width = 18; /* 18-bit RF values */ + rf->init = zyd_maxim2_init; + rf->switch_radio = zyd_maxim2_switch_radio; + rf->set_channel = zyd_maxim2_set_channel; + rf->width = 18; /* 18-bit RF values */ break; default: - DPRINTFN(0, "%s: Sorry, radio %s is not supported yet\n", - sc->sc_name, zyd_rf_name(sc->sc_rf_rev)); - return (1); + device_printf(sc->sc_dev, + "sorry, radio \"%s\" is not supported yet\n", + zyd_rf_name(type)); + return (EINVAL); } + return (0); +} - zyd_cfg_lock_phy(sc); - (rf->cfg_init_hw) (sc, rf); - zyd_cfg_unlock_phy(sc); +static const char * +zyd_rf_name(uint8_t type) +{ + static const char * const zyd_rfs[] = { + "unknown", "unknown", "UW2451", "UCHIP", "AL2230", + "AL7230B", "THETA", "AL2210", "MAXIM_NEW", "GCT", + "AL2230S", "RALINK", "INTERSIL", "RFMD", "MAXIM_NEW2", + "PHILIPS" + }; - return (0); /* success */ + return zyd_rfs[(type > 15) ? 0 : type]; } -/* - * Init the hardware - */ -static uint8_t -zyd_cfg_hw_init(struct zyd_softc *sc) +static int +zyd_hw_init(struct zyd_softc *sc) { + int error; const struct zyd_phy_pair *phyp; - uint32_t tmp; + struct zyd_rf *rf = &sc->sc_rf; + uint16_t val; /* specify that the plug and play is finished */ - zyd_cfg_write32(sc, ZYD_MAC_AFTER_PNP, 1); - - zyd_cfg_read16(sc, ZYD_FIRMWARE_BASE_ADDR, &sc->sc_firmware_base); - DPRINTF("firmware base address=0x%04x\n", sc->sc_firmware_base); + zyd_write32_m(sc, ZYD_MAC_AFTER_PNP, 1); + zyd_read16_m(sc, ZYD_FIRMWARE_BASE_ADDR, &sc->sc_fwbase); + DPRINTF(sc, ZYD_DEBUG_FW, "firmware base address=0x%04x\n", + sc->sc_fwbase); /* retrieve firmware revision number */ - zyd_cfg_read16(sc, sc->sc_firmware_base + ZYD_FW_FIRMWARE_REV, &sc->sc_fw_rev); - - zyd_cfg_write32(sc, ZYD_CR_GPI_EN, 0); - zyd_cfg_write32(sc, ZYD_MAC_CONT_WIN_LIMIT, 0x7f043f); - + zyd_read16_m(sc, sc->sc_fwbase + ZYD_FW_FIRMWARE_REV, &sc->sc_fwrev); + zyd_write32_m(sc, ZYD_CR_GPI_EN, 0); + zyd_write32_m(sc, ZYD_MAC_CONT_WIN_LIMIT, 0x7f043f); /* set mandatory rates - XXX assumes 802.11b/g */ - zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x150f); + zyd_write32_m(sc, ZYD_MAC_MAN_RATE, 0x150f); /* disable interrupts */ - zyd_cfg_write32(sc, ZYD_CR_INTERRUPT, 0); + zyd_write32_m(sc, ZYD_CR_INTERRUPT, 0); - /* PHY init */ - zyd_cfg_lock_phy(sc); - phyp = (sc->sc_mac_rev == ZYD_ZD1211B) ? zyd_def_phyB : zyd_def_phy; - for (; phyp->reg != 0; phyp++) { - zyd_cfg_write16(sc, phyp->reg, phyp->val); + if ((error = zyd_read_pod(sc)) != 0) { + device_printf(sc->sc_dev, "could not read EEPROM\n"); + goto fail; } - if ((sc->sc_mac_rev == ZYD_ZD1211) && sc->sc_fix_cr157) { - zyd_cfg_read32(sc, ZYD_EEPROM_PHY_REG, &tmp); - zyd_cfg_write32(sc, ZYD_CR157, tmp >> 8); + + /* PHY init (resetting) */ + error = zyd_lock_phy(sc); + if (error != 0) + goto fail; + phyp = (sc->sc_macrev == ZYD_ZD1211B) ? zyd_def_phyB : zyd_def_phy; + for (; phyp->reg != 0; phyp++) + zyd_write16_m(sc, phyp->reg, phyp->val); + if (sc->sc_macrev == ZYD_ZD1211 && sc->sc_fix_cr157 != 0) { + zyd_read16_m(sc, ZYD_EEPROM_PHY_REG, &val); + zyd_write32_m(sc, ZYD_CR157, val >> 8); } - zyd_cfg_unlock_phy(sc); + error = zyd_unlock_phy(sc); + if (error != 0) + goto fail; /* HMAC init */ - zyd_cfg_write32(sc, ZYD_MAC_ACK_EXT, 0x00000020); - zyd_cfg_write32(sc, ZYD_CR_ADDA_MBIAS_WT, 0x30000808); - zyd_cfg_write32(sc, ZYD_MAC_SNIFFER, 0x00000000); - zyd_cfg_write32(sc, ZYD_MAC_RXFILTER, 0x00000000); - zyd_cfg_write32(sc, ZYD_MAC_GHTBL, 0x00000000); - zyd_cfg_write32(sc, ZYD_MAC_GHTBH, 0x80000000); - zyd_cfg_write32(sc, ZYD_MAC_MISC, 0x000000a4); - zyd_cfg_write32(sc, ZYD_CR_ADDA_PWR_DWN, 0x0000007f); - zyd_cfg_write32(sc, ZYD_MAC_BCNCFG, 0x00f00401); - zyd_cfg_write32(sc, ZYD_MAC_PHY_DELAY2, 0x00000000); - zyd_cfg_write32(sc, ZYD_MAC_ACK_EXT, 0x00000080); - zyd_cfg_write32(sc, ZYD_CR_ADDA_PWR_DWN, 0x00000000); - zyd_cfg_write32(sc, ZYD_MAC_SIFS_ACK_TIME, 0x00000100); - zyd_cfg_write32(sc, ZYD_CR_RX_PE_DELAY, 0x00000070); - zyd_cfg_write32(sc, ZYD_CR_PS_CTRL, 0x10000000); - zyd_cfg_write32(sc, ZYD_MAC_RTSCTSRATE, 0x02030203); - zyd_cfg_write32(sc, ZYD_MAC_AFTER_PNP, 1); - zyd_cfg_write32(sc, ZYD_MAC_BACKOFF_PROTECT, 0x00000114); - zyd_cfg_write32(sc, ZYD_MAC_DIFS_EIFS_SIFS, 0x0a47c032); - zyd_cfg_write32(sc, ZYD_MAC_CAM_MODE, 0x3); - - if (sc->sc_mac_rev == ZYD_ZD1211) { - zyd_cfg_write32(sc, ZYD_MAC_RETRY, 0x00000002); - zyd_cfg_write32(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0640); + zyd_write32_m(sc, ZYD_MAC_ACK_EXT, 0x00000020); + zyd_write32_m(sc, ZYD_CR_ADDA_MBIAS_WT, 0x30000808); + zyd_write32_m(sc, ZYD_MAC_SNIFFER, 0x00000000); + zyd_write32_m(sc, ZYD_MAC_RXFILTER, 0x00000000); + zyd_write32_m(sc, ZYD_MAC_GHTBL, 0x00000000); + zyd_write32_m(sc, ZYD_MAC_GHTBH, 0x80000000); + zyd_write32_m(sc, ZYD_MAC_MISC, 0x000000a4); + zyd_write32_m(sc, ZYD_CR_ADDA_PWR_DWN, 0x0000007f); + zyd_write32_m(sc, ZYD_MAC_BCNCFG, 0x00f00401); + zyd_write32_m(sc, ZYD_MAC_PHY_DELAY2, 0x00000000); + zyd_write32_m(sc, ZYD_MAC_ACK_EXT, 0x00000080); + zyd_write32_m(sc, ZYD_CR_ADDA_PWR_DWN, 0x00000000); + zyd_write32_m(sc, ZYD_MAC_SIFS_ACK_TIME, 0x00000100); + zyd_write32_m(sc, ZYD_CR_RX_PE_DELAY, 0x00000070); + zyd_write32_m(sc, ZYD_CR_PS_CTRL, 0x10000000); + zyd_write32_m(sc, ZYD_MAC_RTSCTSRATE, 0x02030203); + zyd_write32_m(sc, ZYD_MAC_AFTER_PNP, 1); + zyd_write32_m(sc, ZYD_MAC_BACKOFF_PROTECT, 0x00000114); + zyd_write32_m(sc, ZYD_MAC_DIFS_EIFS_SIFS, 0x0a47c032); + zyd_write32_m(sc, ZYD_MAC_CAM_MODE, 0x3); + + if (sc->sc_macrev == ZYD_ZD1211) { + zyd_write32_m(sc, ZYD_MAC_RETRY, 0x00000002); + zyd_write32_m(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0640); } else { - zyd_cfg_write32(sc, ZYD_MACB_MAX_RETRY, 0x02020202); - zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL4, 0x007f003f); - zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL3, 0x007f003f); - zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL2, 0x003f001f); - zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL1, 0x001f000f); - zyd_cfg_write32(sc, ZYD_MACB_AIFS_CTL1, 0x00280028); - zyd_cfg_write32(sc, ZYD_MACB_AIFS_CTL2, 0x008C003C); - zyd_cfg_write32(sc, ZYD_MACB_TXOP, 0x01800824); - zyd_cfg_write32(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0eff); + zyd_write32_m(sc, ZYD_MACB_MAX_RETRY, 0x02020202); + zyd_write32_m(sc, ZYD_MACB_TXPWR_CTL4, 0x007f003f); + zyd_write32_m(sc, ZYD_MACB_TXPWR_CTL3, 0x007f003f); + zyd_write32_m(sc, ZYD_MACB_TXPWR_CTL2, 0x003f001f); + zyd_write32_m(sc, ZYD_MACB_TXPWR_CTL1, 0x001f000f); + zyd_write32_m(sc, ZYD_MACB_AIFS_CTL1, 0x00280028); + zyd_write32_m(sc, ZYD_MACB_AIFS_CTL2, 0x008C003C); + zyd_write32_m(sc, ZYD_MACB_TXOP, 0x01800824); + zyd_write32_m(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0eff); } /* init beacon interval to 100ms */ - zyd_cfg_set_beacon_interval(sc, 100); + if ((error = zyd_set_beacon_interval(sc, 100)) != 0) + goto fail; + + if ((error = zyd_rf_attach(sc, sc->sc_rfrev)) != 0) { + device_printf(sc->sc_dev, "could not attach RF, rev 0x%x\n", + sc->sc_rfrev); + goto fail; + } + + /* RF chip init */ + error = zyd_lock_phy(sc); + if (error != 0) + goto fail; + error = (*rf->init)(rf); + if (error != 0) { + device_printf(sc->sc_dev, + "radio initialization failed, error %d\n", error); + goto fail; + } + error = zyd_unlock_phy(sc); + if (error != 0) + goto fail; - return (0); /* success */ + if ((error = zyd_read_eeprom(sc)) != 0) { + device_printf(sc->sc_dev, "could not read EEPROM\n"); + goto fail; + } + +fail: return (error); } -/* - * Read information from EEPROM - */ -static void -zyd_cfg_read_eeprom(struct zyd_softc *sc) +static int +zyd_read_pod(struct zyd_softc *sc) { + int error; uint32_t tmp; - uint16_t i; - uint16_t val; - - /* read MAC address */ - zyd_cfg_get_macaddr(sc); - /* read product data */ - zyd_cfg_read32(sc, ZYD_EEPROM_POD, &tmp); - sc->sc_rf_rev = tmp & 0x0f; - sc->sc_ledtype = (tmp >> 4) & 0x01; - sc->sc_cckgain = (tmp >> 8) & 0x01; + zyd_read32_m(sc, ZYD_EEPROM_POD, &tmp); + sc->sc_rfrev = tmp & 0x0f; + sc->sc_ledtype = (tmp >> 4) & 0x01; + sc->sc_al2230s = (tmp >> 7) & 0x01; + sc->sc_cckgain = (tmp >> 8) & 0x01; sc->sc_fix_cr157 = (tmp >> 13) & 0x01; - sc->sc_pa_rev = (tmp >> 16) & 0x0f; - sc->sc_al2230s = (tmp >> 7) & 0x01; + sc->sc_parev = (tmp >> 16) & 0x0f; sc->sc_bandedge6 = (tmp >> 21) & 0x01; - sc->sc_newphy = (tmp >> 31) & 0x01; - sc->sc_txled = ((tmp & (1 << 24)) && (tmp & (1 << 29))) ? 0 : 1; + sc->sc_newphy = (tmp >> 31) & 0x01; + sc->sc_txled = ((tmp & (1 << 24)) && (tmp & (1 << 29))) ? 0 : 1; +fail: + return (error); +} - /* read regulatory domain (currently unused) */ - zyd_cfg_read32(sc, ZYD_EEPROM_SUBID, &tmp); - sc->sc_regdomain = tmp >> 16; - DPRINTF("regulatory domain %x\n", sc->sc_regdomain); +static int +zyd_read_eeprom(struct zyd_softc *sc) +{ + uint16_t val; + int error, i; /* read Tx power calibration tables */ for (i = 0; i < 7; i++) { - zyd_cfg_read16(sc, ZYD_EEPROM_PWR_CAL + i, &val); - sc->sc_pwr_cal[(i * 2)] = val >> 8; - sc->sc_pwr_cal[(i * 2) + 1] = val & 0xff; - - zyd_cfg_read16(sc, ZYD_EEPROM_PWR_INT + i, &val); - sc->sc_pwr_int[(i * 2)] = val >> 8; - sc->sc_pwr_int[(i * 2) + 1] = val & 0xff; - - zyd_cfg_read16(sc, ZYD_EEPROM_36M_CAL + i, &val); - sc->sc_ofdm36_cal[(i * 2)] = val >> 8; - sc->sc_ofdm36_cal[(i * 2) + 1] = val & 0xff; - - zyd_cfg_read16(sc, ZYD_EEPROM_48M_CAL + i, &val); - sc->sc_ofdm48_cal[(i * 2)] = val >> 8; - sc->sc_ofdm48_cal[(i * 2) + 1] = val & 0xff; - - zyd_cfg_read16(sc, ZYD_EEPROM_54M_CAL + i, &val); - sc->sc_ofdm54_cal[(i * 2)] = val >> 8; - sc->sc_ofdm54_cal[(i * 2) + 1] = val & 0xff; - } + zyd_read16_m(sc, ZYD_EEPROM_PWR_CAL + i, &val); + sc->sc_pwrcal[i * 2] = val >> 8; + sc->sc_pwrcal[i * 2 + 1] = val & 0xff; + zyd_read16_m(sc, ZYD_EEPROM_PWR_INT + i, &val); + sc->sc_pwrint[i * 2] = val >> 8; + sc->sc_pwrint[i * 2 + 1] = val & 0xff; + zyd_read16_m(sc, ZYD_EEPROM_36M_CAL + i, &val); + sc->sc_ofdm36_cal[i * 2] = val >> 8; + sc->sc_ofdm36_cal[i * 2 + 1] = val & 0xff; + zyd_read16_m(sc, ZYD_EEPROM_48M_CAL + i, &val); + sc->sc_ofdm48_cal[i * 2] = val >> 8; + sc->sc_ofdm48_cal[i * 2 + 1] = val & 0xff; + zyd_read16_m(sc, ZYD_EEPROM_54M_CAL + i, &val); + sc->sc_ofdm54_cal[i * 2] = val >> 8; + sc->sc_ofdm54_cal[i * 2 + 1] = val & 0xff; + } +fail: + return (error); } -static void -zyd_cfg_get_macaddr(struct zyd_softc *sc) +static int +zyd_get_macaddr(struct zyd_softc *sc) { struct usb2_device_request req; + usb2_error_t error; req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = ZYD_READFWDATAREQ; @@ -1955,379 +1916,424 @@ zyd_cfg_get_macaddr(struct zyd_softc *sc) USETW(req.wIndex, 0); USETW(req.wLength, IEEE80211_ADDR_LEN); - zyd_cfg_usbrequest(sc, &req, sc->sc_myaddr); - return; + error = zyd_do_request(sc, &req, sc->sc_bssid); + if (error != 0) { + device_printf(sc->sc_dev, "could not read EEPROM: %s\n", + usb2_errstr(error)); + } + + return (error); } -static void -zyd_cfg_set_mac_addr(struct zyd_softc *sc, const uint8_t *addr) +static int +zyd_set_macaddr(struct zyd_softc *sc, const uint8_t *addr) { + int error; uint32_t tmp; - tmp = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; - zyd_cfg_write32(sc, ZYD_MAC_MACADRL, tmp); + tmp = addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]; + zyd_write32_m(sc, ZYD_MAC_MACADRL, tmp); + tmp = addr[5] << 8 | addr[4]; + zyd_write32_m(sc, ZYD_MAC_MACADRH, tmp); +fail: + return (error); +} + +static int +zyd_set_bssid(struct zyd_softc *sc, const uint8_t *addr) +{ + int error; + uint32_t tmp; - tmp = (addr[5] << 8) | addr[4]; - zyd_cfg_write32(sc, ZYD_MAC_MACADRH, tmp); + tmp = addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]; + zyd_write32_m(sc, ZYD_MAC_BSSADRL, tmp); + tmp = addr[5] << 8 | addr[4]; + zyd_write32_m(sc, ZYD_MAC_BSSADRH, tmp); +fail: + return (error); } -/* - * Switch radio on/off - */ -static void -zyd_cfg_switch_radio(struct zyd_softc *sc, uint8_t onoff) +static int +zyd_switch_radio(struct zyd_softc *sc, int on) { - zyd_cfg_lock_phy(sc); - (sc->sc_rf.cfg_switch_radio) (sc, onoff); - zyd_cfg_unlock_phy(sc); + struct zyd_rf *rf = &sc->sc_rf; + int error; + + error = zyd_lock_phy(sc); + if (error != 0) + goto fail; + error = (*rf->switch_radio)(rf, on); + if (error != 0) + goto fail; + error = zyd_unlock_phy(sc); +fail: + return (error); } -/* - * Set BSSID - */ -static void -zyd_cfg_set_bssid(struct zyd_softc *sc, uint8_t *addr) +static int +zyd_set_led(struct zyd_softc *sc, int which, int on) { + int error; uint32_t tmp; - tmp = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; - zyd_cfg_write32(sc, ZYD_MAC_BSSADRL, tmp); + zyd_read32_m(sc, ZYD_MAC_TX_PE_CONTROL, &tmp); + tmp &= ~which; + if (on) + tmp |= which; + zyd_write32_m(sc, ZYD_MAC_TX_PE_CONTROL, tmp); +fail: + return (error); +} - tmp = (addr[5] << 8) | addr[4]; - zyd_cfg_write32(sc, ZYD_MAC_BSSADRH, tmp); +static void +zyd_multitask(struct usb2_proc_msg *pm) +{ + struct zyd_task *task = (struct zyd_task *)pm; + struct zyd_softc *sc = task->sc; + + zyd_set_multi(sc); } -/* - * Complete the attach process - */ static void -zyd_cfg_first_time_setup(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) +zyd_set_multi(struct zyd_softc *sc) { - struct usb2_config_descriptor *cd; - struct ieee80211com *ic; - struct ifnet *ifp; - const uint8_t *fw_ptr; - uint32_t fw_len; - uint8_t bands; - usb2_error_t err; + int error; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ifmultiaddr *ifma; + uint32_t low, high; + uint8_t v; - /* setup RX tap header */ - sc->sc_rxtap_len = sizeof(sc->sc_rxtap); - sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); - sc->sc_rxtap.wr_ihdr.it_present = htole32(ZYD_RX_RADIOTAP_PRESENT); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; - /* setup TX tap header */ - sc->sc_txtap_len = sizeof(sc->sc_txtap); - sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); - sc->sc_txtap.wt_ihdr.it_present = htole32(ZYD_TX_RADIOTAP_PRESENT); + low = 0x00000000; + high = 0x80000000; - if (sc->sc_mac_rev == ZYD_ZD1211) { - fw_ptr = zd1211_firmware; - fw_len = sizeof(zd1211_firmware); + if (ic->ic_opmode == IEEE80211_M_MONITOR || + (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { + low = 0xffffffff; + high = 0xffffffff; } else { - fw_ptr = zd1211b_firmware; - fw_len = sizeof(zd1211b_firmware); + IF_ADDR_LOCK(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + v = ((uint8_t *)LLADDR((struct sockaddr_dl *) + ifma->ifma_addr))[5] >> 2; + if (v < 32) + low |= 1 << v; + else + high |= 1 << (v - 32); + } + IF_ADDR_UNLOCK(ifp); } - if (zyd_cfg_uploadfirmware(sc, fw_ptr, fw_len)) { - DPRINTFN(0, "%s: could not " - "upload firmware!\n", sc->sc_name); - return; - } - cd = usb2_get_config_descriptor(sc->sc_udev); + /* reprogram multicast global hash table */ + zyd_write32_m(sc, ZYD_MAC_GHTBL, low); + zyd_write32_m(sc, ZYD_MAC_GHTBH, high); +fail: + if (error != 0) + device_printf(sc->sc_dev, + "could not set multicast hash table\n"); +} - /* reset device */ - err = usb2_req_set_config(sc->sc_udev, &sc->sc_mtx, - cd->bConfigurationValue); - if (err) { - DPRINTF("reset failed (ignored)\n"); - } - /* Read MAC and other stuff rom EEPROM */ - zyd_cfg_read_eeprom(sc); +static void +zyd_update_mcast(struct ifnet *ifp) +{ + struct zyd_softc *sc = ifp->if_softc; - /* Init hardware */ - if (zyd_cfg_hw_init(sc)) { - DPRINTFN(0, "%s: HW init failed!\n", sc->sc_name); - return; - } - /* Now init the RF chip */ - if (zyd_cfg_rf_init_hw(sc, &sc->sc_rf)) { - DPRINTFN(0, "%s: RF init failed!\n", sc->sc_name); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; - } - printf("%s: HMAC ZD1211%s, FW %02x.%02x, RF %s, PA %x, address %02x:%02x:%02x:%02x:%02x:%02x\n", - sc->sc_name, (sc->sc_mac_rev == ZYD_ZD1211) ? "" : "B", - sc->sc_fw_rev >> 8, sc->sc_fw_rev & 0xff, zyd_rf_name(sc->sc_rf_rev), - sc->sc_pa_rev, sc->sc_myaddr[0], - sc->sc_myaddr[1], sc->sc_myaddr[2], - sc->sc_myaddr[3], sc->sc_myaddr[4], - sc->sc_myaddr[5]); - - mtx_unlock(&sc->sc_mtx); - ifp = if_alloc(IFT_IEEE80211); + ZYD_LOCK(sc); + zyd_queue_command(sc, zyd_multitask, + &sc->sc_mcasttask[0].hdr, &sc->sc_mcasttask[1].hdr); + ZYD_UNLOCK(sc); +} - mtx_lock(&sc->sc_mtx); +static int +zyd_set_rxfilter(struct zyd_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint32_t rxfilter; - if (ifp == NULL) { - DPRINTFN(0, "%s: could not if_alloc()!\n", - sc->sc_name); - goto done; + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + rxfilter = ZYD_FILTER_BSS; + break; + case IEEE80211_M_IBSS: + case IEEE80211_M_HOSTAP: + rxfilter = ZYD_FILTER_HOSTAP; + break; + case IEEE80211_M_MONITOR: + rxfilter = ZYD_FILTER_MONITOR; + break; + default: + /* should not get there */ + return (EINVAL); } - sc->sc_ifp = ifp; - ic = ifp->if_l2com; - - ifp->if_softc = sc; - if_initname(ifp, "zyd", sc->sc_unit); - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_init = &zyd_init_cb; - ifp->if_ioctl = &zyd_ioctl_cb; - ifp->if_start = &zyd_start_cb; - ifp->if_watchdog = NULL; - IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); - ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; - IFQ_SET_READY(&ifp->if_snd); - - bcopy(sc->sc_myaddr, ic->ic_myaddr, sizeof(ic->ic_myaddr)); - - ic->ic_ifp = ifp; - ic->ic_phytype = IEEE80211_T_OFDM; - ic->ic_opmode = IEEE80211_M_STA; - - /* Set device capabilities */ - ic->ic_caps = - IEEE80211_C_STA /* station mode supported */ - | IEEE80211_C_MONITOR /* monitor mode */ - | IEEE80211_C_SHPREAMBLE /* short preamble supported */ - | IEEE80211_C_SHSLOT /* short slot time supported */ - | IEEE80211_C_BGSCAN /* capable of bg scanning */ - | IEEE80211_C_WPA /* 802.11i */ - ; - - bands = 0; - setbit(&bands, IEEE80211_MODE_11B); - setbit(&bands, IEEE80211_MODE_11G); - ieee80211_init_channels(ic, NULL, &bands); - - mtx_unlock(&sc->sc_mtx); - - ieee80211_ifattach(ic); + return zyd_write32(sc, ZYD_MAC_RXFILTER, rxfilter); +} - mtx_lock(&sc->sc_mtx); +static void +zyd_set_chan(struct zyd_softc *sc, struct ieee80211_channel *c) +{ + int error; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct zyd_rf *rf = &sc->sc_rf; + uint32_t tmp; + u_int chan; - ic->ic_node_alloc = &zyd_node_alloc_cb; - ic->ic_raw_xmit = &zyd_raw_xmit_cb; - ic->ic_newassoc = &zyd_newassoc_cb; + chan = ieee80211_chan2ieee(ic, c); + if (chan == 0 || chan == IEEE80211_CHAN_ANY) { + /* XXX should NEVER happen */ + device_printf(sc->sc_dev, + "%s: invalid channel %x\n", __func__, chan); + return; + } - ic->ic_scan_start = &zyd_scan_start_cb; - ic->ic_scan_end = &zyd_scan_end_cb; - ic->ic_set_channel = &zyd_set_channel_cb; - ic->ic_vap_create = &zyd_vap_create; - ic->ic_vap_delete = &zyd_vap_delete; - ic->ic_update_mcast = &zyd_update_mcast_cb; - ic->ic_update_promisc = &zyd_update_promisc_cb; + error = zyd_lock_phy(sc); + if (error != 0) + goto fail; - sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); + error = (*rf->set_channel)(rf, chan); + if (error != 0) + goto fail; - mtx_unlock(&sc->sc_mtx); + /* update Tx power */ + zyd_write16_m(sc, ZYD_CR31, sc->sc_pwrint[chan - 1]); - bpfattach(ifp, DLT_IEEE802_11_RADIO, - sizeof(struct ieee80211_frame) + - sizeof(sc->sc_txtap)); + if (sc->sc_macrev == ZYD_ZD1211B) { + zyd_write16_m(sc, ZYD_CR67, sc->sc_ofdm36_cal[chan - 1]); + zyd_write16_m(sc, ZYD_CR66, sc->sc_ofdm48_cal[chan - 1]); + zyd_write16_m(sc, ZYD_CR65, sc->sc_ofdm54_cal[chan - 1]); + zyd_write16_m(sc, ZYD_CR68, sc->sc_pwrcal[chan - 1]); + zyd_write16_m(sc, ZYD_CR69, 0x28); + zyd_write16_m(sc, ZYD_CR69, 0x2a); + } + if (sc->sc_cckgain) { + /* set CCK baseband gain from EEPROM */ + if (zyd_read32(sc, ZYD_EEPROM_PHY_REG, &tmp) == 0) + zyd_write16_m(sc, ZYD_CR47, tmp & 0xff); + } + if (sc->sc_bandedge6 && rf->bandedge6 != NULL) { + error = (*rf->bandedge6)(rf, c); + if (error != 0) + goto fail; + } + zyd_write32_m(sc, ZYD_CR_CONFIG_PHILIPS, 0); - mtx_lock(&sc->sc_mtx); + error = zyd_unlock_phy(sc); + if (error != 0) + goto fail; - if (bootverbose) { - ieee80211_announce(ic); - } - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_DT_RD]); -done: + sc->sc_rxtap.wr_chan_freq = sc->sc_txtap.wt_chan_freq = + htole16(c->ic_freq); + sc->sc_rxtap.wr_chan_flags = sc->sc_txtap.wt_chan_flags = + htole16(c->ic_flags); +fail: return; } -/* - * Detach device - */ static int -zyd_detach(device_t dev) +zyd_set_beacon_interval(struct zyd_softc *sc, int bintval) { - struct zyd_softc *sc = device_get_softc(dev); - struct ieee80211com *ic; - struct ifnet *ifp; - - usb2_config_td_drain(&sc->sc_config_td); + int error; + uint32_t val; - mtx_lock(&sc->sc_mtx); + zyd_read32_m(sc, ZYD_CR_ATIM_WND_PERIOD, &val); + sc->sc_atim_wnd = val; + zyd_read32_m(sc, ZYD_CR_PRE_TBTT, &val); + sc->sc_pre_tbtt = val; + sc->sc_bcn_int = bintval; - usb2_callout_stop(&sc->sc_watchdog); + if (sc->sc_bcn_int <= 5) + sc->sc_bcn_int = 5; + if (sc->sc_pre_tbtt < 4 || sc->sc_pre_tbtt >= sc->sc_bcn_int) + sc->sc_pre_tbtt = sc->sc_bcn_int - 1; + if (sc->sc_atim_wnd >= sc->sc_pre_tbtt) + sc->sc_atim_wnd = sc->sc_pre_tbtt - 1; - zyd_cfg_pre_stop(sc, NULL, 0); + zyd_write32_m(sc, ZYD_CR_ATIM_WND_PERIOD, sc->sc_atim_wnd); + zyd_write32_m(sc, ZYD_CR_PRE_TBTT, sc->sc_pre_tbtt); + zyd_write32_m(sc, ZYD_CR_BCN_INTERVAL, sc->sc_bcn_int); +fail: + return (error); +} - ifp = sc->sc_ifp; - ic = ifp->if_l2com; +static void +zyd_rx_data(struct usb2_xfer *xfer, int offset, uint16_t len) +{ + struct zyd_softc *sc = xfer->priv_sc; + struct ifnet *ifp = sc->sc_ifp; + struct zyd_plcphdr plcp; + struct zyd_rx_stat stat; + struct mbuf *m; + int rlen, rssi; - mtx_unlock(&sc->sc_mtx); + if (len < ZYD_MIN_FRAGSZ) { + DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too short (length=%d)\n", + device_get_nameunit(sc->sc_dev), len); + ifp->if_ierrors++; + return; + } + usb2_copy_out(xfer->frbuffers, offset, &plcp, sizeof(plcp)); + usb2_copy_out(xfer->frbuffers, offset + len - sizeof(stat), + &stat, sizeof(stat)); - /* stop all USB transfers first */ - usb2_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); + if (stat.flags & ZYD_RX_ERROR) { + DPRINTF(sc, ZYD_DEBUG_RECV, + "%s: RX status indicated error (%x)\n", + device_get_nameunit(sc->sc_dev), stat.flags); + ifp->if_ierrors++; + return; + } - /* get rid of any late children */ - bus_generic_detach(dev); + /* compute actual frame length */ + rlen = len - sizeof(struct zyd_plcphdr) - + sizeof(struct zyd_rx_stat) - IEEE80211_CRC_LEN; - if (ifp) { - bpfdetach(ifp); - ieee80211_ifdetach(ic); - if_free(ifp); + /* allocate a mbuf to store the frame */ + if (rlen > MCLBYTES) { + DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too long (length=%d)\n", + device_get_nameunit(sc->sc_dev), rlen); + ifp->if_ierrors++; + return; + } else if (rlen > MHLEN) + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + else + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) { + DPRINTF(sc, ZYD_DEBUG_RECV, "%s: could not allocate rx mbuf\n", + device_get_nameunit(sc->sc_dev)); + ifp->if_ierrors++; + return; } - usb2_config_td_unsetup(&sc->sc_config_td); + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = rlen; + usb2_copy_out(xfer->frbuffers, offset + sizeof(plcp), + mtod(m, uint8_t *), rlen); - usb2_callout_drain(&sc->sc_watchdog); + if (bpf_peers_present(ifp->if_bpf)) { + struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap; - usb2_cv_destroy(&sc->sc_intr_cv); + tap->wr_flags = 0; + if (stat.flags & (ZYD_RX_BADCRC16 | ZYD_RX_BADCRC32)) + tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; + /* XXX toss, no way to express errors */ + if (stat.flags & ZYD_RX_DECRYPTERR) + tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; + tap->wr_rate = ieee80211_plcp2rate(plcp.signal, + (stat.flags & ZYD_RX_OFDM) ? + IEEE80211_T_OFDM : IEEE80211_T_CCK); + tap->wr_antsignal = stat.rssi + -95; + tap->wr_antnoise = -95; /* XXX */ - mtx_destroy(&sc->sc_mtx); + bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); + } + rssi = (stat.rssi > 63) ? 127 : 2 * stat.rssi; - return (0); + sc->sc_rx_data[sc->sc_rx_count].rssi = rssi; + sc->sc_rx_data[sc->sc_rx_count].m = m; + sc->sc_rx_count++; } static void -zyd_cfg_newstate(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) +zyd_bulk_read_callback(struct usb2_xfer *xfer) { + struct zyd_softc *sc = xfer->priv_sc; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct zyd_vap *uvp = ZYD_VAP(vap); - enum ieee80211_state ostate; - enum ieee80211_state nstate; - int arg; - - ostate = vap->iv_state; - nstate = sc->sc_ns_state; - arg = sc->sc_ns_arg; - - switch (nstate) { - case IEEE80211_S_INIT: - break; - - case IEEE80211_S_RUN: - zyd_cfg_set_run(sc, cc); - break; - - default: - break; - } - - mtx_unlock(&sc->sc_mtx); - IEEE80211_LOCK(ic); - uvp->newstate(vap, nstate, arg); - if (vap->iv_newstate_cb != NULL) - vap->iv_newstate_cb(vap, nstate, arg); - IEEE80211_UNLOCK(ic); - mtx_lock(&sc->sc_mtx); -} + struct ieee80211_node *ni; + struct zyd_rx_desc desc; + struct mbuf *m; + uint32_t offset; + uint8_t rssi; + int8_t nf; + int i; -static void -zyd_cfg_set_run(struct zyd_softc *sc, - struct usb2_config_td_cc *cc) -{ - zyd_cfg_set_chan(sc, cc, 0); + sc->sc_rx_count = 0; + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + usb2_copy_out(xfer->frbuffers, xfer->actlen - sizeof(desc), + &desc, sizeof(desc)); - if (cc->ic_opmode != IEEE80211_M_MONITOR) { - /* turn link LED on */ - zyd_cfg_set_led(sc, ZYD_LED1, 1); + offset = 0; + if (UGETW(desc.tag) == ZYD_TAG_MULTIFRAME) { + DPRINTF(sc, ZYD_DEBUG_RECV, + "%s: received multi-frame transfer\n", __func__); - /* make data LED blink upon Tx */ - zyd_cfg_write32(sc, sc->sc_firmware_base + ZYD_FW_LINK_STATUS, 1); + for (i = 0; i < ZYD_MAX_RXFRAMECNT; i++) { + uint16_t len16 = UGETW(desc.len[i]); - zyd_cfg_set_bssid(sc, cc->iv_bss.ni_bssid); - } - if (cc->iv_bss.fixed_rate_none) { - /* enable automatic rate adaptation */ - zyd_cfg_amrr_start(sc); - } -} + if (len16 == 0 || len16 > xfer->actlen) + break; -static int -zyd_newstate_cb(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) -{ - struct zyd_vap *uvp = ZYD_VAP(vap); - struct ieee80211com *ic = vap->iv_ic; - struct zyd_softc *sc = ic->ic_ifp->if_softc; + zyd_rx_data(xfer, offset, len16); - DPRINTF("setting new state: %d\n", nstate); + /* next frame is aligned on a 32-bit boundary */ + len16 = (len16 + 3) & ~3; + offset += len16; + if (len16 > xfer->actlen) + break; + xfer->actlen -= len16; + } + } else { + DPRINTF(sc, ZYD_DEBUG_RECV, + "%s: received single-frame transfer\n", __func__); - mtx_lock(&sc->sc_mtx); - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - mtx_unlock(&sc->sc_mtx); - /* Special case which happens at detach. */ - if (nstate == IEEE80211_S_INIT) { - (uvp->newstate) (vap, nstate, arg); + zyd_rx_data(xfer, 0, xfer->actlen); } - return (0); /* nothing to do */ - } - /* store next state */ - sc->sc_ns_state = nstate; - sc->sc_ns_arg = arg; - - /* stop timers */ - sc->sc_amrr_timer = 0; + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + xfer->frlengths[0] = xfer->max_data_length; + usb2_start_hardware(xfer); - /* - * USB configuration can only be done from the USB configuration - * thread: - */ - usb2_config_td_queue_command - (&sc->sc_config_td, &zyd_config_copy, - &zyd_cfg_newstate, 0, 0); + /* + * At the end of a USB callback it is always safe to unlock + * the private mutex of a device! That is why we do the + * "ieee80211_input" here, and not some lines up! + */ + ZYD_UNLOCK(sc); + for (i = 0; i < sc->sc_rx_count; i++) { + rssi = sc->sc_rx_data[i].rssi; + m = sc->sc_rx_data[i].m; + sc->sc_rx_data[i].m = NULL; - mtx_unlock(&sc->sc_mtx); + nf = -95; /* XXX */ - return EINPROGRESS; -} + ni = ieee80211_find_rxnode(ic, + mtod(m, struct ieee80211_frame_min *)); + if (ni != NULL) { + (void)ieee80211_input(ni, m, rssi, nf, 0); + ieee80211_free_node(ni); + } else + (void)ieee80211_input_all(ic, m, rssi, nf, 0); + } + ZYD_LOCK(sc); + break; -static void -zyd_cfg_update_promisc(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t low; - uint32_t high; + default: /* Error */ + DPRINTF(sc, ZYD_DEBUG_ANY, "frame error: %s\n", usb2_errstr(xfer->error)); - if ((cc->ic_opmode == IEEE80211_M_MONITOR) || - (cc->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { - low = 0xffffffff; - high = 0xffffffff; - } else { - low = cc->zyd_multi_low; - high = cc->zyd_multi_high; + if (xfer->error != USB_ERR_CANCELLED) { + /* try to clear stall first */ + xfer->flags.stall_pipe = 1; + goto tr_setup; + } + break; } - - /* reprogram multicast global hash table */ - zyd_cfg_write32(sc, ZYD_MAC_GHTBL, low); - zyd_cfg_write32(sc, ZYD_MAC_GHTBH, high); } -/* - * Rate-to-bit-converter (Field "rate" in zyd_controlsetformat) - */ static uint8_t -zyd_plcp_signal(uint8_t rate) +zyd_plcp_signal(int rate) { - ; /* fix for indent */ - switch (rate) { - /* CCK rates (NB: not IEEE std, device-specific) */ - case 2: - return (0x0); - case 4: - return (0x1); - case 11: - return (0x2); - case 22: - return (0x3); - - /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ + /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ case 12: return (0xb); case 18: @@ -2344,1032 +2350,771 @@ zyd_plcp_signal(uint8_t rate) return (0x8); case 108: return (0xc); - - /* XXX unsupported/unknown rate */ - default: - return (0xff); + /* CCK rates (NB: not IEEE std, device-specific) */ + case 2: + return (0x0); + case 4: + return (0x1); + case 11: + return (0x2); + case 22: + return (0x3); } + return (0xff); /* XXX unsupported/unknown rate */ } -static void -zyd_std_command(struct ieee80211com *ic, usb2_config_td_command_t *func) +static int +zyd_tx_mgt(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - struct zyd_softc *sc = ic->ic_ifp->if_softc; - - mtx_lock(&sc->sc_mtx); + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = sc->sc_ifp; + struct zyd_tx_desc *desc; + struct zyd_tx_data *data; + struct ieee80211_frame *wh; + struct ieee80211_key *k; + int rate, totlen; + uint16_t pktlen; - sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + desc = &data->desc; - usb2_config_td_queue_command - (&sc->sc_config_td, &zyd_config_copy, func, 0, 0); + rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; - mtx_unlock(&sc->sc_mtx); -} + wh = mtod(m0, struct ieee80211_frame *); -static void -zyd_scan_start_cb(struct ieee80211com *ic) -{ - zyd_std_command(ic, &zyd_cfg_scan_start); -} + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + k = ieee80211_crypto_encap(ni, m0); + if (k == NULL) { + m_freem(m0); + return (ENOBUFS); + } + } -static void -zyd_scan_end_cb(struct ieee80211com *ic) -{ - zyd_std_command(ic, &zyd_cfg_scan_end); -} + data->ni = ni; + data->m = m0; + data->rate = rate; -static void -zyd_set_channel_cb(struct ieee80211com *ic) -{ - zyd_std_command(ic, &zyd_cfg_set_chan); -} + wh = mtod(m0, struct ieee80211_frame *); -/*========================================================================* - * configure sub-routines, zyd_cfg_xxx - *========================================================================*/ + totlen = m0->m_pkthdr.len + IEEE80211_CRC_LEN; -static void -zyd_cfg_scan_start(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - zyd_cfg_set_bssid(sc, cc->if_broadcastaddr); -} + /* fill Tx descriptor */ + desc->len = htole16(totlen); -static void -zyd_cfg_scan_end(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - zyd_cfg_set_bssid(sc, cc->iv_bss.ni_bssid); -} + desc->flags = ZYD_TX_FLAG_BACKOFF; + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + /* multicast frames are not sent at OFDM rates in 802.11b/g */ + if (totlen > vap->iv_rtsthreshold) { + desc->flags |= ZYD_TX_FLAG_RTS; + } else if (ZYD_RATE_IS_OFDM(rate) && + (ic->ic_flags & IEEE80211_F_USEPROT)) { + if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) + desc->flags |= ZYD_TX_FLAG_CTS_TO_SELF; + else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) + desc->flags |= ZYD_TX_FLAG_RTS; + } + } else + desc->flags |= ZYD_TX_FLAG_MULTICAST; -static void -zyd_cfg_set_chan(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t chan; - uint32_t tmp; + if ((wh->i_fc[0] & + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == + (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_PS_POLL)) + desc->flags |= ZYD_TX_FLAG_TYPE(ZYD_TX_TYPE_PS_POLL); - chan = cc->ic_curchan.chan_to_ieee; + desc->phy = zyd_plcp_signal(rate); + if (ZYD_RATE_IS_OFDM(rate)) { + desc->phy |= ZYD_TX_PHY_OFDM; + if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) + desc->phy |= ZYD_TX_PHY_5GHZ; + } else if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + desc->phy |= ZYD_TX_PHY_SHPREAMBLE; - DPRINTF("Will try %d\n", chan); + /* actual transmit length (XXX why +10?) */ + pktlen = ZYD_TX_DESC_SIZE + 10; + if (sc->sc_macrev == ZYD_ZD1211) + pktlen += totlen; + desc->pktlen = htole16(pktlen); - if ((chan == 0) || (chan == IEEE80211_CHAN_ANY)) { - DPRINTF("0 or ANY, exiting\n"); - return; + desc->plcp_length = (16 * totlen + rate - 1) / rate; + desc->plcp_service = 0; + if (rate == 22) { + const int remainder = (16 * totlen) % 22; + if (remainder != 0 && remainder < 7) + desc->plcp_service |= ZYD_PLCP_LENGEXT; } - zyd_cfg_lock_phy(sc); - (sc->sc_rf.cfg_set_channel) (sc, &sc->sc_rf, chan); + if (bpf_peers_present(ifp->if_bpf)) { + struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; - /* update Tx power */ - zyd_cfg_write16(sc, ZYD_CR31, sc->sc_pwr_int[chan - 1]); + tap->wt_flags = 0; + tap->wt_rate = rate; - if (sc->sc_mac_rev == ZYD_ZD1211B) { - zyd_cfg_write16(sc, ZYD_CR67, sc->sc_ofdm36_cal[chan - 1]); - zyd_cfg_write16(sc, ZYD_CR66, sc->sc_ofdm48_cal[chan - 1]); - zyd_cfg_write16(sc, ZYD_CR65, sc->sc_ofdm54_cal[chan - 1]); - zyd_cfg_write16(sc, ZYD_CR68, sc->sc_pwr_cal[chan - 1]); - zyd_cfg_write16(sc, ZYD_CR69, 0x28); - zyd_cfg_write16(sc, ZYD_CR69, 0x2a); + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); } - if (sc->sc_cckgain) { - /* set CCK baseband gain from EEPROM */ - zyd_cfg_read32(sc, ZYD_EEPROM_PHY_REG, &tmp); - zyd_cfg_write16(sc, ZYD_CR47, tmp & 0xff); - } - if (sc->sc_bandedge6 && (sc->sc_rf.cfg_bandedge6 != NULL)) { - (sc->sc_rf.cfg_bandedge6) (sc, &sc->sc_rf, chan); - } - zyd_cfg_write32(sc, ZYD_CR_CONFIG_PHILIPS, 0); - zyd_cfg_unlock_phy(sc); + DPRINTF(sc, ZYD_DEBUG_XMIT, + "%s: sending mgt frame len=%zu rate=%u\n", + device_get_nameunit(sc->sc_dev), (size_t)m0->m_pkthdr.len, + rate); - sc->sc_rxtap.wr_chan_freq = - sc->sc_txtap.wt_chan_freq = - htole16(cc->ic_curchan.ic_freq); + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); - sc->sc_rxtap.wr_chan_flags = - sc->sc_txtap.wt_chan_flags = - htole16(cc->ic_flags); + return (0); } -/* - * Interface: init - */ - -/* immediate configuration */ - static void -zyd_cfg_pre_init(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) +zyd_bulk_write_callback(struct usb2_xfer *xfer) { + struct zyd_softc *sc = xfer->priv_sc; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211_channel *c = ic->ic_curchan; + struct zyd_tx_data *data; + struct mbuf *m; - zyd_cfg_pre_stop(sc, cc, 0); - - ifp->if_drv_flags |= IFF_DRV_RUNNING; - - sc->sc_flags |= ZYD_FLAG_HL_READY; - - IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); -} - -/* delayed configuration */ - -static void -zyd_cfg_init(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - zyd_cfg_stop(sc, cc, 0); - - /* Do initial setup */ - - zyd_cfg_set_mac_addr(sc, cc->ic_myaddr); - - zyd_cfg_write32(sc, ZYD_MAC_ENCRYPTION_TYPE, ZYD_ENC_SNIFFER); - - /* promiscuous mode */ - zyd_cfg_write32(sc, ZYD_MAC_SNIFFER, - (cc->ic_opmode == IEEE80211_M_MONITOR) ? 1 : 0); - - /* multicast setup */ - zyd_cfg_update_promisc(sc, cc, refcount); - - zyd_cfg_set_rxfilter(sc, cc, refcount); - - /* switch radio transmitter ON */ - zyd_cfg_switch_radio(sc, 1); - - /* XXX wrong, can't set here */ - /* set basic rates */ - if (cc->ic_curmode == IEEE80211_MODE_11B) - zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0x0003); - else if (cc->ic_curmode == IEEE80211_MODE_11A) - zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0x1500); - else /* assumes 802.11b/g */ - zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0xff0f); - - /* set mandatory rates */ - if (cc->ic_curmode == IEEE80211_MODE_11B) - zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x000f); - else if (cc->ic_curmode == IEEE80211_MODE_11A) - zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x1500); - else /* assumes 802.11b/g */ - zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x150f); - - /* set default BSS channel */ - zyd_cfg_set_chan(sc, cc, 0); - - /* enable interrupts */ - zyd_cfg_write32(sc, ZYD_CR_INTERRUPT, ZYD_HWINT_MASK); - - /* make sure that the transfers get started */ - sc->sc_flags |= ( - ZYD_FLAG_BULK_READ_STALL | - ZYD_FLAG_BULK_WRITE_STALL | - ZYD_FLAG_LL_READY); - - if ((sc->sc_flags & ZYD_FLAG_LL_READY) && - (sc->sc_flags & ZYD_FLAG_HL_READY)) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - - /* - * start the USB transfers, if not already started: - */ - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_DT_RD]); - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_DT_WR]); - - /* - * start IEEE802.11 layer - */ - mtx_unlock(&sc->sc_mtx); - ieee80211_start_all(ic); - mtx_lock(&sc->sc_mtx); - } -} - -/* immediate configuration */ - -static void -zyd_cfg_pre_stop(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp = sc->sc_ifp; - - if (cc) { - /* copy the needed configuration */ - zyd_config_copy(sc, cc, refcount); - } - if (ifp) { - /* clear flags */ - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - } - sc->sc_flags &= ~(ZYD_FLAG_HL_READY | - ZYD_FLAG_LL_READY); - - /* - * stop all the transfers, if not already stopped: - */ - usb2_transfer_stop(sc->sc_xfer[ZYD_BULK_DT_WR]); - usb2_transfer_stop(sc->sc_xfer[ZYD_BULK_DT_RD]); - usb2_transfer_stop(sc->sc_xfer[ZYD_BULK_CS_WR]); - usb2_transfer_stop(sc->sc_xfer[ZYD_BULK_CS_RD]); + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + DPRINTF(sc, ZYD_DEBUG_ANY, "transfer complete, %u bytes\n", + xfer->actlen); - /* clean up transmission */ - zyd_tx_clean_queue(sc); -} + /* free resources */ + data = xfer->priv_fifo; + zyd_tx_free(data, 0); + xfer->priv_fifo = NULL; -/* delayed configuration */ + ifp->if_opackets++; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; -static void -zyd_cfg_stop(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - /* switch radio transmitter OFF */ - zyd_cfg_switch_radio(sc, 0); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + data = STAILQ_FIRST(&sc->tx_q); + if (data) { + STAILQ_REMOVE_HEAD(&sc->tx_q, next); + m = data->m; - /* disable Rx */ - zyd_cfg_write32(sc, ZYD_MAC_RXFILTER, 0); + if (m->m_pkthdr.len > ZYD_MAX_TXBUFSZ) { + DPRINTF(sc, ZYD_DEBUG_ANY, "data overflow, %u bytes\n", + m->m_pkthdr.len); + m->m_pkthdr.len = ZYD_MAX_TXBUFSZ; + } + usb2_copy_in(xfer->frbuffers, 0, &data->desc, + ZYD_TX_DESC_SIZE); + usb2_m_copy_in(xfer->frbuffers, ZYD_TX_DESC_SIZE, m, 0, + m->m_pkthdr.len); - /* disable interrupts */ - zyd_cfg_write32(sc, ZYD_CR_INTERRUPT, 0); -} + if (bpf_peers_present(ifp->if_bpf)) { + struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; -static void -zyd_update_mcast_cb(struct ifnet *ifp) -{ - struct zyd_softc *sc = ifp->if_softc; + tap->wt_flags = 0; + tap->wt_rate = data->rate; + tap->wt_chan_freq = htole16(c->ic_freq); + tap->wt_chan_flags = htole16(c->ic_flags); - mtx_lock(&sc->sc_mtx); - usb2_config_td_queue_command - (&sc->sc_config_td, &zyd_config_copy, - &zyd_cfg_update_promisc, 0, 0); - mtx_unlock(&sc->sc_mtx); -} + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + } -static void -zyd_update_promisc_cb(struct ifnet *ifp) -{ - struct zyd_softc *sc = ifp->if_softc; + xfer->frlengths[0] = ZYD_TX_DESC_SIZE + m->m_pkthdr.len; + xfer->priv_fifo = data; + usb2_start_hardware(xfer); + } + break; - mtx_lock(&sc->sc_mtx); - usb2_config_td_queue_command - (&sc->sc_config_td, &zyd_config_copy, - &zyd_cfg_update_promisc, 0, 0); - mtx_unlock(&sc->sc_mtx); -} + default: /* Error */ + DPRINTF(sc, ZYD_DEBUG_ANY, "transfer error, %s\n", + usb2_errstr(xfer->error)); -static void -zyd_cfg_set_rxfilter(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t rxfilter; + ifp->if_oerrors++; + data = xfer->priv_fifo; + xfer->priv_fifo = NULL; + if (data != NULL) + zyd_tx_free(data, xfer->error); - switch (cc->ic_opmode) { - case IEEE80211_M_STA: - rxfilter = ZYD_FILTER_BSS; - break; - case IEEE80211_M_IBSS: - case IEEE80211_M_HOSTAP: - rxfilter = ZYD_FILTER_HOSTAP; - break; - case IEEE80211_M_MONITOR: - rxfilter = ZYD_FILTER_MONITOR; + if (xfer->error == USB_ERR_STALLED) { + /* try to clear stall first */ + xfer->flags.stall_pipe = 1; + goto tr_setup; + } + if (xfer->error == USB_ERR_TIMEOUT) + device_printf(sc->sc_dev, "device timeout\n"); break; - default: - /* should not get there */ - return; } - zyd_cfg_write32(sc, ZYD_MAC_RXFILTER, rxfilter); -} - -static void -zyd_cfg_set_led(struct zyd_softc *sc, uint32_t which, uint8_t on) -{ - uint32_t tmp; - - zyd_cfg_read32(sc, ZYD_MAC_TX_PE_CONTROL, &tmp); - if (on) - tmp |= which; - else - tmp &= ~which; - - zyd_cfg_write32(sc, ZYD_MAC_TX_PE_CONTROL, tmp); } -static void -zyd_start_cb(struct ifnet *ifp) +static int +zyd_tx_data(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - struct zyd_softc *sc = ifp->if_softc; - - mtx_lock(&sc->sc_mtx); - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_DT_WR]); - mtx_unlock(&sc->sc_mtx); -} + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct zyd_tx_desc *desc; + struct zyd_tx_data *data; + struct ieee80211_frame *wh; + const struct ieee80211_txparam *tp; + struct ieee80211_key *k; + int rate, totlen; + uint16_t pktlen; -static void -zyd_bulk_write_clear_stall_callback(struct usb2_xfer *xfer) -{ - struct zyd_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_BULK_DT_WR]; + wh = mtod(m0, struct ieee80211_frame *); + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + desc = &data->desc; - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~ZYD_FLAG_BULK_WRITE_STALL; - usb2_transfer_start(xfer_other); + desc->flags = ZYD_TX_FLAG_BACKOFF; + tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { + rate = tp->mcastrate; + desc->flags |= ZYD_TX_FLAG_MULTICAST; + } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + rate = tp->ucastrate; + } else { + (void) ieee80211_amrr_choose(ni, &ZYD_NODE(ni)->amn); + rate = ni->ni_txrate; } -} - -/* - * We assume that "m->m_pkthdr.rcvif" is pointing to the "ni" that - * should be freed, when "zyd_setup_desc_and_tx" is called. - */ -static void -zyd_setup_desc_and_tx(struct zyd_softc *sc, struct mbuf *m, - uint16_t rate) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct mbuf *mm; - enum ieee80211_phytype phytype; - uint16_t len; - uint16_t totlen; - uint16_t pktlen; - uint8_t remainder; - if (sc->sc_tx_queue.ifq_len >= IFQ_MAXLEN) { - /* free packet */ - zyd_tx_freem(m); - ifp->if_oerrors++; - return; - } - if (!((sc->sc_flags & ZYD_FLAG_LL_READY) && - (sc->sc_flags & ZYD_FLAG_HL_READY))) { - /* free packet */ - zyd_tx_freem(m); - ifp->if_oerrors++; - return; + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + k = ieee80211_crypto_encap(ni, m0); + if (k == NULL) { + m_freem(m0); + return (ENOBUFS); + } + /* packet header may have moved, reset our local pointer */ + wh = mtod(m0, struct ieee80211_frame *); } - if (rate < 2) { - DPRINTF("rate < 2!\n"); - /* avoid division by zero */ - rate = 2; - } - ic->ic_lastdata = ticks; + data->ni = ni; + data->m = m0; - if (bpf_peers_present(ifp->if_bpf)) { - struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; + totlen = m0->m_pkthdr.len + IEEE80211_CRC_LEN; - tap->wt_flags = 0; - tap->wt_rate = rate; - tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); - tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); + /* fill Tx descriptor */ + desc->len = htole16(totlen); - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + /* multicast frames are not sent at OFDM rates in 802.11b/g */ + if (totlen > vap->iv_rtsthreshold) { + desc->flags |= ZYD_TX_FLAG_RTS; + } else if (ZYD_RATE_IS_OFDM(rate) && + (ic->ic_flags & IEEE80211_F_USEPROT)) { + if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) + desc->flags |= ZYD_TX_FLAG_CTS_TO_SELF; + else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) + desc->flags |= ZYD_TX_FLAG_RTS; + } } - len = m->m_pkthdr.len; - totlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; - phytype = ieee80211_rate2phytype(sc->sc_rates, rate); - sc->sc_tx_desc.len = htole16(totlen); - sc->sc_tx_desc.phy = zyd_plcp_signal(rate); - if (phytype == IEEE80211_T_OFDM) { - sc->sc_tx_desc.phy |= ZYD_TX_PHY_OFDM; + if ((wh->i_fc[0] & + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == + (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_PS_POLL)) + desc->flags |= ZYD_TX_FLAG_TYPE(ZYD_TX_TYPE_PS_POLL); + + desc->phy = zyd_plcp_signal(rate); + if (ZYD_RATE_IS_OFDM(rate)) { + desc->phy |= ZYD_TX_PHY_OFDM; if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) - sc->sc_tx_desc.phy |= ZYD_TX_PHY_5GHZ; + desc->phy |= ZYD_TX_PHY_5GHZ; } else if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) - sc->sc_tx_desc.phy |= ZYD_TX_PHY_SHPREAMBLE; + desc->phy |= ZYD_TX_PHY_SHPREAMBLE; /* actual transmit length (XXX why +10?) */ pktlen = sizeof(struct zyd_tx_desc) + 10; - if (sc->sc_mac_rev == ZYD_ZD1211) + if (sc->sc_macrev == ZYD_ZD1211) pktlen += totlen; - sc->sc_tx_desc.pktlen = htole16(pktlen); + desc->pktlen = htole16(pktlen); - sc->sc_tx_desc.plcp_length = ((16 * totlen) + rate - 1) / rate; - sc->sc_tx_desc.plcp_service = 0; + desc->plcp_length = (16 * totlen + rate - 1) / rate; + desc->plcp_service = 0; if (rate == 22) { - remainder = (16 * totlen) % 22; - if ((remainder != 0) && (remainder < 7)) - sc->sc_tx_desc.plcp_service |= ZYD_PLCP_LENGEXT; - } - if (sizeof(sc->sc_tx_desc) > MHLEN) { - DPRINTF("No room for header structure!\n"); - zyd_tx_freem(m); - return; - } - mm = m_gethdr(M_NOWAIT, MT_DATA); - if (mm == NULL) { - DPRINTF("Could not allocate header mbuf!\n"); - zyd_tx_freem(m); - return; + const int remainder = (16 * totlen) % 22; + if (remainder != 0 && remainder < 7) + desc->plcp_service |= ZYD_PLCP_LENGEXT; } - bcopy(&sc->sc_tx_desc, mm->m_data, sizeof(sc->sc_tx_desc)); - mm->m_len = sizeof(sc->sc_tx_desc); - mm->m_next = m; - mm->m_pkthdr.len = mm->m_len + m->m_pkthdr.len; - mm->m_pkthdr.rcvif = NULL; + DPRINTF(sc, ZYD_DEBUG_XMIT, + "%s: sending data frame len=%zu rate=%u\n", + device_get_nameunit(sc->sc_dev), (size_t)m0->m_pkthdr.len, + rate); - /* start write transfer, if not started */ - _IF_ENQUEUE(&sc->sc_tx_queue, mm); + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_DT_WR]); + return (0); } static void -zyd_bulk_write_callback(struct usb2_xfer *xfer) +zyd_start(struct ifnet *ifp) { - struct zyd_softc *sc = xfer->priv_sc; - struct ifnet *ifp = sc->sc_ifp; + struct zyd_softc *sc = ifp->if_softc; + struct ieee80211_node *ni; struct mbuf *m; - uint16_t temp_len; - DPRINTF("\n"); - - switch (USB_GET_STATE(xfer)) { - case USB_ST_TRANSFERRED: - DPRINTFN(11, "transfer complete\n"); - - ifp->if_opackets++; - - case USB_ST_SETUP: - if (sc->sc_flags & ZYD_FLAG_BULK_WRITE_STALL) { - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_CS_WR]); - DPRINTFN(11, "write stalled\n"); + ZYD_LOCK(sc); + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) break; - } - if (sc->sc_flags & ZYD_FLAG_WAIT_COMMAND) { - /* - * don't send anything while a command is pending ! - */ - DPRINTFN(11, "wait command\n"); + if (sc->tx_nfree == 0) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } - zyd_fill_write_queue(sc); - - _IF_DEQUEUE(&sc->sc_tx_queue, m); - - if (m) { - if (m->m_pkthdr.len > ZYD_MAX_TXBUFSZ) { - DPRINTFN(0, "data overflow, %u bytes\n", - m->m_pkthdr.len); - m->m_pkthdr.len = ZYD_MAX_TXBUFSZ; - } - usb2_m_copy_in(xfer->frbuffers, 0, - m, 0, m->m_pkthdr.len); - - /* get transfer length */ - temp_len = m->m_pkthdr.len; - - DPRINTFN(11, "sending frame len=%u xferlen=%u\n", - m->m_pkthdr.len, temp_len); - - xfer->frlengths[0] = temp_len; - - usb2_start_hardware(xfer); - - /* free mbuf and node */ - zyd_tx_freem(m); + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m = ieee80211_encap(ni, m); + if (m == NULL) { + ieee80211_free_node(ni); + ifp->if_oerrors++; + continue; } - break; - - default: /* Error */ - DPRINTFN(11, "transfer error, %s\n", - usb2_errstr(xfer->error)); - - if (xfer->error != USB_ERR_CANCELLED) { - /* try to clear stall first */ - sc->sc_flags |= ZYD_FLAG_BULK_WRITE_STALL; - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_CS_WR]); + if (zyd_tx_data(sc, m, ni) != 0) { + ieee80211_free_node(ni); + ifp->if_oerrors++; + break; } - ifp->if_oerrors++; - break; } + ZYD_UNLOCK(sc); } -static void -zyd_init_cb(void *arg) +static int +zyd_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) { - struct zyd_softc *sc = arg; + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; + struct zyd_softc *sc = ifp->if_softc; - mtx_lock(&sc->sc_mtx); - usb2_config_td_queue_command - (&sc->sc_config_td, &zyd_cfg_pre_init, - &zyd_cfg_init, 0, 0); - mtx_unlock(&sc->sc_mtx); + ZYD_LOCK(sc); + /* prevent management frames from being sent if we're not ready */ + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + ZYD_UNLOCK(sc); + m_freem(m); + ieee80211_free_node(ni); + return (ENETDOWN); + } + if (sc->tx_nfree == 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + ZYD_UNLOCK(sc); + m_freem(m); + ieee80211_free_node(ni); + return (ENOBUFS); /* XXX */ + } + + /* + * Legacy path; interpret frame contents to decide + * precisely how to send the frame. + * XXX raw path + */ + if (zyd_tx_mgt(sc, m, ni) != 0) { + ZYD_UNLOCK(sc); + ifp->if_oerrors++; + ieee80211_free_node(ni); + return (EIO); + } + ZYD_UNLOCK(sc); + return (0); } static int -zyd_ioctl_cb(struct ifnet *ifp, u_long cmd, caddr_t data) +zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct zyd_softc *sc = ifp->if_softc; struct ieee80211com *ic = ifp->if_l2com; - int error; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; switch (cmd) { case SIOCSIFFLAGS: - mtx_lock(&sc->sc_mtx); + ZYD_LOCK(sc); if (ifp->if_flags & IFF_UP) { - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - usb2_config_td_queue_command - (&sc->sc_config_td, &zyd_cfg_pre_init, - &zyd_cfg_init, 0, 0); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((ifp->if_flags ^ sc->sc_if_flags) & + (IFF_ALLMULTI | IFF_PROMISC)) + zyd_set_multi(sc); + } else { + zyd_queue_command(sc, zyd_init_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + startall = 1; } } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - usb2_config_td_queue_command - (&sc->sc_config_td, &zyd_cfg_pre_stop, - &zyd_cfg_stop, 0, 0); + zyd_queue_command(sc, zyd_stop_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); } } - mtx_unlock(&sc->sc_mtx); - error = 0; + sc->sc_if_flags = ifp->if_flags; + ZYD_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); break; - case SIOCGIFMEDIA: - case SIOCADDMULTI: - case SIOCDELMULTI: - error = ifmedia_ioctl(ifp, (void *)data, &ic->ic_media, cmd); + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); break; - - default: + case SIOCGIFADDR: error = ether_ioctl(ifp, cmd, data); break; + default: + error = EINVAL; + break; } return (error); } static void -zyd_watchdog(void *arg) +zyd_init_task(struct usb2_proc_msg *pm) { - struct zyd_softc *sc = arg; + struct zyd_task *task = (struct zyd_task *)pm; + struct zyd_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct usb2_config_descriptor *cd; + int error; + uint32_t val; - mtx_assert(&sc->sc_mtx, MA_OWNED); + ZYD_LOCK_ASSERT(sc, MA_OWNED); - if (sc->sc_amrr_timer) { - usb2_config_td_queue_command - (&sc->sc_config_td, NULL, - &zyd_cfg_amrr_timeout, 0, 0); - } - usb2_callout_reset(&sc->sc_watchdog, - hz, &zyd_watchdog, sc); -} + if (!(sc->sc_flags & ZYD_FLAG_INITONCE)) { + error = zyd_loadfirmware(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "could not load firmware (error=%d)\n", error); + goto fail; + } -static void -zyd_config_copy_chan(struct zyd_config_copy_chan *cc, - struct ieee80211com *ic, struct ieee80211_channel *c) -{ - if (!c) - return; - cc->chan_to_ieee = - ieee80211_chan2ieee(ic, c); - if (c != IEEE80211_CHAN_ANYC) { - cc->chan_to_mode = - ieee80211_chan2mode(c); - cc->ic_freq = c->ic_freq; - if (IEEE80211_IS_CHAN_B(c)) - cc->chan_is_b = 1; - if (IEEE80211_IS_CHAN_A(c)) - cc->chan_is_a = 1; - if (IEEE80211_IS_CHAN_2GHZ(c)) - cc->chan_is_2ghz = 1; - if (IEEE80211_IS_CHAN_5GHZ(c)) - cc->chan_is_5ghz = 1; - if (IEEE80211_IS_CHAN_ANYG(c)) - cc->chan_is_g = 1; + /* reset device */ + cd = usb2_get_config_descriptor(sc->sc_udev); + error = usb2_req_set_config(sc->sc_udev, &sc->sc_mtx, + cd->bConfigurationValue); + if (error) + device_printf(sc->sc_dev, "reset failed, continuing\n"); + + error = zyd_hw_init(sc); + if (error) { + device_printf(sc->sc_dev, + "hardware initialization failed\n"); + goto fail; + } + + device_printf(sc->sc_dev, + "HMAC ZD1211%s, FW %02x.%02x, RF %s S%x, PA%x LED %x " + "BE%x NP%x Gain%x F%x\n", + (sc->sc_macrev == ZYD_ZD1211) ? "": "B", + sc->sc_fwrev >> 8, sc->sc_fwrev & 0xff, + zyd_rf_name(sc->sc_rfrev), sc->sc_al2230s, sc->sc_parev, + sc->sc_ledtype, sc->sc_bandedge6, sc->sc_newphy, + sc->sc_cckgain, sc->sc_fix_cr157); + + /* read regulatory domain (currently unused) */ + zyd_read32_m(sc, ZYD_EEPROM_SUBID, &val); + sc->sc_regdomain = val >> 16; + DPRINTF(sc, ZYD_DEBUG_INIT, "regulatory domain %x\n", + sc->sc_regdomain); + + /* we'll do software WEP decryption for now */ + DPRINTF(sc, ZYD_DEBUG_INIT, "%s: setting encryption type\n", + __func__); + zyd_write32_m(sc, ZYD_MAC_ENCRYPTION_TYPE, ZYD_ENC_SNIFFER); + + sc->sc_flags |= ZYD_FLAG_INITONCE; } -} -static void -zyd_config_copy(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - const struct ieee80211_txparam *tp; - struct ieee80211vap *vap; - struct ifmultiaddr *ifma; - struct ieee80211_node *ni; - struct ieee80211com *ic; - struct ifnet *ifp; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + zyd_stop_task(pm); - bzero(cc, sizeof(*cc)); + IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); + DPRINTF(sc, ZYD_DEBUG_INIT, "setting MAC address to %s\n", + ether_sprintf(ic->ic_myaddr)); + error = zyd_set_macaddr(sc, ic->ic_myaddr); + if (error != 0) + return; - ifp = sc->sc_ifp; - if (ifp) { - cc->if_flags = ifp->if_flags; - bcopy(ifp->if_broadcastaddr, cc->if_broadcastaddr, - sizeof(cc->if_broadcastaddr)); + /* set basic rates */ + if (ic->ic_curmode == IEEE80211_MODE_11B) + zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0x0003); + else if (ic->ic_curmode == IEEE80211_MODE_11A) + zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0x1500); + else /* assumes 802.11b/g */ + zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0xff0f); - cc->zyd_multi_low = 0x00000000; - cc->zyd_multi_high = 0x80000000; + /* promiscuous mode */ + zyd_write32_m(sc, ZYD_MAC_SNIFFER, 0); + /* multicast setup */ + zyd_set_multi(sc); + /* set RX filter */ + error = zyd_set_rxfilter(sc); + if (error != 0) + goto fail; - IF_ADDR_LOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - uint8_t v; + /* switch radio transmitter ON */ + error = zyd_switch_radio(sc, 1); + if (error != 0) + goto fail; + /* set default BSS channel */ + zyd_set_chan(sc, ic->ic_curchan); - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - v = ((uint8_t *)LLADDR((struct sockaddr_dl *) - ifma->ifma_addr))[5] >> 2; - if (v < 32) - cc->zyd_multi_low |= 1 << v; - else - cc->zyd_multi_high |= 1 << (v - 32); - } - IF_ADDR_UNLOCK(ifp); + /* + * Allocate Tx and Rx xfer queues. + */ + zyd_setup_tx_list(sc); - ic = ifp->if_l2com; - if (ic) { - zyd_config_copy_chan(&cc->ic_curchan, ic, ic->ic_curchan); - zyd_config_copy_chan(&cc->ic_bsschan, ic, ic->ic_bsschan); - vap = TAILQ_FIRST(&ic->ic_vaps); - if (vap) { - ni = vap->iv_bss; - if (ni) { - cc->iv_bss.ni_intval = ni->ni_intval; - bcopy(ni->ni_bssid, cc->iv_bss.ni_bssid, - sizeof(cc->iv_bss.ni_bssid)); - } - tp = vap->iv_txparms + cc->ic_bsschan.chan_to_mode; - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { - cc->iv_bss.fixed_rate_none = 1; - } - } - cc->ic_opmode = ic->ic_opmode; - cc->ic_flags = ic->ic_flags; - cc->ic_txpowlimit = ic->ic_txpowlimit; - cc->ic_curmode = ic->ic_curmode; + /* enable interrupts */ + zyd_write32_m(sc, ZYD_CR_INTERRUPT, ZYD_HWINT_MASK); - bcopy(ic->ic_myaddr, cc->ic_myaddr, - sizeof(cc->ic_myaddr)); - } - } - sc->sc_flags |= ZYD_FLAG_WAIT_COMMAND; -} + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + usb2_transfer_start(sc->sc_xfer[ZYD_BULK_RD]); + usb2_transfer_start(sc->sc_xfer[ZYD_INTR_RD]); -static void -zyd_end_of_commands(struct zyd_softc *sc) -{ - sc->sc_flags &= ~ZYD_FLAG_WAIT_COMMAND; + return; - /* start write transfer, if not started */ - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_DT_WR]); +fail: zyd_stop_task(pm); + return; } static void -zyd_newassoc_cb(struct ieee80211_node *ni, int isnew) +zyd_init(void *priv) { - struct ieee80211vap *vap = ni->ni_vap; + struct zyd_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - ieee80211_amrr_node_init(&ZYD_VAP(vap)->amrr, &ZYD_NODE(ni)->amn, ni); + ZYD_LOCK(sc); + zyd_queue_command(sc, zyd_init_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + ZYD_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ } static void -zyd_cfg_amrr_timeout(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) +zyd_stop_task(struct usb2_proc_msg *pm) { - struct ieee80211vap *vap; - struct ieee80211_node *ni; - - vap = zyd_get_vap(sc); - if (vap == NULL) { - return; - } - ni = vap->iv_bss; - if (ni == NULL) { - return; - } - if ((sc->sc_flags & ZYD_FLAG_LL_READY) && - (sc->sc_flags & ZYD_FLAG_HL_READY)) { + struct zyd_task *task = (struct zyd_task *)pm; + struct zyd_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + int error; - if (sc->sc_amrr_timer) { + ZYD_LOCK_ASSERT(sc, MA_OWNED); - if (ieee80211_amrr_choose(ni, &ZYD_NODE(ni)->amn)) { - /* ignore */ - } - } - } -} + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -static void -zyd_cfg_amrr_start(struct zyd_softc *sc) -{ - struct ieee80211vap *vap; - struct ieee80211_node *ni; + /* + * Drain all the transfers, if not already drained: + */ + ZYD_UNLOCK(sc); + usb2_transfer_drain(sc->sc_xfer[ZYD_BULK_WR]); + usb2_transfer_drain(sc->sc_xfer[ZYD_BULK_RD]); + ZYD_LOCK(sc); - vap = zyd_get_vap(sc); + zyd_unsetup_tx_list(sc); - if (vap == NULL) { - return; - } - ni = vap->iv_bss; - if (ni == NULL) { + /* Stop now if the device was never set up */ + if (!(sc->sc_flags & ZYD_FLAG_INITONCE)) return; - } - /* init AMRR */ - ieee80211_amrr_node_init(&ZYD_VAP(vap)->amrr, &ZYD_NODE(ni)->amn, ni); - - /* enable AMRR timer */ + /* switch radio transmitter OFF */ + error = zyd_switch_radio(sc, 0); + if (error != 0) + goto fail; + /* disable Rx */ + zyd_write32_m(sc, ZYD_MAC_RXFILTER, 0); + /* disable interrupts */ + zyd_write32_m(sc, ZYD_CR_INTERRUPT, 0); - sc->sc_amrr_timer = 1; +fail: + return; } -static struct ieee80211vap * -zyd_vap_create(struct ieee80211com *ic, - const char name[IFNAMSIZ], int unit, int opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN], - const uint8_t mac[IEEE80211_ADDR_LEN]) +static int +zyd_loadfirmware(struct zyd_softc *sc) { - struct zyd_vap *zvp; - struct ieee80211vap *vap; - struct zyd_softc *sc = ic->ic_ifp->if_softc; + struct usb2_device_request req; + size_t size; + u_char *fw; + uint8_t stat; + uint16_t addr; - /* Need to sync with config thread: */ - mtx_lock(&sc->sc_mtx); - if (usb2_config_td_sync(&sc->sc_config_td)) { - mtx_unlock(&sc->sc_mtx); - /* config thread is gone */ - return (NULL); + if (sc->sc_flags & ZYD_FLAG_FWLOADED) + return (0); + + if (sc->sc_macrev == ZYD_ZD1211) { + fw = (u_char *)zd1211_firmware; + size = sizeof(zd1211_firmware); + } else { + fw = (u_char *)zd1211b_firmware; + size = sizeof(zd1211b_firmware); } - mtx_unlock(&sc->sc_mtx); - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ - return NULL; - zvp = (struct zyd_vap *)malloc(sizeof(struct zyd_vap), - M_80211_VAP, M_NOWAIT | M_ZERO); - if (zvp == NULL) - return NULL; - vap = &zvp->vap; - /* enable s/w bmiss handling for sta mode */ - ieee80211_vap_setup(ic, vap, name, unit, opmode, - flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = ZYD_DOWNLOADREQ; + USETW(req.wIndex, 0); - /* override state transition machine */ - zvp->newstate = vap->iv_newstate; - vap->iv_newstate = &zyd_newstate_cb; + addr = ZYD_FIRMWARE_START_ADDR; + while (size > 0) { + /* + * When the transfer size is 4096 bytes, it is not + * likely to be able to transfer it. + * The cause is port or machine or chip? + */ + const int mlen = min(size, 64); - ieee80211_amrr_init(&zvp->amrr, vap, - IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, - IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, - 1000 /* 1 sec */ ); + DPRINTF(sc, ZYD_DEBUG_FW, + "loading firmware block: len=%d, addr=0x%x\n", mlen, addr); - /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); - ic->ic_opmode = opmode; + USETW(req.wValue, addr); + USETW(req.wLength, mlen); + if (zyd_do_request(sc, &req, fw) != 0) + return (EIO); - return (vap); -} + addr += mlen / 2; + fw += mlen; + size -= mlen; + } -static void -zyd_vap_delete(struct ieee80211vap *vap) -{ - struct zyd_vap *zvp = ZYD_VAP(vap); - struct zyd_softc *sc = vap->iv_ic->ic_ifp->if_softc; + /* check whether the upload succeeded */ + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = ZYD_DOWNLOADSTS; + USETW(req.wValue, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, sizeof(stat)); + if (zyd_do_request(sc, &req, &stat) != 0) + return (EIO); - /* Need to sync with config thread: */ - mtx_lock(&sc->sc_mtx); - if (usb2_config_td_sync(&sc->sc_config_td)) { - /* ignore */ - } - mtx_unlock(&sc->sc_mtx); + sc->sc_flags |= ZYD_FLAG_FWLOADED; - ieee80211_amrr_cleanup(&zvp->amrr); - ieee80211_vap_detach(vap); - free(zvp, M_80211_VAP); + return (stat & 0x80) ? (EIO) : (0); } -/* ARGUSED */ -static struct ieee80211_node * -zyd_node_alloc_cb(struct ieee80211vap *vap __unused, - const uint8_t mac[IEEE80211_ADDR_LEN] __unused) +static void +zyd_newassoc(struct ieee80211_node *ni, int isnew) { - struct zyd_node *zn; + struct ieee80211vap *vap = ni->ni_vap; - zn = malloc(sizeof(struct zyd_node), M_80211_NODE, M_NOWAIT | M_ZERO); - return ((zn != NULL) ? &zn->ni : NULL); + ieee80211_amrr_node_init(&ZYD_VAP(vap)->amrr, &ZYD_NODE(ni)->amn, ni); } static void -zyd_fill_write_queue(struct zyd_softc *sc) +zyd_scan_start(struct ieee80211com *ic) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211_node *ni; - struct mbuf *m; - - /* - * We only fill up half of the queue with data frames. The rest is - * reserved for other kinds of frames. - */ - - while (sc->sc_tx_queue.ifq_len < (IFQ_MAXLEN / 2)) { - - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; + struct zyd_softc *sc = ic->ic_ifp->if_softc; - ni = (void *)(m->m_pkthdr.rcvif); - m = ieee80211_encap(ni, m); - if (m == NULL) { - ieee80211_free_node(ni); - continue; - } - zyd_tx_data(sc, m, ni); - } + ZYD_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = ZYD_SCAN_START; + zyd_queue_command(sc, zyd_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + ZYD_UNLOCK(sc); } static void -zyd_tx_clean_queue(struct zyd_softc *sc) +zyd_scan_end(struct ieee80211com *ic) { - struct mbuf *m; - - for (;;) { - _IF_DEQUEUE(&sc->sc_tx_queue, m); + struct zyd_softc *sc = ic->ic_ifp->if_softc; - if (!m) { - break; - } - zyd_tx_freem(m); - } + ZYD_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = ZYD_SCAN_END; + zyd_queue_command(sc, zyd_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + ZYD_UNLOCK(sc); } static void -zyd_tx_freem(struct mbuf *m) +zyd_set_channel(struct ieee80211com *ic) { - struct ieee80211_node *ni; - - while (m) { - ni = (void *)(m->m_pkthdr.rcvif); - if (!ni) { - m = m_free(m); - continue; - } - if (m->m_flags & M_TXCB) { - ieee80211_process_callback(ni, m, 0); - } - m_freem(m); - ieee80211_free_node(ni); + struct zyd_softc *sc = ic->ic_ifp->if_softc; - break; - } + ZYD_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = ZYD_SET_CHANNEL; + zyd_queue_command(sc, zyd_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + ZYD_UNLOCK(sc); } static void -zyd_tx_mgt(struct zyd_softc *sc, struct mbuf *m, struct ieee80211_node *ni) +zyd_scantask(struct usb2_proc_msg *pm) { - struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = ni->ni_ic; - const struct ieee80211_txparam *tp; - struct ieee80211_frame *wh; - struct ieee80211_key *k; - uint16_t totlen; - uint16_t rate; + struct zyd_task *task = (struct zyd_task *)pm; + struct zyd_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - rate = tp->mgmtrate; + ZYD_LOCK_ASSERT(sc, MA_OWNED); - wh = mtod(m, struct ieee80211_frame *); - if (wh->i_fc[1] & IEEE80211_FC1_WEP) { - k = ieee80211_crypto_encap(ni, m); - if (k == NULL) { - m_freem(m); - ieee80211_free_node(ni); - return; - } - wh = mtod(m, struct ieee80211_frame *); - } - /* fill Tx descriptor */ + switch (sc->sc_scan_action) { + case ZYD_SCAN_START: + /* want broadcast address while scanning */ + zyd_set_bssid(sc, ifp->if_broadcastaddr); + break; - sc->sc_tx_desc.flags = ZYD_TX_FLAG_BACKOFF; - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - /* get total length */ - totlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; - /* multicast frames are not sent at OFDM rates in 802.11b/g */ - if (totlen > vap->iv_rtsthreshold) { - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_RTS; - } else if (ZYD_RATE_IS_OFDM(rate) && - (ic->ic_flags & IEEE80211_F_USEPROT)) { - if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_CTS_TO_SELF; - else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_RTS; - } - } else - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_MULTICAST; + case ZYD_SET_CHANNEL: + zyd_set_chan(sc, ic->ic_curchan); + break; - if ((wh->i_fc[0] & - (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == - (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_PS_POLL)) - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_TYPE(ZYD_TX_TYPE_PS_POLL); - - m->m_pkthdr.rcvif = (void *)ni; - zyd_setup_desc_and_tx(sc, m, rate); + default: /* ZYD_SCAN_END */ + /* restore previous bssid */ + zyd_set_bssid(sc, sc->sc_bssid); + break; + } } static void -zyd_tx_data(struct zyd_softc *sc, struct mbuf *m, struct ieee80211_node *ni) +zyd_queue_command(struct zyd_softc *sc, usb2_proc_callback_t *fn, + struct usb2_proc_msg *t0, struct usb2_proc_msg *t1) { - struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = ni->ni_ic; - const struct ieee80211_txparam *tp; - struct ieee80211_frame *wh; - struct ieee80211_key *k; - uint16_t rate; + struct zyd_task *task; - wh = mtod(m, struct ieee80211_frame *); + ZYD_LOCK_ASSERT(sc, MA_OWNED); - sc->sc_tx_desc.flags = ZYD_TX_FLAG_BACKOFF; - tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; - if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { - rate = tp->mcastrate; - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_MULTICAST; - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { - rate = tp->ucastrate; - } else - rate = ni->ni_txrate; - - if (wh->i_fc[1] & IEEE80211_FC1_WEP) { - k = ieee80211_crypto_encap(ni, m); - if (k == NULL) { - m_freem(m); - ieee80211_free_node(ni); - return; - } - /* packet header may have moved, reset our local pointer */ - wh = mtod(m, struct ieee80211_frame *); + if (usb2_proc_is_gone(&sc->sc_tq)) { + DPRINTF(sc, ZYD_DEBUG_STATE, "proc is gone\n"); + return; /* nothing to do */ } - /* fill Tx descriptor */ - - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - uint16_t totlen; - - totlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; + /* + * NOTE: The task cannot get executed before we drop the + * "sc_mtx" mutex. It is safe to update fields in the message + * structure after that the message got queued. + */ + task = (struct zyd_task *) + usb2_proc_msignal(&sc->sc_tq, t0, t1); - /* multicast frames are not sent at OFDM rates in 802.11b/g */ - if (totlen > vap->iv_rtsthreshold) { - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_RTS; - } else if (ZYD_RATE_IS_OFDM(rate) && - (ic->ic_flags & IEEE80211_F_USEPROT)) { - if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_CTS_TO_SELF; - else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_RTS; - } - } - if ((wh->i_fc[0] & - (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == - (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_PS_POLL)) - sc->sc_tx_desc.flags |= ZYD_TX_FLAG_TYPE(ZYD_TX_TYPE_PS_POLL); + /* Setup callback and softc pointers */ + task->hdr.pm_callback = fn; + task->sc = sc; - m->m_pkthdr.rcvif = (void *)ni; - zyd_setup_desc_and_tx(sc, m, rate); + /* + * Init and stop must be synchronous! + */ + if ((fn == zyd_init_task) || (fn == zyd_stop_task)) + usb2_proc_mwait(&sc->sc_tq, t0, t1); } -static int -zyd_raw_xmit_cb(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) -{ - struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = ic->ic_ifp; - struct zyd_softc *sc = ifp->if_softc; +static device_method_t zyd_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, zyd_match), + DEVMETHOD(device_attach, zyd_attach), + DEVMETHOD(device_detach, zyd_detach), + + { 0, 0 } +}; - mtx_lock(&sc->sc_mtx); - if (params == NULL) { - /* - * Legacy path; interpret frame contents to decide - * precisely how to send the frame. - */ - zyd_tx_mgt(sc, m, ni); - } else { - /* - * Caller supplied explicit parameters to use in - * sending the frame. - */ - zyd_tx_mgt(sc, m, ni); /* XXX zyd_tx_raw() */ - } - mtx_unlock(&sc->sc_mtx); - return (0); -} +static driver_t zyd_driver = { + "zyd", + zyd_methods, + sizeof(struct zyd_softc) +}; -static struct ieee80211vap * -zyd_get_vap(struct zyd_softc *sc) -{ - struct ifnet *ifp; - struct ieee80211com *ic; +static devclass_t zyd_devclass; - if (sc == NULL) { - return NULL; - } - ifp = sc->sc_ifp; - if (ifp == NULL) { - return NULL; - } - ic = ifp->if_l2com; - if (ic == NULL) { - return NULL; - } - return TAILQ_FIRST(&ic->ic_vaps); -} +DRIVER_MODULE(zyd, ushub, zyd_driver, zyd_devclass, NULL, 0); +MODULE_DEPEND(zyd, usb2_wlan, 1, 1, 1); +MODULE_DEPEND(zyd, usb2_core, 1, 1, 1); +MODULE_DEPEND(zyd, wlan, 1, 1, 1); +MODULE_DEPEND(zyd, wlan_amrr, 1, 1, 1); |