diff --git a/sys/dev/usb2/wlan/if_rum2.c b/sys/dev/usb2/wlan/if_rum2.c index 8911a6fb4e8..4e78c37cb8b 100644 --- a/sys/dev/usb2/wlan/if_rum2.c +++ b/sys/dev/usb2/wlan/if_rum2.c @@ -1,3 +1,5 @@ +/* $FreeBSD$ */ + /*- * Copyright (c) 2005-2007 Damien Bergamini * Copyright (c) 2006 Niall O'Higgins @@ -16,11 +18,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * NOTE: all function names beginning like "rum_cfg_" can only - * be called from within the config thread function ! - */ - #include __FBSDID("$FreeBSD$"); @@ -34,15 +31,11 @@ __FBSDID("$FreeBSD$"); #include #include -#define usb2_config_td_cc rum_config_copy -#define usb2_config_td_softc rum_softc - #define USB_DEBUG_VAR rum_debug #include #include #include -#include #include #include #include @@ -61,755 +54,447 @@ SYSCTL_INT(_hw_usb2_rum, OID_AUTO, debug, CTLFLAG_RW, &rum_debug, 0, "Debug level"); #endif -/* prototypes */ +#define rum_do_request(sc,req,data) \ + usb2_do_request_proc((sc)->sc_udev, &(sc)->sc_tq, req, data, 0, NULL, 5000) -static device_probe_t rum_probe; +static const struct usb2_device_id rum_devs[] = { + { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_HWU54DM) }, + { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_2) }, + { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_3) }, + { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_4) }, + { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_WUG2700) }, + { USB_VP(USB_VENDOR_AMIT, USB_PRODUCT_AMIT_CGWLUSB2GO) }, + { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2573_1) }, + { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2573_2) }, + { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050A) }, + { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D9050V3) }, + { USB_VP(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GC) }, + { USB_VP(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GR) }, + { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_C54RU2) }, + { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB2GL) }, + { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB2GPX) }, + { USB_VP(USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_CWD854F) }, + { USB_VP(USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_RT2573) }, + { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWLG122C1) }, + { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_WUA1340) }, + { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA111) }, + { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA110) }, + { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWB01GS) }, + { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWI05GS) }, + { USB_VP(USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_RT2573) }, + { USB_VP(USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_RT2573) }, + { USB_VP(USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254LB) }, + { USB_VP(USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254V2AP) }, + { USB_VP(USB_VENDOR_HUAWEI3COM, USB_PRODUCT_HUAWEI3COM_WUB320G) }, + { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_G54HP) }, + { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_SG54HP) }, + { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_1) }, + { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_2) }, + { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_3) }, + { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_4) }, + { USB_VP(USB_VENDOR_NOVATECH, USB_PRODUCT_NOVATECH_RT2573) }, + { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54HP) }, + { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54MINI2) }, + { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUSMM) }, + { USB_VP(USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2573) }, + { USB_VP(USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2573_2) }, + { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2573) }, + { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2573_2) }, + { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2671) }, + { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL113R2) }, + { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL172) }, + { USB_VP(USB_VENDOR_SPARKLAN, USB_PRODUCT_SPARKLAN_RT2573) }, + { USB_VP(USB_VENDOR_SURECOM, USB_PRODUCT_SURECOM_RT2573) }, +}; + +MODULE_DEPEND(rum, wlan, 1, 1, 1); +MODULE_DEPEND(rum, wlan_amrr, 1, 1, 1); +MODULE_DEPEND(rum, usb2_wlan, 1, 1, 1); +MODULE_DEPEND(rum, usb2_core, 1, 1, 1); + +static device_probe_t rum_match; static device_attach_t rum_attach; static device_detach_t rum_detach; static usb2_callback_t rum_bulk_read_callback; -static usb2_callback_t rum_bulk_read_clear_stall_callback; static usb2_callback_t rum_bulk_write_callback; -static usb2_callback_t rum_bulk_write_clear_stall_callback; -static usb2_config_td_command_t rum_cfg_first_time_setup; -static usb2_config_td_command_t rum_config_copy; -static usb2_config_td_command_t rum_cfg_scan_start; -static usb2_config_td_command_t rum_cfg_scan_end; -static usb2_config_td_command_t rum_cfg_select_band; -static usb2_config_td_command_t rum_cfg_set_chan; -static usb2_config_td_command_t rum_cfg_enable_tsf_sync; -static usb2_config_td_command_t rum_cfg_enable_mrr; -static usb2_config_td_command_t rum_cfg_update_slot; -static usb2_config_td_command_t rum_cfg_select_antenna; -static usb2_config_td_command_t rum_cfg_set_txpreamble; -static usb2_config_td_command_t rum_cfg_update_promisc; -static usb2_config_td_command_t rum_cfg_pre_init; -static usb2_config_td_command_t rum_cfg_init; -static usb2_config_td_command_t rum_cfg_pre_stop; -static usb2_config_td_command_t rum_cfg_stop; -static usb2_config_td_command_t rum_cfg_amrr_timeout; -static usb2_config_td_command_t rum_cfg_prepare_beacon; -static usb2_config_td_command_t rum_cfg_newstate; +static usb2_proc_callback_t rum_attach_post; +static usb2_proc_callback_t rum_task; +static usb2_proc_callback_t rum_scantask; +static usb2_proc_callback_t rum_promisctask; +static usb2_proc_callback_t rum_amrr_task; +static usb2_proc_callback_t rum_init_task; +static usb2_proc_callback_t rum_stop_task; -static const char *rum_get_rf(uint32_t); -static int rum_ioctl_cb(struct ifnet *, u_long, caddr_t); -static void rum_std_command(struct ieee80211com *, usb2_config_td_command_t *); -static void rum_scan_start_cb(struct ieee80211com *); -static void rum_scan_end_cb(struct ieee80211com *); -static void rum_set_channel_cb(struct ieee80211com *); -static uint16_t rum_cfg_eeprom_read_2(struct rum_softc *, uint16_t); -static uint32_t rum_cfg_bbp_disbusy(struct rum_softc *); -static uint32_t rum_cfg_read(struct rum_softc *, uint16_t); -static uint8_t rum_cfg_bbp_init(struct rum_softc *); -static uint8_t rum_cfg_bbp_read(struct rum_softc *, uint8_t); -static void rum_cfg_amrr_start(struct rum_softc *); -static void rum_cfg_bbp_write(struct rum_softc *, uint8_t, uint8_t); -static void rum_cfg_do_request(struct rum_softc *, - struct usb2_device_request *, void *); -static void rum_cfg_eeprom_read(struct rum_softc *, uint16_t, void *, - uint16_t); -static void rum_cfg_load_microcode(struct rum_softc *, const uint8_t *, - uint16_t); -static void rum_cfg_read_eeprom(struct rum_softc *); -static void rum_cfg_read_multi(struct rum_softc *, uint16_t, void *, - uint16_t); -static void rum_cfg_rf_write(struct rum_softc *, uint8_t, uint32_t); -static void rum_cfg_set_bssid(struct rum_softc *, uint8_t *); -static void rum_cfg_set_macaddr(struct rum_softc *, uint8_t *); -static void rum_cfg_write(struct rum_softc *, uint16_t, uint32_t); -static void rum_cfg_write_multi(struct rum_softc *, uint16_t, void *, - uint16_t); -static void rum_end_of_commands(struct rum_softc *); -static void rum_init_cb(void *); -static void rum_start_cb(struct ifnet *); -static void rum_watchdog(void *); -static uint8_t rum_get_rssi(struct rum_softc *, uint8_t); static struct ieee80211vap *rum_vap_create(struct ieee80211com *, - const char[], int, int, int, const uint8_t[], - const uint8_t[]); -static void rum_vap_delete(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 rum_vap_delete(struct ieee80211vap *); +static void rum_tx_free(struct rum_tx_data *, int); +static void rum_setup_tx_list(struct rum_softc *); +static void rum_unsetup_tx_list(struct rum_softc *); +static int rum_newstate(struct ieee80211vap *, + enum ieee80211_state, int); +static void rum_setup_tx_desc(struct rum_softc *, + struct rum_tx_desc *, uint32_t, uint16_t, int, + int); +static int rum_tx_mgt(struct rum_softc *, struct mbuf *, + struct ieee80211_node *); +static int rum_tx_raw(struct rum_softc *, struct mbuf *, + struct ieee80211_node *, + const struct ieee80211_bpf_params *); +static int rum_tx_data(struct rum_softc *, struct mbuf *, + struct ieee80211_node *); +static void rum_start(struct ifnet *); +static int rum_ioctl(struct ifnet *, u_long, caddr_t); +static void rum_eeprom_read(struct rum_softc *, uint16_t, void *, + int); +static uint32_t rum_read(struct rum_softc *, uint16_t); +static void rum_read_multi(struct rum_softc *, uint16_t, void *, + int); +static void rum_write(struct rum_softc *, uint16_t, uint32_t); +static void rum_write_multi(struct rum_softc *, uint16_t, void *, + size_t); +static void rum_bbp_write(struct rum_softc *, uint8_t, uint8_t); +static uint8_t rum_bbp_read(struct rum_softc *, uint8_t); +static void rum_rf_write(struct rum_softc *, uint8_t, uint32_t); +static void rum_select_antenna(struct rum_softc *); +static void rum_enable_mrr(struct rum_softc *); +static void rum_set_txpreamble(struct rum_softc *); +static void rum_set_basicrates(struct rum_softc *); +static void rum_select_band(struct rum_softc *, + struct ieee80211_channel *); +static void rum_set_chan(struct rum_softc *, + struct ieee80211_channel *); +static void rum_enable_tsf_sync(struct rum_softc *); +static void rum_update_slot(struct ifnet *); +static void rum_set_bssid(struct rum_softc *, const uint8_t *); +static void rum_set_macaddr(struct rum_softc *, const uint8_t *); +static const char *rum_get_rf(int); +static void rum_read_eeprom(struct rum_softc *); +static int rum_bbp_init(struct rum_softc *); +static void rum_init(void *); +static int rum_load_microcode(struct rum_softc *, const u_char *, + size_t); +static int rum_prepare_beacon(struct rum_softc *, + struct ieee80211vap *); +static int rum_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); static struct ieee80211_node *rum_node_alloc(struct ieee80211vap *, - const uint8_t[]); -static void rum_newassoc(struct ieee80211_node *, int); -static void rum_cfg_disable_tsf_sync(struct rum_softc *); -static void rum_cfg_set_run(struct rum_softc *, struct rum_config_copy *); -static void rum_fill_write_queue(struct rum_softc *); -static void rum_tx_clean_queue(struct rum_softc *); -static void rum_tx_freem(struct mbuf *); -static void rum_tx_mgt(struct rum_softc *, struct mbuf *, - struct ieee80211_node *); -static struct ieee80211vap *rum_get_vap(struct rum_softc *); -static void rum_tx_data(struct rum_softc *, struct mbuf *, - struct ieee80211_node *); -static void rum_tx_prot(struct rum_softc *, const struct mbuf *, - struct ieee80211_node *, uint8_t, uint16_t); -static void rum_tx_raw(struct rum_softc *, struct mbuf *, - struct ieee80211_node *, - const struct ieee80211_bpf_params *); -static int rum_raw_xmit_cb(struct ieee80211_node *, struct mbuf *, - const struct ieee80211_bpf_params *); -static void rum_setup_desc_and_tx(struct rum_softc *, struct mbuf *, - uint32_t, uint16_t, uint16_t); -static int rum_newstate_cb(struct ieee80211vap *, - enum ieee80211_state nstate, int arg); -static void rum_update_mcast_cb(struct ifnet *); -static void rum_update_promisc_cb(struct ifnet *); + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void rum_newassoc(struct ieee80211_node *, int); +static void rum_scan_start(struct ieee80211com *); +static void rum_scan_end(struct ieee80211com *); +static void rum_set_channel(struct ieee80211com *); +static int rum_get_rssi(struct rum_softc *, uint8_t); +static void rum_amrr_start(struct rum_softc *, + struct ieee80211_node *); +static void rum_amrr_timeout(void *); +static void rum_queue_command(struct rum_softc *, + usb2_proc_callback_t *, struct usb2_proc_msg *, + struct usb2_proc_msg *); -/* various supported device vendors/products */ -static const struct usb2_device_id rum_devs[] = { - {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_HWU54DM, 0)}, - {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_2, 0)}, - {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_3, 0)}, - {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_4, 0)}, - {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_WUG2700, 0)}, - {USB_VPI(USB_VENDOR_AMIT, USB_PRODUCT_AMIT_CGWLUSB2GO, 0)}, - {USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2573_1, 0)}, - {USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2573_2, 0)}, - {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050A, 0)}, - {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D9050V3, 0)}, - {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GC, 0)}, - {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GR, 0)}, - {USB_VPI(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_C54RU2, 0)}, - {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB2GL, 0)}, - {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB2GPX, 0)}, - {USB_VPI(USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_CWD854F, 0)}, - {USB_VPI(USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_RT2573, 0)}, - {USB_VPI(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWLG122C1, 0)}, - {USB_VPI(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_WUA1340, 0)}, - {USB_VPI(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA111, 0)}, - {USB_VPI(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA110, 0)}, - {USB_VPI(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWB01GS, 0)}, - {USB_VPI(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWI05GS, 0)}, - {USB_VPI(USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_RT2573, 0)}, - {USB_VPI(USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_RT2573, 0)}, - {USB_VPI(USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254LB, 0)}, - {USB_VPI(USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254V2AP, 0)}, - {USB_VPI(USB_VENDOR_HUAWEI3COM, USB_PRODUCT_HUAWEI3COM_WUB320G, 0)}, - {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_G54HP, 0)}, - {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_SG54HP, 0)}, - {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_SG54HG, 0)}, - {USB_VPI(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_1, 0)}, - {USB_VPI(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_2, 0)}, - {USB_VPI(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_3, 0)}, - {USB_VPI(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_4, 0)}, - {USB_VPI(USB_VENDOR_NOVATECH, USB_PRODUCT_NOVATECH_RT2573, 0)}, - {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54HP, 0)}, - {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54MINI2, 0)}, - {USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUSMM, 0)}, - {USB_VPI(USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2573, 0)}, - {USB_VPI(USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2573_2, 0)}, - {USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2573, 0)}, - {USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2573_2, 0)}, - {USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2671, 0)}, - {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL113R2, 0)}, - {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL172, 0)}, - {USB_VPI(USB_VENDOR_SPARKLAN, USB_PRODUCT_SPARKLAN_RT2573, 0)}, - {USB_VPI(USB_VENDOR_SURECOM, USB_PRODUCT_SURECOM_RT2573, 0)}, +static const struct { + uint32_t reg; + uint32_t val; +} rum_def_mac[] = { + { RT2573_TXRX_CSR0, 0x025fb032 }, + { RT2573_TXRX_CSR1, 0x9eaa9eaf }, + { RT2573_TXRX_CSR2, 0x8a8b8c8d }, + { RT2573_TXRX_CSR3, 0x00858687 }, + { RT2573_TXRX_CSR7, 0x2e31353b }, + { RT2573_TXRX_CSR8, 0x2a2a2a2c }, + { RT2573_TXRX_CSR15, 0x0000000f }, + { RT2573_MAC_CSR6, 0x00000fff }, + { RT2573_MAC_CSR8, 0x016c030a }, + { RT2573_MAC_CSR10, 0x00000718 }, + { RT2573_MAC_CSR12, 0x00000004 }, + { RT2573_MAC_CSR13, 0x00007f00 }, + { RT2573_SEC_CSR0, 0x00000000 }, + { RT2573_SEC_CSR1, 0x00000000 }, + { RT2573_SEC_CSR5, 0x00000000 }, + { RT2573_PHY_CSR1, 0x000023b0 }, + { RT2573_PHY_CSR5, 0x00040a06 }, + { RT2573_PHY_CSR6, 0x00080606 }, + { RT2573_PHY_CSR7, 0x00000408 }, + { RT2573_AIFSN_CSR, 0x00002273 }, + { RT2573_CWMIN_CSR, 0x00002344 }, + { RT2573_CWMAX_CSR, 0x000034aa } }; -struct rum_def_mac { - uint32_t reg; - uint32_t val; -}; - -static const struct rum_def_mac rum_def_mac[] = { - {RT2573_TXRX_CSR0, 0x025fb032}, - {RT2573_TXRX_CSR1, 0x9eaa9eaf}, - {RT2573_TXRX_CSR2, 0x8a8b8c8d}, - {RT2573_TXRX_CSR3, 0x00858687}, - {RT2573_TXRX_CSR7, 0x2e31353b}, - {RT2573_TXRX_CSR8, 0x2a2a2a2c}, - {RT2573_TXRX_CSR15, 0x0000000f}, - {RT2573_MAC_CSR6, 0x00000fff}, - {RT2573_MAC_CSR8, 0x016c030a}, - {RT2573_MAC_CSR10, 0x00000718}, - {RT2573_MAC_CSR12, 0x00000004}, - {RT2573_MAC_CSR13, 0x00007f00}, - {RT2573_SEC_CSR0, 0x00000000}, - {RT2573_SEC_CSR1, 0x00000000}, - {RT2573_SEC_CSR5, 0x00000000}, - {RT2573_PHY_CSR1, 0x000023b0}, - {RT2573_PHY_CSR5, 0x00040a06}, - {RT2573_PHY_CSR6, 0x00080606}, - {RT2573_PHY_CSR7, 0x00000408}, - {RT2573_AIFSN_CSR, 0x00002273}, - {RT2573_CWMIN_CSR, 0x00002344}, - {RT2573_CWMAX_CSR, 0x000034aa} -}; - -struct rum_def_bbp { +static const struct { uint8_t reg; uint8_t val; +} rum_def_bbp[] = { + { 3, 0x80 }, + { 15, 0x30 }, + { 17, 0x20 }, + { 21, 0xc8 }, + { 22, 0x38 }, + { 23, 0x06 }, + { 24, 0xfe }, + { 25, 0x0a }, + { 26, 0x0d }, + { 32, 0x0b }, + { 34, 0x12 }, + { 37, 0x07 }, + { 39, 0xf8 }, + { 41, 0x60 }, + { 53, 0x10 }, + { 54, 0x18 }, + { 60, 0x10 }, + { 61, 0x04 }, + { 62, 0x04 }, + { 75, 0xfe }, + { 86, 0xfe }, + { 88, 0xfe }, + { 90, 0x0f }, + { 99, 0x00 }, + { 102, 0x16 }, + { 107, 0x04 } }; -static const struct rum_def_bbp rum_def_bbp[] = { - {3, 0x80}, - {15, 0x30}, - {17, 0x20}, - {21, 0xc8}, - {22, 0x38}, - {23, 0x06}, - {24, 0xfe}, - {25, 0x0a}, - {26, 0x0d}, - {32, 0x0b}, - {34, 0x12}, - {37, 0x07}, - {39, 0xf8}, - {41, 0x60}, - {53, 0x10}, - {54, 0x18}, - {60, 0x10}, - {61, 0x04}, - {62, 0x04}, - {75, 0xfe}, - {86, 0xfe}, - {88, 0xfe}, - {90, 0x0f}, - {99, 0x00}, - {102, 0x16}, - {107, 0x04} -}; +static const struct rfprog { + uint8_t chan; + uint32_t r1, r2, r3, r4; +} rum_rf5226[] = { + { 1, 0x00b03, 0x001e1, 0x1a014, 0x30282 }, + { 2, 0x00b03, 0x001e1, 0x1a014, 0x30287 }, + { 3, 0x00b03, 0x001e2, 0x1a014, 0x30282 }, + { 4, 0x00b03, 0x001e2, 0x1a014, 0x30287 }, + { 5, 0x00b03, 0x001e3, 0x1a014, 0x30282 }, + { 6, 0x00b03, 0x001e3, 0x1a014, 0x30287 }, + { 7, 0x00b03, 0x001e4, 0x1a014, 0x30282 }, + { 8, 0x00b03, 0x001e4, 0x1a014, 0x30287 }, + { 9, 0x00b03, 0x001e5, 0x1a014, 0x30282 }, + { 10, 0x00b03, 0x001e5, 0x1a014, 0x30287 }, + { 11, 0x00b03, 0x001e6, 0x1a014, 0x30282 }, + { 12, 0x00b03, 0x001e6, 0x1a014, 0x30287 }, + { 13, 0x00b03, 0x001e7, 0x1a014, 0x30282 }, + { 14, 0x00b03, 0x001e8, 0x1a014, 0x30284 }, -struct rfprog { - uint8_t chan; - uint32_t r1, r2, r3, r4; -}; + { 34, 0x00b03, 0x20266, 0x36014, 0x30282 }, + { 38, 0x00b03, 0x20267, 0x36014, 0x30284 }, + { 42, 0x00b03, 0x20268, 0x36014, 0x30286 }, + { 46, 0x00b03, 0x20269, 0x36014, 0x30288 }, -static const struct rfprog rum_rf5226[] = { - {1, 0x00b03, 0x001e1, 0x1a014, 0x30282}, - {2, 0x00b03, 0x001e1, 0x1a014, 0x30287}, - {3, 0x00b03, 0x001e2, 0x1a014, 0x30282}, - {4, 0x00b03, 0x001e2, 0x1a014, 0x30287}, - {5, 0x00b03, 0x001e3, 0x1a014, 0x30282}, - {6, 0x00b03, 0x001e3, 0x1a014, 0x30287}, - {7, 0x00b03, 0x001e4, 0x1a014, 0x30282}, - {8, 0x00b03, 0x001e4, 0x1a014, 0x30287}, - {9, 0x00b03, 0x001e5, 0x1a014, 0x30282}, - {10, 0x00b03, 0x001e5, 0x1a014, 0x30287}, - {11, 0x00b03, 0x001e6, 0x1a014, 0x30282}, - {12, 0x00b03, 0x001e6, 0x1a014, 0x30287}, - {13, 0x00b03, 0x001e7, 0x1a014, 0x30282}, - {14, 0x00b03, 0x001e8, 0x1a014, 0x30284}, + { 36, 0x00b03, 0x00266, 0x26014, 0x30288 }, + { 40, 0x00b03, 0x00268, 0x26014, 0x30280 }, + { 44, 0x00b03, 0x00269, 0x26014, 0x30282 }, + { 48, 0x00b03, 0x0026a, 0x26014, 0x30284 }, + { 52, 0x00b03, 0x0026b, 0x26014, 0x30286 }, + { 56, 0x00b03, 0x0026c, 0x26014, 0x30288 }, + { 60, 0x00b03, 0x0026e, 0x26014, 0x30280 }, + { 64, 0x00b03, 0x0026f, 0x26014, 0x30282 }, - {34, 0x00b03, 0x20266, 0x36014, 0x30282}, - {38, 0x00b03, 0x20267, 0x36014, 0x30284}, - {42, 0x00b03, 0x20268, 0x36014, 0x30286}, - {46, 0x00b03, 0x20269, 0x36014, 0x30288}, + { 100, 0x00b03, 0x0028a, 0x2e014, 0x30280 }, + { 104, 0x00b03, 0x0028b, 0x2e014, 0x30282 }, + { 108, 0x00b03, 0x0028c, 0x2e014, 0x30284 }, + { 112, 0x00b03, 0x0028d, 0x2e014, 0x30286 }, + { 116, 0x00b03, 0x0028e, 0x2e014, 0x30288 }, + { 120, 0x00b03, 0x002a0, 0x2e014, 0x30280 }, + { 124, 0x00b03, 0x002a1, 0x2e014, 0x30282 }, + { 128, 0x00b03, 0x002a2, 0x2e014, 0x30284 }, + { 132, 0x00b03, 0x002a3, 0x2e014, 0x30286 }, + { 136, 0x00b03, 0x002a4, 0x2e014, 0x30288 }, + { 140, 0x00b03, 0x002a6, 0x2e014, 0x30280 }, - {36, 0x00b03, 0x00266, 0x26014, 0x30288}, - {40, 0x00b03, 0x00268, 0x26014, 0x30280}, - {44, 0x00b03, 0x00269, 0x26014, 0x30282}, - {48, 0x00b03, 0x0026a, 0x26014, 0x30284}, - {52, 0x00b03, 0x0026b, 0x26014, 0x30286}, - {56, 0x00b03, 0x0026c, 0x26014, 0x30288}, - {60, 0x00b03, 0x0026e, 0x26014, 0x30280}, - {64, 0x00b03, 0x0026f, 0x26014, 0x30282}, + { 149, 0x00b03, 0x002a8, 0x2e014, 0x30287 }, + { 153, 0x00b03, 0x002a9, 0x2e014, 0x30289 }, + { 157, 0x00b03, 0x002ab, 0x2e014, 0x30281 }, + { 161, 0x00b03, 0x002ac, 0x2e014, 0x30283 }, + { 165, 0x00b03, 0x002ad, 0x2e014, 0x30285 } +}, rum_rf5225[] = { + { 1, 0x00b33, 0x011e1, 0x1a014, 0x30282 }, + { 2, 0x00b33, 0x011e1, 0x1a014, 0x30287 }, + { 3, 0x00b33, 0x011e2, 0x1a014, 0x30282 }, + { 4, 0x00b33, 0x011e2, 0x1a014, 0x30287 }, + { 5, 0x00b33, 0x011e3, 0x1a014, 0x30282 }, + { 6, 0x00b33, 0x011e3, 0x1a014, 0x30287 }, + { 7, 0x00b33, 0x011e4, 0x1a014, 0x30282 }, + { 8, 0x00b33, 0x011e4, 0x1a014, 0x30287 }, + { 9, 0x00b33, 0x011e5, 0x1a014, 0x30282 }, + { 10, 0x00b33, 0x011e5, 0x1a014, 0x30287 }, + { 11, 0x00b33, 0x011e6, 0x1a014, 0x30282 }, + { 12, 0x00b33, 0x011e6, 0x1a014, 0x30287 }, + { 13, 0x00b33, 0x011e7, 0x1a014, 0x30282 }, + { 14, 0x00b33, 0x011e8, 0x1a014, 0x30284 }, - {100, 0x00b03, 0x0028a, 0x2e014, 0x30280}, - {104, 0x00b03, 0x0028b, 0x2e014, 0x30282}, - {108, 0x00b03, 0x0028c, 0x2e014, 0x30284}, - {112, 0x00b03, 0x0028d, 0x2e014, 0x30286}, - {116, 0x00b03, 0x0028e, 0x2e014, 0x30288}, - {120, 0x00b03, 0x002a0, 0x2e014, 0x30280}, - {124, 0x00b03, 0x002a1, 0x2e014, 0x30282}, - {128, 0x00b03, 0x002a2, 0x2e014, 0x30284}, - {132, 0x00b03, 0x002a3, 0x2e014, 0x30286}, - {136, 0x00b03, 0x002a4, 0x2e014, 0x30288}, - {140, 0x00b03, 0x002a6, 0x2e014, 0x30280}, + { 34, 0x00b33, 0x01266, 0x26014, 0x30282 }, + { 38, 0x00b33, 0x01267, 0x26014, 0x30284 }, + { 42, 0x00b33, 0x01268, 0x26014, 0x30286 }, + { 46, 0x00b33, 0x01269, 0x26014, 0x30288 }, - {149, 0x00b03, 0x002a8, 0x2e014, 0x30287}, - {153, 0x00b03, 0x002a9, 0x2e014, 0x30289}, - {157, 0x00b03, 0x002ab, 0x2e014, 0x30281}, - {161, 0x00b03, 0x002ac, 0x2e014, 0x30283}, - {165, 0x00b03, 0x002ad, 0x2e014, 0x30285} -}; + { 36, 0x00b33, 0x01266, 0x26014, 0x30288 }, + { 40, 0x00b33, 0x01268, 0x26014, 0x30280 }, + { 44, 0x00b33, 0x01269, 0x26014, 0x30282 }, + { 48, 0x00b33, 0x0126a, 0x26014, 0x30284 }, + { 52, 0x00b33, 0x0126b, 0x26014, 0x30286 }, + { 56, 0x00b33, 0x0126c, 0x26014, 0x30288 }, + { 60, 0x00b33, 0x0126e, 0x26014, 0x30280 }, + { 64, 0x00b33, 0x0126f, 0x26014, 0x30282 }, -static const struct rfprog rum_rf5225[] = { - {1, 0x00b33, 0x011e1, 0x1a014, 0x30282}, - {2, 0x00b33, 0x011e1, 0x1a014, 0x30287}, - {3, 0x00b33, 0x011e2, 0x1a014, 0x30282}, - {4, 0x00b33, 0x011e2, 0x1a014, 0x30287}, - {5, 0x00b33, 0x011e3, 0x1a014, 0x30282}, - {6, 0x00b33, 0x011e3, 0x1a014, 0x30287}, - {7, 0x00b33, 0x011e4, 0x1a014, 0x30282}, - {8, 0x00b33, 0x011e4, 0x1a014, 0x30287}, - {9, 0x00b33, 0x011e5, 0x1a014, 0x30282}, - {10, 0x00b33, 0x011e5, 0x1a014, 0x30287}, - {11, 0x00b33, 0x011e6, 0x1a014, 0x30282}, - {12, 0x00b33, 0x011e6, 0x1a014, 0x30287}, - {13, 0x00b33, 0x011e7, 0x1a014, 0x30282}, - {14, 0x00b33, 0x011e8, 0x1a014, 0x30284}, + { 100, 0x00b33, 0x0128a, 0x2e014, 0x30280 }, + { 104, 0x00b33, 0x0128b, 0x2e014, 0x30282 }, + { 108, 0x00b33, 0x0128c, 0x2e014, 0x30284 }, + { 112, 0x00b33, 0x0128d, 0x2e014, 0x30286 }, + { 116, 0x00b33, 0x0128e, 0x2e014, 0x30288 }, + { 120, 0x00b33, 0x012a0, 0x2e014, 0x30280 }, + { 124, 0x00b33, 0x012a1, 0x2e014, 0x30282 }, + { 128, 0x00b33, 0x012a2, 0x2e014, 0x30284 }, + { 132, 0x00b33, 0x012a3, 0x2e014, 0x30286 }, + { 136, 0x00b33, 0x012a4, 0x2e014, 0x30288 }, + { 140, 0x00b33, 0x012a6, 0x2e014, 0x30280 }, - {34, 0x00b33, 0x01266, 0x26014, 0x30282}, - {38, 0x00b33, 0x01267, 0x26014, 0x30284}, - {42, 0x00b33, 0x01268, 0x26014, 0x30286}, - {46, 0x00b33, 0x01269, 0x26014, 0x30288}, - - {36, 0x00b33, 0x01266, 0x26014, 0x30288}, - {40, 0x00b33, 0x01268, 0x26014, 0x30280}, - {44, 0x00b33, 0x01269, 0x26014, 0x30282}, - {48, 0x00b33, 0x0126a, 0x26014, 0x30284}, - {52, 0x00b33, 0x0126b, 0x26014, 0x30286}, - {56, 0x00b33, 0x0126c, 0x26014, 0x30288}, - {60, 0x00b33, 0x0126e, 0x26014, 0x30280}, - {64, 0x00b33, 0x0126f, 0x26014, 0x30282}, - - {100, 0x00b33, 0x0128a, 0x2e014, 0x30280}, - {104, 0x00b33, 0x0128b, 0x2e014, 0x30282}, - {108, 0x00b33, 0x0128c, 0x2e014, 0x30284}, - {112, 0x00b33, 0x0128d, 0x2e014, 0x30286}, - {116, 0x00b33, 0x0128e, 0x2e014, 0x30288}, - {120, 0x00b33, 0x012a0, 0x2e014, 0x30280}, - {124, 0x00b33, 0x012a1, 0x2e014, 0x30282}, - {128, 0x00b33, 0x012a2, 0x2e014, 0x30284}, - {132, 0x00b33, 0x012a3, 0x2e014, 0x30286}, - {136, 0x00b33, 0x012a4, 0x2e014, 0x30288}, - {140, 0x00b33, 0x012a6, 0x2e014, 0x30280}, - - {149, 0x00b33, 0x012a8, 0x2e014, 0x30287}, - {153, 0x00b33, 0x012a9, 0x2e014, 0x30289}, - {157, 0x00b33, 0x012ab, 0x2e014, 0x30281}, - {161, 0x00b33, 0x012ac, 0x2e014, 0x30283}, - {165, 0x00b33, 0x012ad, 0x2e014, 0x30285} + { 149, 0x00b33, 0x012a8, 0x2e014, 0x30287 }, + { 153, 0x00b33, 0x012a9, 0x2e014, 0x30289 }, + { 157, 0x00b33, 0x012ab, 0x2e014, 0x30281 }, + { 161, 0x00b33, 0x012ac, 0x2e014, 0x30283 }, + { 165, 0x00b33, 0x012ad, 0x2e014, 0x30285 } }; static const struct usb2_config rum_config[RUM_N_TRANSFER] = { - [RUM_BULK_DT_WR] = { + [RUM_BULK_WR] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .mh.bufsize = (MCLBYTES + RT2573_TX_DESC_SIZE + 8), .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .mh.callback = &rum_bulk_write_callback, + .mh.callback = rum_bulk_write_callback, .mh.timeout = 5000, /* ms */ }, - - [RUM_BULK_DT_RD] = { + [RUM_BULK_RD] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .mh.bufsize = (MCLBYTES + RT2573_RX_DESC_SIZE), .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, - .mh.callback = &rum_bulk_read_callback, - }, - - [RUM_BULK_CS_WR] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.callback = &rum_bulk_write_clear_stall_callback, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ - }, - - [RUM_BULK_CS_RD] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.callback = &rum_bulk_read_clear_stall_callback, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ + .mh.callback = rum_bulk_read_callback, }, }; -static devclass_t rum_devclass; - -static device_method_t rum_methods[] = { - DEVMETHOD(device_probe, rum_probe), - DEVMETHOD(device_attach, rum_attach), - DEVMETHOD(device_detach, rum_detach), - {0, 0} -}; - -static driver_t rum_driver = { - .name = "rum", - .methods = rum_methods, - .size = sizeof(struct rum_softc), -}; - -DRIVER_MODULE(rum, ushub, rum_driver, rum_devclass, NULL, 0); -MODULE_DEPEND(rum, usb2_wlan, 1, 1, 1); -MODULE_DEPEND(rum, usb2_core, 1, 1, 1); -MODULE_DEPEND(rum, wlan, 1, 1, 1); -MODULE_DEPEND(rum, wlan_amrr, 1, 1, 1); - static int -rum_probe(device_t dev) +rum_match(device_t self) { - struct usb2_attach_arg *uaa = device_get_ivars(dev); + struct usb2_attach_arg *uaa = device_get_ivars(self); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb2_mode != USB_MODE_HOST) return (ENXIO); - } - if (uaa->info.bConfigIndex != 0) { + if (uaa->info.bConfigIndex != 0) return (ENXIO); - } - if (uaa->info.bIfaceIndex != RT2573_IFACE_INDEX) { + if (uaa->info.bIfaceIndex != RT2573_IFACE_INDEX) return (ENXIO); - } + return (usb2_lookup_id_by_uaa(rum_devs, sizeof(rum_devs), uaa)); } static int -rum_attach(device_t dev) +rum_attach(device_t self) { - struct usb2_attach_arg *uaa = device_get_ivars(dev); - struct rum_softc *sc = device_get_softc(dev); - int error; + struct usb2_attach_arg *uaa = device_get_ivars(self); + struct rum_softc *sc = device_get_softc(self); uint8_t iface_index; + int error; - device_set_usb2_desc(dev); - - mtx_init(&sc->sc_mtx, "rum lock", MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); - - snprintf(sc->sc_name, sizeof(sc->sc_name), "%s", - device_get_nameunit(dev)); - + device_set_usb2_desc(self); sc->sc_udev = uaa->device; - sc->sc_unit = device_get_unit(dev); + sc->sc_dev = self; - usb2_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); + mtx_init(&sc->sc_mtx, device_get_nameunit(self), + MTX_NETWORK_LOCK, MTX_DEF); iface_index = RT2573_IFACE_INDEX; error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, rum_config, RUM_N_TRANSFER, sc, &sc->sc_mtx); if (error) { - device_printf(dev, "could not allocate USB transfers, " + device_printf(self, "could not allocate USB transfers, " "err=%s\n", usb2_errstr(error)); goto detach; } - error = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_mtx, - &rum_end_of_commands, - sizeof(struct usb2_config_td_cc), 24); + error = usb2_proc_create(&sc->sc_tq, &sc->sc_mtx, + device_get_nameunit(self), USB_PRI_MED); if (error) { - device_printf(dev, "could not setup config " - "thread!\n"); + device_printf(self, "could not setup config thread!\n"); goto detach; } - mtx_lock(&sc->sc_mtx); - /* start setup */ - - usb2_config_td_queue_command - (&sc->sc_config_td, NULL, &rum_cfg_first_time_setup, 0, 0); - - rum_watchdog(sc); - mtx_unlock(&sc->sc_mtx); - return (0); /* success */ + /* fork rest of the attach code */ + RUM_LOCK(sc); + rum_queue_command(sc, rum_attach_post, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + RUM_UNLOCK(sc); + return (0); detach: - rum_detach(dev); + rum_detach(self); return (ENXIO); /* failure */ } -static int -rum_detach(device_t dev) +static void +rum_attach_post(struct usb2_proc_msg *pm) { - struct rum_softc *sc = device_get_softc(dev); - struct ieee80211com *ic; + struct rum_task *task = (struct rum_task *)pm; + struct rum_softc *sc = task->sc; struct ifnet *ifp; - - usb2_config_td_drain(&sc->sc_config_td); - - mtx_lock(&sc->sc_mtx); - - usb2_callout_stop(&sc->sc_watchdog); - - rum_cfg_pre_stop(sc, NULL, 0); - - ifp = sc->sc_ifp; - ic = ifp->if_l2com; - - mtx_unlock(&sc->sc_mtx); - - /* stop all USB transfers first */ - usb2_transfer_unsetup(sc->sc_xfer, RUM_N_TRANSFER); - - /* get rid of any late children */ - bus_generic_detach(dev); - - if (ifp) { - bpfdetach(ifp); - ieee80211_ifdetach(ic); - if_free(ifp); - } - usb2_config_td_unsetup(&sc->sc_config_td); - - usb2_callout_drain(&sc->sc_watchdog); - - mtx_destroy(&sc->sc_mtx); - - return (0); -} - -static void -rum_cfg_do_request(struct rum_softc *sc, struct usb2_device_request *req, - void *data) -{ - uint16_t length; - usb2_error_t err; - -repeat: - - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - goto error; - } - err = usb2_do_request_flags - (sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 1000); - - if (err) { - - DPRINTF("device request failed, err=%s " - "(ignored)\n", usb2_errstr(err)); - - /* wait a little before next try */ - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 4)) { - goto error; - } - /* try until we are detached */ - goto repeat; - -error: - /* the device has been detached */ - length = UGETW(req->wLength); - - if ((req->bmRequestType & UT_READ) && length) { - bzero(data, length); - } - } -} - -static void -rum_cfg_eeprom_read(struct rum_softc *sc, uint16_t addr, void *buf, uint16_t len) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = RT2573_READ_EEPROM; - USETW(req.wValue, 0); - USETW(req.wIndex, addr); - USETW(req.wLength, len); - - rum_cfg_do_request(sc, &req, buf); -} - -static uint16_t -rum_cfg_eeprom_read_2(struct rum_softc *sc, uint16_t addr) -{ - uint16_t tmp; - - rum_cfg_eeprom_read(sc, addr, &tmp, sizeof(tmp)); - return (le16toh(tmp)); -} - -static uint32_t -rum_cfg_read(struct rum_softc *sc, uint16_t reg) -{ - uint32_t val; - - rum_cfg_read_multi(sc, reg, &val, sizeof(val)); - return (le32toh(val)); -} - -static void -rum_cfg_read_multi(struct rum_softc *sc, uint16_t reg, void *buf, uint16_t len) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = RT2573_READ_MULTI_MAC; - USETW(req.wValue, 0); - USETW(req.wIndex, reg); - USETW(req.wLength, len); - - rum_cfg_do_request(sc, &req, buf); -} - -static void -rum_cfg_write(struct rum_softc *sc, uint16_t reg, uint32_t val) -{ - uint32_t tmp = htole32(val); - - rum_cfg_write_multi(sc, reg, &tmp, sizeof(tmp)); -} - -static void -rum_cfg_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, uint16_t len) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_WRITE_VENDOR_DEVICE; - req.bRequest = RT2573_WRITE_MULTI_MAC; - USETW(req.wValue, 0); - USETW(req.wIndex, reg); - USETW(req.wLength, len); - - rum_cfg_do_request(sc, &req, buf); -} - -static uint32_t -rum_cfg_bbp_disbusy(struct rum_softc *sc) -{ - uint32_t tmp; - uint8_t to; - - for (to = 0;; to++) { - if (to < 100) { - tmp = rum_cfg_read(sc, RT2573_PHY_CSR3); - - if ((tmp & RT2573_BBP_BUSY) == 0) { - return (tmp); - } - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - break; - } - } else { - break; - } - } - DPRINTF("could not disbusy BBP\n"); - return (RT2573_BBP_BUSY); /* failure */ -} - -static void -rum_cfg_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) -{ - uint32_t tmp; - - if (rum_cfg_bbp_disbusy(sc) & RT2573_BBP_BUSY) { - return; - } - tmp = RT2573_BBP_BUSY | ((reg & 0x7f) << 8) | val; - rum_cfg_write(sc, RT2573_PHY_CSR3, tmp); -} - -static uint8_t -rum_cfg_bbp_read(struct rum_softc *sc, uint8_t reg) -{ - uint32_t val; - - if (rum_cfg_bbp_disbusy(sc) & RT2573_BBP_BUSY) { - return (0); - } - val = RT2573_BBP_BUSY | RT2573_BBP_READ | (reg << 8); - rum_cfg_write(sc, RT2573_PHY_CSR3, val); - - val = rum_cfg_bbp_disbusy(sc); - return (val & 0xff); -} - -static void -rum_cfg_rf_write(struct rum_softc *sc, uint8_t reg, uint32_t val) -{ - uint32_t tmp; - uint8_t to; - - reg &= 3; - - for (to = 0;; to++) { - if (to < 100) { - tmp = rum_cfg_read(sc, RT2573_PHY_CSR4); - if (!(tmp & RT2573_RF_BUSY)) { - break; - } - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - return; - } - } else { - DPRINTF("could not write to RF\n"); - return; - } - } - - tmp = RT2573_RF_BUSY | RT2573_RF_20BIT | ((val & 0xfffff) << 2) | reg; - rum_cfg_write(sc, RT2573_PHY_CSR4, tmp); - - DPRINTFN(16, "RF R[%u] <- 0x%05x\n", reg, val & 0xfffff); -} - -static void -rum_cfg_first_time_setup(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ struct ieee80211com *ic; - struct ifnet *ifp; + unsigned int ntries; + int error; uint32_t tmp; - uint16_t i; uint8_t bands; - /* 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(RT2573_RX_RADIOTAP_PRESENT); - - /* 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(RT2573_TX_RADIOTAP_PRESENT); - /* retrieve RT2573 rev. no */ - for (i = 0; i < 100; i++) { - - tmp = rum_cfg_read(sc, RT2573_MAC_CSR0); - if (tmp != 0) { + for (ntries = 0; ntries != 1000; ntries++) { + if ((tmp = rum_read(sc, RT2573_MAC_CSR0)) != 0) break; - } - /* wait a little */ - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - /* device detached */ - goto done; - } + usb2_pause_mtx(&sc->sc_mtx, hz / 1000); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, "timeout waiting for chip to settle\n"); + return; } - if (tmp == 0) { - DPRINTF("chip is maybe not ready\n"); - } /* retrieve MAC address and various other things from EEPROM */ - rum_cfg_read_eeprom(sc); + rum_read_eeprom(sc); - printf("%s: MAC/BBP RT2573 (rev 0x%05x), RF %s\n", - sc->sc_name, tmp, rum_get_rf(sc->sc_rf_rev)); + device_printf(sc->sc_dev, "MAC/BBP RT2573 (rev 0x%05x), RF %s\n", + tmp, rum_get_rf(sc->rf_rev)); - rum_cfg_load_microcode(sc, rt2573_ucode, sizeof(rt2573_ucode)); - - mtx_unlock(&sc->sc_mtx); - - ifp = if_alloc(IFT_IEEE80211); - - mtx_lock(&sc->sc_mtx); - - if (ifp == NULL) { - DPRINTFN(0, "could not if_alloc()!\n"); - goto done; + error = rum_load_microcode(sc, rt2573_ucode, sizeof(rt2573_ucode)); + if (error != 0) { + RUM_UNLOCK(sc); + device_printf(sc->sc_dev, "could not load 8051 microcode\n"); + return; + } + RUM_UNLOCK(sc); + + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + RUM_LOCK(sc); + return; } - sc->sc_ifp = ifp; ic = ifp->if_l2com; ifp->if_softc = sc; - if_initname(ifp, "rum", sc->sc_unit); + if_initname(ifp, "rum", device_get_unit(sc->sc_dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_init = &rum_init_cb; - ifp->if_ioctl = &rum_ioctl_cb; - ifp->if_start = &rum_start_cb; - ifp->if_watchdog = NULL; + ifp->if_init = rum_init; + ifp->if_ioctl = rum_ioctl; + ifp->if_start = rum_start; 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; /* not only, but not used */ - ic->ic_opmode = IEEE80211_M_STA; + IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_bssid); /* set device capabilities */ ic->ic_caps = - IEEE80211_C_STA /* station mode supported */ + IEEE80211_C_STA /* station mode supported */ | IEEE80211_C_IBSS /* IBSS mode supported */ | IEEE80211_C_MONITOR /* monitor mode supported */ | IEEE80211_C_HOSTAP /* HostAp mode supported */ @@ -823,1711 +508,83 @@ rum_cfg_first_time_setup(struct rum_softc *sc, bands = 0; setbit(&bands, IEEE80211_MODE_11B); setbit(&bands, IEEE80211_MODE_11G); + if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) + setbit(&bands, IEEE80211_MODE_11A); ieee80211_init_channels(ic, NULL, &bands); - if ((sc->sc_rf_rev == RT2573_RF_5225) || - (sc->sc_rf_rev == RT2573_RF_5226)) { - - struct ieee80211_channel *c; - - /* set supported .11a channels */ - for (i = 34; i <= 46; i += 4) { - c = ic->ic_channels + (ic->ic_nchans++); - c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A; - c->ic_ieee = i; - } - for (i = 36; i <= 64; i += 4) { - c = ic->ic_channels + (ic->ic_nchans++); - c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A; - c->ic_ieee = i; - } - for (i = 100; i <= 140; i += 4) { - c = ic->ic_channels + (ic->ic_nchans++); - c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A; - c->ic_ieee = i; - } - for (i = 149; i <= 165; i += 4) { - c = ic->ic_channels + (ic->ic_nchans++); - c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A; - c->ic_ieee = i; - } - } - mtx_unlock(&sc->sc_mtx); - ieee80211_ifattach(ic); + ic->ic_newassoc = rum_newassoc; + ic->ic_raw_xmit = rum_raw_xmit; + ic->ic_node_alloc = rum_node_alloc; + ic->ic_scan_start = rum_scan_start; + ic->ic_scan_end = rum_scan_end; + ic->ic_set_channel = rum_set_channel; - mtx_lock(&sc->sc_mtx); - - ic->ic_newassoc = &rum_newassoc; - ic->ic_raw_xmit = &rum_raw_xmit_cb; - ic->ic_node_alloc = &rum_node_alloc; - ic->ic_update_mcast = &rum_update_mcast_cb; - ic->ic_update_promisc = &rum_update_promisc_cb; - ic->ic_scan_start = &rum_scan_start_cb; - ic->ic_scan_end = &rum_scan_end_cb; - ic->ic_set_channel = &rum_set_channel_cb; - ic->ic_vap_create = &rum_vap_create; - ic->ic_vap_delete = &rum_vap_delete; + ic->ic_vap_create = rum_vap_create; + ic->ic_vap_delete = rum_vap_delete; sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); - mtx_unlock(&sc->sc_mtx); - bpfattach(ifp, DLT_IEEE802_11_RADIO, - sizeof(struct ieee80211_frame) + sizeof(sc->sc_txtap)); + sizeof (struct ieee80211_frame) + sizeof(sc->sc_txtap)); - if (bootverbose) { + 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(RT2573_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(RT2573_TX_RADIOTAP_PRESENT); + + if (bootverbose) ieee80211_announce(ic); - } - mtx_lock(&sc->sc_mtx); -done: - return; + + RUM_LOCK(sc); } -static void -rum_end_of_commands(struct rum_softc *sc) +static int +rum_detach(device_t self) { - sc->sc_flags &= ~RUM_FLAG_WAIT_COMMAND; + struct rum_softc *sc = device_get_softc(self); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - /* start write transfer, if not started */ - usb2_transfer_start(sc->sc_xfer[RUM_BULK_DT_WR]); -} + /* wait for any post attach or other command to complete */ + usb2_proc_drain(&sc->sc_tq); -static void -rum_config_copy_chan(struct rum_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); - 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; - } -} + /* stop all USB transfers */ + usb2_transfer_unsetup(sc->sc_xfer, RUM_N_TRANSFER); + usb2_proc_free(&sc->sc_tq); -static void -rum_config_copy(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp; - struct ieee80211com *ic; - struct ieee80211_node *ni; - struct ieee80211vap *vap; - const struct ieee80211_txparam *tp; + /* free TX list, if any */ + RUM_LOCK(sc); + rum_unsetup_tx_list(sc); + RUM_UNLOCK(sc); - bzero(cc, sizeof(*cc)); - - ifp = sc->sc_ifp; if (ifp) { - cc->if_flags = ifp->if_flags; - bcopy(ifp->if_broadcastaddr, cc->if_broadcastaddr, - sizeof(cc->if_broadcastaddr)); - - ic = ifp->if_l2com; - if (ic) { - rum_config_copy_chan(&cc->ic_curchan, ic, ic->ic_curchan); - rum_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; - - bcopy(ic->ic_myaddr, cc->ic_myaddr, - sizeof(cc->ic_myaddr)); - } - } - sc->sc_flags |= RUM_FLAG_WAIT_COMMAND; -} - -static const char * -rum_get_rf(uint32_t rev) -{ - ; /* indent fix */ - switch (rev) { - case RT2573_RF_2527: - return "RT2527 (MIMO XR)"; - case RT2573_RF_2528: - return "RT2528"; - case RT2573_RF_5225: - return "RT5225 (MIMO XR)"; - case RT2573_RF_5226: - return "RT5226"; - default: - return "unknown"; - } -} - -static void -rum_bulk_read_callback(struct usb2_xfer *xfer) -{ - struct rum_softc *sc = xfer->priv_sc; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211_node *ni; - - struct mbuf *m = NULL; - uint32_t flags; - uint32_t max_len; - uint8_t rssi = 0; - - switch (USB_GET_STATE(xfer)) { - case USB_ST_TRANSFERRED: - - DPRINTFN(15, "rx done, actlen=%d\n", xfer->actlen); - - if (xfer->actlen < (RT2573_RX_DESC_SIZE + IEEE80211_MIN_LEN)) { - DPRINTF("too short transfer, " - "%d bytes\n", xfer->actlen); - ifp->if_ierrors++; - goto tr_setup; - } - usb2_copy_out(xfer->frbuffers, 0, - &sc->sc_rx_desc, RT2573_RX_DESC_SIZE); - - flags = le32toh(sc->sc_rx_desc.flags); - - if (flags & RT2573_RX_CRC_ERROR) { - /* - * This should not happen since we did not - * request to receive those frames when we - * filled RAL_TXRX_CSR2: - */ - DPRINTFN(6, "PHY or CRC error\n"); - ifp->if_ierrors++; - goto tr_setup; - } - m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - - if (m == NULL) { - DPRINTF("could not allocate mbuf\n"); - ifp->if_ierrors++; - goto tr_setup; - } - max_len = (xfer->actlen - RT2573_RX_DESC_SIZE); - - usb2_copy_out(xfer->frbuffers, RT2573_RX_DESC_SIZE, - m->m_data, max_len); - - /* finalize mbuf */ - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; - - if (m->m_len > max_len) { - DPRINTF("invalid length in RX " - "descriptor, %u bytes, received %u bytes\n", - m->m_len, max_len); - ifp->if_ierrors++; - m_freem(m); - m = NULL; - goto tr_setup; - } - rssi = rum_get_rssi(sc, sc->sc_rx_desc.rssi); - - DPRINTF("real length=%d bytes, rssi=%d\n", m->m_len, rssi); - - if (bpf_peers_present(ifp->if_bpf)) { - struct rum_rx_radiotap_header *tap = &sc->sc_rxtap; - - tap->wr_flags = IEEE80211_RADIOTAP_F_FCS; - tap->wr_rate = ieee80211_plcp2rate(sc->sc_rx_desc.rate, - (sc->sc_rx_desc.flags & htole32(RT2573_RX_OFDM)) ? - IEEE80211_T_OFDM : IEEE80211_T_CCK); - tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); - tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); - tap->wr_antenna = sc->sc_rx_ant; - tap->wr_antsignal = rssi; - - bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); - } - case USB_ST_SETUP: -tr_setup: - - if (sc->sc_flags & RUM_FLAG_READ_STALL) { - usb2_transfer_start(sc->sc_xfer[RUM_BULK_CS_RD]); - } else { - xfer->frlengths[0] = xfer->max_data_length; - usb2_start_hardware(xfer); - } - - /* - * 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 (m) { - mtx_unlock(&sc->sc_mtx); - - ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); - if (ni != NULL) { - if (ieee80211_input(ni, m, rssi, RT2573_NOISE_FLOOR, 0)) { - /* ignore */ - } - /* node is no longer needed */ - ieee80211_free_node(ni); - } else { - if (ieee80211_input_all(ic, m, rssi, RT2573_NOISE_FLOOR, 0)) { - /* ignore */ - } - } - - mtx_lock(&sc->sc_mtx); - } - return; - - default: /* Error */ - if (xfer->error != USB_ERR_CANCELLED) { - /* try to clear stall first */ - sc->sc_flags |= RUM_FLAG_READ_STALL; - usb2_transfer_start(sc->sc_xfer[RUM_BULK_CS_RD]); - } - return; - - } -} - -static void -rum_bulk_read_clear_stall_callback(struct usb2_xfer *xfer) -{ - struct rum_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[RUM_BULK_DT_RD]; - - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~RUM_FLAG_READ_STALL; - usb2_transfer_start(xfer_other); - } -} - -static uint8_t -rum_plcp_signal(uint16_t rate) -{ - ; /* indent fix */ - 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) */ - case 12: - return (0xb); - case 18: - return (0xf); - case 24: - return (0xa); - case 36: - return (0xe); - case 48: - return (0x9); - case 72: - return (0xd); - case 96: - return (0x8); - case 108: - return (0xc); - - /* XXX unsupported/unknown rate */ - default: - return (0xff); - } -} - -/* - * We assume that "m->m_pkthdr.rcvif" is pointing to the "ni" that - * should be freed, when "rum_setup_desc_and_tx" is called. - */ - -static void -rum_setup_desc_and_tx(struct rum_softc *sc, struct mbuf *m, uint32_t flags, - uint16_t xflags, uint16_t rate) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct mbuf *mm; - enum ieee80211_phytype phytype; - uint16_t plcp_length; - uint16_t len; - uint8_t remainder; - uint8_t is_beacon; - - if (xflags & RT2573_TX_BEACON) { - xflags &= ~RT2573_TX_BEACON; - is_beacon = 1; - } else { - is_beacon = 0; + bpfdetach(ifp); + ieee80211_ifdetach(ic); + if_free(ifp); } - if (sc->sc_tx_queue.ifq_len >= IFQ_MAXLEN) { - /* free packet */ - rum_tx_freem(m); - ifp->if_oerrors++; - return; - } - if (!((sc->sc_flags & RUM_FLAG_LL_READY) && - (sc->sc_flags & RUM_FLAG_HL_READY))) { - /* free packet */ - rum_tx_freem(m); - ifp->if_oerrors++; - return; - } - if (rate < 2) { - DPRINTF("rate < 2!\n"); + mtx_destroy(&sc->sc_mtx); - /* avoid division by zero */ - rate = 2; - } - ic->ic_lastdata = ticks; - if (bpf_peers_present(ifp->if_bpf)) { - struct rum_tx_radiotap_header *tap = &sc->sc_txtap; - - 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); - tap->wt_antenna = sc->sc_tx_ant; - - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); - } - len = m->m_pkthdr.len; - - flags |= RT2573_TX_VALID; - flags |= (len << 16); - - sc->sc_tx_desc.flags = htole32(flags); - sc->sc_tx_desc.xflags = htole16(xflags); - - sc->sc_tx_desc.wme = htole16(RT2573_QID(0) | RT2573_AIFSN(2) | - RT2573_LOGCWMIN(4) | RT2573_LOGCWMAX(10)); - - /* setup PLCP fields */ - sc->sc_tx_desc.plcp_signal = rum_plcp_signal(rate); - sc->sc_tx_desc.plcp_service = 4; - - len += IEEE80211_CRC_LEN; - - phytype = ieee80211_rate2phytype(sc->sc_rates, rate); - - if (phytype == IEEE80211_T_OFDM) { - sc->sc_tx_desc.flags |= htole32(RT2573_TX_OFDM); - - plcp_length = (len & 0xfff); - sc->sc_tx_desc.plcp_length_hi = plcp_length >> 6; - sc->sc_tx_desc.plcp_length_lo = plcp_length & 0x3f; - } else { - plcp_length = ((16 * len) + rate - 1) / rate; - if (rate == 22) { - remainder = (16 * len) % 22; - if ((remainder != 0) && (remainder < 7)) { - sc->sc_tx_desc.plcp_service |= - RT2573_PLCP_LENGEXT; - } - } - sc->sc_tx_desc.plcp_length_hi = plcp_length >> 8; - sc->sc_tx_desc.plcp_length_lo = plcp_length & 0xff; - - if ((rate != 2) && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { - sc->sc_tx_desc.plcp_signal |= 0x08; - } - } - - if (sizeof(sc->sc_tx_desc) > MHLEN) { - DPRINTF("No room for header structure!\n"); - rum_tx_freem(m); - return; - } - mm = m_gethdr(M_NOWAIT, MT_DATA); - if (mm == NULL) { - DPRINTF("Could not allocate header mbuf!\n"); - rum_tx_freem(m); - return; - } - 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; - - if (is_beacon) { - - if (mm->m_pkthdr.len > sizeof(sc->sc_beacon_buf)) { - DPRINTFN(0, "Truncating beacon" - ", %u bytes!\n", mm->m_pkthdr.len); - mm->m_pkthdr.len = sizeof(sc->sc_beacon_buf); - } - m_copydata(mm, 0, mm->m_pkthdr.len, sc->sc_beacon_buf); - - /* copy the first 24 bytes of Tx descriptor into NIC memory */ - rum_cfg_write_multi(sc, RT2573_HW_BEACON_BASE0, - sc->sc_beacon_buf, mm->m_pkthdr.len); - rum_tx_freem(mm); - return; - } - /* start write transfer, if not started */ - _IF_ENQUEUE(&sc->sc_tx_queue, mm); - - usb2_transfer_start(sc->sc_xfer[RUM_BULK_DT_WR]); -} - -static void -rum_bulk_write_callback(struct usb2_xfer *xfer) -{ - struct rum_softc *sc = xfer->priv_sc; - struct ifnet *ifp = sc->sc_ifp; - struct mbuf *m; - uint16_t temp_len; - uint8_t align; - - 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 & RUM_FLAG_WRITE_STALL) { - usb2_transfer_start(sc->sc_xfer[RUM_BULK_CS_WR]); - break; - } - if (sc->sc_flags & RUM_FLAG_WAIT_COMMAND) { - /* - * don't send anything while a command is pending ! - */ - break; - } - rum_fill_write_queue(sc); - - _IF_DEQUEUE(&sc->sc_tx_queue, m); - - if (m) { - - if (m->m_pkthdr.len > (MCLBYTES + RT2573_TX_DESC_SIZE)) { - DPRINTFN(0, "data overflow, %u bytes\n", - m->m_pkthdr.len); - m->m_pkthdr.len = (MCLBYTES + RT2573_TX_DESC_SIZE); - } - usb2_m_copy_in(xfer->frbuffers, 0, - m, 0, m->m_pkthdr.len); - - /* compute transfer length */ - temp_len = m->m_pkthdr.len; - - /* make transfer length 32-bit aligned */ - align = (-(temp_len)) & 3; - - /* check if we need to add four extra bytes */ - if (((temp_len + align) % 64) == 0) { - align += 4; - } - /* check if we need to align length */ - if (align != 0) { - /* zero the extra bytes */ - usb2_bzero(xfer->frbuffers, temp_len, align); - temp_len += align; - } - DPRINTFN(11, "sending frame len=%u ferlen=%u\n", - m->m_pkthdr.len, temp_len); - - xfer->frlengths[0] = temp_len; - usb2_start_hardware(xfer); - - /* free mbuf and node */ - rum_tx_freem(m); - - } - 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 |= RUM_FLAG_WRITE_STALL; - usb2_transfer_start(sc->sc_xfer[RUM_BULK_CS_WR]); - } - ifp->if_oerrors++; - break; - } -} - -static void -rum_bulk_write_clear_stall_callback(struct usb2_xfer *xfer) -{ - struct rum_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[RUM_BULK_DT_WR]; - - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~RUM_FLAG_WRITE_STALL; - usb2_transfer_start(xfer_other); - } -} - -static void -rum_watchdog(void *arg) -{ - struct rum_softc *sc = arg; - - mtx_assert(&sc->sc_mtx, MA_OWNED); - - if (sc->sc_amrr_timer) { - usb2_config_td_queue_command - (&sc->sc_config_td, NULL, - &rum_cfg_amrr_timeout, 0, 0); - } - usb2_callout_reset(&sc->sc_watchdog, - hz, &rum_watchdog, sc); -} - -static void -rum_init_cb(void *arg) -{ - struct rum_softc *sc = arg; - - mtx_lock(&sc->sc_mtx); - usb2_config_td_queue_command - (&sc->sc_config_td, &rum_cfg_pre_init, - &rum_cfg_init, 0, 0); - mtx_unlock(&sc->sc_mtx); -} - -static int -rum_ioctl_cb(struct ifnet *ifp, u_long cmd, caddr_t data) -{ - struct rum_softc *sc = ifp->if_softc; - struct ieee80211com *ic = ifp->if_l2com; - int error; - - switch (cmd) { - case SIOCSIFFLAGS: - mtx_lock(&sc->sc_mtx); - if (ifp->if_flags & IFF_UP) { - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - usb2_config_td_queue_command - (&sc->sc_config_td, &rum_cfg_pre_init, - &rum_cfg_init, 0, 0); - } - } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - usb2_config_td_queue_command - (&sc->sc_config_td, &rum_cfg_pre_stop, - &rum_cfg_stop, 0, 0); - } - } - mtx_unlock(&sc->sc_mtx); - error = 0; - break; - - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, (void *)data, &ic->ic_media, cmd); - break; - - default: - error = ether_ioctl(ifp, cmd, data); - } - return (error); -} - -static void -rum_start_cb(struct ifnet *ifp) -{ - struct rum_softc *sc = ifp->if_softc; - - mtx_lock(&sc->sc_mtx); - /* start write transfer, if not started */ - usb2_transfer_start(sc->sc_xfer[RUM_BULK_DT_WR]); - mtx_unlock(&sc->sc_mtx); -} - -static void -rum_cfg_newstate(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct rum_vap *uvp = RUM_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; - - if (ostate == IEEE80211_S_INIT) { - /* We are leaving INIT. TSF sync should be off. */ - rum_cfg_disable_tsf_sync(sc); - } - switch (nstate) { - case IEEE80211_S_INIT: - break; - - case IEEE80211_S_RUN: - rum_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); -} - -static int -rum_newstate_cb(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) -{ - struct rum_vap *uvp = RUM_VAP(vap); - struct ieee80211com *ic = vap->iv_ic; - struct rum_softc *sc = ic->ic_ifp->if_softc; - - DPRINTF("setting new state: %d\n", nstate); - - /* Special case - cannot defer this call and cannot block ! */ - if (nstate == IEEE80211_S_INIT) { - /* stop timers */ - mtx_lock(&sc->sc_mtx); - sc->sc_amrr_timer = 0; - mtx_unlock(&sc->sc_mtx); - return (uvp->newstate(vap, nstate, arg)); - } - mtx_lock(&sc->sc_mtx); - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - mtx_unlock(&sc->sc_mtx); - 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; - - /* - * USB configuration can only be done from the USB configuration - * thread: - */ - usb2_config_td_queue_command - (&sc->sc_config_td, &rum_config_copy, - &rum_cfg_newstate, 0, 0); - - mtx_unlock(&sc->sc_mtx); - - return (EINPROGRESS); -} - -static void -rum_std_command(struct ieee80211com *ic, usb2_config_td_command_t *func) -{ - struct rum_softc *sc = ic->ic_ifp->if_softc; - - mtx_lock(&sc->sc_mtx); - - sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); - - usb2_config_td_queue_command - (&sc->sc_config_td, &rum_config_copy, func, 0, 0); - - mtx_unlock(&sc->sc_mtx); -} - -static void -rum_scan_start_cb(struct ieee80211com *ic) -{ - rum_std_command(ic, &rum_cfg_scan_start); -} - -static void -rum_scan_end_cb(struct ieee80211com *ic) -{ - rum_std_command(ic, &rum_cfg_scan_end); -} - -static void -rum_set_channel_cb(struct ieee80211com *ic) -{ - rum_std_command(ic, &rum_cfg_set_chan); -} - -static void -rum_cfg_scan_start(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - /* abort TSF synchronization */ - rum_cfg_disable_tsf_sync(sc); - rum_cfg_set_bssid(sc, cc->if_broadcastaddr); -} - -static void -rum_cfg_scan_end(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - /* enable TSF synchronization */ - rum_cfg_enable_tsf_sync(sc, cc, 0); - rum_cfg_set_bssid(sc, cc->iv_bss.ni_bssid); -} - -/* - * Reprogram MAC/BBP to switch to a new band. Values taken from the reference - * driver. - */ -static void -rum_cfg_select_band(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t tmp; - uint8_t bbp17, bbp35, bbp96, bbp97, bbp98, bbp104; - - /* update all BBP registers that depend on the band */ - bbp17 = 0x20; - bbp96 = 0x48; - bbp104 = 0x2c; - bbp35 = 0x50; - bbp97 = 0x48; - bbp98 = 0x48; - - if (cc->ic_curchan.chan_is_5ghz) { - bbp17 += 0x08; - bbp96 += 0x10; - bbp104 += 0x0c; - bbp35 += 0x10; - bbp97 += 0x10; - bbp98 += 0x10; - } - if ((cc->ic_curchan.chan_is_2ghz && sc->sc_ext_2ghz_lna) || - (cc->ic_curchan.chan_is_5ghz && sc->sc_ext_5ghz_lna)) { - bbp17 += 0x10; - bbp96 += 0x10; - bbp104 += 0x10; - } - sc->sc_bbp17 = bbp17; - rum_cfg_bbp_write(sc, 17, bbp17); - rum_cfg_bbp_write(sc, 96, bbp96); - rum_cfg_bbp_write(sc, 104, bbp104); - - if ((cc->ic_curchan.chan_is_2ghz && sc->sc_ext_2ghz_lna) || - (cc->ic_curchan.chan_is_5ghz && sc->sc_ext_5ghz_lna)) { - rum_cfg_bbp_write(sc, 75, 0x80); - rum_cfg_bbp_write(sc, 86, 0x80); - rum_cfg_bbp_write(sc, 88, 0x80); - } - rum_cfg_bbp_write(sc, 35, bbp35); - rum_cfg_bbp_write(sc, 97, bbp97); - rum_cfg_bbp_write(sc, 98, bbp98); - - tmp = rum_cfg_read(sc, RT2573_PHY_CSR0); - tmp &= ~(RT2573_PA_PE_2GHZ | RT2573_PA_PE_5GHZ); - if (cc->ic_curchan.chan_is_2ghz) - tmp |= RT2573_PA_PE_2GHZ; - else - tmp |= RT2573_PA_PE_5GHZ; - rum_cfg_write(sc, RT2573_PHY_CSR0, tmp); - - /* 802.11a uses a 16 microseconds short interframe space */ - sc->sc_sifs = cc->ic_curchan.chan_is_5ghz ? 16 : 10; -} - -static void -rum_cfg_set_chan(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - enum { - N_RF5225 = (sizeof(rum_rf5225) / sizeof(rum_rf5225[0]))}; - const struct rfprog *rfprog; - uint32_t chan; - uint16_t i; - uint8_t bbp3; - uint8_t bbp94 = RT2573_BBPR94_DEFAULT; - int8_t power; - - chan = cc->ic_curchan.chan_to_ieee; - - if ((chan == 0) || - (chan == IEEE80211_CHAN_ANY)) { - /* nothing to do */ - return; - } - if (chan == sc->sc_last_chan) { - return; - } - sc->sc_last_chan = chan; - - /* select the appropriate RF settings based on what EEPROM says */ - rfprog = ((sc->sc_rf_rev == RT2573_RF_5225) || - (sc->sc_rf_rev == RT2573_RF_2527)) ? rum_rf5225 : rum_rf5226; - - /* find the settings for this channel */ - for (i = 0;; i++) { - if (i == (N_RF5225 - 1)) - break; - if (rfprog[i].chan == chan) - break; - } - - DPRINTF("chan=%d, i=%d\n", chan, i); - - power = sc->sc_txpow[i]; - if (power < 0) { - bbp94 += power; - power = 0; - } else if (power > 31) { - bbp94 += power - 31; - power = 31; - } - /* - * If we are switching from the 2GHz band to the 5GHz band or - * vice-versa, BBP registers need to be reprogrammed. - */ - rum_cfg_select_band(sc, cc, 0); - rum_cfg_select_antenna(sc, cc, 0); - - rum_cfg_rf_write(sc, RT2573_RF1, rfprog[i].r1); - rum_cfg_rf_write(sc, RT2573_RF2, rfprog[i].r2); - rum_cfg_rf_write(sc, RT2573_RF3, rfprog[i].r3 | (power << 7)); - rum_cfg_rf_write(sc, RT2573_RF4, rfprog[i].r4 | (sc->sc_rffreq << 10)); - - rum_cfg_rf_write(sc, RT2573_RF1, rfprog[i].r1); - rum_cfg_rf_write(sc, RT2573_RF2, rfprog[i].r2); - rum_cfg_rf_write(sc, RT2573_RF3, rfprog[i].r3 | (power << 7) | 1); - rum_cfg_rf_write(sc, RT2573_RF4, rfprog[i].r4 | (sc->sc_rffreq << 10)); - - rum_cfg_rf_write(sc, RT2573_RF1, rfprog[i].r1); - rum_cfg_rf_write(sc, RT2573_RF2, rfprog[i].r2); - rum_cfg_rf_write(sc, RT2573_RF3, rfprog[i].r3 | (power << 7)); - rum_cfg_rf_write(sc, RT2573_RF4, rfprog[i].r4 | (sc->sc_rffreq << 10)); - - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - return; - } - /* enable smart mode for MIMO-capable RFs */ - bbp3 = rum_cfg_bbp_read(sc, 3); - - if ((sc->sc_rf_rev == RT2573_RF_5225) || - (sc->sc_rf_rev == RT2573_RF_2527)) - bbp3 &= ~RT2573_SMART_MODE; - else - bbp3 |= RT2573_SMART_MODE; - - rum_cfg_bbp_write(sc, 3, bbp3); - - rum_cfg_bbp_write(sc, 94, bbp94); - - /* update basic rate set */ - - if (cc->ic_curchan.chan_is_b) { - /* 11b basic rates: 1, 2Mbps */ - rum_cfg_write(sc, RT2573_TXRX_CSR5, 0x3); - } else if (cc->ic_curchan.chan_is_a) { - /* 11a basic rates: 6, 12, 24Mbps */ - rum_cfg_write(sc, RT2573_TXRX_CSR5, 0x150); - } else { - /* 11b/g basic rates: 1, 2, 5.5, 11Mbps */ - rum_cfg_write(sc, RT2573_TXRX_CSR5, 0xf); - } - - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - return; - } -} - -static void -rum_cfg_set_run(struct rum_softc *sc, - struct usb2_config_td_cc *cc) -{ - - if (cc->ic_opmode != IEEE80211_M_MONITOR) { - rum_cfg_update_slot(sc, cc, 0); - rum_cfg_enable_mrr(sc, cc, 0); - rum_cfg_set_txpreamble(sc, cc, 0); - - /* update basic rate set */ - - if (cc->ic_bsschan.chan_is_5ghz) { - /* 11a basic rates: 6, 12, 24Mbps */ - rum_cfg_write(sc, RT2573_TXRX_CSR5, 0x150); - } else if (cc->ic_bsschan.chan_is_g) { - /* 11b/g basic rates: 1, 2, 5.5, 11Mbps */ - rum_cfg_write(sc, RT2573_TXRX_CSR5, 0xf); - } else { - /* 11b basic rates: 1, 2Mbps */ - rum_cfg_write(sc, RT2573_TXRX_CSR5, 0x3); - } - rum_cfg_set_bssid(sc, cc->iv_bss.ni_bssid); - } - if ((cc->ic_opmode == IEEE80211_M_HOSTAP) || - (cc->ic_opmode == IEEE80211_M_IBSS)) { - rum_cfg_prepare_beacon(sc, cc, 0); - } - if (cc->ic_opmode != IEEE80211_M_MONITOR) { - rum_cfg_enable_tsf_sync(sc, cc, 0); - } - if (cc->iv_bss.fixed_rate_none) { - /* enable automatic rate adaptation */ - rum_cfg_amrr_start(sc); - } -} - -static void -rum_cfg_enable_tsf_sync(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t tmp; - - if (cc->ic_opmode != IEEE80211_M_STA) { - /* - * Change default 16ms TBTT adjustment to 8ms. - * Must be done before enabling beacon generation. - */ - rum_cfg_write(sc, RT2573_TXRX_CSR10, (1 << 12) | 8); - } - tmp = rum_cfg_read(sc, RT2573_TXRX_CSR9) & 0xff000000; - - /* set beacon interval (in 1/16ms unit) */ - tmp |= cc->iv_bss.ni_intval * 16; - - tmp |= RT2573_TSF_TICKING | RT2573_ENABLE_TBTT; - if (cc->ic_opmode == IEEE80211_M_STA) - tmp |= RT2573_TSF_MODE(1); - else - tmp |= RT2573_TSF_MODE(2) | RT2573_GENERATE_BEACON; - - rum_cfg_write(sc, RT2573_TXRX_CSR9, tmp); -} - -static void -rum_cfg_disable_tsf_sync(struct rum_softc *sc) -{ - uint32_t tmp; - - /* abort TSF synchronization */ - tmp = rum_cfg_read(sc, RT2573_TXRX_CSR9); - rum_cfg_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); -} - -/* - * Enable multi-rate retries for frames sent at OFDM rates. - * In 802.11b/g mode, allow fallback to CCK rates. - */ -static void -rum_cfg_enable_mrr(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t tmp; - - tmp = rum_cfg_read(sc, RT2573_TXRX_CSR4); - - if (cc->ic_curchan.chan_is_5ghz) - tmp &= ~RT2573_MRR_CCK_FALLBACK; - else - tmp |= RT2573_MRR_CCK_FALLBACK; - - tmp |= RT2573_MRR_ENABLED; - - rum_cfg_write(sc, RT2573_TXRX_CSR4, tmp); -} - -static void -rum_cfg_update_slot(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t tmp; - uint8_t slottime; - - slottime = (cc->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; - - tmp = rum_cfg_read(sc, RT2573_MAC_CSR9); - tmp = (tmp & ~0xff) | slottime; - rum_cfg_write(sc, RT2573_MAC_CSR9, tmp); - - DPRINTF("setting slot time to %u us\n", slottime); -} - -static void -rum_cfg_set_txpreamble(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t tmp; - - tmp = rum_cfg_read(sc, RT2573_TXRX_CSR4); - - if (cc->ic_flags & IEEE80211_F_SHPREAMBLE) - tmp |= RT2573_SHORT_PREAMBLE; - else - tmp &= ~RT2573_SHORT_PREAMBLE; - - rum_cfg_write(sc, RT2573_TXRX_CSR4, tmp); -} - -static void -rum_cfg_set_bssid(struct rum_softc *sc, uint8_t *bssid) -{ - uint32_t tmp; - - tmp = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24); - rum_cfg_write(sc, RT2573_MAC_CSR4, tmp); - - tmp = (bssid[4]) | (bssid[5] << 8) | (RT2573_ONE_BSSID << 16); - rum_cfg_write(sc, RT2573_MAC_CSR5, tmp); -} - -static void -rum_cfg_set_macaddr(struct rum_softc *sc, uint8_t *addr) -{ - uint32_t tmp; - - tmp = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24); - rum_cfg_write(sc, RT2573_MAC_CSR2, tmp); - - tmp = addr[4] | (addr[5] << 8) | (0xff << 16); - rum_cfg_write(sc, RT2573_MAC_CSR3, tmp); -} - -static void -rum_cfg_update_promisc(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t tmp; - - tmp = rum_cfg_read(sc, RT2573_TXRX_CSR0); - - if (cc->if_flags & IFF_PROMISC) - tmp &= ~RT2573_DROP_NOT_TO_ME; - else - tmp |= RT2573_DROP_NOT_TO_ME; - - rum_cfg_write(sc, RT2573_TXRX_CSR0, tmp); - - DPRINTF("%s promiscuous mode\n", - (cc->if_flags & IFF_PROMISC) ? - "entering" : "leaving"); -} - -static void -rum_cfg_select_antenna(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t tmp; - uint8_t bbp3; - uint8_t bbp4; - uint8_t bbp77; - uint8_t rx_ant; - uint8_t is_5ghz; - - bbp3 = rum_cfg_bbp_read(sc, 3); - bbp4 = rum_cfg_bbp_read(sc, 4); - bbp77 = rum_cfg_bbp_read(sc, 77); - - bbp3 &= ~0x01; - bbp4 &= ~0x23; - - rx_ant = sc->sc_rx_ant; - is_5ghz = cc->ic_curchan.chan_is_5ghz; - - switch (sc->sc_rf_rev) { - case RT2573_RF_5226: - case RT2573_RF_5225: - if (rx_ant == 0) { - /* Diversity */ - bbp4 |= 0x02; - if (is_5ghz == 0) - bbp4 |= 0x20; - } else if (rx_ant == 1) { - /* RX: Antenna A */ - bbp4 |= 0x01; - if (is_5ghz) - bbp77 &= ~0x03; - else - bbp77 |= 0x03; - } else if (rx_ant == 2) { - /* RX: Antenna B */ - bbp4 |= 0x01; - if (is_5ghz) - bbp77 |= 0x03; - else - bbp77 &= ~0x03; - } - break; - - case RT2573_RF_2528: - case RT2573_RF_2527: - if (rx_ant == 0) { - /* Diversity */ - bbp4 |= 0x22; - } else if (rx_ant == 1) { - /* RX: Antenna A */ - bbp4 |= 0x21; - bbp77 |= 0x03; - } else if (rx_ant == 2) { - /* RX: Antenna B */ - bbp4 |= 0x21; - bbp77 &= ~0x03; - } - break; - default: - break; - } - bbp4 &= ~(sc->sc_ftype << 5); - - /* make sure Rx is disabled before switching antenna */ - tmp = rum_cfg_read(sc, RT2573_TXRX_CSR0); - rum_cfg_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); - - rum_cfg_bbp_write(sc, 3, bbp3); - rum_cfg_bbp_write(sc, 4, bbp4); - rum_cfg_bbp_write(sc, 77, bbp77); - - rum_cfg_write(sc, RT2573_TXRX_CSR0, tmp); -} - -static void -rum_cfg_read_eeprom(struct rum_softc *sc) -{ - uint16_t val; - - /* read MAC address */ - rum_cfg_eeprom_read(sc, RT2573_EEPROM_ADDRESS, sc->sc_myaddr, 6); - - val = rum_cfg_eeprom_read_2(sc, RT2573_EEPROM_ANTENNA); - sc->sc_rf_rev = (val >> 11) & 0x1f; - sc->sc_hw_radio = (val >> 10) & 0x1; - sc->sc_ftype = (val >> 6) & 0x1; - sc->sc_rx_ant = (val >> 4) & 0x3; - sc->sc_tx_ant = (val >> 2) & 0x3; - sc->sc_nb_ant = (val & 0x3); - - DPRINTF("RF revision=%d\n", sc->sc_rf_rev); - - val = rum_cfg_eeprom_read_2(sc, RT2573_EEPROM_CONFIG2); - sc->sc_ext_5ghz_lna = (val >> 6) & 0x1; - sc->sc_ext_2ghz_lna = (val >> 4) & 0x1; - - DPRINTF("External 2GHz LNA=%d, External 5GHz LNA=%d\n", - sc->sc_ext_2ghz_lna, sc->sc_ext_5ghz_lna); - - val = rum_cfg_eeprom_read_2(sc, RT2573_EEPROM_RSSI_2GHZ_OFFSET); - if ((val & 0xff) != 0xff) - sc->sc_rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */ - else - sc->sc_rssi_2ghz_corr = 0; - - /* range check */ - if ((sc->sc_rssi_2ghz_corr < -10) || - (sc->sc_rssi_2ghz_corr > 10)) { - sc->sc_rssi_2ghz_corr = 0; - } - val = rum_cfg_eeprom_read_2(sc, RT2573_EEPROM_RSSI_5GHZ_OFFSET); - if ((val & 0xff) != 0xff) - sc->sc_rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */ - else - sc->sc_rssi_5ghz_corr = 0; - - /* range check */ - if ((sc->sc_rssi_5ghz_corr < -10) || - (sc->sc_rssi_5ghz_corr > 10)) { - sc->sc_rssi_5ghz_corr = 0; - } - if (sc->sc_ext_2ghz_lna) { - sc->sc_rssi_2ghz_corr -= 14; - } - if (sc->sc_ext_5ghz_lna) { - sc->sc_rssi_5ghz_corr -= 14; - } - DPRINTF("RSSI 2GHz corr=%d, RSSI 5GHz corr=%d\n", - sc->sc_rssi_2ghz_corr, sc->sc_rssi_5ghz_corr); - - val = rum_cfg_eeprom_read_2(sc, RT2573_EEPROM_FREQ_OFFSET); - if ((val & 0xff) != 0xff) - sc->sc_rffreq = (val & 0xff); - else - sc->sc_rffreq = 0; - - DPRINTF("RF freq=%d\n", sc->sc_rffreq); - - /* read Tx power for all a/b/g channels */ - rum_cfg_eeprom_read(sc, RT2573_EEPROM_TXPOWER, sc->sc_txpow, 14); - - /* XXX default Tx power for 802.11a channels */ - memset(sc->sc_txpow + 14, 24, sizeof(sc->sc_txpow) - 14); - - /* read default values for BBP registers */ - rum_cfg_eeprom_read(sc, RT2573_EEPROM_BBP_BASE, sc->sc_bbp_prom, 2 * 16); -} - -static uint8_t -rum_cfg_bbp_init(struct rum_softc *sc) -{ - enum { - N_DEF_BBP = (sizeof(rum_def_bbp) / sizeof(rum_def_bbp[0])), - }; - uint16_t i; - uint8_t to; - uint8_t tmp; - - /* wait for BBP to become ready */ - for (to = 0;; to++) { - if (to < 100) { - tmp = rum_cfg_bbp_read(sc, 0); - if ((tmp != 0x00) && - (tmp != 0xff)) { - break; - } - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - return (1); /* failure */ - } - } else { - DPRINTF("timeout waiting for BBP\n"); - return (1); /* failure */ - } - } - - /* initialize BBP registers to default values */ - for (i = 0; i < N_DEF_BBP; i++) { - rum_cfg_bbp_write(sc, rum_def_bbp[i].reg, rum_def_bbp[i].val); - } - - /* write vendor-specific BBP values (from EEPROM) */ - for (i = 0; i < 16; i++) { - if ((sc->sc_bbp_prom[i].reg == 0) || - (sc->sc_bbp_prom[i].reg == 0xff)) { - continue; - } - rum_cfg_bbp_write(sc, sc->sc_bbp_prom[i].reg, sc->sc_bbp_prom[i].val); - } return (0); } -static void -rum_cfg_pre_init(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - - /* immediate configuration */ - - rum_cfg_pre_stop(sc, cc, 0); - - ifp->if_drv_flags |= IFF_DRV_RUNNING; - - sc->sc_flags |= RUM_FLAG_HL_READY; - - IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); -} - -static void -rum_cfg_init(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - enum { - N_DEF_MAC = (sizeof(rum_def_mac) / sizeof(rum_def_mac[0])), - }; - - uint32_t tmp; - uint16_t i; - uint8_t to; - - /* delayed configuration */ - - rum_cfg_stop(sc, cc, 0); - - /* initialize MAC registers to default values */ - for (i = 0; i < N_DEF_MAC; i++) { - rum_cfg_write(sc, rum_def_mac[i].reg, rum_def_mac[i].val); - } - - /* set host ready */ - rum_cfg_write(sc, RT2573_MAC_CSR1, 3); - rum_cfg_write(sc, RT2573_MAC_CSR1, 0); - - /* wait for BBP/RF to wakeup */ - for (to = 0;; to++) { - if (to < 100) { - if (rum_cfg_read(sc, RT2573_MAC_CSR12) & 8) { - break; - } - rum_cfg_write(sc, RT2573_MAC_CSR12, 4); /* force wakeup */ - - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - goto fail; - } - } else { - DPRINTF("timeout waiting for " - "BBP/RF to wakeup\n"); - goto fail; - } - } - - if (rum_cfg_bbp_init(sc)) { - goto fail; - } - /* select default channel */ - - sc->sc_last_chan = 0; - - rum_cfg_set_chan(sc, cc, 0); - - /* clear STA registers */ - rum_cfg_read_multi(sc, RT2573_STA_CSR0, sc->sc_sta, sizeof(sc->sc_sta)); - /* set MAC address */ - rum_cfg_set_macaddr(sc, cc->ic_myaddr); - - /* initialize ASIC */ - rum_cfg_write(sc, RT2573_MAC_CSR1, 4); - - /* - * make sure that the first transaction - * clears the stall: - */ - sc->sc_flags |= (RUM_FLAG_READ_STALL | - RUM_FLAG_WRITE_STALL | - RUM_FLAG_LL_READY); - - if ((sc->sc_flags & RUM_FLAG_LL_READY) && - (sc->sc_flags & RUM_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[RUM_BULK_DT_RD]); - usb2_transfer_start(sc->sc_xfer[RUM_BULK_DT_WR]); - - /* - * start IEEE802.11 layer - */ - mtx_unlock(&sc->sc_mtx); - ieee80211_start_all(ic); - mtx_lock(&sc->sc_mtx); - } - /* update Rx filter */ - tmp = rum_cfg_read(sc, RT2573_TXRX_CSR0) & 0xffff; - - tmp |= RT2573_DROP_PHY_ERROR | RT2573_DROP_CRC_ERROR; - - if (cc->ic_opmode != IEEE80211_M_MONITOR) { - tmp |= RT2573_DROP_CTL | RT2573_DROP_VER_ERROR | - RT2573_DROP_ACKCTS; - if (cc->ic_opmode != IEEE80211_M_HOSTAP) { - tmp |= RT2573_DROP_TODS; - } - if (!(cc->if_flags & IFF_PROMISC)) { - tmp |= RT2573_DROP_NOT_TO_ME; - } - } - rum_cfg_write(sc, RT2573_TXRX_CSR0, tmp); - - return; - -fail: - rum_cfg_pre_stop(sc, NULL, 0); - - if (cc) { - rum_cfg_stop(sc, cc, 0); - } -} - -static void -rum_cfg_pre_stop(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp = sc->sc_ifp; - - if (cc) { - /* copy the needed configuration */ - rum_config_copy(sc, cc, refcount); - } - /* immediate configuration */ - - if (ifp) { - /* clear flags */ - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - } - sc->sc_flags &= ~(RUM_FLAG_HL_READY | - RUM_FLAG_LL_READY); - - /* - * stop all the transfers, if not already stopped: - */ - usb2_transfer_stop(sc->sc_xfer[RUM_BULK_DT_WR]); - usb2_transfer_stop(sc->sc_xfer[RUM_BULK_DT_RD]); - usb2_transfer_stop(sc->sc_xfer[RUM_BULK_CS_WR]); - usb2_transfer_stop(sc->sc_xfer[RUM_BULK_CS_RD]); - - /* clean up transmission */ - rum_tx_clean_queue(sc); -} - -static void -rum_cfg_stop(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t tmp; - - /* disable Rx */ - tmp = rum_cfg_read(sc, RT2573_TXRX_CSR0); - rum_cfg_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); - - /* reset ASIC */ - rum_cfg_write(sc, RT2573_MAC_CSR1, 3); - - /* wait a little */ - usb2_config_td_sleep(&sc->sc_config_td, hz / 10); - - rum_cfg_write(sc, RT2573_MAC_CSR1, 0); - - /* wait a little */ - usb2_config_td_sleep(&sc->sc_config_td, hz / 10); -} - -static void -rum_cfg_amrr_start(struct rum_softc *sc) -{ - struct ieee80211vap *vap; - struct ieee80211_node *ni; - - vap = rum_get_vap(sc); - - if (vap == NULL) { - return; - } - ni = vap->iv_bss; - if (ni == NULL) { - return; - } - /* init AMRR */ - - ieee80211_amrr_node_init(&RUM_VAP(vap)->amrr, &RUM_NODE(ni)->amn, ni); - - /* enable AMRR timer */ - - sc->sc_amrr_timer = 1; -} - -static void -rum_cfg_amrr_timeout(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211vap *vap; - struct ieee80211_node *ni; - uint32_t ok; - uint32_t fail; - - /* clear statistic registers (STA_CSR0 to STA_CSR5) */ - rum_cfg_read_multi(sc, RT2573_STA_CSR0, sc->sc_sta, sizeof(sc->sc_sta)); - - vap = rum_get_vap(sc); - if (vap == NULL) { - return; - } - ni = vap->iv_bss; - if (ni == NULL) { - return; - } - if ((sc->sc_flags & RUM_FLAG_LL_READY) && - (sc->sc_flags & RUM_FLAG_HL_READY)) { - - ok = (le32toh(sc->sc_sta[4]) >> 16) + /* TX ok w/o retry */ - (le32toh(sc->sc_sta[5]) & 0xffff); /* TX ok w/ retry */ - fail = (le32toh(sc->sc_sta[5]) >> 16); /* TX retry-fail count */ - - if (sc->sc_amrr_timer) { - ieee80211_amrr_tx_update(&RUM_NODE(vap->iv_bss)->amn, - ok + fail, ok, (le32toh(sc->sc_sta[5]) & 0xffff) + fail); - - if (ieee80211_amrr_choose(ni, &RUM_NODE(ni)->amn)) { - /* ignore */ - } - } - ifp->if_oerrors += fail;/* count TX retry-fail as Tx errors */ - } -} - -static void -rum_cfg_load_microcode(struct rum_softc *sc, const uint8_t *ucode, uint16_t size) -{ - struct usb2_device_request req; - uint16_t reg = RT2573_MCU_CODE_BASE; - - /* copy firmware image into NIC */ - while (size >= 4) { - rum_cfg_write(sc, reg, UGETDW(ucode)); - reg += 4; - ucode += 4; - size -= 4; - } - - if (size != 0) { - DPRINTF("possibly invalid firmware\n"); - } - req.bmRequestType = UT_WRITE_VENDOR_DEVICE; - req.bRequest = RT2573_MCU_CNTL; - USETW(req.wValue, RT2573_MCU_RUN); - USETW(req.wIndex, 0); - USETW(req.wLength, 0); - - rum_cfg_do_request(sc, &req, NULL); -} - -static void -rum_cfg_prepare_beacon(struct rum_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ieee80211_node *ni; - struct ieee80211vap *vap; - struct ieee80211com *ic; - const struct ieee80211_txparam *tp; - struct mbuf *m; - - vap = rum_get_vap(sc); - if (vap == NULL) { - return; - } - ni = vap->iv_bss; - if (ni == NULL) { - return; - } - ic = vap->iv_ic; - if (ic == NULL) { - return; - } - DPRINTFN(11, "Sending beacon frame.\n"); - - m = ieee80211_beacon_alloc(ni, &RUM_VAP(vap)->bo); - if (m == NULL) { - DPRINTFN(0, "could not allocate beacon\n"); - return; - } - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; - - m->m_pkthdr.rcvif = (void *)ieee80211_ref_node(ni); - rum_setup_desc_and_tx(sc, m, RT2573_TX_TIMESTAMP, RT2573_TX_HWSEQ | RT2573_TX_BEACON, tp->mgmtrate); -} - -static uint8_t -rum_get_rssi(struct rum_softc *sc, uint8_t raw) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - int16_t rssi; - uint8_t lna; - uint8_t agc; - - lna = (raw >> 5) & 0x3; - agc = raw & 0x1f; - - if (lna == 0) { - /* - * No RSSI mapping - * - * NB: Since RSSI is relative to noise floor, -1 is - * adequate for caller to know error happened. - */ - return (0); - } - rssi = (2 * agc) - RT2573_NOISE_FLOOR; - - if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { - - rssi += sc->sc_rssi_2ghz_corr; - - if (lna == 1) - rssi -= 64; - else if (lna == 2) - rssi -= 74; - else if (lna == 3) - rssi -= 90; - } else { - - rssi += sc->sc_rssi_5ghz_corr; - - if ((!sc->sc_ext_5ghz_lna) && (lna != 1)) - rssi += 4; - - if (lna == 1) - rssi -= 64; - else if (lna == 2) - rssi -= 86; - else if (lna == 3) - rssi -= 100; - } - - /* range check */ - - if (rssi < 0) - rssi = 0; - else if (rssi > 255) - rssi = 255; - - return (rssi); -} - static struct ieee80211vap * rum_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]) + 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 rum_softc *sc = ic->ic_ifp->if_softc; struct rum_vap *rvp; struct ieee80211vap *vap; - struct rum_softc *sc = ic->ic_ifp->if_softc; - DPRINTF("\n"); - - /* 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); - } - mtx_unlock(&sc->sc_mtx); - - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - rvp = (struct rum_vap *)malloc(sizeof(struct rum_vap), + rvp = (struct rum_vap *) malloc(sizeof(struct rum_vap), M_80211_VAP, M_NOWAIT | M_ZERO); if (rvp == NULL) return NULL; @@ -2538,51 +595,1644 @@ rum_vap_create(struct ieee80211com *ic, /* override state transition machine */ rvp->newstate = vap->iv_newstate; - vap->iv_newstate = &rum_newstate_cb; + vap->iv_newstate = rum_newstate; + rvp->sc = sc; + usb2_callout_init_mtx(&rvp->amrr_ch, &sc->sc_mtx, 0); ieee80211_amrr_init(&rvp->amrr, vap, IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, - 1000 /* 1 sec */ ); + 1000 /* 1 sec */); /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); - - /* store current operation mode */ ic->ic_opmode = opmode; - - return (vap); + return vap; } static void rum_vap_delete(struct ieee80211vap *vap) { struct rum_vap *rvp = RUM_VAP(vap); - struct rum_softc *sc = vap->iv_ic->ic_ifp->if_softc; - - DPRINTF("\n"); - - /* 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); + usb2_callout_drain(&rvp->amrr_ch); ieee80211_amrr_cleanup(&rvp->amrr); ieee80211_vap_detach(vap); free(rvp, M_80211_VAP); } +static void +rum_tx_free(struct rum_tx_data *data, int txerr) +{ + struct rum_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; + + ieee80211_free_node(data->ni); + data->ni = NULL; + } + STAILQ_INSERT_TAIL(&sc->tx_free, data, next); + sc->tx_nfree++; +} + +static void +rum_setup_tx_list(struct rum_softc *sc) +{ + struct rum_tx_data *data; + int i; + + sc->tx_nfree = 0; + STAILQ_INIT(&sc->tx_q); + STAILQ_INIT(&sc->tx_free); + + for (i = 0; i < RUM_TX_LIST_COUNT; i++) { + data = &sc->tx_data[i]; + + data->sc = sc; + STAILQ_INSERT_TAIL(&sc->tx_free, data, next); + sc->tx_nfree++; + } +} + +static void +rum_unsetup_tx_list(struct rum_softc *sc) +{ + struct rum_tx_data *data; + int i; + + /* make sure any subsequent use of the queues will fail */ + sc->tx_nfree = 0; + STAILQ_INIT(&sc->tx_q); + STAILQ_INIT(&sc->tx_free); + + /* free up all node references and mbufs */ + for (i = 0; i < RUM_TX_LIST_COUNT; i++) { + data = &sc->tx_data[i]; + + if (data->m != NULL) { + m_freem(data->m); + data->m = NULL; + } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; + } + } +} + +static void +rum_task(struct usb2_proc_msg *pm) +{ + struct rum_task *task = (struct rum_task *)pm; + struct rum_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct rum_vap *rvp = RUM_VAP(vap); + const struct ieee80211_txparam *tp; + enum ieee80211_state ostate; + struct ieee80211_node *ni; + uint32_t tmp; + + ostate = vap->iv_state; + + switch (sc->sc_state) { + case IEEE80211_S_INIT: + if (ostate == IEEE80211_S_RUN) { + /* abort TSF synchronization */ + tmp = rum_read(sc, RT2573_TXRX_CSR9); + rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); + } + break; + + case IEEE80211_S_RUN: + ni = vap->iv_bss; + + if (vap->iv_opmode != IEEE80211_M_MONITOR) { + rum_update_slot(ic->ic_ifp); + rum_enable_mrr(sc); + rum_set_txpreamble(sc); + rum_set_basicrates(sc); + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); + rum_set_bssid(sc, sc->sc_bssid); + } + + if (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS) + rum_prepare_beacon(sc, vap); + + if (vap->iv_opmode != IEEE80211_M_MONITOR) + rum_enable_tsf_sync(sc); + + /* enable automatic rate adaptation */ + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; + if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) + rum_amrr_start(sc, ni); + break; + default: + break; + } + + RUM_UNLOCK(sc); + IEEE80211_LOCK(ic); + rvp->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); + RUM_LOCK(sc); +} + +static int +rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + struct rum_vap *rvp = RUM_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct rum_softc *sc = ic->ic_ifp->if_softc; + + DPRINTF("%s -> %s\n", + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[nstate]); + + RUM_LOCK(sc); + usb2_callout_stop(&rvp->amrr_ch); + + /* do it in a process context */ + sc->sc_state = nstate; + sc->sc_arg = arg; + RUM_UNLOCK(sc); + + if (nstate == IEEE80211_S_INIT) { + rvp->newstate(vap, nstate, arg); + return 0; + } else { + RUM_LOCK(sc); + rum_queue_command(sc, rum_task, &sc->sc_task[0].hdr, + &sc->sc_task[1].hdr); + RUM_UNLOCK(sc); + return EINPROGRESS; + } +} + +static void +rum_bulk_write_callback(struct usb2_xfer *xfer) +{ + struct rum_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 rum_tx_data *data; + struct mbuf *m; + unsigned int len; + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + DPRINTFN(11, "transfer complete, %d bytes\n", xfer->actlen); + + /* free resources */ + data = xfer->priv_fifo; + rum_tx_free(data, 0); + xfer->priv_fifo = NULL; + + ifp->if_opackets++; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + /* 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; + + if (m->m_pkthdr.len > (MCLBYTES + RT2573_TX_DESC_SIZE)) { + DPRINTFN(0, "data overflow, %u bytes\n", + m->m_pkthdr.len); + m->m_pkthdr.len = (MCLBYTES + RT2573_TX_DESC_SIZE); + } + usb2_copy_in(xfer->frbuffers, 0, &data->desc, + RT2573_TX_DESC_SIZE); + usb2_m_copy_in(xfer->frbuffers, RT2573_TX_DESC_SIZE, m, + 0, m->m_pkthdr.len); + + if (bpf_peers_present(ifp->if_bpf)) { + struct rum_tx_radiotap_header *tap = &sc->sc_txtap; + + 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); + tap->wt_antenna = sc->tx_ant; + + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + } + + /* align end on a 4-bytes boundary */ + len = (RT2573_TX_DESC_SIZE + m->m_pkthdr.len + 3) & ~3; + if ((len % 64) == 0) + len += 4; + + DPRINTFN(11, "sending frame len=%u xferlen=%u\n", + m->m_pkthdr.len, len); + + xfer->frlengths[0] = len; + xfer->priv_fifo = data; + + usb2_start_hardware(xfer); + } + break; + + default: /* Error */ + DPRINTFN(11, "transfer error, %s\n", + usb2_errstr(xfer->error)); + + ifp->if_oerrors++; + data = xfer->priv_fifo; + if (data != NULL) { + rum_tx_free(data, xfer->error); + xfer->priv_fifo = NULL; + } + + 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; + } +} + +static void +rum_bulk_read_callback(struct usb2_xfer *xfer) +{ + struct rum_softc *sc = xfer->priv_sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211_node *ni; + struct mbuf *m = NULL; + uint32_t flags; + uint8_t rssi = 0; + unsigned int len; + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + + DPRINTFN(15, "rx done, actlen=%d\n", xfer->actlen); + + len = xfer->actlen; + if (len < RT2573_RX_DESC_SIZE + IEEE80211_MIN_LEN) { + DPRINTF("%s: xfer too short %d\n", + device_get_nameunit(sc->sc_dev), len); + ifp->if_ierrors++; + goto tr_setup; + } + + len -= RT2573_RX_DESC_SIZE; + usb2_copy_out(xfer->frbuffers, 0, &sc->sc_rx_desc, + RT2573_RX_DESC_SIZE); + + rssi = rum_get_rssi(sc, sc->sc_rx_desc.rssi); + flags = le32toh(sc->sc_rx_desc.flags); + if (flags & RT2573_RX_CRC_ERROR) { + /* + * This should not happen since we did not + * request to receive those frames when we + * filled RUM_TXRX_CSR2: + */ + DPRINTFN(5, "PHY or CRC error\n"); + ifp->if_ierrors++; + goto tr_setup; + } + + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + DPRINTF("could not allocate mbuf\n"); + ifp->if_ierrors++; + goto tr_setup; + } + usb2_copy_out(xfer->frbuffers, RT2573_RX_DESC_SIZE, + mtod(m, uint8_t *), len); + + /* finalize mbuf */ + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; + + if (bpf_peers_present(ifp->if_bpf)) { + struct rum_rx_radiotap_header *tap = &sc->sc_rxtap; + + tap->wr_flags = IEEE80211_RADIOTAP_F_FCS; + tap->wr_rate = ieee80211_plcp2rate(sc->sc_rx_desc.rate, + (flags & RT2573_RX_OFDM) ? + IEEE80211_T_OFDM : IEEE80211_T_CCK); + tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); + tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); + tap->wr_antenna = sc->rx_ant; + tap->wr_antsignal = rssi; + + bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); + } + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + xfer->frlengths[0] = xfer->max_data_length; + usb2_start_hardware(xfer); + + /* + * 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 (m) { + RUM_UNLOCK(sc); + ni = ieee80211_find_rxnode(ic, + mtod(m, struct ieee80211_frame_min *)); + if (ni != NULL) { + (void) ieee80211_input(ni, m, rssi, + RT2573_NOISE_FLOOR, 0); + ieee80211_free_node(ni); + } else + (void) ieee80211_input_all(ic, m, rssi, + RT2573_NOISE_FLOOR, 0); + RUM_LOCK(sc); + } + return; + + default: /* Error */ + if (xfer->error != USB_ERR_CANCELLED) { + /* try to clear stall first */ + xfer->flags.stall_pipe = 1; + goto tr_setup; + } + return; + } +} + +static uint8_t +rum_plcp_signal(int rate) +{ + switch (rate) { + /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ + case 12: return 0xb; + case 18: return 0xf; + case 24: return 0xa; + case 36: return 0xe; + case 48: return 0x9; + case 72: return 0xd; + case 96: return 0x8; + case 108: return 0xc; + + /* 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 +rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, + uint32_t flags, uint16_t xflags, int len, int rate) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint16_t plcp_length; + int remainder; + + desc->flags = htole32(flags); + desc->flags |= htole32(RT2573_TX_VALID); + desc->flags |= htole32(len << 16); + + desc->xflags = htole16(xflags); + + desc->wme = htole16(RT2573_QID(0) | RT2573_AIFSN(2) | + RT2573_LOGCWMIN(4) | RT2573_LOGCWMAX(10)); + + /* setup PLCP fields */ + desc->plcp_signal = rum_plcp_signal(rate); + desc->plcp_service = 4; + + len += IEEE80211_CRC_LEN; + if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) { + desc->flags |= htole32(RT2573_TX_OFDM); + + plcp_length = len & 0xfff; + desc->plcp_length_hi = plcp_length >> 6; + desc->plcp_length_lo = plcp_length & 0x3f; + } else { + plcp_length = (16 * len + rate - 1) / rate; + if (rate == 22) { + remainder = (16 * len) % 22; + if (remainder != 0 && remainder < 7) + desc->plcp_service |= RT2573_PLCP_LENGEXT; + } + desc->plcp_length_hi = plcp_length >> 8; + desc->plcp_length_lo = plcp_length & 0xff; + + if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + desc->plcp_signal |= 0x08; + } +} + +#define RUM_TX_TIMEOUT 5000 + +static int +rum_sendprot(struct rum_softc *sc, + const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) +{ + struct ieee80211com *ic = ni->ni_ic; + const struct ieee80211_frame *wh; + struct rum_tx_data *data; + struct mbuf *mprot; + int protrate, ackrate, pktlen, flags, isshort; + uint16_t dur; + + RUM_LOCK_ASSERT(sc, MA_OWNED); + KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, + ("protection %d", prot)); + + wh = mtod(m, const struct ieee80211_frame *); + pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; + + protrate = ieee80211_ctl_rate(sc->sc_rates, rate); + ackrate = ieee80211_ack_rate(sc->sc_rates, rate); + + isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; + dur = ieee80211_compute_duration(sc->sc_rates, pktlen, rate, isshort); + + ieee80211_ack_duration(sc->sc_rates, rate, isshort); + flags = RT2573_TX_MORE_FRAG; + if (prot == IEEE80211_PROT_RTSCTS) { + /* NB: CTS is the same size as an ACK */ + dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort); + flags |= RT2573_TX_NEED_ACK; + mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); + } else { + mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); + } + if (mprot == NULL) { + /* XXX stat + msg */ + return ENOBUFS; + } + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + + data->m = mprot; + data->ni = ieee80211_ref_node(ni); + data->rate = protrate; + rum_setup_tx_desc(sc, &data->desc, flags, 0, mprot->m_pkthdr.len, protrate); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[RUM_BULK_WR]); + + return 0; +} + +static int +rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct rum_tx_data *data; + struct ieee80211_frame *wh; + const struct ieee80211_txparam *tp; + struct ieee80211_key *k; + uint32_t flags = 0; + uint16_t dur; + + RUM_LOCK_ASSERT(sc, MA_OWNED); + + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + + wh = mtod(m0, struct ieee80211_frame *); + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + k = ieee80211_crypto_encap(ni, m0); + if (k == NULL) { + m_freem(m0); + return ENOBUFS; + } + wh = mtod(m0, struct ieee80211_frame *); + } + + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; + + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + flags |= RT2573_TX_NEED_ACK; + + dur = ieee80211_ack_duration(sc->sc_rates, tp->mgmtrate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); + *(uint16_t *)wh->i_dur = htole16(dur); + + /* tell hardware to add timestamp for probe responses */ + if ((wh->i_fc[0] & + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == + (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) + flags |= RT2573_TX_TIMESTAMP; + } + + data->m = m0; + data->ni = ni; + data->rate = tp->mgmtrate; + + rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, tp->mgmtrate); + + DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", + m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, tp->mgmtrate); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[RUM_BULK_WR]); + + return 0; +} + +static int +rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, + const struct ieee80211_bpf_params *params) +{ + struct rum_tx_data *data; + uint32_t flags; + int rate, error; + + RUM_LOCK_ASSERT(sc, MA_OWNED); + KASSERT(params != NULL, ("no raw xmit params")); + + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + + rate = params->ibp_rate0 & IEEE80211_RATE_VAL; + /* XXX validate */ + if (rate == 0) { + m_freem(m0); + return EINVAL; + } + flags = 0; + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) + flags |= RT2573_TX_NEED_ACK; + if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { + error = rum_sendprot(sc, m0, ni, + params->ibp_flags & IEEE80211_BPF_RTS ? + IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, + rate); + if (error) { + m_freem(m0); + return error; + } + flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; + } + + data->m = m0; + data->ni = ni; + data->rate = rate; + + /* XXX need to setup descriptor ourself */ + rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate); + + DPRINTFN(10, "sending raw frame len=%u rate=%u\n", + m0->m_pkthdr.len, rate); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[RUM_BULK_WR]); + + return 0; +} + +static int +rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct rum_tx_data *data; + struct ieee80211_frame *wh; + const struct ieee80211_txparam *tp; + struct ieee80211_key *k; + uint32_t flags = 0; + uint16_t dur; + int error, rate; + + RUM_LOCK_ASSERT(sc, MA_OWNED); + + wh = mtod(m0, struct ieee80211_frame *); + + tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + rate = tp->mcastrate; + 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, 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 (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + int prot = IEEE80211_PROT_NONE; + if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) + prot = IEEE80211_PROT_RTSCTS; + else if ((ic->ic_flags & IEEE80211_F_USEPROT) && + ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) + prot = ic->ic_protmode; + if (prot != IEEE80211_PROT_NONE) { + error = rum_sendprot(sc, m0, ni, prot, rate); + if (error) { + m_freem(m0); + return error; + } + flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; + } + } + + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + + data->m = m0; + data->ni = ni; + data->rate = rate; + + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + flags |= RT2573_TX_NEED_ACK; + flags |= RT2573_TX_MORE_FRAG; + + dur = ieee80211_ack_duration(sc->sc_rates, rate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); + *(uint16_t *)wh->i_dur = htole16(dur); + } + + rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate); + + DPRINTFN(10, "sending frame len=%d rate=%d\n", + m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, rate); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[RUM_BULK_WR]); + + return 0; +} + +static void +rum_start(struct ifnet *ifp) +{ + struct rum_softc *sc = ifp->if_softc; + struct ieee80211_node *ni; + struct mbuf *m; + + RUM_LOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + RUM_UNLOCK(sc); + return; + } + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->tx_nfree == 0) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; + m = ieee80211_encap(ni, m); + if (m == NULL) { + ieee80211_free_node(ni); + continue; + } + if (rum_tx_data(sc, m, ni) != 0) { + ieee80211_free_node(ni); + ifp->if_oerrors++; + break; + } + } + RUM_UNLOCK(sc); +} + +static int +rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct rum_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; + + switch (cmd) { + case SIOCSIFFLAGS: + RUM_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + rum_queue_command(sc, rum_init_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + startall = 1; + } else + rum_queue_command(sc, rum_promisctask, + &sc->sc_promisctask[0].hdr, + &sc->sc_promisctask[1].hdr); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + rum_queue_command(sc, rum_stop_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + } + } + RUM_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); + break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; + default: + error = EINVAL; + break; + } + return error; +} + +static void +rum_eeprom_read(struct rum_softc *sc, uint16_t addr, void *buf, int len) +{ + struct usb2_device_request req; + usb2_error_t error; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = RT2573_READ_EEPROM; + USETW(req.wValue, 0); + USETW(req.wIndex, addr); + USETW(req.wLength, len); + + error = rum_do_request(sc, &req, buf); + if (error != 0) { + device_printf(sc->sc_dev, "could not read EEPROM: %s\n", + usb2_errstr(error)); + } +} + +static uint32_t +rum_read(struct rum_softc *sc, uint16_t reg) +{ + uint32_t val; + + rum_read_multi(sc, reg, &val, sizeof val); + + return le32toh(val); +} + +static void +rum_read_multi(struct rum_softc *sc, uint16_t reg, void *buf, int len) +{ + struct usb2_device_request req; + usb2_error_t error; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = RT2573_READ_MULTI_MAC; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, len); + + error = rum_do_request(sc, &req, buf); + if (error != 0) { + device_printf(sc->sc_dev, + "could not multi read MAC register: %s\n", + usb2_errstr(error)); + } +} + +static void +rum_write(struct rum_softc *sc, uint16_t reg, uint32_t val) +{ + uint32_t tmp = htole32(val); + + rum_write_multi(sc, reg, &tmp, sizeof tmp); +} + +static void +rum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len) +{ + struct usb2_device_request req; + usb2_error_t error; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = RT2573_WRITE_MULTI_MAC; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, len); + + error = rum_do_request(sc, &req, buf); + if (error != 0) { + device_printf(sc->sc_dev, + "could not multi write MAC register: %s\n", + usb2_errstr(error)); + } +} + +static void +rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) +{ + uint32_t tmp; + int ntries; + + for (ntries = 0; ntries < 5; ntries++) { + if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, "could not write to BBP\n"); + return; + } + + tmp = RT2573_BBP_BUSY | (reg & 0x7f) << 8 | val; + rum_write(sc, RT2573_PHY_CSR3, tmp); +} + +static uint8_t +rum_bbp_read(struct rum_softc *sc, uint8_t reg) +{ + uint32_t val; + int ntries; + + for (ntries = 0; ntries < 5; ntries++) { + if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, "could not read BBP\n"); + return 0; + } + + val = RT2573_BBP_BUSY | RT2573_BBP_READ | reg << 8; + rum_write(sc, RT2573_PHY_CSR3, val); + + for (ntries = 0; ntries < 100; ntries++) { + val = rum_read(sc, RT2573_PHY_CSR3); + if (!(val & RT2573_BBP_BUSY)) + return val & 0xff; + DELAY(1); + } + + device_printf(sc->sc_dev, "could not read BBP\n"); + return 0; +} + +static void +rum_rf_write(struct rum_softc *sc, uint8_t reg, uint32_t val) +{ + uint32_t tmp; + int ntries; + + for (ntries = 0; ntries < 5; ntries++) { + if (!(rum_read(sc, RT2573_PHY_CSR4) & RT2573_RF_BUSY)) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, "could not write to RF\n"); + return; + } + + tmp = RT2573_RF_BUSY | RT2573_RF_20BIT | (val & 0xfffff) << 2 | + (reg & 3); + rum_write(sc, RT2573_PHY_CSR4, tmp); + + /* remember last written value in sc */ + sc->rf_regs[reg] = val; + + DPRINTFN(15, "RF R[%u] <- 0x%05x\n", reg & 3, val & 0xfffff); +} + +static void +rum_select_antenna(struct rum_softc *sc) +{ + uint8_t bbp4, bbp77; + uint32_t tmp; + + bbp4 = rum_bbp_read(sc, 4); + bbp77 = rum_bbp_read(sc, 77); + + /* TBD */ + + /* make sure Rx is disabled before switching antenna */ + tmp = rum_read(sc, RT2573_TXRX_CSR0); + rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); + + rum_bbp_write(sc, 4, bbp4); + rum_bbp_write(sc, 77, bbp77); + + rum_write(sc, RT2573_TXRX_CSR0, tmp); +} + +/* + * Enable multi-rate retries for frames sent at OFDM rates. + * In 802.11b/g mode, allow fallback to CCK rates. + */ +static void +rum_enable_mrr(struct rum_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint32_t tmp; + + tmp = rum_read(sc, RT2573_TXRX_CSR4); + + tmp &= ~RT2573_MRR_CCK_FALLBACK; + if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) + tmp |= RT2573_MRR_CCK_FALLBACK; + tmp |= RT2573_MRR_ENABLED; + + rum_write(sc, RT2573_TXRX_CSR4, tmp); +} + +static void +rum_set_txpreamble(struct rum_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint32_t tmp; + + tmp = rum_read(sc, RT2573_TXRX_CSR4); + + tmp &= ~RT2573_SHORT_PREAMBLE; + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + tmp |= RT2573_SHORT_PREAMBLE; + + rum_write(sc, RT2573_TXRX_CSR4, tmp); +} + +static void +rum_set_basicrates(struct rum_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + /* update basic rate set */ + if (ic->ic_curmode == IEEE80211_MODE_11B) { + /* 11b basic rates: 1, 2Mbps */ + rum_write(sc, RT2573_TXRX_CSR5, 0x3); + } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) { + /* 11a basic rates: 6, 12, 24Mbps */ + rum_write(sc, RT2573_TXRX_CSR5, 0x150); + } else { + /* 11b/g basic rates: 1, 2, 5.5, 11Mbps */ + rum_write(sc, RT2573_TXRX_CSR5, 0xf); + } +} + +/* + * Reprogram MAC/BBP to switch to a new band. Values taken from the reference + * driver. + */ +static void +rum_select_band(struct rum_softc *sc, struct ieee80211_channel *c) +{ + uint8_t bbp17, bbp35, bbp96, bbp97, bbp98, bbp104; + uint32_t tmp; + + /* update all BBP registers that depend on the band */ + bbp17 = 0x20; bbp96 = 0x48; bbp104 = 0x2c; + bbp35 = 0x50; bbp97 = 0x48; bbp98 = 0x48; + if (IEEE80211_IS_CHAN_5GHZ(c)) { + bbp17 += 0x08; bbp96 += 0x10; bbp104 += 0x0c; + bbp35 += 0x10; bbp97 += 0x10; bbp98 += 0x10; + } + if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) || + (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) { + bbp17 += 0x10; bbp96 += 0x10; bbp104 += 0x10; + } + + sc->bbp17 = bbp17; + rum_bbp_write(sc, 17, bbp17); + rum_bbp_write(sc, 96, bbp96); + rum_bbp_write(sc, 104, bbp104); + + if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) || + (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) { + rum_bbp_write(sc, 75, 0x80); + rum_bbp_write(sc, 86, 0x80); + rum_bbp_write(sc, 88, 0x80); + } + + rum_bbp_write(sc, 35, bbp35); + rum_bbp_write(sc, 97, bbp97); + rum_bbp_write(sc, 98, bbp98); + + tmp = rum_read(sc, RT2573_PHY_CSR0); + tmp &= ~(RT2573_PA_PE_2GHZ | RT2573_PA_PE_5GHZ); + if (IEEE80211_IS_CHAN_2GHZ(c)) + tmp |= RT2573_PA_PE_2GHZ; + else + tmp |= RT2573_PA_PE_5GHZ; + rum_write(sc, RT2573_PHY_CSR0, tmp); +} + +static void +rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + const struct rfprog *rfprog; + uint8_t bbp3, bbp94 = RT2573_BBPR94_DEFAULT; + int8_t power; + u_int i, chan; + + chan = ieee80211_chan2ieee(ic, c); + if (chan == 0 || chan == IEEE80211_CHAN_ANY) + return; + + /* select the appropriate RF settings based on what EEPROM says */ + rfprog = (sc->rf_rev == RT2573_RF_5225 || + sc->rf_rev == RT2573_RF_2527) ? rum_rf5225 : rum_rf5226; + + /* find the settings for this channel (we know it exists) */ + for (i = 0; rfprog[i].chan != chan; i++); + + power = sc->txpow[i]; + if (power < 0) { + bbp94 += power; + power = 0; + } else if (power > 31) { + bbp94 += power - 31; + power = 31; + } + + /* + * If we are switching from the 2GHz band to the 5GHz band or + * vice-versa, BBP registers need to be reprogrammed. + */ + if (c->ic_flags != ic->ic_curchan->ic_flags) { + rum_select_band(sc, c); + rum_select_antenna(sc); + } + ic->ic_curchan = c; + + rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); + rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); + rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7); + rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); + + rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); + rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); + rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7 | 1); + rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); + + rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); + rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); + rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7); + rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); + + DELAY(10); + + /* enable smart mode for MIMO-capable RFs */ + bbp3 = rum_bbp_read(sc, 3); + + bbp3 &= ~RT2573_SMART_MODE; + if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_2527) + bbp3 |= RT2573_SMART_MODE; + + rum_bbp_write(sc, 3, bbp3); + + if (bbp94 != RT2573_BBPR94_DEFAULT) + rum_bbp_write(sc, 94, bbp94); +} + +/* + * Enable TSF synchronization and tell h/w to start sending beacons for IBSS + * and HostAP operating modes. + */ +static void +rum_enable_tsf_sync(struct rum_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + uint32_t tmp; + + if (vap->iv_opmode != IEEE80211_M_STA) { + /* + * Change default 16ms TBTT adjustment to 8ms. + * Must be done before enabling beacon generation. + */ + rum_write(sc, RT2573_TXRX_CSR10, 1 << 12 | 8); + } + + tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000; + + /* set beacon interval (in 1/16ms unit) */ + tmp |= vap->iv_bss->ni_intval * 16; + + tmp |= RT2573_TSF_TICKING | RT2573_ENABLE_TBTT; + if (vap->iv_opmode == IEEE80211_M_STA) + tmp |= RT2573_TSF_MODE(1); + else + tmp |= RT2573_TSF_MODE(2) | RT2573_GENERATE_BEACON; + + rum_write(sc, RT2573_TXRX_CSR9, tmp); +} + +static void +rum_update_slot(struct ifnet *ifp) +{ + struct rum_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + uint8_t slottime; + uint32_t tmp; + + slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; + + tmp = rum_read(sc, RT2573_MAC_CSR9); + tmp = (tmp & ~0xff) | slottime; + rum_write(sc, RT2573_MAC_CSR9, tmp); + + DPRINTF("setting slot time to %uus\n", slottime); +} + +static void +rum_set_bssid(struct rum_softc *sc, const uint8_t *bssid) +{ + uint32_t tmp; + + tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; + rum_write(sc, RT2573_MAC_CSR4, tmp); + + tmp = bssid[4] | bssid[5] << 8 | RT2573_ONE_BSSID << 16; + rum_write(sc, RT2573_MAC_CSR5, tmp); +} + +static void +rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr) +{ + uint32_t tmp; + + tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; + rum_write(sc, RT2573_MAC_CSR2, tmp); + + tmp = addr[4] | addr[5] << 8 | 0xff << 16; + rum_write(sc, RT2573_MAC_CSR3, tmp); +} + +static void +rum_promisctask(struct usb2_proc_msg *pm) +{ + struct rum_task *task = (struct rum_task *)pm; + struct rum_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + uint32_t tmp; + + tmp = rum_read(sc, RT2573_TXRX_CSR0); + + tmp &= ~RT2573_DROP_NOT_TO_ME; + if (!(ifp->if_flags & IFF_PROMISC)) + tmp |= RT2573_DROP_NOT_TO_ME; + + rum_write(sc, RT2573_TXRX_CSR0, tmp); + + DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? + "entering" : "leaving"); +} + +static const char * +rum_get_rf(int rev) +{ + switch (rev) { + case RT2573_RF_2527: return "RT2527 (MIMO XR)"; + case RT2573_RF_2528: return "RT2528"; + case RT2573_RF_5225: return "RT5225 (MIMO XR)"; + case RT2573_RF_5226: return "RT5226"; + default: return "unknown"; + } +} + +static void +rum_read_eeprom(struct rum_softc *sc) +{ + uint16_t val; +#ifdef RUM_DEBUG + int i; +#endif + + /* read MAC address */ + rum_eeprom_read(sc, RT2573_EEPROM_ADDRESS, sc->sc_bssid, 6); + + rum_eeprom_read(sc, RT2573_EEPROM_ANTENNA, &val, 2); + val = le16toh(val); + sc->rf_rev = (val >> 11) & 0x1f; + sc->hw_radio = (val >> 10) & 0x1; + sc->rx_ant = (val >> 4) & 0x3; + sc->tx_ant = (val >> 2) & 0x3; + sc->nb_ant = val & 0x3; + + DPRINTF("RF revision=%d\n", sc->rf_rev); + + rum_eeprom_read(sc, RT2573_EEPROM_CONFIG2, &val, 2); + val = le16toh(val); + sc->ext_5ghz_lna = (val >> 6) & 0x1; + sc->ext_2ghz_lna = (val >> 4) & 0x1; + + DPRINTF("External 2GHz LNA=%d\nExternal 5GHz LNA=%d\n", + sc->ext_2ghz_lna, sc->ext_5ghz_lna); + + rum_eeprom_read(sc, RT2573_EEPROM_RSSI_2GHZ_OFFSET, &val, 2); + val = le16toh(val); + if ((val & 0xff) != 0xff) + sc->rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */ + + /* Only [-10, 10] is valid */ + if (sc->rssi_2ghz_corr < -10 || sc->rssi_2ghz_corr > 10) + sc->rssi_2ghz_corr = 0; + + rum_eeprom_read(sc, RT2573_EEPROM_RSSI_5GHZ_OFFSET, &val, 2); + val = le16toh(val); + if ((val & 0xff) != 0xff) + sc->rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */ + + /* Only [-10, 10] is valid */ + if (sc->rssi_5ghz_corr < -10 || sc->rssi_5ghz_corr > 10) + sc->rssi_5ghz_corr = 0; + + if (sc->ext_2ghz_lna) + sc->rssi_2ghz_corr -= 14; + if (sc->ext_5ghz_lna) + sc->rssi_5ghz_corr -= 14; + + DPRINTF("RSSI 2GHz corr=%d\nRSSI 5GHz corr=%d\n", + sc->rssi_2ghz_corr, sc->rssi_5ghz_corr); + + rum_eeprom_read(sc, RT2573_EEPROM_FREQ_OFFSET, &val, 2); + val = le16toh(val); + if ((val & 0xff) != 0xff) + sc->rffreq = val & 0xff; + + DPRINTF("RF freq=%d\n", sc->rffreq); + + /* read Tx power for all a/b/g channels */ + rum_eeprom_read(sc, RT2573_EEPROM_TXPOWER, sc->txpow, 14); + /* XXX default Tx power for 802.11a channels */ + memset(sc->txpow + 14, 24, sizeof (sc->txpow) - 14); +#ifdef RUM_DEBUG + for (i = 0; i < 14; i++) + DPRINTF("Channel=%d Tx power=%d\n", i + 1, sc->txpow[i]); +#endif + + /* read default values for BBP registers */ + rum_eeprom_read(sc, RT2573_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16); +#ifdef RUM_DEBUG + for (i = 0; i < 14; i++) { + if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff) + continue; + DPRINTF("BBP R%d=%02x\n", sc->bbp_prom[i].reg, + sc->bbp_prom[i].val); + } +#endif +} + +static int +rum_bbp_init(struct rum_softc *sc) +{ +#define N(a) (sizeof (a) / sizeof ((a)[0])) + int i, ntries; + + /* wait for BBP to be ready */ + for (ntries = 0; ntries < 100; ntries++) { + const uint8_t val = rum_bbp_read(sc, 0); + if (val != 0 && val != 0xff) + break; + DELAY(1000); + } + if (ntries == 100) { + device_printf(sc->sc_dev, "timeout waiting for BBP\n"); + return EIO; + } + + /* initialize BBP registers to default values */ + for (i = 0; i < N(rum_def_bbp); i++) + rum_bbp_write(sc, rum_def_bbp[i].reg, rum_def_bbp[i].val); + + /* write vendor-specific BBP values (from EEPROM) */ + for (i = 0; i < 16; i++) { + if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff) + continue; + rum_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); + } + + return 0; +#undef N +} + +static void +rum_init_task(struct usb2_proc_msg *pm) +{ +#define N(a) (sizeof (a) / sizeof ((a)[0])) + struct rum_task *task = (struct rum_task *)pm; + struct rum_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint32_t tmp; + usb2_error_t error; + int i, ntries; + + RUM_LOCK_ASSERT(sc, MA_OWNED); + + rum_stop_task(pm); + + /* initialize MAC registers to default values */ + for (i = 0; i < N(rum_def_mac); i++) + rum_write(sc, rum_def_mac[i].reg, rum_def_mac[i].val); + + /* set host ready */ + rum_write(sc, RT2573_MAC_CSR1, 3); + rum_write(sc, RT2573_MAC_CSR1, 0); + + /* wait for BBP/RF to wakeup */ + for (ntries = 0; ntries < 1000; ntries++) { + if (rum_read(sc, RT2573_MAC_CSR12) & 8) + break; + rum_write(sc, RT2573_MAC_CSR12, 4); /* force wakeup */ + DELAY(1000); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout waiting for BBP/RF to wakeup\n"); + goto fail; + } + + if ((error = rum_bbp_init(sc)) != 0) + goto fail; + + /* select default channel */ + rum_select_band(sc, ic->ic_curchan); + rum_select_antenna(sc); + rum_set_chan(sc, ic->ic_curchan); + + /* clear STA registers */ + rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta); + + IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); + rum_set_macaddr(sc, ic->ic_myaddr); + + /* initialize ASIC */ + rum_write(sc, RT2573_MAC_CSR1, 4); + + /* + * Allocate Tx and Rx xfer queues. + */ + rum_setup_tx_list(sc); + + /* update Rx filter */ + tmp = rum_read(sc, RT2573_TXRX_CSR0) & 0xffff; + + tmp |= RT2573_DROP_PHY_ERROR | RT2573_DROP_CRC_ERROR; + if (ic->ic_opmode != IEEE80211_M_MONITOR) { + tmp |= RT2573_DROP_CTL | RT2573_DROP_VER_ERROR | + RT2573_DROP_ACKCTS; + if (ic->ic_opmode != IEEE80211_M_HOSTAP) + tmp |= RT2573_DROP_TODS; + if (!(ifp->if_flags & IFF_PROMISC)) + tmp |= RT2573_DROP_NOT_TO_ME; + } + rum_write(sc, RT2573_TXRX_CSR0, tmp); + + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + usb2_transfer_start(sc->sc_xfer[RUM_BULK_RD]); + return; + +fail: rum_stop_task(pm); +#undef N +} + +static void +rum_init(void *priv) +{ + struct rum_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + RUM_LOCK(sc); + rum_queue_command(sc, rum_init_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + RUM_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void +rum_stop_task(struct usb2_proc_msg *pm) +{ + struct rum_task *task = (struct rum_task *)pm; + struct rum_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + uint32_t tmp; + + RUM_LOCK_ASSERT(sc, MA_OWNED); + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + RUM_UNLOCK(sc); + + /* + * Drain the USB transfers, if not already drained: + */ + usb2_transfer_drain(sc->sc_xfer[RUM_BULK_WR]); + usb2_transfer_drain(sc->sc_xfer[RUM_BULK_RD]); + + RUM_LOCK(sc); + + rum_unsetup_tx_list(sc); + + /* disable Rx */ + tmp = rum_read(sc, RT2573_TXRX_CSR0); + rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); + + /* reset ASIC */ + rum_write(sc, RT2573_MAC_CSR1, 3); + rum_write(sc, RT2573_MAC_CSR1, 0); +} + +static int +rum_load_microcode(struct rum_softc *sc, const u_char *ucode, size_t size) +{ + struct usb2_device_request req; + uint16_t reg = RT2573_MCU_CODE_BASE; + usb2_error_t error; + + /* copy firmware image into NIC */ + for (; size >= 4; reg += 4, ucode += 4, size -= 4) + rum_write(sc, reg, UGETDW(ucode)); + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = RT2573_MCU_CNTL; + USETW(req.wValue, RT2573_MCU_RUN); + USETW(req.wIndex, 0); + USETW(req.wLength, 0); + + error = rum_do_request(sc, &req, NULL); + if (error != 0) { + device_printf(sc->sc_dev, "could not run firmware: %s\n", + usb2_errstr(error)); + } + return error; +} + +static int +rum_prepare_beacon(struct rum_softc *sc, struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + const struct ieee80211_txparam *tp; + struct rum_tx_desc desc; + struct mbuf *m0; + + m0 = ieee80211_beacon_alloc(vap->iv_bss, &RUM_VAP(vap)->bo); + if (m0 == NULL) { + return ENOBUFS; + } + + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; + rum_setup_tx_desc(sc, &desc, RT2573_TX_TIMESTAMP, RT2573_TX_HWSEQ, + m0->m_pkthdr.len, tp->mgmtrate); + + /* copy the first 24 bytes of Tx descriptor into NIC memory */ + rum_write_multi(sc, RT2573_HW_BEACON_BASE0, (uint8_t *)&desc, 24); + + /* copy beacon header and payload into NIC memory */ + rum_write_multi(sc, RT2573_HW_BEACON_BASE0 + 24, mtod(m0, uint8_t *), + m0->m_pkthdr.len); + + m_freem(m0); + + return 0; +} + +static int +rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ifnet *ifp = ni->ni_ic->ic_ifp; + struct rum_softc *sc = ifp->if_softc; + + RUM_LOCK(sc); + /* prevent management frames from being sent if we're not ready */ + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + RUM_UNLOCK(sc); + m_freem(m); + ieee80211_free_node(ni); + return ENETDOWN; + } + if (sc->tx_nfree == 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + RUM_UNLOCK(sc); + m_freem(m); + ieee80211_free_node(ni); + return EIO; + } + + ifp->if_opackets++; + + if (params == NULL) { + /* + * Legacy path; interpret frame contents to decide + * precisely how to send the frame. + */ + if (rum_tx_mgt(sc, m, ni) != 0) + goto bad; + } else { + /* + * Caller supplied explicit parameters to use in + * sending the frame. + */ + if (rum_tx_raw(sc, m, ni, params) != 0) + goto bad; + } + RUM_UNLOCK(sc); + + return 0; +bad: + ifp->if_oerrors++; + RUM_UNLOCK(sc); + ieee80211_free_node(ni); + return EIO; +} + +static void +rum_amrr_start(struct rum_softc *sc, struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rum_vap *rvp = RUM_VAP(vap); + + /* clear statistic registers (STA_CSR0 to STA_CSR5) */ + rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta); + + ieee80211_amrr_node_init(&rvp->amrr, &RUM_NODE(ni)->amn, ni); + + usb2_callout_reset(&rvp->amrr_ch, hz, rum_amrr_timeout, rvp); +} + +static void +rum_amrr_timeout(void *arg) +{ + struct rum_vap *rvp = arg; + struct rum_softc *sc = rvp->sc; + + rum_queue_command(sc, rum_amrr_task, + &rvp->amrr_task[0].hdr, &rvp->amrr_task[1].hdr); +} + +static void +rum_amrr_task(struct usb2_proc_msg *pm) +{ + struct rum_task *task = (struct rum_task *)pm; + struct rum_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct rum_vap *rvp = RUM_VAP(vap); + struct ieee80211_node *ni = vap->iv_bss; + int ok, fail; + + /* read and clear statistic registers (STA_CSR0 to STA_CSR10) */ + rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof(sc->sta)); + + ok = (le32toh(sc->sta[4]) >> 16) + /* TX ok w/o retry */ + (le32toh(sc->sta[5]) & 0xffff); /* TX ok w/ retry */ + fail = (le32toh(sc->sta[5]) >> 16); /* TX retry-fail count */ + + ieee80211_amrr_tx_update(&RUM_NODE(ni)->amn, + ok+fail, ok, (le32toh(sc->sta[5]) & 0xffff) + fail); + (void) ieee80211_amrr_choose(ni, &RUM_NODE(ni)->amn); + + ifp->if_oerrors += fail; /* count TX retry-fail as Tx errors */ + + usb2_callout_reset(&rvp->amrr_ch, hz, rum_amrr_timeout, rvp); +} + /* ARGUSED */ static struct ieee80211_node * rum_node_alloc(struct ieee80211vap *vap __unused, - const uint8_t mac[IEEE80211_ADDR_LEN] __unused) + const uint8_t mac[IEEE80211_ADDR_LEN] __unused) { struct rum_node *rn; rn = malloc(sizeof(struct rum_node), M_80211_NODE, M_NOWAIT | M_ZERO); - return ((rn != NULL) ? &rn->ni : NULL); + return rn != NULL ? &rn->ni : NULL; } static void @@ -2594,305 +2244,171 @@ rum_newassoc(struct ieee80211_node *ni, int isnew) } static void -rum_fill_write_queue(struct rum_softc *sc) +rum_scan_start(struct ieee80211com *ic) { + struct rum_softc *sc = ic->ic_ifp->if_softc; + + RUM_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = RUM_SCAN_START; + rum_queue_command(sc, rum_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + RUM_UNLOCK(sc); + +} + +static void +rum_scan_end(struct ieee80211com *ic) +{ + struct rum_softc *sc = ic->ic_ifp->if_softc; + + RUM_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = RUM_SCAN_END; + rum_queue_command(sc, rum_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + RUM_UNLOCK(sc); + +} + +static void +rum_set_channel(struct ieee80211com *ic) +{ + struct rum_softc *sc = ic->ic_ifp->if_softc; + + RUM_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = RUM_SET_CHANNEL; + rum_queue_command(sc, rum_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + + sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); + RUM_UNLOCK(sc); +} + +static void +rum_scantask(struct usb2_proc_msg *pm) +{ + struct rum_task *task = (struct rum_task *)pm; + struct rum_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211_node *ni; - struct mbuf *m; + struct ieee80211com *ic = ifp->if_l2com; + uint32_t tmp; - /* - * We only fill up half of the queue with data frames. The rest is - * reserved for other kinds of frames. - */ + RUM_LOCK_ASSERT(sc, MA_OWNED); - while (sc->sc_tx_queue.ifq_len < (IFQ_MAXLEN / 2)) { + switch (sc->sc_scan_action) { + case RUM_SCAN_START: + /* abort TSF synchronization */ + tmp = rum_read(sc, RT2573_TXRX_CSR9); + rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); + rum_set_bssid(sc, ifp->if_broadcastaddr); + break; - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; - - ni = (void *)(m->m_pkthdr.rcvif); - m = ieee80211_encap(ni, m); - if (m == NULL) { - ieee80211_free_node(ni); - continue; - } - rum_tx_data(sc, m, ni); - } -} - -static void -rum_tx_clean_queue(struct rum_softc *sc) -{ - struct mbuf *m; - - for (;;) { - _IF_DEQUEUE(&sc->sc_tx_queue, m); - - if (!m) { - break; - } - rum_tx_freem(m); - } -} - -static void -rum_tx_freem(struct mbuf *m) -{ - 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); + case RUM_SET_CHANNEL: + rum_set_chan(sc, ic->ic_curchan); + break; + default: /* RUM_SCAN_END */ + rum_enable_tsf_sync(sc); + rum_set_bssid(sc, sc->sc_bssid); break; } } -static void -rum_tx_mgt(struct rum_softc *sc, struct mbuf *m, struct ieee80211_node *ni) -{ - 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; - uint32_t flags; - uint16_t dur; - - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - - 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 *); - } - flags = 0; - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - flags |= RT2573_TX_NEED_ACK; - - dur = ieee80211_ack_duration(sc->sc_rates, tp->mgmtrate, - ic->ic_flags & IEEE80211_F_SHPREAMBLE); - USETW(wh->i_dur, dur); - - /* tell hardware to add timestamp for probe responses */ - if ((wh->i_fc[0] & - (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == - (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) - flags |= RT2573_TX_TIMESTAMP; - } - m->m_pkthdr.rcvif = (void *)ni; - rum_setup_desc_and_tx(sc, m, flags, 0, tp->mgmtrate); -} - -static struct ieee80211vap * -rum_get_vap(struct rum_softc *sc) -{ - struct ifnet *ifp; - struct ieee80211com *ic; - - 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); -} - -static void -rum_tx_data(struct rum_softc *sc, struct mbuf *m, - struct ieee80211_node *ni) -{ - 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; - uint32_t flags = 0; - uint16_t dur; - uint16_t rate; - - DPRINTFN(11, "Sending data.\n"); - - wh = mtod(m, struct ieee80211_frame *); - - tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; - if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - rate = tp->mcastrate; - 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 (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - uint8_t prot = IEEE80211_PROT_NONE; - - if (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) - prot = IEEE80211_PROT_RTSCTS; - else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) - prot = ic->ic_protmode; - if (prot != IEEE80211_PROT_NONE) { - rum_tx_prot(sc, m, ni, prot, rate); - flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; - } - flags |= RT2573_TX_NEED_ACK; - flags |= RT2573_TX_MORE_FRAG; - - dur = ieee80211_ack_duration(sc->sc_rates, rate, - ic->ic_flags & IEEE80211_F_SHPREAMBLE); - USETW(wh->i_dur, dur); - } - m->m_pkthdr.rcvif = (void *)ni; - rum_setup_desc_and_tx(sc, m, flags, 0, rate); -} - -static void -rum_tx_prot(struct rum_softc *sc, - const struct mbuf *m, struct ieee80211_node *ni, - uint8_t prot, uint16_t rate) -{ - struct ieee80211com *ic = ni->ni_ic; - const struct ieee80211_frame *wh; - struct mbuf *mprot; - uint32_t flags; - uint16_t protrate; - uint16_t ackrate; - uint16_t pktlen; - uint16_t dur; - uint8_t isshort; - - KASSERT((prot == IEEE80211_PROT_RTSCTS) || - (prot == IEEE80211_PROT_CTSONLY), - ("protection %u", prot)); - - DPRINTFN(11, "Sending protection frame.\n"); - - wh = mtod(m, const struct ieee80211_frame *); - pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; - - protrate = ieee80211_ctl_rate(sc->sc_rates, rate); - ackrate = ieee80211_ack_rate(sc->sc_rates, rate); - - isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; - dur = ieee80211_compute_duration(sc->sc_rates, pktlen, rate, isshort); - +ieee80211_ack_duration(sc->sc_rates, rate, isshort); - flags = RT2573_TX_MORE_FRAG; - if (prot == IEEE80211_PROT_RTSCTS) { - /* NB: CTS is the same size as an ACK */ - dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort); - flags |= RT2573_TX_NEED_ACK; - mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); - } else { - mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); - } - if (mprot == NULL) { - return; - } - mprot->m_pkthdr.rcvif = (void *)ieee80211_ref_node(ni); - rum_setup_desc_and_tx(sc, mprot, flags, 0, protrate); -} - -static void -rum_tx_raw(struct rum_softc *sc, struct mbuf *m, struct ieee80211_node *ni, - const struct ieee80211_bpf_params *params) -{ - uint32_t flags; - uint16_t rate; - - DPRINTFN(11, "Sending raw frame.\n"); - - rate = params->ibp_rate0 & IEEE80211_RATE_VAL; - - /* XXX validate */ - if (rate == 0) { - m_freem(m); - ieee80211_free_node(ni); - return; - } - flags = 0; - if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) - flags |= RT2573_TX_NEED_ACK; - if (params->ibp_flags & (IEEE80211_BPF_RTS | IEEE80211_BPF_CTS)) { - rum_tx_prot(sc, m, ni, - params->ibp_flags & IEEE80211_BPF_RTS ? - IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, - rate); - flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; - } - m->m_pkthdr.rcvif = (void *)ni; - rum_setup_desc_and_tx(sc, m, flags, 0, rate); -} - static int -rum_raw_xmit_cb(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) +rum_get_rssi(struct rum_softc *sc, uint8_t raw) { - struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = ic->ic_ifp; - struct rum_softc *sc = ifp->if_softc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + int lna, agc, rssi; - mtx_lock(&sc->sc_mtx); - if (params == NULL) { + lna = (raw >> 5) & 0x3; + agc = raw & 0x1f; + + if (lna == 0) { /* - * Legacy path; interpret frame contents to decide - * precisely how to send the frame. + * No RSSI mapping + * + * NB: Since RSSI is relative to noise floor, -1 is + * adequate for caller to know error happened. */ - rum_tx_mgt(sc, m, ni); - } else { - /* - * Caller supplied explicit parameters to use in - * sending the frame. - */ - rum_tx_raw(sc, m, ni, params); + return -1; } - mtx_unlock(&sc->sc_mtx); - return (0); + + rssi = (2 * agc) - RT2573_NOISE_FLOOR; + + if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { + rssi += sc->rssi_2ghz_corr; + + if (lna == 1) + rssi -= 64; + else if (lna == 2) + rssi -= 74; + else if (lna == 3) + rssi -= 90; + } else { + rssi += sc->rssi_5ghz_corr; + + if (!sc->ext_5ghz_lna && lna != 1) + rssi += 4; + + if (lna == 1) + rssi -= 64; + else if (lna == 2) + rssi -= 86; + else if (lna == 3) + rssi -= 100; + } + return rssi; } static void -rum_update_mcast_cb(struct ifnet *ifp) +rum_queue_command(struct rum_softc *sc, usb2_proc_callback_t *fn, + struct usb2_proc_msg *t0, struct usb2_proc_msg *t1) { - /* not supported */ + struct rum_task *task; + + RUM_LOCK_ASSERT(sc, MA_OWNED); + + if (usb2_proc_is_gone(&sc->sc_tq)) { + DPRINTF("proc is gone\n"); + return; /* nothing to do */ + } + /* + * 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 rum_task *) + usb2_proc_msignal(&sc->sc_tq, t0, t1); + + /* Setup callback and softc pointers */ + task->hdr.pm_callback = fn; + task->sc = sc; + + /* + * Init and stop must be synchronous! + */ + if ((fn == rum_init_task) || (fn == rum_stop_task)) + usb2_proc_mwait(&sc->sc_tq, t0, t1); } -static void -rum_update_promisc_cb(struct ifnet *ifp) -{ - struct rum_softc *sc = ifp->if_softc; +static device_method_t rum_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rum_match), + DEVMETHOD(device_attach, rum_attach), + DEVMETHOD(device_detach, rum_detach), - mtx_lock(&sc->sc_mtx); - usb2_config_td_queue_command - (&sc->sc_config_td, &rum_config_copy, - &rum_cfg_update_promisc, 0, 0); - mtx_unlock(&sc->sc_mtx); -} + { 0, 0 } +}; + +static driver_t rum_driver = { + .name = "rum", + .methods = rum_methods, + .size = sizeof(struct rum_softc), +}; + +static devclass_t rum_devclass; + +DRIVER_MODULE(rum, ushub, rum_driver, rum_devclass, NULL, 0); diff --git a/sys/dev/usb2/wlan/if_rumreg.h b/sys/dev/usb2/wlan/if_rumreg.h index cc88ef8eadb..75a51bcd4ad 100644 --- a/sys/dev/usb2/wlan/if_rumreg.h +++ b/sys/dev/usb2/wlan/if_rumreg.h @@ -17,219 +17,219 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RT2573_NOISE_FLOOR -95 +#define RT2573_NOISE_FLOOR -95 -#define RT2573_TX_DESC_SIZE (sizeof (struct rum_tx_desc)) -#define RT2573_RX_DESC_SIZE (sizeof (struct rum_rx_desc)) +#define RT2573_TX_DESC_SIZE (sizeof (struct rum_tx_desc)) +#define RT2573_RX_DESC_SIZE (sizeof (struct rum_rx_desc)) -#define RT2573_CONFIG_NO 1 -#define RT2573_IFACE_INDEX 0 +#define RT2573_CONFIG_NO 1 +#define RT2573_IFACE_INDEX 0 -#define RT2573_MCU_CNTL 0x01 -#define RT2573_WRITE_MAC 0x02 -#define RT2573_READ_MAC 0x03 -#define RT2573_WRITE_MULTI_MAC 0x06 -#define RT2573_READ_MULTI_MAC 0x07 -#define RT2573_READ_EEPROM 0x09 -#define RT2573_WRITE_LED 0x0a +#define RT2573_MCU_CNTL 0x01 +#define RT2573_WRITE_MAC 0x02 +#define RT2573_READ_MAC 0x03 +#define RT2573_WRITE_MULTI_MAC 0x06 +#define RT2573_READ_MULTI_MAC 0x07 +#define RT2573_READ_EEPROM 0x09 +#define RT2573_WRITE_LED 0x0a /* * Control and status registers. */ -#define RT2573_AIFSN_CSR 0x0400 -#define RT2573_CWMIN_CSR 0x0404 -#define RT2573_CWMAX_CSR 0x0408 -#define RT2573_MCU_CODE_BASE 0x0800 -#define RT2573_HW_BEACON_BASE0 0x2400 -#define RT2573_MAC_CSR0 0x3000 -#define RT2573_MAC_CSR1 0x3004 -#define RT2573_MAC_CSR2 0x3008 -#define RT2573_MAC_CSR3 0x300c -#define RT2573_MAC_CSR4 0x3010 -#define RT2573_MAC_CSR5 0x3014 -#define RT2573_MAC_CSR6 0x3018 -#define RT2573_MAC_CSR7 0x301c -#define RT2573_MAC_CSR8 0x3020 -#define RT2573_MAC_CSR9 0x3024 -#define RT2573_MAC_CSR10 0x3028 -#define RT2573_MAC_CSR11 0x302c -#define RT2573_MAC_CSR12 0x3030 -#define RT2573_MAC_CSR13 0x3034 -#define RT2573_MAC_CSR14 0x3038 -#define RT2573_MAC_CSR15 0x303c -#define RT2573_TXRX_CSR0 0x3040 -#define RT2573_TXRX_CSR1 0x3044 -#define RT2573_TXRX_CSR2 0x3048 -#define RT2573_TXRX_CSR3 0x304c -#define RT2573_TXRX_CSR4 0x3050 -#define RT2573_TXRX_CSR5 0x3054 -#define RT2573_TXRX_CSR6 0x3058 -#define RT2573_TXRX_CSR7 0x305c -#define RT2573_TXRX_CSR8 0x3060 -#define RT2573_TXRX_CSR9 0x3064 -#define RT2573_TXRX_CSR10 0x3068 -#define RT2573_TXRX_CSR11 0x306c -#define RT2573_TXRX_CSR12 0x3070 -#define RT2573_TXRX_CSR13 0x3074 -#define RT2573_TXRX_CSR14 0x3078 -#define RT2573_TXRX_CSR15 0x307c -#define RT2573_PHY_CSR0 0x3080 -#define RT2573_PHY_CSR1 0x3084 -#define RT2573_PHY_CSR2 0x3088 -#define RT2573_PHY_CSR3 0x308c -#define RT2573_PHY_CSR4 0x3090 -#define RT2573_PHY_CSR5 0x3094 -#define RT2573_PHY_CSR6 0x3098 -#define RT2573_PHY_CSR7 0x309c -#define RT2573_SEC_CSR0 0x30a0 -#define RT2573_SEC_CSR1 0x30a4 -#define RT2573_SEC_CSR2 0x30a8 -#define RT2573_SEC_CSR3 0x30ac -#define RT2573_SEC_CSR4 0x30b0 -#define RT2573_SEC_CSR5 0x30b4 -#define RT2573_STA_CSR0 0x30c0 -#define RT2573_STA_CSR1 0x30c4 -#define RT2573_STA_CSR2 0x30c8 -#define RT2573_STA_CSR3 0x30cc -#define RT2573_STA_CSR4 0x30d0 -#define RT2573_STA_CSR5 0x30d4 +#define RT2573_AIFSN_CSR 0x0400 +#define RT2573_CWMIN_CSR 0x0404 +#define RT2573_CWMAX_CSR 0x0408 +#define RT2573_MCU_CODE_BASE 0x0800 +#define RT2573_HW_BEACON_BASE0 0x2400 +#define RT2573_MAC_CSR0 0x3000 +#define RT2573_MAC_CSR1 0x3004 +#define RT2573_MAC_CSR2 0x3008 +#define RT2573_MAC_CSR3 0x300c +#define RT2573_MAC_CSR4 0x3010 +#define RT2573_MAC_CSR5 0x3014 +#define RT2573_MAC_CSR6 0x3018 +#define RT2573_MAC_CSR7 0x301c +#define RT2573_MAC_CSR8 0x3020 +#define RT2573_MAC_CSR9 0x3024 +#define RT2573_MAC_CSR10 0x3028 +#define RT2573_MAC_CSR11 0x302c +#define RT2573_MAC_CSR12 0x3030 +#define RT2573_MAC_CSR13 0x3034 +#define RT2573_MAC_CSR14 0x3038 +#define RT2573_MAC_CSR15 0x303c +#define RT2573_TXRX_CSR0 0x3040 +#define RT2573_TXRX_CSR1 0x3044 +#define RT2573_TXRX_CSR2 0x3048 +#define RT2573_TXRX_CSR3 0x304c +#define RT2573_TXRX_CSR4 0x3050 +#define RT2573_TXRX_CSR5 0x3054 +#define RT2573_TXRX_CSR6 0x3058 +#define RT2573_TXRX_CSR7 0x305c +#define RT2573_TXRX_CSR8 0x3060 +#define RT2573_TXRX_CSR9 0x3064 +#define RT2573_TXRX_CSR10 0x3068 +#define RT2573_TXRX_CSR11 0x306c +#define RT2573_TXRX_CSR12 0x3070 +#define RT2573_TXRX_CSR13 0x3074 +#define RT2573_TXRX_CSR14 0x3078 +#define RT2573_TXRX_CSR15 0x307c +#define RT2573_PHY_CSR0 0x3080 +#define RT2573_PHY_CSR1 0x3084 +#define RT2573_PHY_CSR2 0x3088 +#define RT2573_PHY_CSR3 0x308c +#define RT2573_PHY_CSR4 0x3090 +#define RT2573_PHY_CSR5 0x3094 +#define RT2573_PHY_CSR6 0x3098 +#define RT2573_PHY_CSR7 0x309c +#define RT2573_SEC_CSR0 0x30a0 +#define RT2573_SEC_CSR1 0x30a4 +#define RT2573_SEC_CSR2 0x30a8 +#define RT2573_SEC_CSR3 0x30ac +#define RT2573_SEC_CSR4 0x30b0 +#define RT2573_SEC_CSR5 0x30b4 +#define RT2573_STA_CSR0 0x30c0 +#define RT2573_STA_CSR1 0x30c4 +#define RT2573_STA_CSR2 0x30c8 +#define RT2573_STA_CSR3 0x30cc +#define RT2573_STA_CSR4 0x30d0 +#define RT2573_STA_CSR5 0x30d4 /* possible flags for register RT2573_MAC_CSR1 */ -#define RT2573_RESET_ASIC (1 << 0) -#define RT2573_RESET_BBP (1 << 1) -#define RT2573_HOST_READY (1 << 2) +#define RT2573_RESET_ASIC (1 << 0) +#define RT2573_RESET_BBP (1 << 1) +#define RT2573_HOST_READY (1 << 2) /* possible flags for register MAC_CSR5 */ -#define RT2573_ONE_BSSID 3 +#define RT2573_ONE_BSSID 3 /* possible flags for register TXRX_CSR0 */ /* Tx filter flags are in the low 16 bits */ -#define RT2573_AUTO_TX_SEQ (1 << 15) +#define RT2573_AUTO_TX_SEQ (1 << 15) /* Rx filter flags are in the high 16 bits */ -#define RT2573_DISABLE_RX (1 << 16) -#define RT2573_DROP_CRC_ERROR (1 << 17) -#define RT2573_DROP_PHY_ERROR (1 << 18) -#define RT2573_DROP_CTL (1 << 19) -#define RT2573_DROP_NOT_TO_ME (1 << 20) -#define RT2573_DROP_TODS (1 << 21) -#define RT2573_DROP_VER_ERROR (1 << 22) -#define RT2573_DROP_MULTICAST (1 << 23) -#define RT2573_DROP_BROADCAST (1 << 24) -#define RT2573_DROP_ACKCTS (1 << 25) +#define RT2573_DISABLE_RX (1 << 16) +#define RT2573_DROP_CRC_ERROR (1 << 17) +#define RT2573_DROP_PHY_ERROR (1 << 18) +#define RT2573_DROP_CTL (1 << 19) +#define RT2573_DROP_NOT_TO_ME (1 << 20) +#define RT2573_DROP_TODS (1 << 21) +#define RT2573_DROP_VER_ERROR (1 << 22) +#define RT2573_DROP_MULTICAST (1 << 23) +#define RT2573_DROP_BROADCAST (1 << 24) +#define RT2573_DROP_ACKCTS (1 << 25) /* possible flags for register TXRX_CSR4 */ -#define RT2573_SHORT_PREAMBLE (1 << 18) -#define RT2573_MRR_ENABLED (1 << 19) -#define RT2573_MRR_CCK_FALLBACK (1 << 22) +#define RT2573_SHORT_PREAMBLE (1 << 18) +#define RT2573_MRR_ENABLED (1 << 19) +#define RT2573_MRR_CCK_FALLBACK (1 << 22) /* possible flags for register TXRX_CSR9 */ -#define RT2573_TSF_TICKING (1 << 16) -#define RT2573_TSF_MODE(x) (((x) & 0x3) << 17) +#define RT2573_TSF_TICKING (1 << 16) +#define RT2573_TSF_MODE(x) (((x) & 0x3) << 17) /* TBTT stands for Target Beacon Transmission Time */ -#define RT2573_ENABLE_TBTT (1 << 19) -#define RT2573_GENERATE_BEACON (1 << 20) +#define RT2573_ENABLE_TBTT (1 << 19) +#define RT2573_GENERATE_BEACON (1 << 20) /* possible flags for register PHY_CSR0 */ -#define RT2573_PA_PE_2GHZ (1 << 16) -#define RT2573_PA_PE_5GHZ (1 << 17) +#define RT2573_PA_PE_2GHZ (1 << 16) +#define RT2573_PA_PE_5GHZ (1 << 17) /* possible flags for register PHY_CSR3 */ -#define RT2573_BBP_READ (1 << 15) -#define RT2573_BBP_BUSY (1 << 16) +#define RT2573_BBP_READ (1 << 15) +#define RT2573_BBP_BUSY (1 << 16) /* possible flags for register PHY_CSR4 */ -#define RT2573_RF_20BIT (20 << 24) -#define RT2573_RF_BUSY (1 << 31) +#define RT2573_RF_20BIT (20 << 24) +#define RT2573_RF_BUSY (1 << 31) /* LED values */ -#define RT2573_LED_RADIO (1 << 8) -#define RT2573_LED_G (1 << 9) -#define RT2573_LED_A (1 << 10) -#define RT2573_LED_ON 0x1e1e -#define RT2573_LED_OFF 0x0 +#define RT2573_LED_RADIO (1 << 8) +#define RT2573_LED_G (1 << 9) +#define RT2573_LED_A (1 << 10) +#define RT2573_LED_ON 0x1e1e +#define RT2573_LED_OFF 0x0 -#define RT2573_MCU_RUN (1 << 3) +#define RT2573_MCU_RUN (1 << 3) -#define RT2573_SMART_MODE (1 << 0) +#define RT2573_SMART_MODE (1 << 0) -#define RT2573_BBPR94_DEFAULT 6 +#define RT2573_BBPR94_DEFAULT 6 -#define RT2573_BBP_WRITE (1 << 15) +#define RT2573_BBP_WRITE (1 << 15) /* dual-band RF */ -#define RT2573_RF_5226 1 -#define RT2573_RF_5225 3 +#define RT2573_RF_5226 1 +#define RT2573_RF_5225 3 /* single-band RF */ -#define RT2573_RF_2528 2 -#define RT2573_RF_2527 4 +#define RT2573_RF_2528 2 +#define RT2573_RF_2527 4 -#define RT2573_BBP_VERSION 0 +#define RT2573_BBP_VERSION 0 struct rum_tx_desc { - uint32_t flags; -#define RT2573_TX_BURST (1 << 0) -#define RT2573_TX_VALID (1 << 1) -#define RT2573_TX_MORE_FRAG (1 << 2) -#define RT2573_TX_NEED_ACK (1 << 3) -#define RT2573_TX_TIMESTAMP (1 << 4) -#define RT2573_TX_OFDM (1 << 5) -#define RT2573_TX_IFS_SIFS (1 << 6) -#define RT2573_TX_LONG_RETRY (1 << 7) - uint16_t wme; -#define RT2573_QID(v) (v) -#define RT2573_AIFSN(v) ((v) << 4) -#define RT2573_LOGCWMIN(v) ((v) << 8) -#define RT2573_LOGCWMAX(v) ((v) << 12) + uint32_t flags; +#define RT2573_TX_BURST (1 << 0) +#define RT2573_TX_VALID (1 << 1) +#define RT2573_TX_MORE_FRAG (1 << 2) +#define RT2573_TX_NEED_ACK (1 << 3) +#define RT2573_TX_TIMESTAMP (1 << 4) +#define RT2573_TX_OFDM (1 << 5) +#define RT2573_TX_IFS_SIFS (1 << 6) +#define RT2573_TX_LONG_RETRY (1 << 7) - uint16_t xflags; -#define RT2573_TX_HWSEQ (1 << 12) -#define RT2573_TX_BEACON (1 << 15) /* Internal flag only! */ + uint16_t wme; +#define RT2573_QID(v) (v) +#define RT2573_AIFSN(v) ((v) << 4) +#define RT2573_LOGCWMIN(v) ((v) << 8) +#define RT2573_LOGCWMAX(v) ((v) << 12) - uint8_t plcp_signal; - uint8_t plcp_service; -#define RT2573_PLCP_LENGEXT 0x80 + uint16_t xflags; +#define RT2573_TX_HWSEQ (1 << 12) - uint8_t plcp_length_lo; - uint8_t plcp_length_hi; + uint8_t plcp_signal; + uint8_t plcp_service; +#define RT2573_PLCP_LENGEXT 0x80 - uint32_t iv; - uint32_t eiv; + uint8_t plcp_length_lo; + uint8_t plcp_length_hi; - uint8_t offset; - uint8_t qid; - uint8_t txpower; -#define RT2573_DEFAULT_TXPOWER 0 + uint32_t iv; + uint32_t eiv; - uint8_t reserved; + uint8_t offset; + uint8_t qid; + uint8_t txpower; +#define RT2573_DEFAULT_TXPOWER 0 + + uint8_t reserved; } __packed; struct rum_rx_desc { - uint32_t flags; -#define RT2573_RX_BUSY (1 << 0) -#define RT2573_RX_DROP (1 << 1) -#define RT2573_RX_CRC_ERROR (1 << 6) -#define RT2573_RX_OFDM (1 << 7) + uint32_t flags; +#define RT2573_RX_BUSY (1 << 0) +#define RT2573_RX_DROP (1 << 1) +#define RT2573_RX_CRC_ERROR (1 << 6) +#define RT2573_RX_OFDM (1 << 7) - uint8_t rate; - uint8_t rssi; - uint8_t reserved1; - uint8_t offset; - uint32_t iv; - uint32_t eiv; - uint32_t reserved2[2]; + uint8_t rate; + uint8_t rssi; + uint8_t reserved1; + uint8_t offset; + uint32_t iv; + uint32_t eiv; + uint32_t reserved2[2]; } __packed; -#define RT2573_RF1 0 -#define RT2573_RF2 2 -#define RT2573_RF3 1 -#define RT2573_RF4 3 +#define RT2573_RF1 0 +#define RT2573_RF2 2 +#define RT2573_RF3 1 +#define RT2573_RF4 3 -#define RT2573_EEPROM_MACBBP 0x0000 -#define RT2573_EEPROM_ADDRESS 0x0004 -#define RT2573_EEPROM_ANTENNA 0x0020 -#define RT2573_EEPROM_CONFIG2 0x0022 -#define RT2573_EEPROM_BBP_BASE 0x0026 -#define RT2573_EEPROM_TXPOWER 0x0046 -#define RT2573_EEPROM_FREQ_OFFSET 0x005e -#define RT2573_EEPROM_RSSI_2GHZ_OFFSET 0x009a -#define RT2573_EEPROM_RSSI_5GHZ_OFFSET 0x009c +#define RT2573_EEPROM_MACBBP 0x0000 +#define RT2573_EEPROM_ADDRESS 0x0004 +#define RT2573_EEPROM_ANTENNA 0x0020 +#define RT2573_EEPROM_CONFIG2 0x0022 +#define RT2573_EEPROM_BBP_BASE 0x0026 +#define RT2573_EEPROM_TXPOWER 0x0046 +#define RT2573_EEPROM_FREQ_OFFSET 0x005e +#define RT2573_EEPROM_RSSI_2GHZ_OFFSET 0x009a +#define RT2573_EEPROM_RSSI_5GHZ_OFFSET 0x009c diff --git a/sys/dev/usb2/wlan/if_rumvar.h b/sys/dev/usb2/wlan/if_rumvar.h index 29ee0a5b613..1b58dc47b54 100644 --- a/sys/dev/usb2/wlan/if_rumvar.h +++ b/sys/dev/usb2/wlan/if_rumvar.h @@ -1,4 +1,4 @@ -/* $FreeBSD$ */ +/* $FreeBSD$ */ /*- * Copyright (c) 2005, 2006 Damien Bergamini @@ -17,68 +17,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct rum_node { - struct ieee80211_node ni; - struct ieee80211_amrr_node amn; -}; - -#define RUM_NODE(ni) ((struct rum_node *)(ni)) - -struct rum_vap { - struct ieee80211vap vap; - struct ieee80211_beacon_offsets bo; - struct ieee80211_amrr amrr; - - int (*newstate) (struct ieee80211vap *, - enum ieee80211_state, int); -}; - -#define RUM_VAP(vap) ((struct rum_vap *)(vap)) - -struct rum_config_copy_chan { - uint32_t chan_to_ieee; - enum ieee80211_phymode chan_to_mode; - uint8_t chan_is_5ghz:1; - uint8_t chan_is_2ghz:1; - uint8_t chan_is_b:1; - uint8_t chan_is_a:1; - uint8_t chan_is_g:1; - uint8_t unused:3; -}; - -struct rum_config_copy_bss { - uint16_t ni_intval; - uint8_t ni_bssid[IEEE80211_ADDR_LEN]; - uint8_t fixed_rate_none; -}; - -struct rum_config_copy { - struct rum_config_copy_chan ic_curchan; - struct rum_config_copy_chan ic_bsschan; - struct rum_config_copy_bss iv_bss; - - enum ieee80211_opmode ic_opmode; - uint32_t ic_flags; - uint32_t if_flags; - - uint16_t ic_txpowlimit; - uint16_t ic_curmode; - - uint8_t ic_myaddr[IEEE80211_ADDR_LEN]; - uint8_t if_broadcastaddr[IEEE80211_ADDR_LEN]; -}; +#define RUM_TX_LIST_COUNT 8 struct rum_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; - uint8_t wr_flags; - uint8_t wr_rate; - uint16_t wr_chan_freq; - uint16_t wr_chan_flags; - uint8_t wr_antenna; - uint8_t wr_antsignal; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + uint8_t wr_antenna; + uint8_t wr_antsignal; }; -#define RT2573_RX_RADIOTAP_PRESENT \ +#define RT2573_RX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL) | \ @@ -87,91 +38,119 @@ struct rum_rx_radiotap_header { struct rum_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; - uint8_t wt_flags; - uint8_t wt_rate; - uint16_t wt_chan_freq; - uint16_t wt_chan_flags; - uint8_t wt_antenna; + uint8_t wt_flags; + uint8_t wt_rate; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; + uint8_t wt_antenna; }; -#define RT2573_TX_RADIOTAP_PRESENT \ +#define RT2573_TX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL) | \ (1 << IEEE80211_RADIOTAP_ANTENNA)) -struct rum_bbp_prom { - uint8_t val; - uint8_t reg; -} __packed; +struct rum_softc; -struct rum_ifq { - struct mbuf *ifq_head; - struct mbuf *ifq_tail; - uint16_t ifq_len; +struct rum_task { + struct usb2_proc_msg hdr; + struct rum_softc *sc; }; +struct rum_tx_data { + STAILQ_ENTRY(rum_tx_data) next; + struct rum_softc *sc; + struct rum_tx_desc desc; + struct mbuf *m; + struct ieee80211_node *ni; + int rate; +}; +typedef STAILQ_HEAD(, rum_tx_data) rum_txdhead; + +struct rum_node { + struct ieee80211_node ni; + struct ieee80211_amrr_node amn; +}; +#define RUM_NODE(ni) ((struct rum_node *)(ni)) + +struct rum_vap { + struct ieee80211vap vap; + struct rum_softc *sc; + struct ieee80211_beacon_offsets bo; + struct ieee80211_amrr amrr; + struct usb2_callout amrr_ch; + struct rum_task amrr_task[2]; + + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); +}; +#define RUM_VAP(vap) ((struct rum_vap *)(vap)) + enum { - RUM_BULK_DT_WR, - RUM_BULK_DT_RD, - RUM_BULK_CS_WR, - RUM_BULK_CS_RD, - RUM_N_TRANSFER = 4, + RUM_BULK_WR, + RUM_BULK_RD, + RUM_N_TRANSFER = 2, }; struct rum_softc { - struct ifnet *sc_ifp; + struct ifnet *sc_ifp; + device_t sc_dev; + struct usb2_device *sc_udev; + struct usb2_process sc_tq; - struct rum_ifq sc_tx_queue; - struct usb2_config_td sc_config_td; - struct rum_tx_desc sc_tx_desc; - struct rum_rx_desc sc_rx_desc; - struct mtx sc_mtx; - struct usb2_callout sc_watchdog; - struct rum_bbp_prom sc_bbp_prom[16]; - struct rum_rx_radiotap_header sc_rxtap; - struct rum_tx_radiotap_header sc_txtap; - - struct usb2_xfer *sc_xfer[RUM_N_TRANSFER]; - struct usb2_device *sc_udev; const struct ieee80211_rate_table *sc_rates; + struct usb2_xfer *sc_xfer[RUM_N_TRANSFER]; - int (*sc_newstate) - (struct ieee80211com *, enum ieee80211_state, int); + uint8_t rf_rev; + uint8_t rffreq; - enum ieee80211_state sc_ns_state; - uint32_t sc_sta[6]; - uint32_t sc_unit; - int sc_ns_arg; + enum ieee80211_state sc_state; + int sc_arg; + struct rum_task sc_synctask[2]; + struct rum_task sc_task[2]; + struct rum_task sc_promisctask[2]; + struct rum_task sc_scantask[2]; + int sc_scan_action; +#define RUM_SCAN_START 0 +#define RUM_SCAN_END 1 +#define RUM_SET_CHANNEL 2 - uint16_t sc_flags; -#define RUM_FLAG_READ_STALL 0x0001 -#define RUM_FLAG_WRITE_STALL 0x0002 -#define RUM_FLAG_LL_READY 0x0008 -#define RUM_FLAG_HL_READY 0x0010 -#define RUM_FLAG_WAIT_COMMAND 0x0020 - uint16_t sc_txtap_len; - uint16_t sc_rxtap_len; - uint16_t sc_last_chan; + struct rum_tx_data tx_data[RUM_TX_LIST_COUNT]; + rum_txdhead tx_q; + rum_txdhead tx_free; + int tx_nfree; + struct rum_rx_desc sc_rx_desc; - uint8_t sc_txpow[44]; - uint8_t sc_rf_rev; - uint8_t sc_rffreq; - uint8_t sc_ftype; - uint8_t sc_rx_ant; - uint8_t sc_tx_ant; - uint8_t sc_nb_ant; - uint8_t sc_ext_2ghz_lna; - uint8_t sc_ext_5ghz_lna; - uint8_t sc_sifs; - uint8_t sc_bbp17; - uint8_t sc_hw_radio; - uint8_t sc_amrr_timer; - uint8_t sc_beacon_buf[0x800]; - uint8_t sc_myaddr[IEEE80211_ADDR_LEN]; + struct mtx sc_mtx; - int8_t sc_rssi_2ghz_corr; - int8_t sc_rssi_5ghz_corr; + uint32_t sta[6]; + uint32_t rf_regs[4]; + uint8_t txpow[44]; + uint8_t sc_bssid[6]; - char sc_name[32]; + struct { + uint8_t val; + uint8_t reg; + } __packed bbp_prom[16]; + + int hw_radio; + int rx_ant; + int tx_ant; + int nb_ant; + int ext_2ghz_lna; + int ext_5ghz_lna; + int rssi_2ghz_corr; + int rssi_5ghz_corr; + uint8_t bbp17; + + struct rum_rx_radiotap_header sc_rxtap; + int sc_rxtap_len; + + struct rum_tx_radiotap_header sc_txtap; + int sc_txtap_len; }; + +#define RUM_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define RUM_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define RUM_LOCK_ASSERT(sc, t) mtx_assert(&(sc)->sc_mtx, t) diff --git a/sys/dev/usb2/wlan/if_ural2.c b/sys/dev/usb2/wlan/if_ural2.c index 2a66ce0268e..34bb1b37ac3 100644 --- a/sys/dev/usb2/wlan/if_ural2.c +++ b/sys/dev/usb2/wlan/if_ural2.c @@ -18,13 +18,6 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -/* - * - * NOTE: all function names beginning like "ural_cfg_" can only - * be called from within the config thread function ! */ #include @@ -40,15 +33,11 @@ __FBSDID("$FreeBSD$"); #include #include -#define usb2_config_td_cc ural_config_copy -#define usb2_config_td_softc ural_softc - #define USB_DEBUG_VAR ural_debug #include #include #include -#include #include #include #include @@ -66,207 +55,185 @@ SYSCTL_INT(_hw_usb2_ural, OID_AUTO, debug, CTLFLAG_RW, &ural_debug, 0, "Debug level"); #endif -#define URAL_RSSI(rssi) \ - ((rssi) > (RAL_NOISE_FLOOR + RAL_RSSI_CORR) ? \ - ((rssi) - (RAL_NOISE_FLOOR + RAL_RSSI_CORR)) : 0) +#define ural_do_request(sc,req,data) \ + usb2_do_request_proc((sc)->sc_udev, &(sc)->sc_tq, req, data, 0, NULL, 5000) -/* prototypes */ - -static device_probe_t ural_probe; -static device_attach_t ural_attach; -static device_detach_t ural_detach; - -static usb2_callback_t ural_bulk_read_callback; -static usb2_callback_t ural_bulk_read_clear_stall_callback; -static usb2_callback_t ural_bulk_write_callback; -static usb2_callback_t ural_bulk_write_clear_stall_callback; - -static usb2_config_td_command_t ural_cfg_first_time_setup; -static usb2_config_td_command_t ural_config_copy; -static usb2_config_td_command_t ural_cfg_scan_start; -static usb2_config_td_command_t ural_cfg_scan_end; -static usb2_config_td_command_t ural_cfg_set_chan; -static usb2_config_td_command_t ural_cfg_enable_tsf_sync; -static usb2_config_td_command_t ural_cfg_update_slot; -static usb2_config_td_command_t ural_cfg_set_txpreamble; -static usb2_config_td_command_t ural_cfg_update_promisc; -static usb2_config_td_command_t ural_cfg_pre_init; -static usb2_config_td_command_t ural_cfg_init; -static usb2_config_td_command_t ural_cfg_pre_stop; -static usb2_config_td_command_t ural_cfg_stop; -static usb2_config_td_command_t ural_cfg_amrr_timeout; -static usb2_config_td_command_t ural_cfg_newstate; - -static void ural_cfg_do_request(struct ural_softc *, - struct usb2_device_request *, void *); -static void ural_cfg_set_testmode(struct ural_softc *); -static void ural_cfg_eeprom_read(struct ural_softc *, uint16_t, void *, - uint16_t); -static uint16_t ural_cfg_read(struct ural_softc *, uint16_t); -static void ural_cfg_read_multi(struct ural_softc *, uint16_t, void *, - uint16_t); -static void ural_cfg_write(struct ural_softc *, uint16_t, uint16_t); -static void ural_cfg_write_multi(struct ural_softc *, uint16_t, void *, - uint16_t); -static void ural_cfg_bbp_write(struct ural_softc *, uint8_t, uint8_t); -static uint8_t ural_cfg_bbp_read(struct ural_softc *, uint8_t); -static void ural_cfg_rf_write(struct ural_softc *, uint8_t, uint32_t); -static void ural_end_of_commands(struct ural_softc *); -static const char *ural_get_rf(int rev); -static void ural_watchdog(void *); -static void ural_init_cb(void *); -static int ural_ioctl_cb(struct ifnet *, u_long cmd, caddr_t data); -static void ural_start_cb(struct ifnet *); -static int ural_newstate_cb(struct ieee80211vap *, - enum ieee80211_state, int); -static void ural_std_command(struct ieee80211com *, - usb2_config_td_command_t *); -static void ural_scan_start_cb(struct ieee80211com *); -static void ural_scan_end_cb(struct ieee80211com *); -static void ural_set_channel_cb(struct ieee80211com *); -static void ural_cfg_disable_rf_tune(struct ural_softc *); -static void ural_cfg_set_bssid(struct ural_softc *, uint8_t *); -static void ural_cfg_set_macaddr(struct ural_softc *, uint8_t *); -static void ural_cfg_set_txantenna(struct ural_softc *, uint8_t); -static void ural_cfg_set_rxantenna(struct ural_softc *, uint8_t); -static void ural_cfg_read_eeprom(struct ural_softc *); -static uint8_t ural_cfg_bbp_init(struct ural_softc *); -static void ural_cfg_amrr_start(struct ural_softc *); -static struct ieee80211vap *ural_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 ural_vap_delete(struct ieee80211vap *); -static struct ieee80211_node *ural_node_alloc(struct ieee80211vap *, - const uint8_t mac[IEEE80211_ADDR_LEN]); -static void ural_newassoc(struct ieee80211_node *, int); -static void ural_cfg_disable_tsf_sync(struct ural_softc *); -static void ural_cfg_set_run(struct ural_softc *, - struct usb2_config_td_cc *); -static void ural_fill_write_queue(struct ural_softc *); -static void ural_tx_clean_queue(struct ural_softc *); -static void ural_tx_freem(struct mbuf *); -static void ural_tx_mgt(struct ural_softc *, struct mbuf *, - struct ieee80211_node *); -static struct ieee80211vap *ural_get_vap(struct ural_softc *); -static void ural_tx_bcn(struct ural_softc *); -static void ural_tx_data(struct ural_softc *, struct mbuf *, - struct ieee80211_node *); -static void ural_tx_prot(struct ural_softc *, const struct mbuf *, - struct ieee80211_node *, uint8_t, uint16_t); -static void ural_tx_raw(struct ural_softc *, struct mbuf *, - struct ieee80211_node *, - const struct ieee80211_bpf_params *); -static int ural_raw_xmit_cb(struct ieee80211_node *, struct mbuf *, - const struct ieee80211_bpf_params *); -static void ural_setup_desc_and_tx(struct ural_softc *, struct mbuf *, - uint32_t, uint16_t); -static void ural_update_mcast_cb(struct ifnet *); -static void ural_update_promisc_cb(struct ifnet *); +#define URAL_RSSI(rssi) \ + ((rssi) > (RAL_NOISE_FLOOR + RAL_RSSI_CORR) ? \ + ((rssi) - (RAL_NOISE_FLOOR + RAL_RSSI_CORR)) : 0) /* various supported device vendors/products */ static const struct usb2_device_id ural_devs[] = { - {USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_WL167G, 0)}, - {USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_RALINK_RT2570, 0)}, - {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050, 0)}, - {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7051, 0)}, - {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_HU200TS, 0)}, - {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54G, 0)}, - {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GP, 0)}, - {USB_VPI(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_C54RU, 0)}, - {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWLG122, 0)}, - {USB_VPI(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GN54G, 0)}, - {USB_VPI(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWBKG, 0)}, - {USB_VPI(USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254, 0)}, - {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54, 0)}, - {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54AI, 0)}, - {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54YB, 0)}, - {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_NINWIFI, 0)}, - {USB_VPI(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570, 0)}, - {USB_VPI(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570_2, 0)}, - {USB_VPI(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570_3, 0)}, - {USB_VPI(USB_VENDOR_NOVATECH, USB_PRODUCT_NOVATECH_NV902, 0)}, - {USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570, 0)}, - {USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570_2, 0)}, - {USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570_3, 0)}, - {USB_VPI(USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_WL54G, 0)}, - {USB_VPI(USB_VENDOR_SMC, USB_PRODUCT_SMC_2862WG, 0)}, - {USB_VPI(USB_VENDOR_SPHAIRON, USB_PRODUCT_SPHAIRON_UB801R, 0)}, - {USB_VPI(USB_VENDOR_SURECOM, USB_PRODUCT_SURECOM_RT2570, 0)}, - {USB_VPI(USB_VENDOR_VTECH, USB_PRODUCT_VTECH_RT2570, 0)}, - {USB_VPI(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT2570, 0)}, + { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_WL167G) }, + { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_RALINK_RT2570) }, + { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050) }, + { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7051) }, + { USB_VP(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_HU200TS) }, + { USB_VP(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54G) }, + { USB_VP(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GP) }, + { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_C54RU) }, + { USB_VP(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWLG122) }, + { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GN54G) }, + { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWBKG) }, + { USB_VP(USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254) }, + { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54) }, + { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54AI) }, + { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54YB) }, + { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_NINWIFI) }, + { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570) }, + { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570_2) }, + { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2570_3) }, + { USB_VP(USB_VENDOR_NOVATECH, USB_PRODUCT_NOVATECH_NV902) }, + { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570) }, + { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570_2) }, + { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570_3) }, + { USB_VP(USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_WL54G) }, + { USB_VP(USB_VENDOR_SMC, USB_PRODUCT_SMC_2862WG) }, + { USB_VP(USB_VENDOR_SPHAIRON, USB_PRODUCT_SPHAIRON_UB801R) }, + { USB_VP(USB_VENDOR_SURECOM, USB_PRODUCT_SURECOM_RT2570) }, + { USB_VP(USB_VENDOR_VTECH, USB_PRODUCT_VTECH_RT2570) }, + { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT2570) }, }; +static usb2_callback_t ural_bulk_read_callback; +static usb2_callback_t ural_bulk_write_callback; + +static usb2_proc_callback_t ural_attach_post; +static usb2_proc_callback_t ural_task; +static usb2_proc_callback_t ural_scantask; +static usb2_proc_callback_t ural_promisctask; +static usb2_proc_callback_t ural_amrr_task; +static usb2_proc_callback_t ural_init_task; +static usb2_proc_callback_t ural_stop_task; + +static struct ieee80211vap *ural_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 ural_vap_delete(struct ieee80211vap *); +static void ural_tx_free(struct ural_tx_data *, int); +static void ural_setup_tx_list(struct ural_softc *); +static void ural_unsetup_tx_list(struct ural_softc *); +static int ural_newstate(struct ieee80211vap *, + enum ieee80211_state, int); +static void ural_setup_tx_desc(struct ural_softc *, + struct ural_tx_desc *, uint32_t, int, int); +static int ural_tx_bcn(struct ural_softc *, struct mbuf *, + struct ieee80211_node *); +static int ural_tx_mgt(struct ural_softc *, struct mbuf *, + struct ieee80211_node *); +static int ural_tx_data(struct ural_softc *, struct mbuf *, + struct ieee80211_node *); +static void ural_start(struct ifnet *); +static int ural_ioctl(struct ifnet *, u_long, caddr_t); +static void ural_set_testmode(struct ural_softc *); +static void ural_eeprom_read(struct ural_softc *, uint16_t, void *, + int); +static uint16_t ural_read(struct ural_softc *, uint16_t); +static void ural_read_multi(struct ural_softc *, uint16_t, void *, + int); +static void ural_write(struct ural_softc *, uint16_t, uint16_t); +static void ural_write_multi(struct ural_softc *, uint16_t, void *, + int) __unused; +static void ural_bbp_write(struct ural_softc *, uint8_t, uint8_t); +static uint8_t ural_bbp_read(struct ural_softc *, uint8_t); +static void ural_rf_write(struct ural_softc *, uint8_t, uint32_t); +static struct ieee80211_node *ural_node_alloc(struct ieee80211vap *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void ural_newassoc(struct ieee80211_node *, int); +static void ural_scan_start(struct ieee80211com *); +static void ural_scan_end(struct ieee80211com *); +static void ural_set_channel(struct ieee80211com *); +static void ural_set_chan(struct ural_softc *, + struct ieee80211_channel *); +static void ural_disable_rf_tune(struct ural_softc *); +static void ural_enable_tsf_sync(struct ural_softc *); +static void ural_update_slot(struct ifnet *); +static void ural_set_txpreamble(struct ural_softc *); +static void ural_set_basicrates(struct ural_softc *, + const struct ieee80211_channel *); +static void ural_set_bssid(struct ural_softc *, const uint8_t *); +static void ural_set_macaddr(struct ural_softc *, uint8_t *); +static const char *ural_get_rf(int); +static void ural_read_eeprom(struct ural_softc *); +static int ural_bbp_init(struct ural_softc *); +static void ural_set_txantenna(struct ural_softc *, int); +static void ural_set_rxantenna(struct ural_softc *, int); +static void ural_init(void *); +static int ural_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); +static void ural_amrr_start(struct ural_softc *, + struct ieee80211_node *); +static void ural_amrr_timeout(void *); +static void ural_queue_command(struct ural_softc *, + usb2_proc_callback_t *, struct usb2_proc_msg *, + struct usb2_proc_msg *); + /* - * Default values for MAC registers; values taken from - * the reference driver: + * Default values for MAC registers; values taken from the reference driver. */ -struct ural_def_mac { - uint16_t reg; - uint16_t val; -}; - -static const struct ural_def_mac ural_def_mac[] = { - {RAL_TXRX_CSR5, 0x8c8d}, - {RAL_TXRX_CSR6, 0x8b8a}, - {RAL_TXRX_CSR7, 0x8687}, - {RAL_TXRX_CSR8, 0x0085}, - {RAL_MAC_CSR13, 0x1111}, - {RAL_MAC_CSR14, 0x1e11}, - {RAL_TXRX_CSR21, 0xe78f}, - {RAL_MAC_CSR9, 0xff1d}, - {RAL_MAC_CSR11, 0x0002}, - {RAL_MAC_CSR22, 0x0053}, - {RAL_MAC_CSR15, 0x0000}, - {RAL_MAC_CSR8, RAL_FRAME_SIZE}, - {RAL_TXRX_CSR19, 0x0000}, - {RAL_TXRX_CSR18, 0x005a}, - {RAL_PHY_CSR2, 0x0000}, - {RAL_TXRX_CSR0, 0x1ec0}, - {RAL_PHY_CSR4, 0x000f} +static const struct { + uint16_t reg; + uint16_t val; +} ural_def_mac[] = { + { RAL_TXRX_CSR5, 0x8c8d }, + { RAL_TXRX_CSR6, 0x8b8a }, + { RAL_TXRX_CSR7, 0x8687 }, + { RAL_TXRX_CSR8, 0x0085 }, + { RAL_MAC_CSR13, 0x1111 }, + { RAL_MAC_CSR14, 0x1e11 }, + { RAL_TXRX_CSR21, 0xe78f }, + { RAL_MAC_CSR9, 0xff1d }, + { RAL_MAC_CSR11, 0x0002 }, + { RAL_MAC_CSR22, 0x0053 }, + { RAL_MAC_CSR15, 0x0000 }, + { RAL_MAC_CSR8, RAL_FRAME_SIZE }, + { RAL_TXRX_CSR19, 0x0000 }, + { RAL_TXRX_CSR18, 0x005a }, + { RAL_PHY_CSR2, 0x0000 }, + { RAL_TXRX_CSR0, 0x1ec0 }, + { RAL_PHY_CSR4, 0x000f } }; /* * Default values for BBP registers; values taken from the reference driver. */ -struct ural_def_bbp { +static const struct { uint8_t reg; uint8_t val; -}; - -static const struct ural_def_bbp ural_def_bbp[] = { - {3, 0x02}, - {4, 0x19}, - {14, 0x1c}, - {15, 0x30}, - {16, 0xac}, - {17, 0x48}, - {18, 0x18}, - {19, 0xff}, - {20, 0x1e}, - {21, 0x08}, - {22, 0x08}, - {23, 0x08}, - {24, 0x80}, - {25, 0x50}, - {26, 0x08}, - {27, 0x23}, - {30, 0x10}, - {31, 0x2b}, - {32, 0xb9}, - {34, 0x12}, - {35, 0x50}, - {39, 0xc4}, - {40, 0x02}, - {41, 0x60}, - {53, 0x10}, - {54, 0x18}, - {56, 0x08}, - {57, 0x10}, - {58, 0x08}, - {61, 0x60}, - {62, 0x10}, - {75, 0xff} +} ural_def_bbp[] = { + { 3, 0x02 }, + { 4, 0x19 }, + { 14, 0x1c }, + { 15, 0x30 }, + { 16, 0xac }, + { 17, 0x48 }, + { 18, 0x18 }, + { 19, 0xff }, + { 20, 0x1e }, + { 21, 0x08 }, + { 22, 0x08 }, + { 23, 0x08 }, + { 24, 0x80 }, + { 25, 0x50 }, + { 26, 0x08 }, + { 27, 0x23 }, + { 30, 0x10 }, + { 31, 0x2b }, + { 32, 0xb9 }, + { 34, 0x12 }, + { 35, 0x50 }, + { 39, 0xc4 }, + { 40, 0x02 }, + { 41, 0x60 }, + { 53, 0x10 }, + { 54, 0x18 }, + { 56, 0x08 }, + { 57, 0x10 }, + { 58, 0x08 }, + { 61, 0x60 }, + { 62, 0x10 }, + { 75, 0xff } }; /* @@ -316,104 +283,85 @@ static const uint32_t ural_rf2526_r2[] = { * For dual-band RF, RF registers R1 and R4 also depend on channel number; * values taken from the reference driver. */ -struct ural_rf5222 { - uint8_t chan; - uint32_t r1; - uint32_t r2; - uint32_t r4; -}; +static const struct { + uint8_t chan; + uint32_t r1; + uint32_t r2; + uint32_t r4; +} ural_rf5222[] = { + { 1, 0x08808, 0x0044d, 0x00282 }, + { 2, 0x08808, 0x0044e, 0x00282 }, + { 3, 0x08808, 0x0044f, 0x00282 }, + { 4, 0x08808, 0x00460, 0x00282 }, + { 5, 0x08808, 0x00461, 0x00282 }, + { 6, 0x08808, 0x00462, 0x00282 }, + { 7, 0x08808, 0x00463, 0x00282 }, + { 8, 0x08808, 0x00464, 0x00282 }, + { 9, 0x08808, 0x00465, 0x00282 }, + { 10, 0x08808, 0x00466, 0x00282 }, + { 11, 0x08808, 0x00467, 0x00282 }, + { 12, 0x08808, 0x00468, 0x00282 }, + { 13, 0x08808, 0x00469, 0x00282 }, + { 14, 0x08808, 0x0046b, 0x00286 }, -static const struct ural_rf5222 ural_rf5222[] = { - {1, 0x08808, 0x0044d, 0x00282}, - {2, 0x08808, 0x0044e, 0x00282}, - {3, 0x08808, 0x0044f, 0x00282}, - {4, 0x08808, 0x00460, 0x00282}, - {5, 0x08808, 0x00461, 0x00282}, - {6, 0x08808, 0x00462, 0x00282}, - {7, 0x08808, 0x00463, 0x00282}, - {8, 0x08808, 0x00464, 0x00282}, - {9, 0x08808, 0x00465, 0x00282}, - {10, 0x08808, 0x00466, 0x00282}, - {11, 0x08808, 0x00467, 0x00282}, - {12, 0x08808, 0x00468, 0x00282}, - {13, 0x08808, 0x00469, 0x00282}, - {14, 0x08808, 0x0046b, 0x00286}, + { 36, 0x08804, 0x06225, 0x00287 }, + { 40, 0x08804, 0x06226, 0x00287 }, + { 44, 0x08804, 0x06227, 0x00287 }, + { 48, 0x08804, 0x06228, 0x00287 }, + { 52, 0x08804, 0x06229, 0x00287 }, + { 56, 0x08804, 0x0622a, 0x00287 }, + { 60, 0x08804, 0x0622b, 0x00287 }, + { 64, 0x08804, 0x0622c, 0x00287 }, - {36, 0x08804, 0x06225, 0x00287}, - {40, 0x08804, 0x06226, 0x00287}, - {44, 0x08804, 0x06227, 0x00287}, - {48, 0x08804, 0x06228, 0x00287}, - {52, 0x08804, 0x06229, 0x00287}, - {56, 0x08804, 0x0622a, 0x00287}, - {60, 0x08804, 0x0622b, 0x00287}, - {64, 0x08804, 0x0622c, 0x00287}, + { 100, 0x08804, 0x02200, 0x00283 }, + { 104, 0x08804, 0x02201, 0x00283 }, + { 108, 0x08804, 0x02202, 0x00283 }, + { 112, 0x08804, 0x02203, 0x00283 }, + { 116, 0x08804, 0x02204, 0x00283 }, + { 120, 0x08804, 0x02205, 0x00283 }, + { 124, 0x08804, 0x02206, 0x00283 }, + { 128, 0x08804, 0x02207, 0x00283 }, + { 132, 0x08804, 0x02208, 0x00283 }, + { 136, 0x08804, 0x02209, 0x00283 }, + { 140, 0x08804, 0x0220a, 0x00283 }, - {100, 0x08804, 0x02200, 0x00283}, - {104, 0x08804, 0x02201, 0x00283}, - {108, 0x08804, 0x02202, 0x00283}, - {112, 0x08804, 0x02203, 0x00283}, - {116, 0x08804, 0x02204, 0x00283}, - {120, 0x08804, 0x02205, 0x00283}, - {124, 0x08804, 0x02206, 0x00283}, - {128, 0x08804, 0x02207, 0x00283}, - {132, 0x08804, 0x02208, 0x00283}, - {136, 0x08804, 0x02209, 0x00283}, - {140, 0x08804, 0x0220a, 0x00283}, - - {149, 0x08808, 0x02429, 0x00281}, - {153, 0x08808, 0x0242b, 0x00281}, - {157, 0x08808, 0x0242d, 0x00281}, - {161, 0x08808, 0x0242f, 0x00281} + { 149, 0x08808, 0x02429, 0x00281 }, + { 153, 0x08808, 0x0242b, 0x00281 }, + { 157, 0x08808, 0x0242d, 0x00281 }, + { 161, 0x08808, 0x0242f, 0x00281 } }; static const struct usb2_config ural_config[URAL_N_TRANSFER] = { - [URAL_BULK_DT_WR] = { + [URAL_BULK_WR] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .mh.bufsize = (RAL_FRAME_SIZE + RAL_TX_DESC_SIZE + 4), .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, - .mh.callback = &ural_bulk_write_callback, + .mh.callback = ural_bulk_write_callback, .mh.timeout = 5000, /* ms */ }, - - [URAL_BULK_DT_RD] = { + [URAL_BULK_RD] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .mh.bufsize = (RAL_FRAME_SIZE + RAL_RX_DESC_SIZE), .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, - .mh.callback = &ural_bulk_read_callback, - }, - - [URAL_BULK_CS_WR] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.callback = &ural_bulk_write_clear_stall_callback, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ - }, - - [URAL_BULK_CS_RD] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .mh.bufsize = sizeof(struct usb2_device_request), - .mh.callback = &ural_bulk_read_clear_stall_callback, - .mh.timeout = 1000, /* 1 second */ - .mh.interval = 50, /* 50ms */ + .mh.callback = ural_bulk_read_callback, }, }; -static devclass_t ural_devclass; +static device_probe_t ural_match; +static device_attach_t ural_attach; +static device_detach_t ural_detach; static device_method_t ural_methods[] = { - DEVMETHOD(device_probe, ural_probe), - DEVMETHOD(device_attach, ural_attach), - DEVMETHOD(device_detach, ural_detach), - {0, 0} + /* Device interface */ + DEVMETHOD(device_probe, ural_match), + DEVMETHOD(device_attach, ural_attach), + DEVMETHOD(device_detach, ural_detach), + + { 0, 0 } }; static driver_t ural_driver = { @@ -422,6 +370,8 @@ static driver_t ural_driver = { .size = sizeof(struct ural_softc), }; +static devclass_t ural_devclass; + DRIVER_MODULE(ural, ushub, ural_driver, ural_devclass, NULL, 0); MODULE_DEPEND(ural, usb2_wlan, 1, 1, 1); MODULE_DEPEND(ural, usb2_core, 1, 1, 1); @@ -429,397 +379,108 @@ MODULE_DEPEND(ural, wlan, 1, 1, 1); MODULE_DEPEND(ural, wlan_amrr, 1, 1, 1); static int -ural_probe(device_t dev) +ural_match(device_t self) { - struct usb2_attach_arg *uaa = device_get_ivars(dev); + struct usb2_attach_arg *uaa = device_get_ivars(self); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb2_mode != USB_MODE_HOST) return (ENXIO); - } - if (uaa->info.bConfigIndex != 0) { + if (uaa->info.bConfigIndex != 0) return (ENXIO); - } - if (uaa->info.bIfaceIndex != RAL_IFACE_INDEX) { + if (uaa->info.bIfaceIndex != RAL_IFACE_INDEX) return (ENXIO); - } + return (usb2_lookup_id_by_uaa(ural_devs, sizeof(ural_devs), uaa)); } static int -ural_attach(device_t dev) +ural_attach(device_t self) { - struct usb2_attach_arg *uaa = device_get_ivars(dev); - struct ural_softc *sc = device_get_softc(dev); + struct usb2_attach_arg *uaa = device_get_ivars(self); + struct ural_softc *sc = device_get_softc(self); int error; uint8_t iface_index; - device_set_usb2_desc(dev); - - mtx_init(&sc->sc_mtx, "ural lock", MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); - - snprintf(sc->sc_name, sizeof(sc->sc_name), "%s", - device_get_nameunit(dev)); - + device_set_usb2_desc(self); sc->sc_udev = uaa->device; - sc->sc_unit = device_get_unit(dev); + sc->sc_dev = self; - usb2_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); + mtx_init(&sc->sc_mtx, device_get_nameunit(self), + MTX_NETWORK_LOCK, MTX_DEF); iface_index = RAL_IFACE_INDEX; error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, ural_config, URAL_N_TRANSFER, sc, &sc->sc_mtx); - if (error) { - device_printf(dev, "could not allocate USB transfers, " + device_printf(self, "could not allocate USB transfers, " "err=%s\n", usb2_errstr(error)); goto detach; } - error = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_mtx, - &ural_end_of_commands, - sizeof(struct usb2_config_td_cc), 24); + error = usb2_proc_create(&sc->sc_tq, &sc->sc_mtx, + device_get_nameunit(self), USB_PRI_MED); if (error) { - device_printf(dev, "could not setup config " - "thread!\n"); + device_printf(self, "could not setup config thread!\n"); goto detach; } - mtx_lock(&sc->sc_mtx); - /* start setup */ - - usb2_config_td_queue_command - (&sc->sc_config_td, NULL, &ural_cfg_first_time_setup, 0, 0); - - ural_watchdog(sc); - mtx_unlock(&sc->sc_mtx); - return (0); /* success */ + /* fork rest of the attach code */ + RAL_LOCK(sc); + ural_queue_command(sc, ural_attach_post, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + RAL_UNLOCK(sc); + return (0); detach: - ural_detach(dev); + ural_detach(self); return (ENXIO); /* failure */ } -static int -ural_detach(device_t dev) +static void +ural_attach_post(struct usb2_proc_msg *pm) { - struct ural_softc *sc = device_get_softc(dev); - struct ieee80211com *ic; + struct ural_task *task = (struct ural_task *)pm; + struct ural_softc *sc = task->sc; struct ifnet *ifp; - - usb2_config_td_drain(&sc->sc_config_td); - - mtx_lock(&sc->sc_mtx); - - usb2_callout_stop(&sc->sc_watchdog); - - ural_cfg_pre_stop(sc, NULL, 0); - - ifp = sc->sc_ifp; - ic = ifp->if_l2com; - - mtx_unlock(&sc->sc_mtx); - - /* stop all USB transfers first */ - usb2_transfer_unsetup(sc->sc_xfer, URAL_N_TRANSFER); - - /* get rid of any late children */ - bus_generic_detach(dev); - - if (ifp) { - bpfdetach(ifp); - ieee80211_ifdetach(ic); - if_free(ifp); - } - usb2_config_td_unsetup(&sc->sc_config_td); - - usb2_callout_drain(&sc->sc_watchdog); - - mtx_destroy(&sc->sc_mtx); - - return (0); -} - -/*========================================================================* - * REGISTER READ / WRITE WRAPPER ROUTINES - *========================================================================*/ - -static void -ural_cfg_do_request(struct ural_softc *sc, struct usb2_device_request *req, - void *data) -{ - uint16_t length; - usb2_error_t err; - -repeat: - - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - goto error; - } - err = usb2_do_request_flags - (sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 1000); - - if (err) { - - DPRINTF("device request failed, err=%s " - "(ignored)\n", usb2_errstr(err)); - - /* wait a little before next try */ - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 4)) { - goto error; - } - /* try until we are detached */ - goto repeat; - -error: - /* the device has been detached */ - length = UGETW(req->wLength); - - if ((req->bmRequestType & UT_READ) && length) { - bzero(data, length); - } - } -} - -static void -ural_cfg_set_testmode(struct ural_softc *sc) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_WRITE_VENDOR_DEVICE; - req.bRequest = RAL_VENDOR_REQUEST; - USETW(req.wValue, 4); - USETW(req.wIndex, 1); - USETW(req.wLength, 0); - - ural_cfg_do_request(sc, &req, NULL); -} - -static void -ural_cfg_eeprom_read(struct ural_softc *sc, uint16_t addr, - void *buf, uint16_t len) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = RAL_READ_EEPROM; - USETW(req.wValue, 0); - USETW(req.wIndex, addr); - USETW(req.wLength, len); - - ural_cfg_do_request(sc, &req, buf); -} - -static uint16_t -ural_cfg_read(struct ural_softc *sc, uint16_t reg) -{ - struct usb2_device_request req; - uint16_t val; - - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = RAL_READ_MAC; - USETW(req.wValue, 0); - USETW(req.wIndex, reg); - USETW(req.wLength, sizeof(val)); - - ural_cfg_do_request(sc, &req, &val); - - return (le16toh(val)); -} - -static void -ural_cfg_read_multi(struct ural_softc *sc, uint16_t reg, - void *buf, uint16_t len) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = RAL_READ_MULTI_MAC; - USETW(req.wValue, 0); - USETW(req.wIndex, reg); - USETW(req.wLength, len); - - ural_cfg_do_request(sc, &req, buf); -} - -static void -ural_cfg_write(struct ural_softc *sc, uint16_t reg, uint16_t val) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_WRITE_VENDOR_DEVICE; - req.bRequest = RAL_WRITE_MAC; - USETW(req.wValue, val); - USETW(req.wIndex, reg); - USETW(req.wLength, 0); - - ural_cfg_do_request(sc, &req, NULL); -} - -static void -ural_cfg_write_multi(struct ural_softc *sc, uint16_t reg, - void *buf, uint16_t len) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_WRITE_VENDOR_DEVICE; - req.bRequest = RAL_WRITE_MULTI_MAC; - USETW(req.wValue, 0); - USETW(req.wIndex, reg); - USETW(req.wLength, len); - - ural_cfg_do_request(sc, &req, buf); -} - -static uint8_t -ural_cfg_bbp_disbusy(struct ural_softc *sc) -{ - uint16_t tmp; - uint8_t to; - - for (to = 0;; to++) { - if (to < 100) { - tmp = ural_cfg_read(sc, RAL_PHY_CSR8); - tmp &= RAL_BBP_BUSY; - - if (tmp == 0) { - return (0); - } - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - break; - } - } else { - break; - } - } - DPRINTF("could not disbusy BBP\n"); - return (1); /* failure */ -} - -static void -ural_cfg_bbp_write(struct ural_softc *sc, uint8_t reg, uint8_t val) -{ - uint16_t tmp; - - if (ural_cfg_bbp_disbusy(sc)) { - return; - } - tmp = (reg << 8) | val; - ural_cfg_write(sc, RAL_PHY_CSR7, tmp); -} - -static uint8_t -ural_cfg_bbp_read(struct ural_softc *sc, uint8_t reg) -{ - uint16_t val; - - if (ural_cfg_bbp_disbusy(sc)) { - return (0); - } - val = RAL_BBP_WRITE | (reg << 8); - ural_cfg_write(sc, RAL_PHY_CSR7, val); - - if (ural_cfg_bbp_disbusy(sc)) { - return (0); - } - return (ural_cfg_read(sc, RAL_PHY_CSR7) & 0xff); -} - -static void -ural_cfg_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val) -{ - uint32_t tmp; - uint8_t to; - - reg &= 3; - - /* remember last written value */ - sc->sc_rf_regs[reg] = val; - - for (to = 0;; to++) { - if (to < 100) { - tmp = ural_cfg_read(sc, RAL_PHY_CSR10); - - if (!(tmp & RAL_RF_LOBUSY)) { - break; - } - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - return; - } - } else { - DPRINTF("could not write to RF\n"); - return; - } - } - - tmp = RAL_RF_BUSY | RAL_RF_20BIT | ((val & 0xfffff) << 2) | reg; - ural_cfg_write(sc, RAL_PHY_CSR9, tmp & 0xffff); - ural_cfg_write(sc, RAL_PHY_CSR10, tmp >> 16); - - DPRINTFN(16, "RF R[%u] <- 0x%05x\n", reg, val & 0xfffff); -} - -static void -ural_cfg_first_time_setup(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ struct ieee80211com *ic; - struct ifnet *ifp; uint8_t bands; - /* 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(RAL_RX_RADIOTAP_PRESENT); - - /* 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(RAL_TX_RADIOTAP_PRESENT); - /* retrieve RT2570 rev. no */ - sc->sc_asic_rev = ural_cfg_read(sc, RAL_MAC_CSR0); + sc->asic_rev = ural_read(sc, RAL_MAC_CSR0); /* retrieve MAC address and various other things from EEPROM */ - ural_cfg_read_eeprom(sc); + ural_read_eeprom(sc); + RAL_UNLOCK(sc); - printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s (0x%02x)\n", - sc->sc_name, sc->sc_asic_rev, ural_get_rf(sc->sc_rf_rev), - sc->sc_rf_rev); - - mtx_unlock(&sc->sc_mtx); - - ifp = if_alloc(IFT_IEEE80211); - - mtx_lock(&sc->sc_mtx); + device_printf(sc->sc_dev, "MAC/BBP RT2570 (rev 0x%02x), RF %s\n", + sc->asic_rev, ural_get_rf(sc->rf_rev)); + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { - DPRINTFN(0, "could not if_alloc()!\n"); - goto done; + device_printf(sc->sc_dev, "can not if_alloc()\n"); + RAL_LOCK(sc); + return; } - sc->sc_ifp = ifp; ic = ifp->if_l2com; ifp->if_softc = sc; - if_initname(ifp, "ural", sc->sc_unit); + if_initname(ifp, "ural", device_get_unit(sc->sc_dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_init = &ural_init_cb; - ifp->if_ioctl = &ural_ioctl_cb; - ifp->if_start = &ural_start_cb; - ifp->if_watchdog = NULL; + ifp->if_init = ural_init; + ifp->if_ioctl = ural_ioctl; + ifp->if_start = ural_start; 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; /* not only, but not used */ - ic->ic_opmode = IEEE80211_M_STA; + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_bssid); /* set device capabilities */ ic->ic_caps = - IEEE80211_C_STA /* station mode supported */ + IEEE80211_C_STA /* station mode supported */ | IEEE80211_C_IBSS /* IBSS mode supported */ | IEEE80211_C_MONITOR /* monitor mode supported */ | IEEE80211_C_HOSTAP /* HostAp mode supported */ @@ -833,152 +494,415 @@ ural_cfg_first_time_setup(struct ural_softc *sc, bands = 0; setbit(&bands, IEEE80211_MODE_11B); setbit(&bands, IEEE80211_MODE_11G); - - if (sc->sc_rf_rev == RAL_RF_5222) { + if (sc->rf_rev == RAL_RF_5222) setbit(&bands, IEEE80211_MODE_11A); - } ieee80211_init_channels(ic, NULL, &bands); - mtx_unlock(&sc->sc_mtx); - ieee80211_ifattach(ic); + ic->ic_newassoc = ural_newassoc; + ic->ic_raw_xmit = ural_raw_xmit; + ic->ic_node_alloc = ural_node_alloc; + ic->ic_scan_start = ural_scan_start; + ic->ic_scan_end = ural_scan_end; + ic->ic_set_channel = ural_set_channel; - mtx_lock(&sc->sc_mtx); - - ic->ic_newassoc = &ural_newassoc; - ic->ic_raw_xmit = &ural_raw_xmit_cb; - ic->ic_node_alloc = &ural_node_alloc; - ic->ic_update_mcast = &ural_update_mcast_cb; - ic->ic_update_promisc = &ural_update_promisc_cb; - ic->ic_scan_start = &ural_scan_start_cb; - ic->ic_scan_end = &ural_scan_end_cb; - ic->ic_set_channel = &ural_set_channel_cb; - ic->ic_vap_create = &ural_vap_create; - ic->ic_vap_delete = &ural_vap_delete; + ic->ic_vap_create = ural_vap_create; + ic->ic_vap_delete = ural_vap_delete; sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); - mtx_unlock(&sc->sc_mtx); - bpfattach(ifp, DLT_IEEE802_11_RADIO, - sizeof(struct ieee80211_frame) + sizeof(sc->sc_txtap)); + sizeof (struct ieee80211_frame) + sizeof(sc->sc_txtap)); - if (bootverbose) { + 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(RAL_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(RAL_TX_RADIOTAP_PRESENT); + + if (bootverbose) ieee80211_announce(ic); - } - mtx_lock(&sc->sc_mtx); -done: - return; + + RAL_LOCK(sc); } -static void -ural_end_of_commands(struct ural_softc *sc) +static int +ural_detach(device_t self) { - sc->sc_flags &= ~URAL_FLAG_WAIT_COMMAND; + struct ural_softc *sc = device_get_softc(self); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - /* start write transfer, if not started */ - usb2_transfer_start(sc->sc_xfer[URAL_BULK_DT_WR]); -} + /* wait for any post attach or other command to complete */ + usb2_proc_drain(&sc->sc_tq); -static void -ural_config_copy_chan(struct ural_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); - 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; - } -} + /* stop all USB transfers */ + usb2_transfer_unsetup(sc->sc_xfer, URAL_N_TRANSFER); + usb2_proc_free(&sc->sc_tq); -static void -ural_config_copy(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp; - struct ieee80211com *ic; - struct ieee80211_node *ni; - struct ieee80211vap *vap; - const struct ieee80211_txparam *tp; + /* free TX list, if any */ + RAL_LOCK(sc); + ural_unsetup_tx_list(sc); + RAL_UNLOCK(sc); - bzero(cc, sizeof(*cc)); - - ifp = sc->sc_ifp; if (ifp) { - cc->if_flags = ifp->if_flags; - bcopy(ifp->if_broadcastaddr, cc->if_broadcastaddr, - sizeof(cc->if_broadcastaddr)); + bpfdetach(ifp); + ieee80211_ifdetach(ic); + if_free(ifp); + } - ic = ifp->if_l2com; - if (ic) { - ural_config_copy_chan(&cc->ic_curchan, ic, ic->ic_curchan); - ural_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; + mtx_destroy(&sc->sc_mtx); - bcopy(ic->ic_myaddr, cc->ic_myaddr, - sizeof(cc->ic_myaddr)); + return (0); +} + +static struct ieee80211vap * +ural_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 ural_softc *sc = ic->ic_ifp->if_softc; + struct ural_vap *uvp; + struct ieee80211vap *vap; + + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + return NULL; + uvp = (struct ural_vap *) malloc(sizeof(struct ural_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (uvp == NULL) + return NULL; + vap = &uvp->vap; + /* enable s/w bmiss handling for sta mode */ + ieee80211_vap_setup(ic, vap, name, unit, opmode, + flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); + + /* override state transition machine */ + uvp->newstate = vap->iv_newstate; + vap->iv_newstate = ural_newstate; + + uvp->sc = sc; + usb2_callout_init_mtx(&uvp->amrr_ch, &sc->sc_mtx, 0); + ieee80211_amrr_init(&uvp->amrr, vap, + IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, + IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, + 1000 /* 1 sec */); + + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); + ic->ic_opmode = opmode; + return vap; +} + +static void +ural_vap_delete(struct ieee80211vap *vap) +{ + struct ural_vap *uvp = URAL_VAP(vap); + + usb2_callout_drain(&uvp->amrr_ch); + ieee80211_amrr_cleanup(&uvp->amrr); + ieee80211_vap_detach(vap); + free(uvp, M_80211_VAP); +} + +static void +ural_tx_free(struct ural_tx_data *data, int txerr) +{ + struct ural_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; + + ieee80211_free_node(data->ni); + data->ni = NULL; + } + STAILQ_INSERT_TAIL(&sc->tx_free, data, next); + sc->tx_nfree++; +} + +static void +ural_setup_tx_list(struct ural_softc *sc) +{ + struct ural_tx_data *data; + int i; + + sc->tx_nfree = 0; + STAILQ_INIT(&sc->tx_q); + STAILQ_INIT(&sc->tx_free); + + for (i = 0; i < RAL_TX_LIST_COUNT; i++) { + data = &sc->tx_data[i]; + + data->sc = sc; + STAILQ_INSERT_TAIL(&sc->tx_free, data, next); + sc->tx_nfree++; + } +} + +static void +ural_unsetup_tx_list(struct ural_softc *sc) +{ + struct ural_tx_data *data; + int i; + + /* make sure any subsequent use of the queues will fail */ + sc->tx_nfree = 0; + STAILQ_INIT(&sc->tx_q); + STAILQ_INIT(&sc->tx_free); + + /* free up all node references and mbufs */ + for (i = 0; i < RAL_TX_LIST_COUNT; i++) { + data = &sc->tx_data[i]; + + if (data->m != NULL) { + m_freem(data->m); + data->m = NULL; + } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; } } - sc->sc_flags |= URAL_FLAG_WAIT_COMMAND; } -static const char * -ural_get_rf(int rev) +static void +ural_task(struct usb2_proc_msg *pm) { - ; /* style fix */ + struct ural_task *task = (struct ural_task *)pm; + struct ural_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ural_vap *uvp = URAL_VAP(vap); + const struct ieee80211_txparam *tp; + enum ieee80211_state ostate; + struct ieee80211_node *ni; + struct mbuf *m; + + ostate = vap->iv_state; + + switch (sc->sc_state) { + case IEEE80211_S_INIT: + if (ostate == IEEE80211_S_RUN) { + /* abort TSF synchronization */ + ural_write(sc, RAL_TXRX_CSR19, 0); + + /* force tx led to stop blinking */ + ural_write(sc, RAL_MAC_CSR20, 0); + } + break; + + case IEEE80211_S_RUN: + ni = vap->iv_bss; + + if (vap->iv_opmode != IEEE80211_M_MONITOR) { + ural_update_slot(ic->ic_ifp); + ural_set_txpreamble(sc); + ural_set_basicrates(sc, ic->ic_bsschan); + IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); + ural_set_bssid(sc, sc->sc_bssid); + } + + if (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS) { + m = ieee80211_beacon_alloc(ni, &uvp->bo); + if (m == NULL) { + device_printf(sc->sc_dev, + "could not allocate beacon\n"); + return; + } + + if (ural_tx_bcn(sc, m, ni) != 0) { + device_printf(sc->sc_dev, + "could not send beacon\n"); + return; + } + } + + /* make tx led blink on tx (controlled by ASIC) */ + ural_write(sc, RAL_MAC_CSR20, 1); + + if (vap->iv_opmode != IEEE80211_M_MONITOR) + ural_enable_tsf_sync(sc); + + /* enable automatic rate adaptation */ + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; + if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) + ural_amrr_start(sc, ni); + + break; - switch (rev) { - case RAL_RF_2522: - return "RT2522"; - case RAL_RF_2523: - return "RT2523"; - case RAL_RF_2524: - return "RT2524"; - case RAL_RF_2525: - return "RT2525"; - case RAL_RF_2525E: - return "RT2525e"; - case RAL_RF_2526: - return "RT2526"; - case RAL_RF_5222: - return "RT5222"; default: - return "unknown"; + break; + } + + RAL_UNLOCK(sc); + IEEE80211_LOCK(ic); + uvp->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); + RAL_LOCK(sc); +} + +static void +ural_scantask(struct usb2_proc_msg *pm) +{ + struct ural_task *task = (struct ural_task *)pm; + struct ural_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + RAL_LOCK_ASSERT(sc, MA_OWNED); + + switch (sc->sc_scan_action) { + case URAL_SCAN_START: + /* abort TSF synchronization */ + DPRINTF("starting scan\n"); + ural_write(sc, RAL_TXRX_CSR19, 0); + ural_set_bssid(sc, ifp->if_broadcastaddr); + break; + + case URAL_SET_CHANNEL: + ural_set_chan(sc, ic->ic_curchan); + break; + + default: /* URAL_SCAN_END */ + DPRINTF("stopping scan\n"); + ural_enable_tsf_sync(sc); + ural_set_bssid(sc, sc->sc_bssid); + break; + } +} + +static int +ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + struct ural_vap *uvp = URAL_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct ural_softc *sc = ic->ic_ifp->if_softc; + + DPRINTF("%s -> %s\n", + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[nstate]); + + RAL_LOCK(sc); + usb2_callout_stop(&uvp->amrr_ch); + + /* do it in a process context */ + sc->sc_state = nstate; + sc->sc_arg = arg; + RAL_UNLOCK(sc); + + if (nstate == IEEE80211_S_INIT) { + uvp->newstate(vap, nstate, arg); + return 0; + } else { + RAL_LOCK(sc); + ural_queue_command(sc, ural_task, &sc->sc_task[0].hdr, + &sc->sc_task[1].hdr); + RAL_UNLOCK(sc); + return EINPROGRESS; + } +} + + +static void +ural_bulk_write_callback(struct usb2_xfer *xfer) +{ + struct ural_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 ural_tx_data *data; + struct mbuf *m; + unsigned int len; + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + DPRINTFN(11, "transfer complete, %d bytes\n", xfer->actlen); + + /* free resources */ + data = xfer->priv_fifo; + ural_tx_free(data, 0); + xfer->priv_fifo = NULL; + + ifp->if_opackets++; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + /* 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; + + if (m->m_pkthdr.len > (RAL_FRAME_SIZE + RAL_TX_DESC_SIZE)) { + DPRINTFN(0, "data overflow, %u bytes\n", + m->m_pkthdr.len); + m->m_pkthdr.len = (RAL_FRAME_SIZE + RAL_TX_DESC_SIZE); + } + usb2_copy_in(xfer->frbuffers, 0, &data->desc, + RAL_TX_DESC_SIZE); + usb2_m_copy_in(xfer->frbuffers, RAL_TX_DESC_SIZE, m, 0, + m->m_pkthdr.len); + + if (bpf_peers_present(ifp->if_bpf)) { + struct ural_tx_radiotap_header *tap = &sc->sc_txtap; + + 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); + tap->wt_antenna = sc->tx_ant; + + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + } + + /* xfer length needs to be a multiple of two! */ + len = (RAL_TX_DESC_SIZE + m->m_pkthdr.len + 1) & ~1; + if ((len % 64) == 0) + len += 2; + + DPRINTFN(11, "sending frame len=%u xferlen=%u\n", + m->m_pkthdr.len, len); + + xfer->frlengths[0] = len; + xfer->priv_fifo = data; + + usb2_start_hardware(xfer); + } + break; + + default: /* Error */ + DPRINTFN(11, "transfer error, %s\n", + usb2_errstr(xfer->error)); + + ifp->if_oerrors++; + data = xfer->priv_fifo; + if (data != NULL) { + ural_tx_free(data, xfer->error); + xfer->priv_fifo = NULL; + } + + 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; } } -/*------------------------------------------------------------------------* - * ural_bulk_read_callback - data read "thread" - *------------------------------------------------------------------------*/ static void ural_bulk_read_callback(struct usb2_xfer *xfer) { @@ -988,80 +912,62 @@ ural_bulk_read_callback(struct usb2_xfer *xfer) struct ieee80211_node *ni; struct mbuf *m = NULL; uint32_t flags; - uint32_t max_len; - uint32_t real_len; uint8_t rssi = 0; + unsigned int len; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(15, "rx done, actlen=%d\n", xfer->actlen); - if (xfer->actlen < RAL_RX_DESC_SIZE) { - DPRINTF("too short transfer, " - "%d bytes\n", xfer->actlen); + len = xfer->actlen; + if (len < RAL_RX_DESC_SIZE + IEEE80211_MIN_LEN) { + DPRINTF("%s: xfer too short %d\n", + device_get_nameunit(sc->sc_dev), len); ifp->if_ierrors++; goto tr_setup; } - max_len = (xfer->actlen - RAL_RX_DESC_SIZE); - usb2_copy_out(xfer->frbuffers, max_len, - &sc->sc_rx_desc, RAL_RX_DESC_SIZE); + len -= RAL_RX_DESC_SIZE; + /* rx descriptor is located at the end */ + usb2_copy_out(xfer->frbuffers, len, &sc->sc_rx_desc, + RAL_RX_DESC_SIZE); + rssi = URAL_RSSI(sc->sc_rx_desc.rssi); flags = le32toh(sc->sc_rx_desc.flags); - if (flags & (RAL_RX_PHY_ERROR | RAL_RX_CRC_ERROR)) { /* * This should not happen since we did not * request to receive those frames when we * filled RAL_TXRX_CSR2: */ - DPRINTFN(6, "PHY or CRC error\n"); + DPRINTFN(5, "PHY or CRC error\n"); ifp->if_ierrors++; goto tr_setup; } - if (max_len > MCLBYTES) { - max_len = MCLBYTES; - } - real_len = (flags >> 16) & 0xfff; - - if (real_len > max_len) { - DPRINTF("invalid length in RX " - "descriptor, %u bytes, received %u bytes\n", - real_len, max_len); - ifp->if_ierrors++; - goto tr_setup; - } - /* ieee80211_input() will check if the mbuf is too short */ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - if (m == NULL) { DPRINTF("could not allocate mbuf\n"); ifp->if_ierrors++; goto tr_setup; } - usb2_copy_out(xfer->frbuffers, 0, m->m_data, max_len); + usb2_copy_out(xfer->frbuffers, 0, mtod(m, uint8_t *), len); /* finalize mbuf */ m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = real_len; - - DPRINTF("real length=%d bytes\n", real_len); - - rssi = URAL_RSSI(sc->sc_rx_desc.rssi); + m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; if (bpf_peers_present(ifp->if_bpf)) { struct ural_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = IEEE80211_RADIOTAP_F_FCS; tap->wr_rate = ieee80211_plcp2rate(sc->sc_rx_desc.rate, - (sc->sc_rx_desc.flags & htole32(RAL_RX_OFDM)) ? + (flags & RAL_RX_OFDM) ? IEEE80211_T_OFDM : IEEE80211_T_CCK); - tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); - tap->wr_antenna = sc->sc_rx_ant; + tap->wr_antenna = sc->rx_ant; tap->wr_antsignal = rssi; bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); @@ -1069,15 +975,11 @@ ural_bulk_read_callback(struct usb2_xfer *xfer) /* Strip trailing 802.11 MAC FCS. */ m_adj(m, -IEEE80211_CRC_LEN); + /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: - - if (sc->sc_flags & URAL_FLAG_READ_STALL) { - usb2_transfer_start(sc->sc_xfer[URAL_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); /* * At the end of a USB callback it is always safe to unlock @@ -1085,1304 +987,653 @@ tr_setup: * "ieee80211_input" here, and not some lines up! */ if (m) { - mtx_unlock(&sc->sc_mtx); - - ni = ieee80211_find_rxnode(ic, (void *)(m->m_data)); - - if (ni) { - /* send the frame to the 802.11 layer */ - if (ieee80211_input(ni, m, rssi, RAL_NOISE_FLOOR, 0)) { - /* ignore */ - } - /* node is no longer needed */ + RAL_UNLOCK(sc); + ni = ieee80211_find_rxnode(ic, + mtod(m, struct ieee80211_frame_min *)); + if (ni != NULL) { + (void) ieee80211_input(ni, m, rssi, + RAL_NOISE_FLOOR, 0); ieee80211_free_node(ni); - } else { - /* broadcast */ - if (ieee80211_input_all(ic, m, rssi, RAL_NOISE_FLOOR, 0)) { - /* ignore */ - } - } - - mtx_lock(&sc->sc_mtx); + } else + (void) ieee80211_input_all(ic, m, rssi, + RAL_NOISE_FLOOR, 0); + RAL_LOCK(sc); } return; default: /* Error */ if (xfer->error != USB_ERR_CANCELLED) { /* try to clear stall first */ - sc->sc_flags |= URAL_FLAG_READ_STALL; - usb2_transfer_start(sc->sc_xfer[URAL_BULK_CS_RD]); + xfer->flags.stall_pipe = 1; + goto tr_setup; } return; - - } -} - -static void -ural_bulk_read_clear_stall_callback(struct usb2_xfer *xfer) -{ - struct ural_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[URAL_BULK_DT_RD]; - - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~URAL_FLAG_READ_STALL; - usb2_transfer_start(xfer_other); } } static uint8_t -ural_plcp_signal(uint16_t rate) +ural_plcp_signal(int rate) { - ; /* indent fix */ 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) */ + case 12: return 0xb; + case 18: return 0xf; + case 24: return 0xa; + case 36: return 0xe; + case 48: return 0x9; + case 72: return 0xd; + case 96: return 0x8; + case 108: return 0xc; - /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ - case 12: - return (0xb); - case 18: - return (0xf); - case 24: - return (0xa); - case 36: - return (0xe); - case 48: - return (0x9); - case 72: - return (0xd); - case 96: - 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 */ } -/* - * We assume that "m->m_pkthdr.rcvif" is pointing to the "ni" that - * should be freed, when "ural_setup_desc_and_tx" is called. - */ static void -ural_setup_desc_and_tx(struct ural_softc *sc, struct mbuf *m, - uint32_t flags, uint16_t rate) +ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc, + uint32_t flags, int len, int rate) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct mbuf *mm; - enum ieee80211_phytype phytype; uint16_t plcp_length; - uint16_t len; - uint8_t remainder; + int remainder; - DPRINTF("in\n"); + desc->flags = htole32(flags); + desc->flags |= htole32(RAL_TX_NEWSEQ); + desc->flags |= htole32(len << 16); - if (sc->sc_tx_queue.ifq_len >= IFQ_MAXLEN) { - /* free packet */ - ural_tx_freem(m); - ifp->if_oerrors++; - return; - } - if (!((sc->sc_flags & URAL_FLAG_LL_READY) && - (sc->sc_flags & URAL_FLAG_HL_READY))) { - /* free packet */ - ural_tx_freem(m); - ifp->if_oerrors++; - return; - } - if (rate < 2) { - DPRINTF("rate < 2!\n"); - - /* avoid division by zero */ - rate = 2; - } - ic->ic_lastdata = ticks; - - if (bpf_peers_present(ifp->if_bpf)) { - struct ural_tx_radiotap_header *tap = &sc->sc_txtap; - - 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); - tap->wt_antenna = sc->sc_tx_ant; - - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); - } - len = m->m_pkthdr.len; - - sc->sc_tx_desc.flags = htole32(flags); - sc->sc_tx_desc.flags |= htole32(RAL_TX_NEWSEQ); - sc->sc_tx_desc.flags |= htole32(len << 16); - - sc->sc_tx_desc.wme = htole16(RAL_AIFSN(2) | - RAL_LOGCWMIN(3) | - RAL_LOGCWMAX(5) | - RAL_IVOFFSET(sizeof(struct ieee80211_frame))); + desc->wme = htole16(RAL_AIFSN(2) | RAL_LOGCWMIN(3) | RAL_LOGCWMAX(5)); + desc->wme |= htole16(RAL_IVOFFSET(sizeof (struct ieee80211_frame))); /* setup PLCP fields */ - sc->sc_tx_desc.plcp_signal = ural_plcp_signal(rate); - sc->sc_tx_desc.plcp_service = 4; + desc->plcp_signal = ural_plcp_signal(rate); + desc->plcp_service = 4; len += IEEE80211_CRC_LEN; - - phytype = ieee80211_rate2phytype(sc->sc_rates, rate); - - if (phytype == IEEE80211_T_OFDM) { - sc->sc_tx_desc.flags |= htole32(RAL_TX_OFDM); + if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) { + desc->flags |= htole32(RAL_TX_OFDM); plcp_length = len & 0xfff; - sc->sc_tx_desc.plcp_length_hi = plcp_length >> 6; - sc->sc_tx_desc.plcp_length_lo = plcp_length & 0x3f; - + desc->plcp_length_hi = plcp_length >> 6; + desc->plcp_length_lo = plcp_length & 0x3f; } else { - plcp_length = ((16 * len) + rate - 1) / rate; + plcp_length = (16 * len + rate - 1) / rate; if (rate == 22) { remainder = (16 * len) % 22; - if ((remainder != 0) && (remainder < 7)) { - sc->sc_tx_desc.plcp_service |= - RAL_PLCP_LENGEXT; - } + if (remainder != 0 && remainder < 7) + desc->plcp_service |= RAL_PLCP_LENGEXT; } - sc->sc_tx_desc.plcp_length_hi = plcp_length >> 8; - sc->sc_tx_desc.plcp_length_lo = plcp_length & 0xff; + desc->plcp_length_hi = plcp_length >> 8; + desc->plcp_length_lo = plcp_length & 0xff; - if ((rate != 2) && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { - sc->sc_tx_desc.plcp_signal |= 0x08; - } + if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + desc->plcp_signal |= 0x08; } - sc->sc_tx_desc.iv = 0; - sc->sc_tx_desc.eiv = 0; - - if (sizeof(sc->sc_tx_desc) > MHLEN) { - DPRINTF("No room for header structure!\n"); - ural_tx_freem(m); - return; - } - mm = m_gethdr(M_NOWAIT, MT_DATA); - if (mm == NULL) { - DPRINTF("Could not allocate header mbuf!\n"); - ural_tx_freem(m); - return; - } - DPRINTF(" %zu %u (out)\n", sizeof(sc->sc_tx_desc), m->m_pkthdr.len); - - 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; - - /* start write transfer, if not started */ - _IF_ENQUEUE(&sc->sc_tx_queue, mm); - - usb2_transfer_start(sc->sc_xfer[URAL_BULK_DT_WR]); + desc->iv = 0; + desc->eiv = 0; } -static void -ural_bulk_write_callback(struct usb2_xfer *xfer) +#define RAL_TX_TIMEOUT 5000 + +static int +ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - struct ural_softc *sc = xfer->priv_sc; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; struct ifnet *ifp = sc->sc_ifp; - struct mbuf *m; - uint16_t temp_len; - uint8_t align; + const struct ieee80211_txparam *tp; + struct ural_tx_data *data; - switch (USB_GET_STATE(xfer)) { - case USB_ST_TRANSFERRED: - DPRINTFN(11, "transfer complete, %d bytes\n", xfer->actlen); - - ifp->if_opackets++; - - case USB_ST_SETUP: - if (sc->sc_flags & URAL_FLAG_WRITE_STALL) { - usb2_transfer_start(sc->sc_xfer[URAL_BULK_CS_WR]); - break; - } - if (sc->sc_flags & URAL_FLAG_WAIT_COMMAND) { - /* - * don't send anything while a command is pending ! - */ - break; - } - ural_fill_write_queue(sc); - - _IF_DEQUEUE(&sc->sc_tx_queue, m); - - if (m) { - - if (m->m_pkthdr.len > (RAL_FRAME_SIZE + RAL_TX_DESC_SIZE)) { - DPRINTFN(0, "data overflow, %u bytes\n", - m->m_pkthdr.len); - m->m_pkthdr.len = (RAL_FRAME_SIZE + RAL_TX_DESC_SIZE); - } - usb2_m_copy_in(xfer->frbuffers, 0, - m, 0, m->m_pkthdr.len); - - /* compute transfer length */ - temp_len = m->m_pkthdr.len; - - /* make transfer length 16-bit aligned */ - align = (temp_len & 1); - - /* check if we need to add two extra bytes */ - if (((temp_len + align) % 64) == 0) { - align += 2; - } - /* check if we need to align length */ - if (align != 0) { - /* zero the extra bytes */ - usb2_bzero(xfer->frbuffers, temp_len, align); - temp_len += align; - } - 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 */ - ural_tx_freem(m); - } - 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 |= URAL_FLAG_WRITE_STALL; - usb2_transfer_start(sc->sc_xfer[URAL_BULK_CS_WR]); - } - ifp->if_oerrors++; - break; + if (sc->tx_nfree == 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + m_freem(m0); + ieee80211_free_node(ni); + return EIO; } -} + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; -static void -ural_bulk_write_clear_stall_callback(struct usb2_xfer *xfer) -{ - struct ural_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[URAL_BULK_DT_WR]; + data->m = m0; + data->ni = ni; + data->rate = tp->mgmtrate; - if (usb2_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - sc->sc_flags &= ~URAL_FLAG_WRITE_STALL; - usb2_transfer_start(xfer_other); - } -} + ural_setup_tx_desc(sc, &data->desc, + RAL_TX_IFS_NEWBACKOFF | RAL_TX_TIMESTAMP, m0->m_pkthdr.len, + tp->mgmtrate); -static void -ural_watchdog(void *arg) -{ - struct ural_softc *sc = arg; + DPRINTFN(10, "sending beacon frame len=%u rate=%u\n", + m0->m_pkthdr.len, tp->mgmtrate); - mtx_assert(&sc->sc_mtx, MA_OWNED); + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[URAL_BULK_WR]); - if (sc->sc_amrr_timer) { - usb2_config_td_queue_command - (&sc->sc_config_td, NULL, - &ural_cfg_amrr_timeout, 0, 0); - } - usb2_callout_reset(&sc->sc_watchdog, - hz, &ural_watchdog, sc); -} - -/*========================================================================* - * IF-net callbacks - *========================================================================*/ - -static void -ural_init_cb(void *arg) -{ - struct ural_softc *sc = arg; - - mtx_lock(&sc->sc_mtx); - usb2_config_td_queue_command - (&sc->sc_config_td, &ural_cfg_pre_init, - &ural_cfg_init, 0, 0); - mtx_unlock(&sc->sc_mtx); + return (0); } static int -ural_ioctl_cb(struct ifnet *ifp, u_long cmd, caddr_t data) +ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + const struct ieee80211_txparam *tp; + struct ural_tx_data *data; + struct ieee80211_frame *wh; + struct ieee80211_key *k; + uint32_t flags; + uint16_t dur; + + RAL_LOCK_ASSERT(sc, MA_OWNED); + + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; + + wh = mtod(m0, struct ieee80211_frame *); + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + k = ieee80211_crypto_encap(ni, m0); + if (k == NULL) { + m_freem(m0); + return ENOBUFS; + } + wh = mtod(m0, struct ieee80211_frame *); + } + + data->m = m0; + data->ni = ni; + data->rate = tp->mgmtrate; + + flags = 0; + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + flags |= RAL_TX_ACK; + + dur = ieee80211_ack_duration(sc->sc_rates, tp->mgmtrate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); + *(uint16_t *)wh->i_dur = htole16(dur); + + /* tell hardware to add timestamp for probe responses */ + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_MGT && + (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == + IEEE80211_FC0_SUBTYPE_PROBE_RESP) + flags |= RAL_TX_TIMESTAMP; + } + + ural_setup_tx_desc(sc, &data->desc, flags, m0->m_pkthdr.len, tp->mgmtrate); + + DPRINTFN(10, "sending mgt frame len=%u rate=%u\n", + m0->m_pkthdr.len, tp->mgmtrate); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[URAL_BULK_WR]); + + return 0; +} + +static int +ural_sendprot(struct ural_softc *sc, + const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) +{ + struct ieee80211com *ic = ni->ni_ic; + const struct ieee80211_frame *wh; + struct ural_tx_data *data; + struct mbuf *mprot; + int protrate, ackrate, pktlen, flags, isshort; + uint16_t dur; + + KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, + ("protection %d", prot)); + + wh = mtod(m, const struct ieee80211_frame *); + pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; + + protrate = ieee80211_ctl_rate(sc->sc_rates, rate); + ackrate = ieee80211_ack_rate(sc->sc_rates, rate); + + isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; + dur = ieee80211_compute_duration(sc->sc_rates, pktlen, rate, isshort); + + ieee80211_ack_duration(sc->sc_rates, rate, isshort); + flags = RAL_TX_RETRY(7); + if (prot == IEEE80211_PROT_RTSCTS) { + /* NB: CTS is the same size as an ACK */ + dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort); + flags |= RAL_TX_ACK; + mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); + } else { + mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); + } + if (mprot == NULL) { + /* XXX stat + msg */ + return ENOBUFS; + } + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + + data->m = mprot; + data->ni = ieee80211_ref_node(ni); + data->rate = protrate; + ural_setup_tx_desc(sc, &data->desc, flags, mprot->m_pkthdr.len, protrate); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[URAL_BULK_WR]); + + return 0; +} + +static int +ural_tx_raw(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, + const struct ieee80211_bpf_params *params) +{ + struct ural_tx_data *data; + uint32_t flags; + int error; + int rate; + + RAL_LOCK_ASSERT(sc, MA_OWNED); + KASSERT(params != NULL, ("no raw xmit params")); + + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + + rate = params->ibp_rate0 & IEEE80211_RATE_VAL; + /* XXX validate */ + if (rate == 0) { + m_freem(m0); + return EINVAL; + } + flags = 0; + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) + flags |= RAL_TX_ACK; + if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { + error = ural_sendprot(sc, m0, ni, + params->ibp_flags & IEEE80211_BPF_RTS ? + IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, + rate); + if (error) { + m_freem(m0); + return error; + } + flags |= RAL_TX_IFS_SIFS; + } + + data->m = m0; + data->ni = ni; + data->rate = rate; + + /* XXX need to setup descriptor ourself */ + ural_setup_tx_desc(sc, &data->desc, flags, m0->m_pkthdr.len, rate); + + DPRINTFN(10, "sending raw frame len=%u rate=%u\n", + m0->m_pkthdr.len, rate); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[URAL_BULK_WR]); + + return 0; +} + +static int +ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct ural_tx_data *data; + struct ieee80211_frame *wh; + const struct ieee80211_txparam *tp; + struct ieee80211_key *k; + uint32_t flags = 0; + uint16_t dur; + int error, rate; + + RAL_LOCK_ASSERT(sc, MA_OWNED); + + wh = mtod(m0, struct ieee80211_frame *); + + tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + rate = tp->mcastrate; + 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, 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 (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + int prot = IEEE80211_PROT_NONE; + if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) + prot = IEEE80211_PROT_RTSCTS; + else if ((ic->ic_flags & IEEE80211_F_USEPROT) && + ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) + prot = ic->ic_protmode; + if (prot != IEEE80211_PROT_NONE) { + error = ural_sendprot(sc, m0, ni, prot, rate); + if (error) { + m_freem(m0); + return error; + } + flags |= RAL_TX_IFS_SIFS; + } + } + + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + + data->m = m0; + data->ni = ni; + data->rate = rate; + + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + flags |= RAL_TX_ACK; + flags |= RAL_TX_RETRY(7); + + dur = ieee80211_ack_duration(sc->sc_rates, rate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); + *(uint16_t *)wh->i_dur = htole16(dur); + } + + ural_setup_tx_desc(sc, &data->desc, flags, m0->m_pkthdr.len, rate); + + DPRINTFN(10, "sending data frame len=%u rate=%u\n", + m0->m_pkthdr.len, rate); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[URAL_BULK_WR]); + + return 0; +} + +static void +ural_start(struct ifnet *ifp) +{ + struct ural_softc *sc = ifp->if_softc; + struct ieee80211_node *ni; + struct mbuf *m; + + RAL_LOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + RAL_UNLOCK(sc); + return; + } + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->tx_nfree == 0) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; + m = ieee80211_encap(ni, m); + if (m == NULL) { + ieee80211_free_node(ni); + continue; + } + if (ural_tx_data(sc, m, ni) != 0) { + ieee80211_free_node(ni); + ifp->if_oerrors++; + break; + } + } + RAL_UNLOCK(sc); +} + +static int +ural_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ural_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); + RAL_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, &ural_cfg_pre_init, - &ural_cfg_init, 0, 0); - } + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + ural_queue_command(sc, ural_init_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + startall = 1; + } else + ural_queue_command(sc, ural_promisctask, + &sc->sc_promisctask[0].hdr, + &sc->sc_promisctask[1].hdr); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - usb2_config_td_queue_command - (&sc->sc_config_td, &ural_cfg_pre_stop, - &ural_cfg_stop, 0, 0); + ural_queue_command(sc, ural_stop_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); } } - mtx_unlock(&sc->sc_mtx); - error = 0; + RAL_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); break; - case SIOCGIFMEDIA: case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, (void *)data, &ic->ic_media, cmd); + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); break; - default: error = ether_ioctl(ifp, cmd, data); - } - return (error); -} - -static void -ural_start_cb(struct ifnet *ifp) -{ - struct ural_softc *sc = ifp->if_softc; - - mtx_lock(&sc->sc_mtx); - /* start write transfer, if not started */ - usb2_transfer_start(sc->sc_xfer[URAL_BULK_DT_WR]); - mtx_unlock(&sc->sc_mtx); -} - -static void -ural_cfg_newstate(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ural_vap *uvp = URAL_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; - - if (ostate == IEEE80211_S_INIT) { - /* We are leaving INIT. TSF sync should be off. */ - ural_cfg_disable_tsf_sync(sc); - } - switch (nstate) { - case IEEE80211_S_INIT: - break; - - case IEEE80211_S_RUN: - ural_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); -} - -static int -ural_newstate_cb(struct ieee80211vap *vap, - enum ieee80211_state nstate, int arg) -{ - struct ural_vap *uvp = URAL_VAP(vap); - struct ieee80211com *ic = vap->iv_ic; - struct ural_softc *sc = ic->ic_ifp->if_softc; - - DPRINTF("setting new state: %d\n", nstate); - - /* Special case - cannot defer this call and cannot block ! */ - if (nstate == IEEE80211_S_INIT) { - /* stop timers */ - mtx_lock(&sc->sc_mtx); - sc->sc_amrr_timer = 0; - mtx_unlock(&sc->sc_mtx); - return (uvp->newstate(vap, nstate, arg)); - } - mtx_lock(&sc->sc_mtx); - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - mtx_unlock(&sc->sc_mtx); - 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; - - /* - * USB configuration can only be done from the USB configuration - * thread: - */ - usb2_config_td_queue_command - (&sc->sc_config_td, &ural_config_copy, - &ural_cfg_newstate, 0, 0); - - mtx_unlock(&sc->sc_mtx); - - return (EINPROGRESS); + return error; } static void -ural_std_command(struct ieee80211com *ic, usb2_config_td_command_t *func) +ural_set_testmode(struct ural_softc *sc) { - struct ural_softc *sc = ic->ic_ifp->if_softc; + struct usb2_device_request req; + usb2_error_t error; - mtx_lock(&sc->sc_mtx); + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = RAL_VENDOR_REQUEST; + USETW(req.wValue, 4); + USETW(req.wIndex, 1); + USETW(req.wLength, 0); - sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); - - usb2_config_td_queue_command - (&sc->sc_config_td, &ural_config_copy, func, 0, 0); - - mtx_unlock(&sc->sc_mtx); -} - -static void -ural_scan_start_cb(struct ieee80211com *ic) -{ - ural_std_command(ic, &ural_cfg_scan_start); -} - -static void -ural_scan_end_cb(struct ieee80211com *ic) -{ - ural_std_command(ic, &ural_cfg_scan_end); -} - -static void -ural_set_channel_cb(struct ieee80211com *ic) -{ - ural_std_command(ic, &ural_cfg_set_chan); -} - -/*========================================================================* - * configure sub-routines, ural_cfg_xxx - *========================================================================*/ - -static void -ural_cfg_scan_start(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - /* abort TSF synchronization */ - ural_cfg_disable_tsf_sync(sc); - ural_cfg_set_bssid(sc, cc->if_broadcastaddr); -} - -static void -ural_cfg_scan_end(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - /* enable TSF synchronization */ - ural_cfg_enable_tsf_sync(sc, cc, 0); - ural_cfg_set_bssid(sc, cc->iv_bss.ni_bssid); -} - -static void -ural_cfg_set_chan(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - enum { - N_RF5222 = (sizeof(ural_rf5222) / sizeof(ural_rf5222[0])), - }; - uint32_t i; - uint32_t chan; - uint8_t power; - uint8_t tmp; - - chan = cc->ic_curchan.chan_to_ieee; - - if ((chan == 0) || - (chan == IEEE80211_CHAN_ANY)) { - /* nothing to do */ - return; - } - if (cc->ic_curchan.chan_is_2ghz) - power = min(sc->sc_txpow[chan - 1], 31); - else - power = 31; - - /* adjust txpower using ifconfig settings */ - power -= (100 - cc->ic_txpowlimit) / 8; - - DPRINTFN(3, "setting channel to %u, " - "tx-power to %u\n", chan, power); - - switch (sc->sc_rf_rev) { - case RAL_RF_2522: - ural_cfg_rf_write(sc, RAL_RF1, 0x00814); - ural_cfg_rf_write(sc, RAL_RF2, ural_rf2522_r2[chan - 1]); - ural_cfg_rf_write(sc, RAL_RF3, (power << 7) | 0x00040); - break; - - case RAL_RF_2523: - ural_cfg_rf_write(sc, RAL_RF1, 0x08804); - ural_cfg_rf_write(sc, RAL_RF2, ural_rf2523_r2[chan - 1]); - ural_cfg_rf_write(sc, RAL_RF3, (power << 7) | 0x38044); - ural_cfg_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); - break; - - case RAL_RF_2524: - ural_cfg_rf_write(sc, RAL_RF1, 0x0c808); - ural_cfg_rf_write(sc, RAL_RF2, ural_rf2524_r2[chan - 1]); - ural_cfg_rf_write(sc, RAL_RF3, (power << 7) | 0x00040); - ural_cfg_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); - break; - - case RAL_RF_2525: - ural_cfg_rf_write(sc, RAL_RF1, 0x08808); - ural_cfg_rf_write(sc, RAL_RF2, ural_rf2525_hi_r2[chan - 1]); - ural_cfg_rf_write(sc, RAL_RF3, (power << 7) | 0x18044); - ural_cfg_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); - - ural_cfg_rf_write(sc, RAL_RF1, 0x08808); - ural_cfg_rf_write(sc, RAL_RF2, ural_rf2525_r2[chan - 1]); - ural_cfg_rf_write(sc, RAL_RF3, (power << 7) | 0x18044); - ural_cfg_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); - break; - - case RAL_RF_2525E: - ural_cfg_rf_write(sc, RAL_RF1, 0x08808); - ural_cfg_rf_write(sc, RAL_RF2, ural_rf2525e_r2[chan - 1]); - ural_cfg_rf_write(sc, RAL_RF3, (power << 7) | 0x18044); - ural_cfg_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); - break; - - case RAL_RF_2526: - ural_cfg_rf_write(sc, RAL_RF2, ural_rf2526_hi_r2[chan - 1]); - ural_cfg_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); - ural_cfg_rf_write(sc, RAL_RF1, 0x08804); - - ural_cfg_rf_write(sc, RAL_RF2, ural_rf2526_r2[chan - 1]); - ural_cfg_rf_write(sc, RAL_RF3, (power << 7) | 0x18044); - ural_cfg_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); - break; - - /* dual-band RF */ - case RAL_RF_5222: - for (i = 0; i < N_RF5222; i++) { - if (ural_rf5222[i].chan == chan) { - ural_cfg_rf_write(sc, RAL_RF1, ural_rf5222[i].r1); - ural_cfg_rf_write(sc, RAL_RF2, ural_rf5222[i].r2); - ural_cfg_rf_write(sc, RAL_RF3, (power << 7) | 0x00040); - ural_cfg_rf_write(sc, RAL_RF4, ural_rf5222[i].r4); - break; - } - } - break; - } - - if ((cc->ic_opmode != IEEE80211_M_MONITOR) && - (!(cc->ic_flags & IEEE80211_F_SCAN))) { - - /* set Japan filter bit for channel 14 */ - tmp = ural_cfg_bbp_read(sc, 70); - - if (chan == 14) { - tmp |= RAL_JAPAN_FILTER; - } else { - tmp &= ~RAL_JAPAN_FILTER; - } - - ural_cfg_bbp_write(sc, 70, tmp); - - /* clear CRC errors */ - ural_cfg_read(sc, RAL_STA_CSR0); - - ural_cfg_disable_rf_tune(sc); - } - /* update basic rate set */ - if (cc->ic_curchan.chan_is_b) { - /* 11b basic rates: 1, 2Mbps */ - ural_cfg_write(sc, RAL_TXRX_CSR11, 0x3); - } else if (cc->ic_curchan.chan_is_a) { - /* 11a basic rates: 6, 12, 24Mbps */ - ural_cfg_write(sc, RAL_TXRX_CSR11, 0x150); - } else { - /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ - ural_cfg_write(sc, RAL_TXRX_CSR11, 0x15f); - } - - /* wait a little */ - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - return; + error = ural_do_request(sc, &req, NULL); + if (error != 0) { + device_printf(sc->sc_dev, "could not set test mode: %s\n", + usb2_errstr(error)); } } static void -ural_cfg_set_run(struct ural_softc *sc, - struct usb2_config_td_cc *cc) +ural_eeprom_read(struct ural_softc *sc, uint16_t addr, void *buf, int len) { - if (cc->ic_opmode != IEEE80211_M_MONITOR) { - ural_cfg_update_slot(sc, cc, 0); - ural_cfg_set_txpreamble(sc, cc, 0); + struct usb2_device_request req; + usb2_error_t error; - /* update basic rate set */ + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = RAL_READ_EEPROM; + USETW(req.wValue, 0); + USETW(req.wIndex, addr); + USETW(req.wLength, len); - if (cc->ic_bsschan.chan_is_5ghz) { - /* 11a basic rates: 6, 12, 24Mbps */ - ural_cfg_write(sc, RAL_TXRX_CSR11, 0x150); - } else if (cc->ic_bsschan.chan_is_g) { - /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ - ural_cfg_write(sc, RAL_TXRX_CSR11, 0x15f); - } else { - /* 11b basic rates: 1, 2Mbps */ - ural_cfg_write(sc, RAL_TXRX_CSR11, 0x3); - } - ural_cfg_set_bssid(sc, cc->iv_bss.ni_bssid); - } - if ((cc->ic_opmode == IEEE80211_M_HOSTAP) || - (cc->ic_opmode == IEEE80211_M_IBSS)) { - ural_tx_bcn(sc); - } - /* make tx led blink on tx (controlled by ASIC) */ - ural_cfg_write(sc, RAL_MAC_CSR20, 1); - - if (cc->ic_opmode != IEEE80211_M_MONITOR) { - ural_cfg_enable_tsf_sync(sc, cc, 0); - } - /* clear statistic registers (STA_CSR0 to STA_CSR10) */ - ural_cfg_read_multi(sc, RAL_STA_CSR0, sc->sc_sta, sizeof(sc->sc_sta)); - - if (cc->iv_bss.fixed_rate_none) { - /* enable automatic rate adaptation */ - ural_cfg_amrr_start(sc); + error = ural_do_request(sc, &req, buf); + if (error != 0) { + device_printf(sc->sc_dev, "could not read EEPROM: %s\n", + usb2_errstr(error)); } } -/*------------------------------------------------------------------------* - * ural_cfg_disable_rf_tune - disable RF auto-tuning - *------------------------------------------------------------------------*/ -static void -ural_cfg_disable_rf_tune(struct ural_softc *sc) -{ - uint32_t tmp; - - if (sc->sc_rf_rev != RAL_RF_2523) { - tmp = sc->sc_rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; - ural_cfg_rf_write(sc, RAL_RF1, tmp); - } - tmp = sc->sc_rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; - ural_cfg_rf_write(sc, RAL_RF3, tmp); - - DPRINTFN(3, "disabling RF autotune\n"); -} - -/*------------------------------------------------------------------------* - * ural_cfg_enable_tsf_sync - refer to IEEE Std 802.11-1999 pp. 123 - * for more information on TSF synchronization - *------------------------------------------------------------------------*/ -static void -ural_cfg_enable_tsf_sync(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint16_t logcwmin; - uint16_t preload; - uint16_t tmp; - - /* first, disable TSF synchronization */ - ural_cfg_write(sc, RAL_TXRX_CSR19, 0); - - tmp = (16 * cc->iv_bss.ni_intval) << 4; - ural_cfg_write(sc, RAL_TXRX_CSR18, tmp); - - logcwmin = (cc->ic_opmode == IEEE80211_M_IBSS) ? 2 : 0; - preload = (cc->ic_opmode == IEEE80211_M_IBSS) ? 320 : 6; - tmp = (logcwmin << 12) | preload; - ural_cfg_write(sc, RAL_TXRX_CSR20, tmp); - - /* finally, enable TSF synchronization */ - tmp = RAL_ENABLE_TSF | RAL_ENABLE_TBCN; - if (cc->ic_opmode == IEEE80211_M_STA) - tmp |= RAL_ENABLE_TSF_SYNC(1); - else - tmp |= RAL_ENABLE_TSF_SYNC(2) | RAL_ENABLE_BEACON_GENERATOR; - - ural_cfg_write(sc, RAL_TXRX_CSR19, tmp); - - DPRINTF("enabling TSF synchronization\n"); -} - -static void -ural_cfg_disable_tsf_sync(struct ural_softc *sc) -{ - /* abort TSF synchronization */ - ural_cfg_write(sc, RAL_TXRX_CSR19, 0); - - /* force tx led to stop blinking */ - ural_cfg_write(sc, RAL_MAC_CSR20, 0); -} - -#define RAL_RXTX_TURNAROUND 5 /* us */ - -static void -ural_cfg_update_slot(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint16_t slottime; - uint16_t sifs; - uint16_t eifs; - - slottime = (cc->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; - - /* - * These settings may sound a bit inconsistent but this is what the - * reference driver does. - */ - if (cc->ic_curmode == IEEE80211_MODE_11B) { - sifs = 16 - RAL_RXTX_TURNAROUND; - eifs = 364; - } else { - sifs = 10 - RAL_RXTX_TURNAROUND; - eifs = 64; - } - - ural_cfg_write(sc, RAL_MAC_CSR10, slottime); - ural_cfg_write(sc, RAL_MAC_CSR11, sifs); - ural_cfg_write(sc, RAL_MAC_CSR12, eifs); -} - -static void -ural_cfg_set_txpreamble(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint16_t tmp; - - tmp = ural_cfg_read(sc, RAL_TXRX_CSR10); - - if (cc->ic_flags & IEEE80211_F_SHPREAMBLE) { - tmp |= RAL_SHORT_PREAMBLE; - } else { - tmp &= ~RAL_SHORT_PREAMBLE; - } - - ural_cfg_write(sc, RAL_TXRX_CSR10, tmp); -} - -static void -ural_cfg_set_bssid(struct ural_softc *sc, uint8_t *bssid) -{ - ural_cfg_write_multi(sc, RAL_MAC_CSR5, bssid, IEEE80211_ADDR_LEN); - - DPRINTF("setting BSSID to 0x%02x%02x%02x%02x%02x%02x\n", - bssid[5], bssid[4], bssid[3], - bssid[2], bssid[1], bssid[0]); -} - -static void -ural_cfg_set_macaddr(struct ural_softc *sc, uint8_t *addr) -{ - ural_cfg_write_multi(sc, RAL_MAC_CSR2, addr, IEEE80211_ADDR_LEN); - - DPRINTF("setting MAC to 0x%02x%02x%02x%02x%02x%02x\n", - addr[5], addr[4], addr[3], - addr[2], addr[1], addr[0]); -} - -static void -ural_cfg_update_promisc(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint16_t tmp; - - tmp = ural_cfg_read(sc, RAL_TXRX_CSR2); - - if (cc->if_flags & IFF_PROMISC) { - tmp &= ~RAL_DROP_NOT_TO_ME; - } else { - tmp |= RAL_DROP_NOT_TO_ME; - } - - ural_cfg_write(sc, RAL_TXRX_CSR2, tmp); - - DPRINTF("%s promiscuous mode\n", - (cc->if_flags & IFF_PROMISC) ? - "entering" : "leaving"); -} - -static void -ural_cfg_set_txantenna(struct ural_softc *sc, uint8_t antenna) -{ - uint16_t tmp; - uint8_t tx; - - tx = ural_cfg_bbp_read(sc, RAL_BBP_TX) & ~RAL_BBP_ANTMASK; - if (antenna == 1) - tx |= RAL_BBP_ANTA; - else if (antenna == 2) - tx |= RAL_BBP_ANTB; - else - tx |= RAL_BBP_DIVERSITY; - - /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ - if ((sc->sc_rf_rev == RAL_RF_2525E) || - (sc->sc_rf_rev == RAL_RF_2526) || - (sc->sc_rf_rev == RAL_RF_5222)) { - tx |= RAL_BBP_FLIPIQ; - } - ural_cfg_bbp_write(sc, RAL_BBP_TX, tx); - - /* update values in PHY_CSR5 and PHY_CSR6 */ - tmp = ural_cfg_read(sc, RAL_PHY_CSR5) & ~0x7; - ural_cfg_write(sc, RAL_PHY_CSR5, tmp | (tx & 0x7)); - - tmp = ural_cfg_read(sc, RAL_PHY_CSR6) & ~0x7; - ural_cfg_write(sc, RAL_PHY_CSR6, tmp | (tx & 0x7)); -} - -static void -ural_cfg_set_rxantenna(struct ural_softc *sc, uint8_t antenna) -{ - uint8_t rx; - - rx = ural_cfg_bbp_read(sc, RAL_BBP_RX) & ~RAL_BBP_ANTMASK; - if (antenna == 1) - rx |= RAL_BBP_ANTA; - else if (antenna == 2) - rx |= RAL_BBP_ANTB; - else - rx |= RAL_BBP_DIVERSITY; - - /* need to force no I/Q flip for RF 2525e and 2526 */ - - if ((sc->sc_rf_rev == RAL_RF_2525E) || - (sc->sc_rf_rev == RAL_RF_2526)) { - rx &= ~RAL_BBP_FLIPIQ; - } - ural_cfg_bbp_write(sc, RAL_BBP_RX, rx); -} - -static void -ural_cfg_read_eeprom(struct ural_softc *sc) +static uint16_t +ural_read(struct ural_softc *sc, uint16_t reg) { + struct usb2_device_request req; + usb2_error_t error; uint16_t val; - ural_cfg_eeprom_read(sc, RAL_EEPROM_CONFIG0, &val, 2); + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = RAL_READ_MAC; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, sizeof (uint16_t)); - val = le16toh(val); + error = ural_do_request(sc, &req, &val); + if (error != 0) { + device_printf(sc->sc_dev, "could not read MAC register: %s\n", + usb2_errstr(error)); + return 0; + } - sc->sc_rf_rev = (val >> 11) & 0x7; - sc->sc_hw_radio = (val >> 10) & 0x1; - sc->sc_led_mode = (val >> 6) & 0x7; - sc->sc_rx_ant = (val >> 4) & 0x3; - sc->sc_tx_ant = (val >> 2) & 0x3; - sc->sc_nb_ant = (val & 0x3); + return le16toh(val); +} - DPRINTF("val = 0x%04x\n", val); +static void +ural_read_multi(struct ural_softc *sc, uint16_t reg, void *buf, int len) +{ + struct usb2_device_request req; + usb2_error_t error; - /* read MAC address */ - ural_cfg_eeprom_read(sc, RAL_EEPROM_ADDRESS, sc->sc_myaddr, - sizeof(sc->sc_myaddr)); + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = RAL_READ_MULTI_MAC; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, len); - /* read default values for BBP registers */ - ural_cfg_eeprom_read(sc, RAL_EEPROM_BBP_BASE, sc->sc_bbp_prom, - sizeof(sc->sc_bbp_prom)); + error = ural_do_request(sc, &req, buf); + if (error != 0) { + device_printf(sc->sc_dev, "could not read MAC register: %s\n", + usb2_errstr(error)); + } +} - /* read Tx power for all b/g channels */ - ural_cfg_eeprom_read(sc, RAL_EEPROM_TXPOWER, sc->sc_txpow, - sizeof(sc->sc_txpow)); +static void +ural_write(struct ural_softc *sc, uint16_t reg, uint16_t val) +{ + struct usb2_device_request req; + usb2_error_t error; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = RAL_WRITE_MAC; + USETW(req.wValue, val); + USETW(req.wIndex, reg); + USETW(req.wLength, 0); + + error = ural_do_request(sc, &req, NULL); + if (error != 0) { + device_printf(sc->sc_dev, "could not write MAC register: %s\n", + usb2_errstr(error)); + } +} + +static void +ural_write_multi(struct ural_softc *sc, uint16_t reg, void *buf, int len) +{ + struct usb2_device_request req; + usb2_error_t error; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = RAL_WRITE_MULTI_MAC; + USETW(req.wValue, 0); + USETW(req.wIndex, reg); + USETW(req.wLength, len); + + error = ural_do_request(sc, &req, buf); + if (error != 0) { + device_printf(sc->sc_dev, "could not write MAC register: %s\n", + usb2_errstr(error)); + } +} + +static void +ural_bbp_write(struct ural_softc *sc, uint8_t reg, uint8_t val) +{ + uint16_t tmp; + int ntries; + + for (ntries = 0; ntries < 5; ntries++) { + if (!(ural_read(sc, RAL_PHY_CSR8) & RAL_BBP_BUSY)) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, "could not write to BBP\n"); + return; + } + + tmp = reg << 8 | val; + ural_write(sc, RAL_PHY_CSR7, tmp); } static uint8_t -ural_cfg_bbp_init(struct ural_softc *sc) +ural_bbp_read(struct ural_softc *sc, uint8_t reg) { - enum { - N_DEF_BBP = (sizeof(ural_def_bbp) / sizeof(ural_def_bbp[0])), - }; - uint16_t i; - uint8_t to; + uint16_t val; + int ntries; - /* wait for BBP to become ready */ - for (to = 0;; to++) { - if (to < 100) { - if (ural_cfg_bbp_read(sc, RAL_BBP_VERSION) != 0) { - break; - } - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - return (1); /* failure */ - } - } else { - DPRINTF("timeout waiting for BBP\n"); - return (1); /* failure */ - } + val = RAL_BBP_WRITE | reg << 8; + ural_write(sc, RAL_PHY_CSR7, val); + + for (ntries = 0; ntries < 5; ntries++) { + if (!(ural_read(sc, RAL_PHY_CSR8) & RAL_BBP_BUSY)) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, "could not read BBP\n"); + return 0; } - /* initialize BBP registers to default values */ - for (i = 0; i < N_DEF_BBP; i++) { - ural_cfg_bbp_write(sc, ural_def_bbp[i].reg, - ural_def_bbp[i].val); - } - -#if 0 - /* initialize BBP registers to values stored in EEPROM */ - for (i = 0; i < 16; i++) { - if (sc->sc_bbp_prom[i].reg == 0xff) { - continue; - } - ural_cfg_bbp_write(sc, sc->sc_bbp_prom[i].reg, - sc->sc_bbp_prom[i].val); - } -#endif - return (0); /* success */ + return ural_read(sc, RAL_PHY_CSR7) & 0xff; } static void -ural_cfg_pre_init(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) +ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; + uint32_t tmp; + int ntries; - /* immediate configuration */ - - ural_cfg_pre_stop(sc, cc, 0); - - ifp->if_drv_flags |= IFF_DRV_RUNNING; - - sc->sc_flags |= URAL_FLAG_HL_READY; - - IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); -} - -static void -ural_cfg_init(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - enum { - N_DEF_MAC = (sizeof(ural_def_mac) / sizeof(ural_def_mac[0])), - }; - uint16_t tmp; - uint16_t i; - uint8_t to; - - /* delayed configuration */ - - ural_cfg_set_testmode(sc); - - ural_cfg_write(sc, 0x308, 0x00f0); /* XXX magic */ - - ural_cfg_stop(sc, cc, 0); - - /* initialize MAC registers to default values */ - for (i = 0; i < N_DEF_MAC; i++) { - ural_cfg_write(sc, ural_def_mac[i].reg, - ural_def_mac[i].val); + for (ntries = 0; ntries < 5; ntries++) { + if (!(ural_read(sc, RAL_PHY_CSR10) & RAL_RF_LOBUSY)) + break; } - - /* wait for BBP and RF to wake up (this can take a long time!) */ - for (to = 0;; to++) { - if (to < 100) { - tmp = ural_cfg_read(sc, RAL_MAC_CSR17); - if ((tmp & (RAL_BBP_AWAKE | RAL_RF_AWAKE)) == - (RAL_BBP_AWAKE | RAL_RF_AWAKE)) { - break; - } - if (usb2_config_td_sleep(&sc->sc_config_td, hz / 100)) { - goto fail; - } - } else { - DPRINTF("timeout waiting for " - "BBP/RF to wakeup\n"); - goto fail; - } - } - - /* we're ready! */ - ural_cfg_write(sc, RAL_MAC_CSR1, RAL_HOST_READY); - - /* set basic rate set (will be updated later) */ - ural_cfg_write(sc, RAL_TXRX_CSR11, 0x15f); - - if (ural_cfg_bbp_init(sc)) { - goto fail; - } - /* set default BSS channel */ - ural_cfg_set_chan(sc, cc, 0); - - /* clear statistic registers (STA_CSR0 to STA_CSR10) */ - ural_cfg_read_multi(sc, RAL_STA_CSR0, sc->sc_sta, - sizeof(sc->sc_sta)); - - DPRINTF("rx_ant=%d, tx_ant=%d\n", - sc->sc_rx_ant, sc->sc_tx_ant); - - ural_cfg_set_txantenna(sc, sc->sc_tx_ant); - ural_cfg_set_rxantenna(sc, sc->sc_rx_ant); - - ural_cfg_set_macaddr(sc, cc->ic_myaddr); - - /* - * make sure that the first transaction - * clears the stall: - */ - sc->sc_flags |= (URAL_FLAG_READ_STALL | - URAL_FLAG_WRITE_STALL | - URAL_FLAG_LL_READY); - - if ((sc->sc_flags & URAL_FLAG_LL_READY) && - (sc->sc_flags & URAL_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[URAL_BULK_DT_RD]); - usb2_transfer_start(sc->sc_xfer[URAL_BULK_DT_WR]); - - /* - * start IEEE802.11 layer - */ - mtx_unlock(&sc->sc_mtx); - ieee80211_start_all(ic); - mtx_lock(&sc->sc_mtx); - } - /* - * start Rx - */ - tmp = RAL_DROP_PHY | RAL_DROP_CRC; - if (cc->ic_opmode != IEEE80211_M_MONITOR) { - - tmp |= (RAL_DROP_CTL | RAL_DROP_BAD_VERSION); - - if (cc->ic_opmode != IEEE80211_M_HOSTAP) { - tmp |= RAL_DROP_TODS; - } - if (!(cc->if_flags & IFF_PROMISC)) { - tmp |= RAL_DROP_NOT_TO_ME; - } - } - ural_cfg_write(sc, RAL_TXRX_CSR2, tmp); - - return; - -fail: - ural_cfg_pre_stop(sc, NULL, 0); - - if (cc) { - ural_cfg_stop(sc, cc, 0); - } -} - -static void -ural_cfg_pre_stop(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp = sc->sc_ifp; - - if (cc) { - /* copy the needed configuration */ - ural_config_copy(sc, cc, refcount); - } - /* immediate configuration */ - - if (ifp) { - /* clear flags */ - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - } - sc->sc_flags &= ~(URAL_FLAG_HL_READY | - URAL_FLAG_LL_READY); - - /* - * stop all the transfers, if not already stopped: - */ - usb2_transfer_stop(sc->sc_xfer[URAL_BULK_DT_WR]); - usb2_transfer_stop(sc->sc_xfer[URAL_BULK_DT_RD]); - usb2_transfer_stop(sc->sc_xfer[URAL_BULK_CS_WR]); - usb2_transfer_stop(sc->sc_xfer[URAL_BULK_CS_RD]); - - /* clean up transmission */ - ural_tx_clean_queue(sc); -} - -static void -ural_cfg_stop(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - /* disable Rx */ - ural_cfg_write(sc, RAL_TXRX_CSR2, RAL_DISABLE_RX); - - /* reset ASIC and BBP (but won't reset MAC registers!) */ - ural_cfg_write(sc, RAL_MAC_CSR1, RAL_RESET_ASIC | RAL_RESET_BBP); - - /* wait a little */ - usb2_config_td_sleep(&sc->sc_config_td, hz / 10); - - /* clear reset */ - ural_cfg_write(sc, RAL_MAC_CSR1, 0); - - /* wait a little */ - usb2_config_td_sleep(&sc->sc_config_td, hz / 10); -} - -static void -ural_cfg_amrr_start(struct ural_softc *sc) -{ - struct ieee80211vap *vap; - struct ieee80211_node *ni; - - vap = ural_get_vap(sc); - - if (vap == NULL) { + if (ntries == 5) { + device_printf(sc->sc_dev, "could not write to RF\n"); return; } - ni = vap->iv_bss; - if (ni == NULL) { - return; - } - /* init AMRR */ - ieee80211_amrr_node_init(&URAL_VAP(vap)->amrr, &URAL_NODE(ni)->amn, ni); - /* enable AMRR timer */ + tmp = RAL_RF_BUSY | RAL_RF_20BIT | (val & 0xfffff) << 2 | (reg & 0x3); + ural_write(sc, RAL_PHY_CSR9, tmp & 0xffff); + ural_write(sc, RAL_PHY_CSR10, tmp >> 16); - sc->sc_amrr_timer = 1; -} + /* remember last written value in sc */ + sc->rf_regs[reg] = val; -static void -ural_cfg_amrr_timeout(struct ural_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211vap *vap; - struct ieee80211_node *ni; - uint32_t ok; - uint32_t fail; - - /* read and clear statistic registers (STA_CSR0 to STA_CSR10) */ - ural_cfg_read_multi(sc, RAL_STA_CSR0, sc->sc_sta, sizeof(sc->sc_sta)); - - vap = ural_get_vap(sc); - if (vap == NULL) { - return; - } - ni = vap->iv_bss; - if (ni == NULL) { - return; - } - if ((sc->sc_flags & URAL_FLAG_LL_READY) && - (sc->sc_flags & URAL_FLAG_HL_READY)) { - - ok = sc->sc_sta[7] + /* TX ok w/o retry */ - sc->sc_sta[8]; /* TX ok w/ retry */ - fail = sc->sc_sta[9]; /* TX retry-fail count */ - - if (sc->sc_amrr_timer) { - - ieee80211_amrr_tx_update(&URAL_NODE(ni)->amn, - ok + fail, ok, sc->sc_sta[8] + fail); - - if (ieee80211_amrr_choose(ni, &URAL_NODE(ni)->amn)) { - /* ignore */ - } - } - ifp->if_oerrors += fail; - } -} - -static struct ieee80211vap * -ural_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 ural_vap *uvp; - struct ieee80211vap *vap; - struct ural_softc *sc = ic->ic_ifp->if_softc; - - /* 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); - } - mtx_unlock(&sc->sc_mtx); - - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ - return NULL; - uvp = (struct ural_vap *)malloc(sizeof(struct ural_vap), - M_80211_VAP, M_NOWAIT | M_ZERO); - if (uvp == NULL) - return NULL; - - vap = &uvp->vap; - /* enable s/w bmiss handling for sta mode */ - ieee80211_vap_setup(ic, vap, name, unit, opmode, - flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); - - /* override state transition machine */ - uvp->newstate = vap->iv_newstate; - vap->iv_newstate = &ural_newstate_cb; - - ieee80211_amrr_init(&uvp->amrr, vap, - IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, - IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, - 1000 /* 1 sec */ ); - - /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); - - /* store current operation mode */ - ic->ic_opmode = opmode; - - return (vap); -} - -static void -ural_vap_delete(struct ieee80211vap *vap) -{ - struct ural_vap *uvp = URAL_VAP(vap); - struct ural_softc *sc = vap->iv_ic->ic_ifp->if_softc; - - /* 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); - - ieee80211_amrr_cleanup(&uvp->amrr); - ieee80211_vap_detach(vap); - free(uvp, M_80211_VAP); + DPRINTFN(15, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); } /* ARGUSED */ static struct ieee80211_node * ural_node_alloc(struct ieee80211vap *vap __unused, - const uint8_t mac[IEEE80211_ADDR_LEN] __unused) + const uint8_t mac[IEEE80211_ADDR_LEN] __unused) { struct ural_node *un; un = malloc(sizeof(struct ural_node), M_80211_NODE, M_NOWAIT | M_ZERO); - return ((un != NULL) ? &un->ni : NULL); + return un != NULL ? &un->ni : NULL; } static void @@ -2394,340 +1645,699 @@ ural_newassoc(struct ieee80211_node *ni, int isnew) } static void -ural_fill_write_queue(struct ural_softc *sc) +ural_scan_start(struct ieee80211com *ic) +{ + struct ural_softc *sc = ic->ic_ifp->if_softc; + + RAL_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = URAL_SCAN_START; + ural_queue_command(sc, ural_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + RAL_UNLOCK(sc); + +} + +static void +ural_scan_end(struct ieee80211com *ic) +{ + struct ural_softc *sc = ic->ic_ifp->if_softc; + + RAL_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = URAL_SCAN_END; + ural_queue_command(sc, ural_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + RAL_UNLOCK(sc); + +} + +static void +ural_set_channel(struct ieee80211com *ic) +{ + struct ural_softc *sc = ic->ic_ifp->if_softc; + + RAL_LOCK(sc); + /* do it in a process context */ + sc->sc_scan_action = URAL_SET_CHANNEL; + ural_queue_command(sc, ural_scantask, + &sc->sc_scantask[0].hdr, &sc->sc_scantask[1].hdr); + + sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); + RAL_UNLOCK(sc); +} + +static void +ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c) { struct ifnet *ifp = sc->sc_ifp; - struct ieee80211_node *ni; - struct mbuf *m; + struct ieee80211com *ic = ifp->if_l2com; + uint8_t power, tmp; + u_int i, chan; - /* - * We only fill up half of the queue with data frames. The rest is - * reserved for other kinds of frames. - */ + chan = ieee80211_chan2ieee(ic, c); + if (chan == 0 || chan == IEEE80211_CHAN_ANY) + return; - while (sc->sc_tx_queue.ifq_len < (IFQ_MAXLEN / 2)) { + if (IEEE80211_IS_CHAN_2GHZ(c)) + power = min(sc->txpow[chan - 1], 31); + else + power = 31; - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; + /* adjust txpower using ifconfig settings */ + power -= (100 - ic->ic_txpowlimit) / 8; - ni = (void *)(m->m_pkthdr.rcvif); - m = ieee80211_encap(ni, m); - if (m == NULL) { - ieee80211_free_node(ni); - continue; - } - ural_tx_data(sc, m, ni); - } -} + DPRINTFN(2, "setting channel to %u, txpower to %u\n", chan, power); -static void -ural_tx_clean_queue(struct ural_softc *sc) -{ - struct mbuf *m; + switch (sc->rf_rev) { + case RAL_RF_2522: + ural_rf_write(sc, RAL_RF1, 0x00814); + ural_rf_write(sc, RAL_RF2, ural_rf2522_r2[chan - 1]); + ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040); + break; - for (;;) { - _IF_DEQUEUE(&sc->sc_tx_queue, m); + case RAL_RF_2523: + ural_rf_write(sc, RAL_RF1, 0x08804); + ural_rf_write(sc, RAL_RF2, ural_rf2523_r2[chan - 1]); + ural_rf_write(sc, RAL_RF3, power << 7 | 0x38044); + ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); + break; - if (!m) { - break; - } - ural_tx_freem(m); - } -} + case RAL_RF_2524: + ural_rf_write(sc, RAL_RF1, 0x0c808); + ural_rf_write(sc, RAL_RF2, ural_rf2524_r2[chan - 1]); + ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040); + ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); + break; -static void -ural_tx_freem(struct mbuf *m) -{ - struct ieee80211_node *ni; + case RAL_RF_2525: + ural_rf_write(sc, RAL_RF1, 0x08808); + ural_rf_write(sc, RAL_RF2, ural_rf2525_hi_r2[chan - 1]); + ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044); + ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); - 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); + ural_rf_write(sc, RAL_RF1, 0x08808); + ural_rf_write(sc, RAL_RF2, ural_rf2525_r2[chan - 1]); + ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044); + ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); + break; + case RAL_RF_2525E: + ural_rf_write(sc, RAL_RF1, 0x08808); + ural_rf_write(sc, RAL_RF2, ural_rf2525e_r2[chan - 1]); + ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044); + ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); + break; + + case RAL_RF_2526: + ural_rf_write(sc, RAL_RF2, ural_rf2526_hi_r2[chan - 1]); + ural_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); + ural_rf_write(sc, RAL_RF1, 0x08804); + + ural_rf_write(sc, RAL_RF2, ural_rf2526_r2[chan - 1]); + ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044); + ural_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); + break; + + /* dual-band RF */ + case RAL_RF_5222: + for (i = 0; ural_rf5222[i].chan != chan; i++); + + ural_rf_write(sc, RAL_RF1, ural_rf5222[i].r1); + ural_rf_write(sc, RAL_RF2, ural_rf5222[i].r2); + ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040); + ural_rf_write(sc, RAL_RF4, ural_rf5222[i].r4); break; } + + if (ic->ic_opmode != IEEE80211_M_MONITOR && + (ic->ic_flags & IEEE80211_F_SCAN) == 0) { + /* set Japan filter bit for channel 14 */ + tmp = ural_bbp_read(sc, 70); + + tmp &= ~RAL_JAPAN_FILTER; + if (chan == 14) + tmp |= RAL_JAPAN_FILTER; + + ural_bbp_write(sc, 70, tmp); + + /* clear CRC errors */ + ural_read(sc, RAL_STA_CSR0); + + DELAY(10000); + ural_disable_rf_tune(sc); + } + + /* XXX doesn't belong here */ + /* update basic rate set */ + ural_set_basicrates(sc, c); } +/* + * Disable RF auto-tuning. + */ static void -ural_tx_mgt(struct ural_softc *sc, struct mbuf *m, struct ieee80211_node *ni) +ural_disable_rf_tune(struct ural_softc *sc) { - 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; - uint32_t flags; - uint16_t dur; + uint32_t tmp; - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - - 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 *); + if (sc->rf_rev != RAL_RF_2523) { + tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE; + ural_rf_write(sc, RAL_RF1, tmp); } - flags = 0; - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - flags |= RAL_TX_ACK; - dur = ieee80211_ack_duration(sc->sc_rates, tp->mgmtrate, - ic->ic_flags & IEEE80211_F_SHPREAMBLE); - USETW(wh->i_dur, dur); + tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE; + ural_rf_write(sc, RAL_RF3, tmp); - /* tell hardware to add timestamp for probe responses */ - if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == - IEEE80211_FC0_TYPE_MGT && - (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == - IEEE80211_FC0_SUBTYPE_PROBE_RESP) - flags |= RAL_TX_TIMESTAMP; - } - m->m_pkthdr.rcvif = (void *)ni; - ural_setup_desc_and_tx(sc, m, flags, tp->mgmtrate); -} - -static struct ieee80211vap * -ural_get_vap(struct ural_softc *sc) -{ - struct ifnet *ifp; - struct ieee80211com *ic; - - 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); + DPRINTFN(2, "disabling RF autotune\n"); } +/* + * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF + * synchronization. + */ static void -ural_tx_bcn(struct ural_softc *sc) +ural_enable_tsf_sync(struct ural_softc *sc) { - struct ieee80211_node *ni; - struct ieee80211vap *vap; - struct ieee80211com *ic; - const struct ieee80211_txparam *tp; - struct mbuf *m; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + uint16_t logcwmin, preload, tmp; - vap = ural_get_vap(sc); - if (vap == NULL) { - return; - } - ni = vap->iv_bss; - if (ni == NULL) { - return; - } - ic = vap->iv_ic; - if (ic == NULL) { - return; - } - DPRINTFN(11, "Sending beacon frame.\n"); + /* first, disable TSF synchronization */ + ural_write(sc, RAL_TXRX_CSR19, 0); - m = ieee80211_beacon_alloc(ni, &URAL_VAP(vap)->bo); - if (m == NULL) { - DPRINTFN(0, "could not allocate beacon\n"); - return; - } - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; + tmp = (16 * vap->iv_bss->ni_intval) << 4; + ural_write(sc, RAL_TXRX_CSR18, tmp); - m->m_pkthdr.rcvif = (void *)ieee80211_ref_node(ni); - ural_setup_desc_and_tx(sc, m, RAL_TX_IFS_NEWBACKOFF | RAL_TX_TIMESTAMP, - tp->mgmtrate); -} + logcwmin = (ic->ic_opmode == IEEE80211_M_IBSS) ? 2 : 0; + preload = (ic->ic_opmode == IEEE80211_M_IBSS) ? 320 : 6; + tmp = logcwmin << 12 | preload; + ural_write(sc, RAL_TXRX_CSR20, tmp); -static void -ural_tx_data(struct ural_softc *sc, struct mbuf *m, struct ieee80211_node *ni) -{ - 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; - uint32_t flags = 0; - uint16_t dur; - uint16_t rate; - - DPRINTFN(11, "Sending data.\n"); - - wh = mtod(m, struct ieee80211_frame *); - - tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; - if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; + /* finally, enable TSF synchronization */ + tmp = RAL_ENABLE_TSF | RAL_ENABLE_TBCN; + if (ic->ic_opmode == IEEE80211_M_STA) + tmp |= RAL_ENABLE_TSF_SYNC(1); else - rate = ni->ni_txrate; + tmp |= RAL_ENABLE_TSF_SYNC(2) | RAL_ENABLE_BEACON_GENERATOR; + ural_write(sc, RAL_TXRX_CSR19, tmp); - 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 (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - uint8_t prot = IEEE80211_PROT_NONE; - - if (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) - prot = IEEE80211_PROT_RTSCTS; - else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) - prot = ic->ic_protmode; - if (prot != IEEE80211_PROT_NONE) { - ural_tx_prot(sc, m, ni, prot, rate); - flags |= RAL_TX_IFS_SIFS; - } - flags |= RAL_TX_ACK; - flags |= RAL_TX_RETRY(7); - - dur = ieee80211_ack_duration(sc->sc_rates, rate, - ic->ic_flags & IEEE80211_F_SHPREAMBLE); - USETW(wh->i_dur, dur); - } - m->m_pkthdr.rcvif = (void *)ni; - ural_setup_desc_and_tx(sc, m, flags, rate); + DPRINTF("enabling TSF synchronization\n"); } +#define RAL_RXTX_TURNAROUND 5 /* us */ static void -ural_tx_prot(struct ural_softc *sc, - const struct mbuf *m, struct ieee80211_node *ni, - uint8_t prot, uint16_t rate) +ural_update_slot(struct ifnet *ifp) { - struct ieee80211com *ic = ni->ni_ic; - const struct ieee80211_frame *wh; - struct mbuf *mprot; - uint32_t flags; - uint16_t protrate; - uint16_t ackrate; - uint16_t pktlen; - uint16_t dur; - uint8_t isshort; + struct ural_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + uint16_t slottime, sifs, eifs; - KASSERT((prot == IEEE80211_PROT_RTSCTS) || - (prot == IEEE80211_PROT_CTSONLY), - ("protection %u", prot)); + slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; - DPRINTFN(16, "Sending protection frame.\n"); - - wh = mtod(m, const struct ieee80211_frame *); - pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; - - protrate = ieee80211_ctl_rate(sc->sc_rates, rate); - ackrate = ieee80211_ack_rate(sc->sc_rates, rate); - - isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; - dur = ieee80211_compute_duration(sc->sc_rates, pktlen, rate, isshort); - +ieee80211_ack_duration(sc->sc_rates, rate, isshort); - flags = RAL_TX_RETRY(7); - if (prot == IEEE80211_PROT_RTSCTS) { - /* NB: CTS is the same size as an ACK */ - dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort); - flags |= RAL_TX_ACK; - mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); + /* + * These settings may sound a bit inconsistent but this is what the + * reference driver does. + */ + if (ic->ic_curmode == IEEE80211_MODE_11B) { + sifs = 16 - RAL_RXTX_TURNAROUND; + eifs = 364; } else { - mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); + sifs = 10 - RAL_RXTX_TURNAROUND; + eifs = 64; } - if (mprot == NULL) { - return; - } - mprot->m_pkthdr.rcvif = (void *)ieee80211_ref_node(ni); - ural_setup_desc_and_tx(sc, mprot, flags, protrate); + + ural_write(sc, RAL_MAC_CSR10, slottime); + ural_write(sc, RAL_MAC_CSR11, sifs); + ural_write(sc, RAL_MAC_CSR12, eifs); } static void -ural_tx_raw(struct ural_softc *sc, struct mbuf *m, struct ieee80211_node *ni, - const struct ieee80211_bpf_params *params) +ural_set_txpreamble(struct ural_softc *sc) { - uint32_t flags; - uint16_t rate; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint16_t tmp; - DPRINTFN(11, "Sending raw frame.\n"); + tmp = ural_read(sc, RAL_TXRX_CSR10); - rate = params->ibp_rate0 & IEEE80211_RATE_VAL; + tmp &= ~RAL_SHORT_PREAMBLE; + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + tmp |= RAL_SHORT_PREAMBLE; - /* XXX validate */ - if (rate == 0) { - m_freem(m); - ieee80211_free_node(ni); - return; + ural_write(sc, RAL_TXRX_CSR10, tmp); +} + +static void +ural_set_basicrates(struct ural_softc *sc, const struct ieee80211_channel *c) +{ + /* XXX wrong, take from rate set */ + /* update basic rate set */ + if (IEEE80211_IS_CHAN_5GHZ(c)) { + /* 11a basic rates: 6, 12, 24Mbps */ + ural_write(sc, RAL_TXRX_CSR11, 0x150); + } else if (IEEE80211_IS_CHAN_ANYG(c)) { + /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ + ural_write(sc, RAL_TXRX_CSR11, 0x15f); + } else { + /* 11b basic rates: 1, 2Mbps */ + ural_write(sc, RAL_TXRX_CSR11, 0x3); } - flags = 0; - if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) - flags |= RAL_TX_ACK; - if (params->ibp_flags & (IEEE80211_BPF_RTS | IEEE80211_BPF_CTS)) { - ural_tx_prot(sc, m, ni, - (params->ibp_flags & IEEE80211_BPF_RTS) ? - IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, - rate); - flags |= RAL_TX_IFS_SIFS; +} + +static void +ural_set_bssid(struct ural_softc *sc, const uint8_t *bssid) +{ + uint16_t tmp; + + tmp = bssid[0] | bssid[1] << 8; + ural_write(sc, RAL_MAC_CSR5, tmp); + + tmp = bssid[2] | bssid[3] << 8; + ural_write(sc, RAL_MAC_CSR6, tmp); + + tmp = bssid[4] | bssid[5] << 8; + ural_write(sc, RAL_MAC_CSR7, tmp); + + DPRINTF("setting BSSID to %6D\n", bssid, ":"); +} + +static void +ural_set_macaddr(struct ural_softc *sc, uint8_t *addr) +{ + uint16_t tmp; + + tmp = addr[0] | addr[1] << 8; + ural_write(sc, RAL_MAC_CSR2, tmp); + + tmp = addr[2] | addr[3] << 8; + ural_write(sc, RAL_MAC_CSR3, tmp); + + tmp = addr[4] | addr[5] << 8; + ural_write(sc, RAL_MAC_CSR4, tmp); + + DPRINTF("setting MAC address to %6D\n", addr, ":"); +} + +static void +ural_promisctask(struct usb2_proc_msg *pm) +{ + struct ural_task *task = (struct ural_task *)pm; + struct ural_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + uint32_t tmp; + + tmp = ural_read(sc, RAL_TXRX_CSR2); + + tmp &= ~RAL_DROP_NOT_TO_ME; + if (!(ifp->if_flags & IFF_PROMISC)) + tmp |= RAL_DROP_NOT_TO_ME; + + ural_write(sc, RAL_TXRX_CSR2, tmp); + + DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? + "entering" : "leaving"); +} + +static const char * +ural_get_rf(int rev) +{ + switch (rev) { + case RAL_RF_2522: return "RT2522"; + case RAL_RF_2523: return "RT2523"; + case RAL_RF_2524: return "RT2524"; + case RAL_RF_2525: return "RT2525"; + case RAL_RF_2525E: return "RT2525e"; + case RAL_RF_2526: return "RT2526"; + case RAL_RF_5222: return "RT5222"; + default: return "unknown"; } - m->m_pkthdr.rcvif = (void *)ni; - ural_setup_desc_and_tx(sc, m, flags, rate); +} + +static void +ural_read_eeprom(struct ural_softc *sc) +{ + uint16_t val; + + ural_eeprom_read(sc, RAL_EEPROM_CONFIG0, &val, 2); + val = le16toh(val); + sc->rf_rev = (val >> 11) & 0x7; + sc->hw_radio = (val >> 10) & 0x1; + sc->led_mode = (val >> 6) & 0x7; + sc->rx_ant = (val >> 4) & 0x3; + sc->tx_ant = (val >> 2) & 0x3; + sc->nb_ant = val & 0x3; + + /* read MAC address */ + ural_eeprom_read(sc, RAL_EEPROM_ADDRESS, sc->sc_bssid, 6); + + /* read default values for BBP registers */ + ural_eeprom_read(sc, RAL_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16); + + /* read Tx power for all b/g channels */ + ural_eeprom_read(sc, RAL_EEPROM_TXPOWER, sc->txpow, 14); } static int -ural_raw_xmit_cb(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) +ural_bbp_init(struct ural_softc *sc) +{ +#define N(a) (sizeof (a) / sizeof ((a)[0])) + int i, ntries; + + /* wait for BBP to be ready */ + for (ntries = 0; ntries < 100; ntries++) { + if (ural_bbp_read(sc, RAL_BBP_VERSION) != 0) + break; + DELAY(1000); + } + if (ntries == 100) { + device_printf(sc->sc_dev, "timeout waiting for BBP\n"); + return EIO; + } + + /* initialize BBP registers to default values */ + for (i = 0; i < N(ural_def_bbp); i++) + ural_bbp_write(sc, ural_def_bbp[i].reg, ural_def_bbp[i].val); + +#if 0 + /* initialize BBP registers to values stored in EEPROM */ + for (i = 0; i < 16; i++) { + if (sc->bbp_prom[i].reg == 0xff) + continue; + ural_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); + } +#endif + + return 0; +#undef N +} + +static void +ural_set_txantenna(struct ural_softc *sc, int antenna) +{ + uint16_t tmp; + uint8_t tx; + + tx = ural_bbp_read(sc, RAL_BBP_TX) & ~RAL_BBP_ANTMASK; + if (antenna == 1) + tx |= RAL_BBP_ANTA; + else if (antenna == 2) + tx |= RAL_BBP_ANTB; + else + tx |= RAL_BBP_DIVERSITY; + + /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ + if (sc->rf_rev == RAL_RF_2525E || sc->rf_rev == RAL_RF_2526 || + sc->rf_rev == RAL_RF_5222) + tx |= RAL_BBP_FLIPIQ; + + ural_bbp_write(sc, RAL_BBP_TX, tx); + + /* update values in PHY_CSR5 and PHY_CSR6 */ + tmp = ural_read(sc, RAL_PHY_CSR5) & ~0x7; + ural_write(sc, RAL_PHY_CSR5, tmp | (tx & 0x7)); + + tmp = ural_read(sc, RAL_PHY_CSR6) & ~0x7; + ural_write(sc, RAL_PHY_CSR6, tmp | (tx & 0x7)); +} + +static void +ural_set_rxantenna(struct ural_softc *sc, int antenna) +{ + uint8_t rx; + + rx = ural_bbp_read(sc, RAL_BBP_RX) & ~RAL_BBP_ANTMASK; + if (antenna == 1) + rx |= RAL_BBP_ANTA; + else if (antenna == 2) + rx |= RAL_BBP_ANTB; + else + rx |= RAL_BBP_DIVERSITY; + + /* need to force no I/Q flip for RF 2525e and 2526 */ + if (sc->rf_rev == RAL_RF_2525E || sc->rf_rev == RAL_RF_2526) + rx &= ~RAL_BBP_FLIPIQ; + + ural_bbp_write(sc, RAL_BBP_RX, rx); +} + +static void +ural_init_task(struct usb2_proc_msg *pm) +{ +#define N(a) (sizeof (a) / sizeof ((a)[0])) + struct ural_task *task = (struct ural_task *)pm; + struct ural_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint16_t tmp; + int i, ntries; + + RAL_LOCK_ASSERT(sc, MA_OWNED); + + ural_set_testmode(sc); + ural_write(sc, 0x308, 0x00f0); /* XXX magic */ + + ural_stop_task(pm); + + /* initialize MAC registers to default values */ + for (i = 0; i < N(ural_def_mac); i++) + ural_write(sc, ural_def_mac[i].reg, ural_def_mac[i].val); + + /* wait for BBP and RF to wake up (this can take a long time!) */ + for (ntries = 0; ntries < 100; ntries++) { + tmp = ural_read(sc, RAL_MAC_CSR17); + if ((tmp & (RAL_BBP_AWAKE | RAL_RF_AWAKE)) == + (RAL_BBP_AWAKE | RAL_RF_AWAKE)) + break; + DELAY(1000); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "timeout waiting for BBP/RF to wakeup\n"); + goto fail; + } + + /* we're ready! */ + ural_write(sc, RAL_MAC_CSR1, RAL_HOST_READY); + + /* set basic rate set (will be updated later) */ + ural_write(sc, RAL_TXRX_CSR11, 0x15f); + + if (ural_bbp_init(sc) != 0) + goto fail; + + ural_set_chan(sc, ic->ic_curchan); + + /* clear statistic registers (STA_CSR0 to STA_CSR10) */ + ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof sc->sta); + + ural_set_txantenna(sc, sc->tx_ant); + ural_set_rxantenna(sc, sc->rx_ant); + + IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); + ural_set_macaddr(sc, ic->ic_myaddr); + + /* + * Allocate Tx and Rx xfer queues. + */ + ural_setup_tx_list(sc); + + /* kick Rx */ + tmp = RAL_DROP_PHY | RAL_DROP_CRC; + if (ic->ic_opmode != IEEE80211_M_MONITOR) { + tmp |= RAL_DROP_CTL | RAL_DROP_BAD_VERSION; + if (ic->ic_opmode != IEEE80211_M_HOSTAP) + tmp |= RAL_DROP_TODS; + if (!(ifp->if_flags & IFF_PROMISC)) + tmp |= RAL_DROP_NOT_TO_ME; + } + ural_write(sc, RAL_TXRX_CSR2, tmp); + + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + usb2_transfer_start(sc->sc_xfer[URAL_BULK_RD]); + return; + +fail: ural_stop_task(pm); +#undef N +} + +static void +ural_init(void *priv) +{ + struct ural_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + RAL_LOCK(sc); + ural_queue_command(sc, ural_init_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + RAL_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void +ural_stop_task(struct usb2_proc_msg *pm) +{ + struct ural_task *task = (struct ural_task *)pm; + struct ural_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + + RAL_LOCK_ASSERT(sc, MA_OWNED); + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + /* + * Drain all the transfers, if not already drained: + */ + RAL_UNLOCK(sc); + usb2_transfer_drain(sc->sc_xfer[URAL_BULK_WR]); + usb2_transfer_drain(sc->sc_xfer[URAL_BULK_RD]); + RAL_LOCK(sc); + + ural_unsetup_tx_list(sc); + + /* disable Rx */ + ural_write(sc, RAL_TXRX_CSR2, RAL_DISABLE_RX); + /* reset ASIC and BBP (but won't reset MAC registers!) */ + ural_write(sc, RAL_MAC_CSR1, RAL_RESET_ASIC | RAL_RESET_BBP); + ural_write(sc, RAL_MAC_CSR1, 0); +} + +static int +ural_raw_xmit(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 ural_softc *sc = ifp->if_softc; - mtx_lock(&sc->sc_mtx); + RAL_LOCK(sc); + /* prevent management frames from being sent if we're not ready */ + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + RAL_UNLOCK(sc); + m_freem(m); + ieee80211_free_node(ni); + return ENETDOWN; + } + if (sc->tx_nfree == 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + RAL_UNLOCK(sc); + m_freem(m); + ieee80211_free_node(ni); + return EIO; + } + + ifp->if_opackets++; + if (params == NULL) { /* * Legacy path; interpret frame contents to decide * precisely how to send the frame. */ - ural_tx_mgt(sc, m, ni); + if (ural_tx_mgt(sc, m, ni) != 0) + goto bad; } else { /* * Caller supplied explicit parameters to use in * sending the frame. */ - ural_tx_raw(sc, m, ni, params); + if (ural_tx_raw(sc, m, ni, params) != 0) + goto bad; } - mtx_unlock(&sc->sc_mtx); - return (0); + RAL_UNLOCK(sc); + return 0; +bad: + ifp->if_oerrors++; + RAL_UNLOCK(sc); + ieee80211_free_node(ni); + return EIO; /* XXX */ } static void -ural_update_mcast_cb(struct ifnet *ifp) +ural_amrr_start(struct ural_softc *sc, struct ieee80211_node *ni) { - /* not supported */ + struct ieee80211vap *vap = ni->ni_vap; + struct ural_vap *uvp = URAL_VAP(vap); + + /* clear statistic registers (STA_CSR0 to STA_CSR10) */ + ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof sc->sta); + + ieee80211_amrr_node_init(&uvp->amrr, &URAL_NODE(ni)->amn, ni); + + usb2_callout_reset(&uvp->amrr_ch, hz, ural_amrr_timeout, uvp); } static void -ural_update_promisc_cb(struct ifnet *ifp) +ural_amrr_timeout(void *arg) { - struct ural_softc *sc = ifp->if_softc; + struct ural_vap *uvp = arg; + struct ural_softc *sc = uvp->sc; - mtx_lock(&sc->sc_mtx); - usb2_config_td_queue_command - (&sc->sc_config_td, &ural_config_copy, - &ural_cfg_update_promisc, 0, 0); - mtx_unlock(&sc->sc_mtx); + ural_queue_command(sc, ural_amrr_task, + &uvp->amrr_task[0].hdr, &uvp->amrr_task[1].hdr); } + +static void +ural_amrr_task(struct usb2_proc_msg *pm) +{ + struct ural_task *task = (struct ural_task *)pm; + struct ural_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ural_vap *uvp = URAL_VAP(vap); + struct ieee80211_node *ni = vap->iv_bss; + int ok, fail; + + /* read and clear statistic registers (STA_CSR0 to STA_CSR10) */ + ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof(sc->sta)); + + ok = sc->sta[7] + /* TX ok w/o retry */ + sc->sta[8]; /* TX ok w/ retry */ + fail = sc->sta[9]; /* TX retry-fail count */ + + ieee80211_amrr_tx_update(&URAL_NODE(ni)->amn, + ok+fail, ok, sc->sta[8] + fail); + (void) ieee80211_amrr_choose(ni, &URAL_NODE(ni)->amn); + + ifp->if_oerrors += fail; /* count TX retry-fail as Tx errors */ + + usb2_callout_reset(&uvp->amrr_ch, hz, ural_amrr_timeout, uvp); +} + +static void +ural_queue_command(struct ural_softc *sc, usb2_proc_callback_t *fn, + struct usb2_proc_msg *t0, struct usb2_proc_msg *t1) +{ + struct ural_task *task; + + RAL_LOCK_ASSERT(sc, MA_OWNED); + + if (usb2_proc_is_gone(&sc->sc_tq)) { + DPRINTF("proc is gone\n"); + return; /* nothing to do */ + } + /* + * 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 ural_task *) + usb2_proc_msignal(&sc->sc_tq, t0, t1); + + /* Setup callback and softc pointers */ + task->hdr.pm_callback = fn; + task->sc = sc; + + /* + * Init and stop must be synchronous! + */ + if ((fn == ural_init_task) || (fn == ural_stop_task)) + usb2_proc_mwait(&sc->sc_tq, t0, t1); +} + diff --git a/sys/dev/usb2/wlan/if_uralreg.h b/sys/dev/usb2/wlan/if_uralreg.h index 1837693e03a..042cf5ace51 100644 --- a/sys/dev/usb2/wlan/if_uralreg.h +++ b/sys/dev/usb2/wlan/if_uralreg.h @@ -17,182 +17,195 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RAL_NOISE_FLOOR -95 -#define RAL_RSSI_CORR 120 +#define RAL_NOISE_FLOOR -95 +#define RAL_RSSI_CORR 120 -#define RAL_RX_DESC_SIZE (sizeof (struct ural_rx_desc)) -#define RAL_TX_DESC_SIZE (sizeof (struct ural_tx_desc)) -#define RAL_FRAME_SIZE 0x780 /* NOTE: using 0x980 does not work */ -#if (RAL_FRAME_SIZE % 0x80) -#error "Invalid RAL_FRAME_SIZE" -#endif +#define RAL_RX_DESC_SIZE (sizeof (struct ural_rx_desc)) +#define RAL_TX_DESC_SIZE (sizeof (struct ural_tx_desc)) +#define RAL_FRAME_SIZE 0x780 /* NOTE: using 0x980 does not work */ -#define RAL_CONFIG_NO 1 -#define RAL_IFACE_INDEX 0 +#define RAL_CONFIG_NO 1 +#define RAL_IFACE_INDEX 0 -#define RAL_VENDOR_REQUEST 0x01 -#define RAL_WRITE_MAC 0x02 -#define RAL_READ_MAC 0x03 -#define RAL_WRITE_MULTI_MAC 0x06 -#define RAL_READ_MULTI_MAC 0x07 -#define RAL_READ_EEPROM 0x09 +#define RAL_VENDOR_REQUEST 0x01 +#define RAL_WRITE_MAC 0x02 +#define RAL_READ_MAC 0x03 +#define RAL_WRITE_MULTI_MAC 0x06 +#define RAL_READ_MULTI_MAC 0x07 +#define RAL_READ_EEPROM 0x09 -/* MAC registers. */ -#define RAL_MAC_CSR0 0x0400 /* ASIC Version */ -#define RAL_MAC_CSR1 0x0402 /* System control */ -#define RAL_MAC_CSR2 0x0404 /* MAC addr0 */ -#define RAL_MAC_CSR3 0x0406 /* MAC addr1 */ -#define RAL_MAC_CSR4 0x0408 /* MAC addr2 */ -#define RAL_MAC_CSR5 0x040a /* BSSID0 */ -#define RAL_MAC_CSR6 0x040c /* BSSID1 */ -#define RAL_MAC_CSR7 0x040e /* BSSID2 */ -#define RAL_MAC_CSR8 0x0410 /* Max frame length */ -#define RAL_MAC_CSR9 0x0412 /* Timer control */ -#define RAL_MAC_CSR10 0x0414 /* Slot time */ -#define RAL_MAC_CSR11 0x0416 /* IFS */ -#define RAL_MAC_CSR12 0x0418 /* EIFS */ -#define RAL_MAC_CSR13 0x041a /* Power mode0 */ -#define RAL_MAC_CSR14 0x041c /* Power mode1 */ -#define RAL_MAC_CSR15 0x041e /* Power saving transition0 */ -#define RAL_MAC_CSR16 0x0420 /* Power saving transition1 */ -#define RAL_MAC_CSR17 0x0422 /* Power state control */ -#define RAL_MAC_CSR18 0x0424 /* Auto wake-up control */ -#define RAL_MAC_CSR19 0x0426 /* GPIO control */ -#define RAL_MAC_CSR20 0x0428 /* LED control0 */ -#define RAL_MAC_CSR22 0x042c /* XXX not documented */ +/* + * MAC registers. + */ +#define RAL_MAC_CSR0 0x0400 /* ASIC Version */ +#define RAL_MAC_CSR1 0x0402 /* System control */ +#define RAL_MAC_CSR2 0x0404 /* MAC addr0 */ +#define RAL_MAC_CSR3 0x0406 /* MAC addr1 */ +#define RAL_MAC_CSR4 0x0408 /* MAC addr2 */ +#define RAL_MAC_CSR5 0x040a /* BSSID0 */ +#define RAL_MAC_CSR6 0x040c /* BSSID1 */ +#define RAL_MAC_CSR7 0x040e /* BSSID2 */ +#define RAL_MAC_CSR8 0x0410 /* Max frame length */ +#define RAL_MAC_CSR9 0x0412 /* Timer control */ +#define RAL_MAC_CSR10 0x0414 /* Slot time */ +#define RAL_MAC_CSR11 0x0416 /* IFS */ +#define RAL_MAC_CSR12 0x0418 /* EIFS */ +#define RAL_MAC_CSR13 0x041a /* Power mode0 */ +#define RAL_MAC_CSR14 0x041c /* Power mode1 */ +#define RAL_MAC_CSR15 0x041e /* Power saving transition0 */ +#define RAL_MAC_CSR16 0x0420 /* Power saving transition1 */ +#define RAL_MAC_CSR17 0x0422 /* Power state control */ +#define RAL_MAC_CSR18 0x0424 /* Auto wake-up control */ +#define RAL_MAC_CSR19 0x0426 /* GPIO control */ +#define RAL_MAC_CSR20 0x0428 /* LED control0 */ +#define RAL_MAC_CSR22 0x042c /* XXX not documented */ -/* Tx/Rx Registers. */ -#define RAL_TXRX_CSR0 0x0440 /* Security control */ -#define RAL_TXRX_CSR2 0x0444 /* Rx control */ -#define RAL_TXRX_CSR5 0x044a /* CCK Tx BBP ID0 */ -#define RAL_TXRX_CSR6 0x044c /* CCK Tx BBP ID1 */ -#define RAL_TXRX_CSR7 0x044e /* OFDM Tx BBP ID0 */ -#define RAL_TXRX_CSR8 0x0450 /* OFDM Tx BBP ID1 */ -#define RAL_TXRX_CSR10 0x0454 /* Auto responder control */ -#define RAL_TXRX_CSR11 0x0456 /* Auto responder basic rate */ -#define RAL_TXRX_CSR18 0x0464 /* Beacon interval */ -#define RAL_TXRX_CSR19 0x0466 /* Beacon/sync control */ -#define RAL_TXRX_CSR20 0x0468 /* Beacon alignment */ -#define RAL_TXRX_CSR21 0x046a /* XXX not documented */ +/* + * Tx/Rx Registers. + */ +#define RAL_TXRX_CSR0 0x0440 /* Security control */ +#define RAL_TXRX_CSR2 0x0444 /* Rx control */ +#define RAL_TXRX_CSR5 0x044a /* CCK Tx BBP ID0 */ +#define RAL_TXRX_CSR6 0x044c /* CCK Tx BBP ID1 */ +#define RAL_TXRX_CSR7 0x044e /* OFDM Tx BBP ID0 */ +#define RAL_TXRX_CSR8 0x0450 /* OFDM Tx BBP ID1 */ +#define RAL_TXRX_CSR10 0x0454 /* Auto responder control */ +#define RAL_TXRX_CSR11 0x0456 /* Auto responder basic rate */ +#define RAL_TXRX_CSR18 0x0464 /* Beacon interval */ +#define RAL_TXRX_CSR19 0x0466 /* Beacon/sync control */ +#define RAL_TXRX_CSR20 0x0468 /* Beacon alignment */ +#define RAL_TXRX_CSR21 0x046a /* XXX not documented */ -/* Security registers. */ -#define RAL_SEC_CSR0 0x0480 /* Shared key 0, word 0 */ +/* + * Security registers. + */ +#define RAL_SEC_CSR0 0x0480 /* Shared key 0, word 0 */ -/* PHY registers. */ -#define RAL_PHY_CSR2 0x04c4 /* Tx MAC configuration */ -#define RAL_PHY_CSR4 0x04c8 /* Interface configuration */ -#define RAL_PHY_CSR5 0x04ca /* BBP Pre-Tx CCK */ -#define RAL_PHY_CSR6 0x04cc /* BBP Pre-Tx OFDM */ -#define RAL_PHY_CSR7 0x04ce /* BBP serial control */ -#define RAL_PHY_CSR8 0x04d0 /* BBP serial status */ -#define RAL_PHY_CSR9 0x04d2 /* RF serial control0 */ -#define RAL_PHY_CSR10 0x04d4 /* RF serial control1 */ +/* + * PHY registers. + */ +#define RAL_PHY_CSR2 0x04c4 /* Tx MAC configuration */ +#define RAL_PHY_CSR4 0x04c8 /* Interface configuration */ +#define RAL_PHY_CSR5 0x04ca /* BBP Pre-Tx CCK */ +#define RAL_PHY_CSR6 0x04cc /* BBP Pre-Tx OFDM */ +#define RAL_PHY_CSR7 0x04ce /* BBP serial control */ +#define RAL_PHY_CSR8 0x04d0 /* BBP serial status */ +#define RAL_PHY_CSR9 0x04d2 /* RF serial control0 */ +#define RAL_PHY_CSR10 0x04d4 /* RF serial control1 */ -/* Statistics registers. */ -#define RAL_STA_CSR0 0x04e0 /* FCS error */ +/* + * Statistics registers. + */ +#define RAL_STA_CSR0 0x04e0 /* FCS error */ -#define RAL_DISABLE_RX (1 << 0) -#define RAL_DROP_CRC (1 << 1) -#define RAL_DROP_PHY (1 << 2) -#define RAL_DROP_CTL (1 << 3) -#define RAL_DROP_NOT_TO_ME (1 << 4) -#define RAL_DROP_TODS (1 << 5) -#define RAL_DROP_BAD_VERSION (1 << 6) -#define RAL_DROP_MULTICAST (1 << 9) -#define RAL_DROP_BROADCAST (1 << 10) -#define RAL_SHORT_PREAMBLE (1 << 2) +#define RAL_DISABLE_RX (1 << 0) +#define RAL_DROP_CRC (1 << 1) +#define RAL_DROP_PHY (1 << 2) +#define RAL_DROP_CTL (1 << 3) +#define RAL_DROP_NOT_TO_ME (1 << 4) +#define RAL_DROP_TODS (1 << 5) +#define RAL_DROP_BAD_VERSION (1 << 6) +#define RAL_DROP_MULTICAST (1 << 9) +#define RAL_DROP_BROADCAST (1 << 10) -#define RAL_RESET_ASIC (1 << 0) -#define RAL_RESET_BBP (1 << 1) -#define RAL_HOST_READY (1 << 2) +#define RAL_SHORT_PREAMBLE (1 << 2) -#define RAL_ENABLE_TSF (1 << 0) -#define RAL_ENABLE_TSF_SYNC(x) (((x) & 0x3) << 1) -#define RAL_ENABLE_TBCN (1 << 3) -#define RAL_ENABLE_BEACON_GENERATOR (1 << 4) +#define RAL_RESET_ASIC (1 << 0) +#define RAL_RESET_BBP (1 << 1) +#define RAL_HOST_READY (1 << 2) -#define RAL_RF_AWAKE (3 << 7) -#define RAL_BBP_AWAKE (3 << 5) +#define RAL_ENABLE_TSF (1 << 0) +#define RAL_ENABLE_TSF_SYNC(x) (((x) & 0x3) << 1) +#define RAL_ENABLE_TBCN (1 << 3) +#define RAL_ENABLE_BEACON_GENERATOR (1 << 4) -#define RAL_BBP_WRITE (1 << 15) -#define RAL_BBP_BUSY (1 << 0) +#define RAL_RF_AWAKE (3 << 7) +#define RAL_BBP_AWAKE (3 << 5) -#define RAL_RF1_AUTOTUNE 0x08000 -#define RAL_RF3_AUTOTUNE 0x00040 +#define RAL_BBP_WRITE (1 << 15) +#define RAL_BBP_BUSY (1 << 0) -#define RAL_RF_2522 0x00 -#define RAL_RF_2523 0x01 -#define RAL_RF_2524 0x02 -#define RAL_RF_2525 0x03 -#define RAL_RF_2525E 0x04 -#define RAL_RF_2526 0x05 +#define RAL_RF1_AUTOTUNE 0x08000 +#define RAL_RF3_AUTOTUNE 0x00040 + +#define RAL_RF_2522 0x00 +#define RAL_RF_2523 0x01 +#define RAL_RF_2524 0x02 +#define RAL_RF_2525 0x03 +#define RAL_RF_2525E 0x04 +#define RAL_RF_2526 0x05 /* dual-band RF */ -#define RAL_RF_5222 0x10 +#define RAL_RF_5222 0x10 -#define RAL_BBP_VERSION 0 -#define RAL_BBP_TX 2 -#define RAL_BBP_RX 14 +#define RAL_BBP_VERSION 0 +#define RAL_BBP_TX 2 +#define RAL_BBP_RX 14 -#define RAL_BBP_ANTA 0x00 -#define RAL_BBP_DIVERSITY 0x01 -#define RAL_BBP_ANTB 0x02 -#define RAL_BBP_ANTMASK 0x03 -#define RAL_BBP_FLIPIQ 0x04 +#define RAL_BBP_ANTA 0x00 +#define RAL_BBP_DIVERSITY 0x01 +#define RAL_BBP_ANTB 0x02 +#define RAL_BBP_ANTMASK 0x03 +#define RAL_BBP_FLIPIQ 0x04 -#define RAL_JAPAN_FILTER 0x08 - -#define RAL_RF_LOBUSY (1 << 15) -#define RAL_RF_BUSY (1 << 31) -#define RAL_RF_20BIT (20 << 24) - -#define RAL_RF1 0 -#define RAL_RF2 2 -#define RAL_RF3 1 -#define RAL_RF4 3 - -#define RAL_EEPROM_ADDRESS 0x0004 -#define RAL_EEPROM_TXPOWER 0x003c -#define RAL_EEPROM_CONFIG0 0x0016 -#define RAL_EEPROM_BBP_BASE 0x001c +#define RAL_JAPAN_FILTER 0x08 struct ural_tx_desc { - uint32_t flags; -#define RAL_TX_PACKET_ID(x) ((x) & 0xf) -#define RAL_TX_RETRY(x) ((x) << 4) -#define RAL_TX_MORE_FRAG (1 << 8) -#define RAL_TX_ACK (1 << 9) -#define RAL_TX_TIMESTAMP (1 << 10) -#define RAL_TX_OFDM (1 << 11) -#define RAL_TX_NEWSEQ (1 << 12) -#define RAL_TX_IFS_MASK 0x00006000 -#define RAL_TX_IFS_BACKOFF (0 << 13) -#define RAL_TX_IFS_SIFS (1 << 13) -#define RAL_TX_IFS_NEWBACKOFF (2 << 13) -#define RAL_TX_IFS_NONE (3 << 13) - uint16_t wme; -#define RAL_LOGCWMAX(x) (((x) & 0xf) << 12) -#define RAL_LOGCWMIN(x) (((x) & 0xf) << 8) -#define RAL_AIFSN(x) (((x) & 0x3) << 6) -#define RAL_IVOFFSET(x) (((x) & 0x3f)) - uint16_t reserved1; - uint8_t plcp_signal; - uint8_t plcp_service; -#define RAL_PLCP_LENGEXT 0x80 - uint8_t plcp_length_lo; - uint8_t plcp_length_hi; - uint32_t iv; - uint32_t eiv; + uint32_t flags; +#define RAL_TX_RETRY(x) ((x) << 4) +#define RAL_TX_MORE_FRAG (1 << 8) +#define RAL_TX_ACK (1 << 9) +#define RAL_TX_TIMESTAMP (1 << 10) +#define RAL_TX_OFDM (1 << 11) +#define RAL_TX_NEWSEQ (1 << 12) + +#define RAL_TX_IFS_MASK 0x00006000 +#define RAL_TX_IFS_BACKOFF (0 << 13) +#define RAL_TX_IFS_SIFS (1 << 13) +#define RAL_TX_IFS_NEWBACKOFF (2 << 13) +#define RAL_TX_IFS_NONE (3 << 13) + + uint16_t wme; +#define RAL_LOGCWMAX(x) (((x) & 0xf) << 12) +#define RAL_LOGCWMIN(x) (((x) & 0xf) << 8) +#define RAL_AIFSN(x) (((x) & 0x3) << 6) +#define RAL_IVOFFSET(x) (((x) & 0x3f)) + + uint16_t reserved1; + uint8_t plcp_signal; + uint8_t plcp_service; +#define RAL_PLCP_LENGEXT 0x80 + + uint8_t plcp_length_lo; + uint8_t plcp_length_hi; + uint32_t iv; + uint32_t eiv; } __packed; struct ural_rx_desc { - uint32_t flags; -#define RAL_RX_CRC_ERROR (1 << 5) -#define RAL_RX_OFDM (1 << 6) -#define RAL_RX_PHY_ERROR (1 << 7) - uint8_t rssi; - uint8_t rate; - uint16_t reserved; - uint32_t iv; - uint32_t eiv; + uint32_t flags; +#define RAL_RX_CRC_ERROR (1 << 5) +#define RAL_RX_OFDM (1 << 6) +#define RAL_RX_PHY_ERROR (1 << 7) + + uint8_t rssi; + uint8_t rate; + uint16_t reserved; + + uint32_t iv; + uint32_t eiv; } __packed; + +#define RAL_RF_LOBUSY (1 << 15) +#define RAL_RF_BUSY (1 << 31) +#define RAL_RF_20BIT (20 << 24) + +#define RAL_RF1 0 +#define RAL_RF2 2 +#define RAL_RF3 1 +#define RAL_RF4 3 + +#define RAL_EEPROM_ADDRESS 0x0004 +#define RAL_EEPROM_TXPOWER 0x003c +#define RAL_EEPROM_CONFIG0 0x0016 +#define RAL_EEPROM_BBP_BASE 0x001c diff --git a/sys/dev/usb2/wlan/if_uralvar.h b/sys/dev/usb2/wlan/if_uralvar.h index bab8965f791..c7e546951e8 100644 --- a/sys/dev/usb2/wlan/if_uralvar.h +++ b/sys/dev/usb2/wlan/if_uralvar.h @@ -17,150 +17,139 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct ural_node { - struct ieee80211_node ni; - struct ieee80211_amrr_node amn; -}; +#define RAL_TX_LIST_COUNT 8 -#define URAL_NODE(ni) ((struct ural_node *)(ni)) +#define URAL_SCAN_START 1 +#define URAL_SCAN_END 2 +#define URAL_SET_CHANNEL 3 -struct ural_vap { - struct ieee80211vap vap; - struct ieee80211_beacon_offsets bo; - struct ieee80211_amrr amrr; - - int (*newstate) (struct ieee80211vap *, - enum ieee80211_state, int); -}; - -#define URAL_VAP(vap) ((struct ural_vap *)(vap)) - -struct ural_config_copy_chan { - uint32_t chan_to_ieee; - enum ieee80211_phymode chan_to_mode; - uint8_t chan_is_5ghz:1; - uint8_t chan_is_2ghz:1; - uint8_t chan_is_b:1; - uint8_t chan_is_a:1; - uint8_t chan_is_g:1; - uint8_t unused:3; -}; - -struct ural_config_copy_bss { - uint16_t ni_intval; - uint8_t ni_bssid[IEEE80211_ADDR_LEN]; - uint8_t fixed_rate_none; -}; - -struct ural_config_copy { - struct ural_config_copy_chan ic_curchan; - struct ural_config_copy_chan ic_bsschan; - struct ural_config_copy_bss iv_bss; - - enum ieee80211_opmode ic_opmode; - uint32_t ic_flags; - uint32_t if_flags; - - uint16_t ic_txpowlimit; - uint16_t ic_curmode; - - uint8_t ic_myaddr[IEEE80211_ADDR_LEN]; - uint8_t if_broadcastaddr[IEEE80211_ADDR_LEN]; -}; struct ural_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; - uint8_t wr_flags; - uint8_t wr_rate; - uint16_t wr_chan_freq; - uint16_t wr_chan_flags; - uint8_t wr_antenna; - uint8_t wr_antsignal; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + uint8_t wr_antenna; + uint8_t wr_antsignal; }; -#define RAL_RX_RADIOTAP_PRESENT \ - ((1 << IEEE80211_RADIOTAP_FLAGS) | \ - (1 << IEEE80211_RADIOTAP_RATE) | \ - (1 << IEEE80211_RADIOTAP_CHANNEL) | \ - (1 << IEEE80211_RADIOTAP_ANTENNA) | \ - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)) +#define RAL_RX_RADIOTAP_PRESENT \ + ((1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)) struct ural_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; - uint8_t wt_flags; - uint8_t wt_rate; - uint16_t wt_chan_freq; - uint16_t wt_chan_flags; - uint8_t wt_antenna; + uint8_t wt_flags; + uint8_t wt_rate; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; + uint8_t wt_antenna; }; -#define RAL_TX_RADIOTAP_PRESENT \ - ((1 << IEEE80211_RADIOTAP_FLAGS) | \ - (1 << IEEE80211_RADIOTAP_RATE) | \ - (1 << IEEE80211_RADIOTAP_CHANNEL) | \ - (1 << IEEE80211_RADIOTAP_ANTENNA)) +#define RAL_TX_RADIOTAP_PRESENT \ + ((1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA)) -struct ural_bbp_prom { - uint8_t val; - uint8_t reg; -} __packed; +struct ural_softc; -struct ural_ifq { - struct mbuf *ifq_head; - struct mbuf *ifq_tail; - uint16_t ifq_len; +struct ural_task { + struct usb2_proc_msg hdr; + struct ural_softc *sc; }; +struct ural_tx_data { + STAILQ_ENTRY(ural_tx_data) next; + struct ural_softc *sc; + struct ural_tx_desc desc; + struct mbuf *m; + struct ieee80211_node *ni; + int rate; +}; +typedef STAILQ_HEAD(, ural_tx_data) ural_txdhead; + +struct ural_node { + struct ieee80211_node ni; + struct ieee80211_amrr_node amn; +}; +#define URAL_NODE(ni) ((struct ural_node *)(ni)) + +struct ural_vap { + struct ieee80211vap vap; + struct ural_softc *sc; + struct ieee80211_beacon_offsets bo; + struct ieee80211_amrr amrr; + struct usb2_callout amrr_ch; + struct ural_task amrr_task[2]; + + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); +}; +#define URAL_VAP(vap) ((struct ural_vap *)(vap)) + enum { - URAL_BULK_DT_WR, - URAL_BULK_DT_RD, - URAL_BULK_CS_WR, - URAL_BULK_CS_RD, - URAL_N_TRANSFER = 4, + URAL_BULK_WR, + URAL_BULK_RD, + URAL_N_TRANSFER = 2, }; struct ural_softc { - struct ifnet *sc_ifp; + struct ifnet *sc_ifp; + device_t sc_dev; + struct usb2_device *sc_udev; + struct usb2_process sc_tq; - struct ural_ifq sc_tx_queue; - struct usb2_config_td sc_config_td; - struct ural_tx_desc sc_tx_desc; - struct ural_rx_desc sc_rx_desc; - struct mtx sc_mtx; - struct usb2_callout sc_watchdog; - struct ural_bbp_prom sc_bbp_prom[16]; - struct ural_rx_radiotap_header sc_rxtap; - struct ural_tx_radiotap_header sc_txtap; - - struct usb2_xfer *sc_xfer[URAL_N_TRANSFER]; - struct usb2_device *sc_udev; const struct ieee80211_rate_table *sc_rates; - enum ieee80211_state sc_ns_state; - uint32_t sc_unit; - uint32_t sc_asic_rev; - uint32_t sc_rf_regs[4]; - int sc_ns_arg; + uint32_t asic_rev; + uint8_t rf_rev; - uint16_t sc_flags; -#define URAL_FLAG_READ_STALL 0x0001 -#define URAL_FLAG_WRITE_STALL 0x0002 -#define URAL_FLAG_LL_READY 0x0004 -#define URAL_FLAG_HL_READY 0x0008 -#define URAL_FLAG_WAIT_COMMAND 0x0010 - uint16_t sc_txtap_len; - uint16_t sc_rxtap_len; - uint16_t sc_sta[11]; + struct usb2_xfer *sc_xfer[URAL_N_TRANSFER]; - uint8_t sc_rf_rev; - uint8_t sc_txpow[14]; - uint8_t sc_led_mode; - uint8_t sc_hw_radio; - uint8_t sc_rx_ant; - uint8_t sc_tx_ant; - uint8_t sc_nb_ant; - uint8_t sc_amrr_timer; - uint8_t sc_myaddr[IEEE80211_ADDR_LEN]; + enum ieee80211_state sc_state; + int sc_arg; + int sc_scan_action; /* should be an enum */ + struct ural_task sc_synctask[2]; + struct ural_task sc_task[2]; + struct ural_task sc_promisctask[2]; + struct ural_task sc_scantask[2]; - char sc_name[32]; + struct ural_tx_data tx_data[RAL_TX_LIST_COUNT]; + ural_txdhead tx_q; + ural_txdhead tx_free; + int tx_nfree; + struct ural_rx_desc sc_rx_desc; + + struct mtx sc_mtx; + + uint16_t sta[11]; + uint32_t rf_regs[4]; + uint8_t txpow[14]; + uint8_t sc_bssid[6]; + + struct { + uint8_t val; + uint8_t reg; + } __packed bbp_prom[16]; + + int led_mode; + int hw_radio; + int rx_ant; + int tx_ant; + int nb_ant; + + struct ural_rx_radiotap_header sc_rxtap; + int sc_rxtap_len; + + struct ural_tx_radiotap_header sc_txtap; + int sc_txtap_len; }; + +#define RAL_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define RAL_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define RAL_LOCK_ASSERT(sc, t) mtx_assert(&(sc)->sc_mtx, t) diff --git a/sys/dev/usb2/wlan/if_zyd2.c b/sys/dev/usb2/wlan/if_zyd2.c index 5b61f008891..0195bd8ea4a 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 @@ -34,15 +31,9 @@ __FBSDID("$FreeBSD$"); #include #include -#define usb2_config_td_cc zyd_config_copy -#define usb2_config_td_softc zyd_softc - -#define USB_DEBUG_VAR zyd_debug - #include #include #include -#include #include #include #include @@ -58,1009 +49,258 @@ 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 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 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 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) -{ - if (isofdm) { - static const uint8_t ofdmrates[16] = - {0, 0, 0, 0, 0, 0, 0, 96, 48, 24, 12, 108, 72, 36, 18}; - - 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}; - - return cckrates[signal & 0xf]; - } -} - -/* - * USB request basic wrapper - */ -static void -zyd_cfg_usbrequest(struct zyd_softc *sc, struct usb2_device_request *req, uint8_t *data) -{ - usb2_error_t err; - uint16_t length; - - if (usb2_config_td_is_gone(&sc->sc_config_td)) { - goto error; - } - err = usb2_do_request_flags - (sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 1000); - - if (err) { - - DPRINTFN(0, "%s: device request failed, err=%s " - "(ignored)\n", sc->sc_name, usb2_errstr(err)); - -error: - length = UGETW(req->wLength); - - if ((req->bmRequestType & UT_READ) && length) { - bzero(data, length); - } - } -} - -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]; - - 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); - } -} - -/* - * Callback handler for interrupt transfer - */ -static void -zyd_intr_read_callback(struct usb2_xfer *xfer) -{ - 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 */ - - 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; - - default: /* Error */ - DPRINTFN(3, "error = %s\n", - usb2_errstr(xfer->error)); - - 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; - } - return; - -handle_notif_retrystatus:{ - - struct zyd_notif_retry *retry = (void *)(cmd->data); - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211vap *vap; - struct ieee80211_node *ni; - - 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)); - - 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; - } - -handle_notif_iord: - - 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; - - sc->sc_intr_ilen = actlen; - - 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! - */ -} - -/* - * Interrupt call reply transfer, read - */ -static void -zyd_cfg_usb2_intr_read(struct zyd_softc *sc, void *data, uint32_t size) -{ - 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; - - while (sc->sc_intr_iwakeup) { - - /* wait for data */ - - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_DT_RD]); - - 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; - } - } - - 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]; - - 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); - } -} - -static void -zyd_intr_write_callback(struct usb2_xfer *xfer) -{ - 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); - - xfer->frlengths[0] = sc->sc_intr_olen; - usb2_start_hardware(xfer); - } - break; - - default: /* Error */ - DPRINTFN(3, "error = %s\n", - usb2_errstr(xfer->error)); - - 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; - -wakeup: - if (sc->sc_intr_owakeup) { - sc->sc_intr_owakeup = 0; - usb2_cv_signal(&sc->sc_intr_cv); - } -} - -/* - * 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) -{ - 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]); - - 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; -} - -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_cfg_usb2_intr_write(sc, idata, code, ilen); - - if (flags & ZYD_CMD_FLAG_READ) { - zyd_cfg_usb2_intr_read(sc, odata, olen); - } -} - -static void -zyd_cfg_read16(struct zyd_softc *sc, uint16_t addr, uint16_t *value) -{ - 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); -} - -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]; - - pair[0].reg = htole16(reg); - pair[0].val = htole16(val); - - zyd_cfg_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0); -} - -static void -zyd_cfg_write32(struct zyd_softc *sc, uint16_t reg, uint32_t val) -{ - 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); - - zyd_cfg_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0); -} - -/*------------------------------------------------------------------------* - * 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; - - 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); - } - 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) -{ - struct zyd_softc *sc = xfer->priv_sc; - struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_BULK_DT_RD]; - - 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); - } -} - -static void -zyd_bulk_read_callback_sub(struct usb2_xfer *xfer, struct zyd_ifq *mq, - uint32_t offset, uint16_t len) -{ - enum { - ZYD_OVERHEAD = (ZYD_HW_PADDING + IEEE80211_CRC_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; - - 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; - - /* 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); - - if (m == NULL) { - DPRINTF("could not allocate rx mbuf\n"); - ifp->if_ierrors++; - return; - } - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = len; - m->m_len = len; - - usb2_copy_out(xfer->frbuffers, offset + - sizeof(plcp), m->m_data, len); - - if (bpf_peers_present(ifp->if_bpf)) { - struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap; - - 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 */ - - 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_ENQUEUE(mq, m); -} - -static void -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 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; - - switch (USB_GET_STATE(xfer)) { - case USB_ST_TRANSFERRED: - - 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)); - - if (UGETW(rx_desc.tag) == ZYD_TAG_MULTIFRAME) { - - offset = 0; - - DPRINTFN(4, "received multi-frame transfer, " - "%u bytes\n", xfer->actlen); - - for (x = 0; x < ZYD_MAX_RXFRAMECNT; x++) { - len16 = UGETW(rx_desc.len[x]); - - if ((len16 == 0) || (len16 > xfer->actlen)) { - break; - } - zyd_bulk_read_callback_sub(xfer, &mq, offset, len16); - - /* - * next frame is aligned on a 32-bit - * boundary - */ - len16 = (len16 + 3) & ~3; - offset += len16; - if (len16 > xfer->actlen) { - break; - } - xfer->actlen -= len16; - } - } else { - DPRINTFN(4, "received single-frame transfer, " - "%u bytes\n", xfer->actlen); - zyd_bulk_read_callback_sub(xfer, &mq, 0, xfer->actlen); - } - - 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); - } - - /* - * 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) { - - mtx_unlock(&sc->sc_mtx); - - while (1) { - - _IF_DEQUEUE(&mq, m); - - if (m == NULL) - break; - - 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 */ - } - } - } - - mtx_lock(&sc->sc_mtx); - } - break; - - default: /* Error */ - DPRINTF("frame 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]); - } - 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) -{ - 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)); - - addr += (temp / 2); - fw_len -= temp; - fw_ptr += temp; - } - - /* 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)); - - zyd_cfg_usbrequest(sc, &req, &stat); - - return ((stat & 0x80) ? 1 : 0); -} - -/* - * Driver OS interface - */ - -/* - * Probe for a ZD1211-containing product - */ static int -zyd_probe(device_t dev) +zyd_match(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb2_mode != USB_MODE_HOST) return (ENXIO); - } - if (uaa->info.bConfigIndex != 0) { + if (uaa->info.bConfigIndex != ZYD_CONFIG_INDEX) return (ENXIO); - } - if (uaa->info.bIfaceIndex != ZYD_IFACE_INDEX) { + if (uaa->info.bIfaceIndex != ZYD_IFACE_INDEX) return (ENXIO); - } + return (usb2_lookup_id_by_uaa(zyd_devs, sizeof(zyd_devs), uaa)); } -/* - * Attach the interface. Allocate softc structures, do - * setup and ethernet/BPF attach. - */ static int zyd_attach(device_t dev) { @@ -1075,93 +315,1838 @@ zyd_attach(device_t dev) 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_dev = dev; sc->sc_udev = uaa->device; - sc->sc_mac_rev = USB_GET_DRIVER_INFO(uaa); + sc->sc_macrev = USB_GET_DRIVER_INFO(uaa); - mtx_init(&sc->sc_mtx, "zyd lock", MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), + MTX_NETWORK_LOCK, MTX_DEF); - usb2_cv_init(&sc->sc_intr_cv, "IWAIT"); + STAILQ_INIT(&sc->sc_rqh); - usb2_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); - - /* - * 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); + 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)); + device_printf(dev, "could not allocate USB transfers, " + "err=%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); + 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"); + device_printf(dev, "could not setup config thread!\n"); goto detach; } - mtx_lock(&sc->sc_mtx); - /* start setup */ - - usb2_config_td_queue_command - (&sc->sc_config_td, NULL, &zyd_cfg_first_time_setup, 0, 0); - - zyd_watchdog(sc); - mtx_unlock(&sc->sc_mtx); + /* 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); detach: zyd_detach(dev); - return (ENXIO); + return (ENXIO); /* failure */ +} + +static void +zyd_attach_post(struct usb2_proc_msg *pm) +{ + 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; + + if ((error = zyd_get_macaddr(sc)) != 0) { + device_printf(sc->sc_dev, "could not read EEPROM\n"); + return; + } + + ZYD_UNLOCK(sc); + + 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; + } + 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); + + 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); + + /* 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 */ + ; + + bands = 0; + setbit(&bands, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11G); + ieee80211_init_channels(ic, NULL, &bands); + + 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; + + ic->ic_vap_create = zyd_vap_create; + ic->ic_vap_delete = zyd_vap_delete; + ic->ic_update_mcast = zyd_update_mcast; + + 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); + + if (bootverbose) + ieee80211_announce(ic); + + ZYD_LOCK(sc); +} + +static int +zyd_detach(device_t dev) +{ + struct zyd_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + /* wait for any post attach or other command to complete */ + usb2_proc_drain(&sc->sc_tq); + + /* stop all USB transfers */ + usb2_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); + usb2_proc_free(&sc->sc_tq); + + /* free TX list, if any */ + zyd_unsetup_tx_list(sc); + + if (ifp) { + bpfdetach(ifp); + ieee80211_ifdetach(ic); + if_free(ifp); + } + + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +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_vap *zvp; + struct ieee80211vap *vap; + + 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); + + /* override state transition machine */ + zvp->newstate = vap->iv_newstate; + vap->iv_newstate = zyd_newstate; + + ieee80211_amrr_init(&zvp->amrr, vap, + IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, + IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, + 1000 /* 1 sec */); + + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, + ieee80211_media_status); + ic->ic_opmode = opmode; + return (vap); +} + +static void +zyd_vap_delete(struct ieee80211vap *vap) +{ + struct zyd_vap *zvp = ZYD_VAP(vap); + + ieee80211_amrr_cleanup(&zvp->amrr); + ieee80211_vap_detach(vap); + free(zvp, M_80211_VAP); +} + +static void +zyd_tx_free(struct zyd_tx_data *data, int txerr) +{ + 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; + + ieee80211_free_node(data->ni); + data->ni = NULL; + } + STAILQ_INSERT_TAIL(&sc->tx_free, data, next); + sc->tx_nfree++; +} + +static void +zyd_setup_tx_list(struct zyd_softc *sc) +{ + struct zyd_tx_data *data; + int i; + + sc->tx_nfree = 0; + STAILQ_INIT(&sc->tx_q); + STAILQ_INIT(&sc->tx_free); + + for (i = 0; i < ZYD_TX_LIST_CNT; i++) { + data = &sc->tx_data[i]; + + data->sc = sc; + STAILQ_INSERT_TAIL(&sc->tx_free, data, next); + sc->tx_nfree++; + } +} + +static void +zyd_unsetup_tx_list(struct zyd_softc *sc) +{ + struct zyd_tx_data *data; + int i; + + /* make sure any subsequent use of the queues will fail */ + sc->tx_nfree = 0; + STAILQ_INIT(&sc->tx_q); + STAILQ_INIT(&sc->tx_free); + + /* free up all node references and mbufs */ + for (i = 0; i < ZYD_TX_LIST_CNT; i++) { + data = &sc->tx_data[i]; + + if (data->m != NULL) { + m_freem(data->m); + data->m = NULL; + } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; + } + } +} + +/* ARGUSED */ +static struct ieee80211_node * +zyd_node_alloc(struct ieee80211vap *vap __unused, + const uint8_t mac[IEEE80211_ADDR_LEN] __unused) +{ + struct zyd_node *zn; + + zn = malloc(sizeof(struct zyd_node), M_80211_NODE, M_NOWAIT | M_ZERO); + return (zn != NULL) ? (&zn->ni) : (NULL); +} + +static void +zyd_task(struct usb2_proc_msg *pm) +{ + 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 ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211_node *ni = vap->iv_bss; + struct zyd_vap *zvp = ZYD_VAP(vap); + int error; + + 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; + + /* 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; + } +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); +} + +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; + + DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[nstate]); + + ZYD_LOCK(sc); + /* do it in a process context */ + sc->sc_state = nstate; + sc->sc_arg = arg; + ZYD_UNLOCK(sc); + + 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); + } } /* - * Lock PHY registers + * Callback handler for interrupt transfer */ static void -zyd_cfg_lock_phy(struct zyd_softc *sc) +zyd_intr_read_callback(struct usb2_xfer *xfer) { - uint32_t temp; + 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_cmd *cmd = &sc->sc_ibuf; + int datalen; - zyd_cfg_read32(sc, ZYD_MAC_MISC, &temp); - temp &= ~ZYD_UNLOCK_PHY_REGS; - zyd_cfg_write32(sc, ZYD_MAC_MISC, temp); + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + usb2_copy_out(xfer->frbuffers, 0, cmd, sizeof(*cmd)); + + switch (le16toh(cmd->code)) { + case ZYD_NOTIF_RETRYSTATUS: + { + struct zyd_notif_retry *retry = + (struct zyd_notif_retry *)cmd->data; + + 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)); + + /* + * 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; + + if (le16toh(*(uint16_t *)cmd->data) == ZYD_CR_INTERRUPT) + break; /* HMAC interrupt */ + + datalen = xfer->actlen - sizeof(cmd->code); + datalen -= 2; /* XXX: padding? */ + + STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) { + int i, cnt; + + 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; + } + 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; + } + 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: + xfer->frlengths[0] = xfer->max_data_length; + usb2_start_hardware(xfer); + break; + + default: /* Error */ + DPRINTF(sc, ZYD_DEBUG_CMD, "error = %s\n", + usb2_errstr(xfer->error)); + + if (xfer->error != USB_ERR_CANCELLED) { + /* try to clear stall first */ + xfer->flags.stall_pipe = 1; + goto tr_setup; + } + break; + } +} + +static void +zyd_intr_write_callback(struct usb2_xfer *xfer) +{ + struct zyd_softc *sc = xfer->priv_sc; + struct zyd_rq *rqp; + + 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 */ + + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) { + if (rqp->flags & ZYD_CMD_FLAG_SENT) + continue; + + usb2_copy_in(xfer->frbuffers, 0, rqp->cmd, rqp->ilen); + + xfer->frlengths[0] = rqp->ilen; + xfer->priv_fifo = rqp; + rqp->flags |= ZYD_CMD_FLAG_SENT; + usb2_start_hardware(xfer); + break; + } + break; + + default: /* Error */ + DPRINTF(sc, ZYD_DEBUG_ANY, "error = %s\n", + usb2_errstr(xfer->error)); + + if (xfer->error != USB_ERR_CANCELLED) { + /* try to clear stall first */ + xfer->flags.stall_pipe = 1; + goto tr_setup; + } + break; + } +} + +static int +zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen, + void *odata, int olen, u_int flags) +{ + struct zyd_cmd cmd; + struct zyd_rq rq; + int error; + + if (ilen > sizeof(cmd.data)) + return (EINVAL); + + if (usb2_proc_is_gone(&sc->sc_tq)) + return (ENXIO); + + 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 (error); +} + +static int +zyd_read16(struct zyd_softc *sc, uint16_t reg, uint16_t *val) +{ + struct zyd_pair tmp; + int error; + + 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); +} + +static int +zyd_read32(struct zyd_softc *sc, uint16_t reg, uint32_t *val) +{ + struct zyd_pair tmp[2]; + uint16_t regs[2]; + int error; + + 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); +} + +static int +zyd_write16(struct zyd_softc *sc, uint16_t reg, uint16_t val) +{ + struct zyd_pair pair; + + pair.reg = htole16(reg); + pair.val = htole16(val); + + return zyd_cmd(sc, ZYD_CMD_IOWR, &pair, sizeof(pair), NULL, 0, 0); +} + +static int +zyd_write32(struct zyd_softc *sc, uint16_t reg, uint32_t val) +{ + 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); + + return zyd_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0); +} + +static int +zyd_rfwrite(struct zyd_softc *sc, uint32_t val) +{ + 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); + + 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); +} + +static int +zyd_rfwrite_cr(struct zyd_softc *sc, uint32_t val) +{ + int error; + + 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 int +zyd_lock_phy(struct zyd_softc *sc) +{ + int error; + uint32_t tmp; + + zyd_read32_m(sc, ZYD_MAC_MISC, &tmp); + tmp &= ~ZYD_UNLOCK_PHY_REGS; + zyd_write32_m(sc, ZYD_MAC_MISC, tmp); +fail: + return (error); +} + +static int +zyd_unlock_phy(struct zyd_softc *sc) +{ + int error; + uint32_t tmp; + + zyd_read32_m(sc, ZYD_MAC_MISC, &tmp); + tmp |= ZYD_UNLOCK_PHY_REGS; + zyd_write32_m(sc, ZYD_MAC_MISC, tmp); +fail: + return (error); } /* - * Unlock PHY registers + * RFMD RF methods. */ -static void -zyd_cfg_unlock_phy(struct zyd_softc *sc) +static int +zyd_rfmd_init(struct zyd_rf *rf) { - uint32_t temp; +#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; + int i, error; - zyd_cfg_read32(sc, ZYD_MAC_MISC, &temp); - temp |= ZYD_UNLOCK_PHY_REGS; - zyd_cfg_write32(sc, ZYD_MAC_MISC, temp); + /* init RF-dependent PHY registers */ + for (i = 0; i < N(phyini); i++) { + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + } + + /* init RFMD radio */ + for (i = 0; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); + } +fail: + return (error); +#undef N +} + +static int +zyd_rfmd_switch_radio(struct zyd_rf *rf, int on) +{ + 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); +} + +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; + + 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; + +fail: + return (error); +} + +/* + * AL2230 RF methods. + */ +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 } + }; + 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; + int i, error; + + /* init RF-dependent PHY registers */ + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[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 < N(rfini1); i++) { + error = zyd_rfwrite(sc, rfini1[i]); + if (error != 0) + goto fail; + } + + if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) + error = zyd_rfwrite(sc, 0x000824); + else + error = zyd_rfwrite(sc, 0x0005a4); + if (error != 0) + goto fail; + + for (i = 0; i < N(rfini2); i++) { + error = zyd_rfwrite(sc, rfini2[i]); + if (error != 0) + goto fail; + } + + for (i = 0; i < N(phypll); i++) + zyd_write16_m(sc, phypll[i].reg, phypll[i].val); + + for (i = 0; i < N(rfini3); i++) { + error = zyd_rfwrite(sc, rfini3[i]); + if (error != 0) + goto fail; + } +fail: + return (error); +#undef N +} + +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; + + for (i = 0; i < N(phy); i++) + zyd_write16_m(sc, phy[i].reg, phy[i].val); + + if (sc->sc_newphy != 0) + zyd_write16_m(sc, ZYD_CR9, 0xe1); + + zyd_write16_m(sc, ZYD_CR203, 0x6); +fail: + return (error); +#undef N +} + +static int +zyd_al2230_init_b(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 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; + int i, error; + + 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 < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[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++) { + error = zyd_rfwrite_cr(sc, zyd_al2230_chtable[0][i]); + if (error != 0) + return (error); + } + + for (i = 0; i < N(rfini_part1); i++) { + error = zyd_rfwrite_cr(sc, rfini_part1[i]); + if (error != 0) + return (error); + } + + if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) + error = zyd_rfwrite(sc, 0x241000); + else + 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 < N(rfini_part3); i++) { + error = zyd_rfwrite_cr(sc, rfini_part3[i]); + if (error != 0) + return (error); + } + + for (i = 0; i < N(phy3); i++) + zyd_write16_m(sc, phy3[i].reg, phy3[i].val); + + error = zyd_al2230_fini(rf); +fail: + return (error); +#undef N +} + +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_write16_m(sc, ZYD_CR11, on ? 0x00 : 0x04); + zyd_write16_m(sc, ZYD_CR251, on ? on251 : 0x2f); +fail: + return (error); +} + +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 }, + }; + static const struct { + 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 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; + + 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_CR47, 0x1e } \ +} + +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; + u_int chan = ieee80211_chan2ieee(ic, c); + + if (chan == 1 || chan == 11) + r[0].val = 0x12; + + 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 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; + 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 < 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 < 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 < 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 < 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 < N(phyini_3); i++) + zyd_write16_m(sc, phyini_3[i].reg, phyini_3[i].val); +fail: + return (error); +#undef N +} + +static int +zyd_al7230B_switch_radio(struct zyd_rf *rf, int on) +{ + int error; + struct zyd_softc *sc = rf->rf_sc; + + 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 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; + int i, error; + + zyd_write32_m(sc, ZYD_CR18, 2); + + /* init RF-dependent PHY registers */ + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + + /* init AL2210 radio */ + 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 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_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 */ + error = zyd_rfwrite(sc, rfprog[chan - 1]); + if (error != 0) + goto fail; + + zyd_write32_m(sc, ZYD_CR18, 3); +fail: + return (error); +} + +/* + * GCT RF methods. + */ +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; + int i, error; + + /* init RF-dependent PHY registers */ + for (i = 0; i < N(phyini); i++) + zyd_write16_m(sc, phyini[i].reg, phyini[i].val); + + /* init cgt radio */ + for (i = 0; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); + } +fail: + return (error); +#undef N +} + +static int +zyd_gct_switch_radio(struct zyd_rf *rf, int on) +{ + /* vendor driver does nothing for this RF chip */ + + return (0); +} + +static int +zyd_gct_set_channel(struct zyd_rf *rf, uint8_t chan) +{ + 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); +} + +/* + * 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; + int i, error; + + /* init RF-dependent PHY registers */ + 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 < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); + } + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); +fail: + return (error); +#undef N +} + +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; + uint16_t tmp; + int i, error; + + /* + * Do the same as we do when initializing it, except for the channel + * values coming from the two channel tables. + */ + + /* init RF-dependent PHY registers */ + 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 */ + 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 */ + for (i = 2; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); + } + 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 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; + int i, error; + + /* init RF-dependent PHY registers */ + 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 < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); + } + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); +fail: + return (error); +#undef N +} + +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; + uint16_t tmp; + int i, error; + + /* + * Do the same as we do when initializing it, except for the channel + * values coming from the two channel tables. + */ + + /* init RF-dependent PHY registers */ + 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 */ + 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 */ + for (i = 2; i < N(rfini); i++) { + if ((error = zyd_rfwrite(sc, rfini[i])) != 0) + return (error); + } + zyd_read16_m(sc, ZYD_CR203, &tmp); + zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); +fail: + return (error); +#undef N +} + +static int +zyd_rf_attach(struct zyd_softc *sc, uint8_t type) +{ + struct zyd_rf *rf = &sc->sc_rf; + + rf->rf_sc = sc; + + switch (type) { + case ZYD_RF_RFMD: + 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_macrev == ZYD_ZD1211B) { + rf->init = zyd_al2230_init_b; + rf->set_channel = zyd_al2230_set_channel_b; + } else { + rf->init = zyd_al2230_init; + rf->set_channel = zyd_al2230_set_channel; + } + 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->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->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->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->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->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: + device_printf(sc->sc_dev, + "sorry, radio \"%s\" is not supported yet\n", + zyd_rf_name(type)); + return (EINVAL); + } + return (0); +} + +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 zyd_rfs[(type > 15) ? 0 : type]; +} + +static int +zyd_hw_init(struct zyd_softc *sc) +{ + int error; + const struct zyd_phy_pair *phyp; + struct zyd_rf *rf = &sc->sc_rf; + uint16_t val; + + /* specify that the plug and play is finished */ + 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_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_write32_m(sc, ZYD_MAC_MAN_RATE, 0x150f); + + /* disable interrupts */ + zyd_write32_m(sc, ZYD_CR_INTERRUPT, 0); + + if ((error = zyd_read_pod(sc)) != 0) { + device_printf(sc->sc_dev, "could not read EEPROM\n"); + goto fail; + } + + /* 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); + } + error = zyd_unlock_phy(sc); + if (error != 0) + goto fail; + + /* HMAC init */ + 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_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 */ + 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; + + if ((error = zyd_read_eeprom(sc)) != 0) { + device_printf(sc->sc_dev, "could not read EEPROM\n"); + goto fail; + } + +fail: return (error); +} + +static int +zyd_read_pod(struct zyd_softc *sc) +{ + int error; + uint32_t tmp; + + 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_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; +fail: + return (error); +} + +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_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 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; + USETW(req.wValue, ZYD_EEPROM_MAC_ADDR_P1); + USETW(req.wIndex, 0); + USETW(req.wLength, IEEE80211_ADDR_LEN); + + 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 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_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[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); +} + +static int +zyd_switch_radio(struct zyd_softc *sc, int on) +{ + 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); +} + +static int +zyd_set_led(struct zyd_softc *sc, int which, int on) +{ + int error; + uint32_t 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); } static void -zyd_cfg_set_beacon_interval(struct zyd_softc *sc, uint32_t bintval) +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); +} + +static void +zyd_set_multi(struct zyd_softc *sc) +{ + int error; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ifmultiaddr *ifma; + uint32_t low, high; + uint8_t v; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + low = 0x00000000; + high = 0x80000000; + + if (ic->ic_opmode == IEEE80211_M_MONITOR || + (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { + low = 0xffffffff; + high = 0xffffffff; + } else { + 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); + } + + /* 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"); +} + +static void +zyd_update_mcast(struct ifnet *ifp) +{ + struct zyd_softc *sc = ifp->if_softc; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + ZYD_LOCK(sc); + zyd_queue_command(sc, zyd_multitask, + &sc->sc_mcasttask[0].hdr, &sc->sc_mcasttask[1].hdr); + ZYD_UNLOCK(sc); +} + +static int +zyd_set_rxfilter(struct zyd_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + uint32_t rxfilter; + + 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); + } + return zyd_write32(sc, ZYD_MAC_RXFILTER, rxfilter); +} + +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; + + 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; + } + + error = zyd_lock_phy(sc); + if (error != 0) + goto fail; + + error = (*rf->set_channel)(rf, chan); + if (error != 0) + goto fail; + + /* update Tx power */ + zyd_write16_m(sc, ZYD_CR31, sc->sc_pwrint[chan - 1]); + + 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); + + error = zyd_unlock_phy(sc); + if (error != 0) + goto fail; + + 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; +} + +static int +zyd_set_beacon_interval(struct zyd_softc *sc, int bintval) +{ + int error; uint32_t val; - zyd_cfg_read32(sc, ZYD_CR_ATIM_WND_PERIOD, &val); + zyd_read32_m(sc, ZYD_CR_ATIM_WND_PERIOD, &val); sc->sc_atim_wnd = val; - zyd_cfg_read32(sc, ZYD_CR_PRE_TBTT, &val); + zyd_read32_m(sc, ZYD_CR_PRE_TBTT, &val); sc->sc_pre_tbtt = val; sc->sc_bcn_int = bintval; @@ -1172,1162 +2157,183 @@ zyd_cfg_set_beacon_interval(struct zyd_softc *sc, uint32_t bintval) if (sc->sc_atim_wnd >= sc->sc_pre_tbtt) sc->sc_atim_wnd = sc->sc_pre_tbtt - 1; - 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_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); } -/* - * Get RF name - */ -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 (zyd_rfs[(type > 15) ? 0 : type]); -} - -/* - * RF driver: Init for RFMD chip - */ static void -zyd_cfg_rf_rfmd_init(struct zyd_softc *sc, struct zyd_rf *rf) +zyd_rx_data(struct usb2_xfer *xfer, int offset, uint16_t len) { - static const struct zyd_phy_pair phyini[] = ZYD_RFMD_PHY; - static const uint32_t rfini[] = ZYD_RFMD_RF; - uint32_t i; + 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; - /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); + 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)); + + 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; } - /* init RFMD radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); - } -} + /* compute actual frame length */ + rlen = len - sizeof(struct zyd_plcphdr) - + sizeof(struct zyd_rx_stat) - IEEE80211_CRC_LEN; -/* - * RF driver: Switch radio on/off for RFMD chip - */ -static void -zyd_cfg_rf_rfmd_switch_radio(struct zyd_softc *sc, uint8_t on) -{ - zyd_cfg_write16(sc, ZYD_CR10, on ? 0x89 : 0x15); - zyd_cfg_write16(sc, ZYD_CR11, on ? 0x00 : 0x81); -} - -/* - * 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 const struct { - uint32_t r1, r2; - } rfprog[] = ZYD_RFMD_CHANTABLE; - - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2); -} - -/* - * 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); -} - -/* - * RF driver: Init for AL2230 chip - */ -static void -zyd_cfg_rf_al2230_init(struct zyd_softc *sc, struct zyd_rf *rf) -{ - 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} - }; - 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; - - /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) - zyd_cfg_write16(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); - } - /* init AL2230 radio */ - for (i = 0; i != INDEXES(rfini1); i++) - zyd_cfg_rfwrite(sc, rfini1[i]); - - if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0)) - zyd_cfg_rfwrite(sc, 0x000824); + /* 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 - zyd_cfg_rfwrite(sc, 0x0005a4); - - for (i = 0; i != INDEXES(rfini2); i++) - zyd_cfg_rfwrite(sc, rfini2[i]); - - for (i = 0; i != INDEXES(phypll); i++) - zyd_cfg_write16(sc, phypll[i].reg, phypll[i].val); - - for (i = 0; i != INDEXES(rfini3); i++) - zyd_cfg_rfwrite(sc, rfini3[i]); -} - -static void -zyd_cfg_rf_al2230_fini(struct zyd_softc *sc, struct zyd_rf *rf) -{ - 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); - - if (sc->sc_newphy != 0) - zyd_cfg_write16(sc, ZYD_CR9, 0xe1); - zyd_cfg_write16(sc, ZYD_CR203, 0x6); -} - -static void -zyd_cfg_rf_al2230_init_b(struct zyd_softc *sc, struct zyd_rf *rf) -{ - static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY_B; - 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 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; - - for (i = 0; i != INDEXES(phy1); i++) - zyd_cfg_write16(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); - - 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); - - for (i = 0; i != 3; i++) - zyd_cfg_rfwrite_cr(sc, zyd_al2230_chtable[0][i]); - - for (i = 0; i != INDEXES(rfini_part1); i++) - zyd_cfg_rfwrite_cr(sc, rfini_part1[i]); - - if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0)) - zyd_cfg_rfwrite(sc, 0x241000); - else - zyd_cfg_rfwrite(sc, 0x25a000); - - for (i = 0; i != INDEXES(rfini_part2); i++) - zyd_cfg_rfwrite_cr(sc, rfini_part2[i]); - - for (i = 0; i != INDEXES(phy2); i++) - zyd_cfg_write16(sc, phy2[i].reg, phy2[i].val); - - for (i = 0; i != INDEXES(rfini_part3); i++) - zyd_cfg_rfwrite_cr(sc, rfini_part3[i]); - - for (i = 0; i < INDEXES(phy3); i++) - zyd_cfg_write16(sc, phy3[i].reg, phy3[i].val); - - zyd_cfg_rf_al2230_fini(sc, rf); -} - -/* - * 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 const struct zyd_phy_pair phy1[] = { - {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); -} - -static void -zyd_cfg_rf_al2230_set_channel_b(struct zyd_softc *sc, - struct zyd_rf *rf, uint8_t chan) -{ - 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); -} - -#define ZYD_AL2230_PHY_BANDEDGE6 \ -{ \ - { 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) -{ - struct zyd_phy_pair r[] = ZYD_AL2230_PHY_BANDEDGE6; - uint32_t i; - - 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); -} - -/* - * 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 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; - - /* 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); - } - /* init AL7230B radio, part one */ - for (i = 0; i != INDEXES(rfini_1); i++) { - zyd_cfg_rfwrite(sc, rfini_1[i]); - } - /* 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); - } - /* init AL7230B radio, part two */ - for (i = 0; i != INDEXES(rfini_2); i++) { - zyd_cfg_rfwrite(sc, rfini_2[i]); - } - /* 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); - } -} - -static void -zyd_cfg_rf_al7230b_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) -{ - 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); - - zyd_cfg_write16(sc, ZYD_CR251, 0x3f); - zyd_cfg_write16(sc, ZYD_CR203, 0x06); - zyd_cfg_write16(sc, ZYD_CR240, 0x08); - -} - -/* - * 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 const struct zyd_phy_pair phyini[] = ZYD_AL2210_PHY; - static const uint32_t rfini[] = ZYD_AL2210_RF; - uint32_t tmp; - uint32_t i; - - zyd_cfg_write32(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); - } - /* 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); -} - -static void -zyd_cfg_rf_al2210_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) -{ - 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); - - /* actually set the channel */ - zyd_cfg_rfwrite(sc, rfprog[channel - 1]); - - zyd_cfg_write32(sc, ZYD_CR18, 3); -} - -/* - * 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 const struct zyd_phy_pair phyini[] = ZYD_GCT_PHY; - static const uint32_t rfini[] = ZYD_GCT_RF; - uint32_t i; - - /* init RF-dependent PHY registers */ - for (i = 0; i != INDEXES(phyini); i++) { - zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val); - } - /* init cgt radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); - } -} - -static void -zyd_cfg_rf_gct_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) -{ - static const uint32_t rfprog[] = ZYD_GCT_CHANTABLE; - - zyd_cfg_rfwrite(sc, 0x1c0000); - zyd_cfg_rfwrite(sc, rfprog[channel - 1]); - zyd_cfg_rfwrite(sc, 0x1c0008); -} - -/* - * Maxim RF methods. - */ -static void -zyd_cfg_rf_maxim_switch_radio(struct zyd_softc *sc, uint8_t on) -{ - /* vendor driver does nothing for this RF chip */ - -} - -static void -zyd_cfg_rf_maxim_init(struct zyd_softc *sc, struct zyd_rf *rf) -{ - static const struct zyd_phy_pair phyini[] = ZYD_MAXIM_PHY; - static const uint32_t rfini[] = ZYD_MAXIM_RF; - uint16_t tmp; - uint32_t i; - - /* 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)); - - /* init maxim radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); - } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4)); -} - -static void -zyd_cfg_rf_maxim_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) -{ - 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; - uint16_t tmp; - uint32_t i; - - /* - * Do the same as we do when initializing it, except for the channel - * values coming from the two channel tables. - */ - - /* 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)); - - /* first two values taken from the chantables */ - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2); - - /* 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]); - } - } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4)); -} - -/* - * 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 const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY; - static const uint32_t rfini[] = ZYD_MAXIM2_RF; - uint16_t tmp; - uint32_t i; - - /* 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)); - - /* init maxim2 radio */ - for (i = 0; i != INDEXES(rfini); i++) { - zyd_cfg_rfwrite(sc, rfini[i]); - } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4)); -} - -static void -zyd_cfg_rf_maxim2_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, - uint8_t channel) -{ - 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; - uint16_t tmp; - uint32_t i; - - /* - * Do the same as we do when initializing it, except for the channel - * values coming from the two channel tables. - */ - - /* 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)); - - /* first two values taken from the chantables */ - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1); - zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2); - - /* 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]); - } - } - zyd_cfg_read16(sc, ZYD_CR203, &tmp); - zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4)); -} - -/* - * Assign drivers and init the RF - */ -static uint8_t -zyd_cfg_rf_init_hw(struct zyd_softc *sc, struct zyd_rf *rf) -{ - ; /* fix for indent */ - - switch (sc->sc_rf_rev) { - 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 */ - 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; - } else { - rf->cfg_init_hw = zyd_cfg_rf_al2230_init; - rf->cfg_set_channel = zyd_cfg_rf_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 */ - 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 */ - 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 */ - 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 */ - 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 */ - 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 */ - 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); - } - - zyd_cfg_lock_phy(sc); - (rf->cfg_init_hw) (sc, rf); - zyd_cfg_unlock_phy(sc); - - return (0); /* success */ -} - -/* - * Init the hardware - */ -static uint8_t -zyd_cfg_hw_init(struct zyd_softc *sc) -{ - const struct zyd_phy_pair *phyp; - uint32_t tmp; - - /* 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); - - /* 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); - - /* set mandatory rates - XXX assumes 802.11b/g */ - zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x150f); - - /* disable interrupts */ - zyd_cfg_write32(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 ((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); - } - zyd_cfg_unlock_phy(sc); - - /* 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); - } 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); - } - - /* init beacon interval to 100ms */ - zyd_cfg_set_beacon_interval(sc, 100); - - return (0); /* success */ -} - -/* - * Read information from EEPROM - */ -static void -zyd_cfg_read_eeprom(struct zyd_softc *sc) -{ - 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; - sc->sc_fix_cr157 = (tmp >> 13) & 0x01; - sc->sc_pa_rev = (tmp >> 16) & 0x0f; - sc->sc_al2230s = (tmp >> 7) & 0x01; - sc->sc_bandedge6 = (tmp >> 21) & 0x01; - sc->sc_newphy = (tmp >> 31) & 0x01; - sc->sc_txled = ((tmp & (1 << 24)) && (tmp & (1 << 29))) ? 0 : 1; - - /* 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); - - /* 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; - } -} - -static void -zyd_cfg_get_macaddr(struct zyd_softc *sc) -{ - struct usb2_device_request req; - - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = ZYD_READFWDATAREQ; - USETW(req.wValue, ZYD_EEPROM_MAC_ADDR_P1); - USETW(req.wIndex, 0); - USETW(req.wLength, IEEE80211_ADDR_LEN); - - zyd_cfg_usbrequest(sc, &req, sc->sc_myaddr); - return; -} - -static void -zyd_cfg_set_mac_addr(struct zyd_softc *sc, const uint8_t *addr) -{ - 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[5] << 8) | addr[4]; - zyd_cfg_write32(sc, ZYD_MAC_MACADRH, tmp); -} - -/* - * Switch radio on/off - */ -static void -zyd_cfg_switch_radio(struct zyd_softc *sc, uint8_t onoff) -{ - zyd_cfg_lock_phy(sc); - (sc->sc_rf.cfg_switch_radio) (sc, onoff); - zyd_cfg_unlock_phy(sc); -} - -/* - * Set BSSID - */ -static void -zyd_cfg_set_bssid(struct zyd_softc *sc, uint8_t *addr) -{ - uint32_t tmp; - - tmp = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; - zyd_cfg_write32(sc, ZYD_MAC_BSSADRL, tmp); - - tmp = (addr[5] << 8) | addr[4]; - zyd_cfg_write32(sc, ZYD_MAC_BSSADRH, tmp); -} - -/* - * Complete the attach process - */ -static void -zyd_cfg_first_time_setup(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - 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; - - /* 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); - - /* 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); - - if (sc->sc_mac_rev == ZYD_ZD1211) { - fw_ptr = zd1211_firmware; - fw_len = sizeof(zd1211_firmware); - } else { - fw_ptr = zd1211b_firmware; - fw_len = sizeof(zd1211b_firmware); - } - - if (zyd_cfg_uploadfirmware(sc, fw_ptr, fw_len)) { - DPRINTFN(0, "%s: could not " - "upload firmware!\n", sc->sc_name); + 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; } - cd = usb2_get_config_descriptor(sc->sc_udev); + 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); - /* reset device */ - err = usb2_req_set_config(sc->sc_udev, &sc->sc_mtx, - cd->bConfigurationValue); - if (err) { - DPRINTF("reset failed (ignored)\n"); + if (bpf_peers_present(ifp->if_bpf)) { + struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap; + + 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 */ + + bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); } - /* Read MAC and other stuff rom EEPROM */ - zyd_cfg_read_eeprom(sc); + rssi = (stat.rssi > 63) ? 127 : 2 * stat.rssi; - /* 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); - 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); - - mtx_lock(&sc->sc_mtx); - - if (ifp == NULL) { - DPRINTFN(0, "%s: could not if_alloc()!\n", - sc->sc_name); - goto done; - } - 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); - - mtx_lock(&sc->sc_mtx); - - ic->ic_node_alloc = &zyd_node_alloc_cb; - ic->ic_raw_xmit = &zyd_raw_xmit_cb; - ic->ic_newassoc = &zyd_newassoc_cb; - - 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; - - sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); - - mtx_unlock(&sc->sc_mtx); - - bpfattach(ifp, DLT_IEEE802_11_RADIO, - sizeof(struct ieee80211_frame) + - sizeof(sc->sc_txtap)); - - mtx_lock(&sc->sc_mtx); - - if (bootverbose) { - ieee80211_announce(ic); - } - usb2_transfer_start(sc->sc_xfer[ZYD_INTR_DT_RD]); -done: - return; -} - -/* - * Detach device - */ -static int -zyd_detach(device_t dev) -{ - struct zyd_softc *sc = device_get_softc(dev); - struct ieee80211com *ic; - struct ifnet *ifp; - - usb2_config_td_drain(&sc->sc_config_td); - - mtx_lock(&sc->sc_mtx); - - usb2_callout_stop(&sc->sc_watchdog); - - zyd_cfg_pre_stop(sc, NULL, 0); - - ifp = sc->sc_ifp; - ic = ifp->if_l2com; - - mtx_unlock(&sc->sc_mtx); - - /* stop all USB transfers first */ - usb2_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); - - /* get rid of any late children */ - bus_generic_detach(dev); - - if (ifp) { - bpfdetach(ifp); - ieee80211_ifdetach(ic); - if_free(ifp); - } - usb2_config_td_unsetup(&sc->sc_config_td); - - usb2_callout_drain(&sc->sc_watchdog); - - usb2_cv_destroy(&sc->sc_intr_cv); - - mtx_destroy(&sc->sc_mtx); - - 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; + struct ieee80211_node *ni; + struct zyd_rx_desc desc; + struct mbuf *m; + uint32_t offset; + uint8_t rssi; + int8_t nf; + int i; - ostate = vap->iv_state; - nstate = sc->sc_ns_state; - arg = sc->sc_ns_arg; + 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)); - switch (nstate) { - case IEEE80211_S_INIT: - break; + offset = 0; + if (UGETW(desc.tag) == ZYD_TAG_MULTIFRAME) { + DPRINTF(sc, ZYD_DEBUG_RECV, + "%s: received multi-frame transfer\n", __func__); - case IEEE80211_S_RUN: - zyd_cfg_set_run(sc, cc); - break; + for (i = 0; i < ZYD_MAX_RXFRAMECNT; i++) { + uint16_t len16 = UGETW(desc.len[i]); - default: - break; - } + if (len16 == 0 || len16 > xfer->actlen) + 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); -} + zyd_rx_data(xfer, offset, len16); -static void -zyd_cfg_set_run(struct zyd_softc *sc, - struct usb2_config_td_cc *cc) -{ - zyd_cfg_set_chan(sc, cc, 0); + /* 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__); - if (cc->ic_opmode != IEEE80211_M_MONITOR) { - /* turn link LED on */ - zyd_cfg_set_led(sc, ZYD_LED1, 1); - - /* make data LED blink upon Tx */ - zyd_cfg_write32(sc, sc->sc_firmware_base + ZYD_FW_LINK_STATUS, 1); - - 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); - } -} - -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; - - DPRINTF("setting new state: %d\n", nstate); - - 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 */ + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + xfer->frlengths[0] = xfer->max_data_length; + usb2_start_hardware(xfer); + + /* + * 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; + + nf = -95; /* XXX */ + + 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; + + default: /* Error */ + DPRINTF(sc, ZYD_DEBUG_ANY, "frame error: %s\n", usb2_errstr(xfer->error)); + + if (xfer->error != USB_ERR_CANCELLED) { + /* try to clear stall first */ + xfer->flags.stall_pipe = 1; + goto tr_setup; + } + break; } - /* store next state */ - sc->sc_ns_state = nstate; - sc->sc_ns_arg = arg; - - /* stop timers */ - sc->sc_amrr_timer = 0; - - /* - * 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); - - mtx_unlock(&sc->sc_mtx); - - return EINPROGRESS; } -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; - - 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; - } - - /* 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,440 +2350,120 @@ 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) -{ - struct zyd_softc *sc = ic->ic_ifp->if_softc; - - mtx_lock(&sc->sc_mtx); - - sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); - - usb2_config_td_queue_command - (&sc->sc_config_td, &zyd_config_copy, func, 0, 0); - - mtx_unlock(&sc->sc_mtx); -} - -static void -zyd_scan_start_cb(struct ieee80211com *ic) -{ - zyd_std_command(ic, &zyd_cfg_scan_start); -} - -static void -zyd_scan_end_cb(struct ieee80211com *ic) -{ - zyd_std_command(ic, &zyd_cfg_scan_end); -} - -static void -zyd_set_channel_cb(struct ieee80211com *ic) -{ - zyd_std_command(ic, &zyd_cfg_set_chan); -} - -/*========================================================================* - * configure sub-routines, zyd_cfg_xxx - *========================================================================*/ - -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); -} - -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); -} - -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; - - chan = cc->ic_curchan.chan_to_ieee; - - DPRINTF("Will try %d\n", chan); - - if ((chan == 0) || (chan == IEEE80211_CHAN_ANY)) { - DPRINTF("0 or ANY, exiting\n"); - return; - } - zyd_cfg_lock_phy(sc); - - (sc->sc_rf.cfg_set_channel) (sc, &sc->sc_rf, chan); - - /* update Tx power */ - zyd_cfg_write16(sc, ZYD_CR31, sc->sc_pwr_int[chan - 1]); - - 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); - } - 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); - - sc->sc_rxtap.wr_chan_freq = - sc->sc_txtap.wt_chan_freq = - htole16(cc->ic_curchan.ic_freq); - - sc->sc_rxtap.wr_chan_flags = - sc->sc_txtap.wt_chan_flags = - htole16(cc->ic_flags); -} - -/* - * Interface: init - */ - -/* immediate configuration */ - -static void -zyd_cfg_pre_init(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) +static int +zyd_tx_mgt(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - - 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]); - - /* clean up transmission */ - zyd_tx_clean_queue(sc); -} - -/* delayed configuration */ - -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); - - /* disable Rx */ - zyd_cfg_write32(sc, ZYD_MAC_RXFILTER, 0); - - /* disable interrupts */ - zyd_cfg_write32(sc, ZYD_CR_INTERRUPT, 0); -} - -static void -zyd_update_mcast_cb(struct ifnet *ifp) -{ - struct zyd_softc *sc = ifp->if_softc; - - 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); -} - -static void -zyd_update_promisc_cb(struct ifnet *ifp) -{ - struct zyd_softc *sc = ifp->if_softc; - - 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); -} - -static void -zyd_cfg_set_rxfilter(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - uint32_t rxfilter; - - 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; - 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) -{ - 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); -} - -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]; - - 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); - } -} - -/* - * 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; + struct zyd_tx_desc *desc; + struct zyd_tx_data *data; + struct ieee80211_frame *wh; + struct ieee80211_key *k; + int rate, 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 (rate < 2) { - DPRINTF("rate < 2!\n"); + data = STAILQ_FIRST(&sc->tx_free); + STAILQ_REMOVE_HEAD(&sc->tx_free, next); + sc->tx_nfree--; + desc = &data->desc; - /* avoid division by zero */ - rate = 2; + rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; + + wh = mtod(m0, struct ieee80211_frame *); + + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + k = ieee80211_crypto_encap(ni, m0); + if (k == NULL) { + m_freem(m0); + return (ENOBUFS); + } + } + + data->ni = ni; + data->m = m0; + data->rate = rate; + + wh = mtod(m0, struct ieee80211_frame *); + + totlen = m0->m_pkthdr.len + IEEE80211_CRC_LEN; + + /* fill Tx descriptor */ + desc->len = htole16(totlen); + + 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; + + 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)) + desc->phy |= ZYD_TX_PHY_5GHZ; + } else if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + desc->phy |= ZYD_TX_PHY_SHPREAMBLE; + + /* actual transmit length (XXX why +10?) */ + pktlen = ZYD_TX_DESC_SIZE + 10; + if (sc->sc_macrev == ZYD_ZD1211) + pktlen += totlen; + desc->pktlen = htole16(pktlen); + + 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; } - ic->ic_lastdata = ticks; if (bpf_peers_present(ifp->if_bpf)) { struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; 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); - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); } - 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 (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) - sc->sc_tx_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; + 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); - /* actual transmit length (XXX why +10?) */ - pktlen = sizeof(struct zyd_tx_desc) + 10; - if (sc->sc_mac_rev == ZYD_ZD1211) - pktlen += totlen; - sc->sc_tx_desc.pktlen = htole16(pktlen); + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); - sc->sc_tx_desc.plcp_length = ((16 * totlen) + rate - 1) / rate; - sc->sc_tx_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; - } - 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; - - /* start write transfer, if not started */ - _IF_ENQUEUE(&sc->sc_tx_queue, mm); - - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_DT_WR]); + return (0); } static void @@ -2785,591 +2471,650 @@ 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; - uint16_t temp_len; - - DPRINTF("\n"); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: - DPRINTFN(11, "transfer complete\n"); + DPRINTF(sc, ZYD_DEBUG_ANY, "transfer complete, %u bytes\n", + xfer->actlen); + + /* free resources */ + data = xfer->priv_fifo; + zyd_tx_free(data, 0); + xfer->priv_fifo = NULL; ifp->if_opackets++; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + /* FALLTHROUGH */ 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"); - break; - } - if (sc->sc_flags & ZYD_FLAG_WAIT_COMMAND) { - /* - * don't send anything while a command is pending ! - */ - DPRINTFN(11, "wait command\n"); - break; - } - zyd_fill_write_queue(sc); +tr_setup: + data = STAILQ_FIRST(&sc->tx_q); + if (data) { + STAILQ_REMOVE_HEAD(&sc->tx_q, next); + m = data->m; - _IF_DEQUEUE(&sc->sc_tx_queue, m); - - if (m) { if (m->m_pkthdr.len > ZYD_MAX_TXBUFSZ) { - DPRINTFN(0, "data overflow, %u bytes\n", + DPRINTF(sc, ZYD_DEBUG_ANY, "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); + 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); - /* get transfer length */ - temp_len = m->m_pkthdr.len; + if (bpf_peers_present(ifp->if_bpf)) { + struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; - DPRINTFN(11, "sending frame len=%u xferlen=%u\n", - m->m_pkthdr.len, temp_len); + 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); - xfer->frlengths[0] = temp_len; + bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + } + xfer->frlengths[0] = ZYD_TX_DESC_SIZE + m->m_pkthdr.len; + xfer->priv_fifo = data; usb2_start_hardware(xfer); - - /* free mbuf and node */ - zyd_tx_freem(m); } break; default: /* Error */ - DPRINTFN(11, "transfer error, %s\n", + DPRINTF(sc, ZYD_DEBUG_ANY, "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]); - } ifp->if_oerrors++; + data = xfer->priv_fifo; + xfer->priv_fifo = NULL; + if (data != NULL) + zyd_tx_free(data, xfer->error); + + 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; } } -static void -zyd_init_cb(void *arg) +static int +zyd_tx_data(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - struct zyd_softc *sc = arg; + 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; - 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); + 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; + + 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; + } + + 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 *); + } + + data->ni = ni; + data->m = m0; + + totlen = m0->m_pkthdr.len + IEEE80211_CRC_LEN; + + /* fill Tx descriptor */ + desc->len = htole16(totlen); + + 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; + } + } + + 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)) + desc->phy |= ZYD_TX_PHY_5GHZ; + } else if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + desc->phy |= ZYD_TX_PHY_SHPREAMBLE; + + /* actual transmit length (XXX why +10?) */ + pktlen = sizeof(struct zyd_tx_desc) + 10; + if (sc->sc_macrev == ZYD_ZD1211) + pktlen += totlen; + desc->pktlen = htole16(pktlen); + + 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; + } + + 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); + + STAILQ_INSERT_TAIL(&sc->tx_q, data, next); + usb2_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); + + return (0); +} + +static void +zyd_start(struct ifnet *ifp) +{ + struct zyd_softc *sc = ifp->if_softc; + struct ieee80211_node *ni; + struct mbuf *m; + + ZYD_LOCK(sc); + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + if (sc->tx_nfree == 0) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m = ieee80211_encap(ni, m); + if (m == NULL) { + ieee80211_free_node(ni); + ifp->if_oerrors++; + continue; + } + if (zyd_tx_data(sc, m, ni) != 0) { + ieee80211_free_node(ni); + ifp->if_oerrors++; + break; + } + } + ZYD_UNLOCK(sc); } static int -zyd_ioctl_cb(struct ifnet *ifp, u_long cmd, caddr_t data) +zyd_raw_xmit(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; + + 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(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) -{ - struct zyd_softc *sc = arg; - - mtx_assert(&sc->sc_mtx, 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); -} - -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; - } -} - -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; - - bzero(cc, sizeof(*cc)); - - ifp = sc->sc_ifp; - if (ifp) { - cc->if_flags = ifp->if_flags; - bcopy(ifp->if_broadcastaddr, cc->if_broadcastaddr, - sizeof(cc->if_broadcastaddr)); - - cc->zyd_multi_low = 0x00000000; - cc->zyd_multi_high = 0x80000000; - - IF_ADDR_LOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - uint8_t v; - - 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); - - 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; - - bcopy(ic->ic_myaddr, cc->ic_myaddr, - sizeof(cc->ic_myaddr)); - } - } - sc->sc_flags |= ZYD_FLAG_WAIT_COMMAND; -} - -static void -zyd_end_of_commands(struct zyd_softc *sc) -{ - sc->sc_flags &= ~ZYD_FLAG_WAIT_COMMAND; - - /* start write transfer, if not started */ - usb2_transfer_start(sc->sc_xfer[ZYD_BULK_DT_WR]); -} - -static void -zyd_newassoc_cb(struct ieee80211_node *ni, int isnew) -{ - struct ieee80211vap *vap = ni->ni_vap; - - ieee80211_amrr_node_init(&ZYD_VAP(vap)->amrr, &ZYD_NODE(ni)->amn, ni); -} - -static void -zyd_cfg_amrr_timeout(struct zyd_softc *sc, - struct usb2_config_td_cc *cc, uint16_t refcount) -{ - 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)) { - - if (sc->sc_amrr_timer) { - - if (ieee80211_amrr_choose(ni, &ZYD_NODE(ni)->amn)) { - /* ignore */ - } - } - } -} - -static void -zyd_cfg_amrr_start(struct zyd_softc *sc) -{ - struct ieee80211vap *vap; - struct ieee80211_node *ni; - - vap = zyd_get_vap(sc); - - if (vap == NULL) { - return; - } - ni = vap->iv_bss; - if (ni == NULL) { - return; - } - /* init AMRR */ - - ieee80211_amrr_node_init(&ZYD_VAP(vap)->amrr, &ZYD_NODE(ni)->amn, ni); - - /* enable AMRR timer */ - - sc->sc_amrr_timer = 1; -} - -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_vap *zvp; - struct ieee80211vap *vap; - struct zyd_softc *sc = ic->ic_ifp->if_softc; - - /* 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); - } - 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); - - /* override state transition machine */ - zvp->newstate = vap->iv_newstate; - vap->iv_newstate = &zyd_newstate_cb; - - ieee80211_amrr_init(&zvp->amrr, vap, - IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, - IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, - 1000 /* 1 sec */ ); - - /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); - ic->ic_opmode = opmode; - - return (vap); -} - -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; - - /* 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); - - ieee80211_amrr_cleanup(&zvp->amrr); - ieee80211_vap_detach(vap); - free(zvp, M_80211_VAP); -} - -/* ARGUSED */ -static struct ieee80211_node * -zyd_node_alloc_cb(struct ieee80211vap *vap __unused, - const uint8_t mac[IEEE80211_ADDR_LEN] __unused) -{ - struct zyd_node *zn; - - zn = malloc(sizeof(struct zyd_node), M_80211_NODE, M_NOWAIT | M_ZERO); - return ((zn != NULL) ? &zn->ni : NULL); -} - -static void -zyd_fill_write_queue(struct zyd_softc *sc) +zyd_init_task(struct usb2_proc_msg *pm) { + struct zyd_task *task = (struct zyd_task *)pm; + struct zyd_softc *sc = task->sc; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211_node *ni; - struct mbuf *m; + struct ieee80211com *ic = ifp->if_l2com; + struct usb2_config_descriptor *cd; + int error; + uint32_t val; + + ZYD_LOCK_ASSERT(sc, MA_OWNED); + + 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; + } + + /* 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; + } + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + zyd_stop_task(pm); + + 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; + + /* 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); + + /* 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; + + /* 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); /* - * We only fill up half of the queue with data frames. The rest is - * reserved for other kinds of frames. + * Allocate Tx and Rx xfer queues. */ + zyd_setup_tx_list(sc); - while (sc->sc_tx_queue.ifq_len < (IFQ_MAXLEN / 2)) { + /* enable interrupts */ + zyd_write32_m(sc, ZYD_CR_INTERRUPT, ZYD_HWINT_MASK); - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; + 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]); - 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); - } + return; + +fail: zyd_stop_task(pm); + return; } static void -zyd_tx_clean_queue(struct zyd_softc *sc) +zyd_init(void *priv) { - struct mbuf *m; + struct zyd_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - for (;;) { - _IF_DEQUEUE(&sc->sc_tx_queue, m); + ZYD_LOCK(sc); + zyd_queue_command(sc, zyd_init_task, + &sc->sc_synctask[0].hdr, + &sc->sc_synctask[1].hdr); + ZYD_UNLOCK(sc); - if (!m) { - break; - } - zyd_tx_freem(m); - } + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ } static void -zyd_tx_freem(struct mbuf *m) +zyd_stop_task(struct usb2_proc_msg *pm) { - struct ieee80211_node *ni; + struct zyd_task *task = (struct zyd_task *)pm; + struct zyd_softc *sc = task->sc; + struct ifnet *ifp = sc->sc_ifp; + int error; - 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); + ZYD_LOCK_ASSERT(sc, MA_OWNED); - break; - } -} + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -static void -zyd_tx_mgt(struct zyd_softc *sc, struct mbuf *m, struct ieee80211_node *ni) -{ - 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; + /* + * 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); - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - rate = tp->mgmtrate; + zyd_unsetup_tx_list(sc); - 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 */ + /* Stop now if the device was never set up */ + if (!(sc->sc_flags & ZYD_FLAG_INITONCE)) + return; - 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; + /* 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); - 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); -} - -static void -zyd_tx_data(struct zyd_softc *sc, struct mbuf *m, struct ieee80211_node *ni) -{ - 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; - - wh = mtod(m, struct ieee80211_frame *); - - 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 *); - } - /* fill Tx descriptor */ - - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - uint16_t totlen; - - 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; - } - } - 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); +fail: + return; } static int -zyd_raw_xmit_cb(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) +zyd_loadfirmware(struct zyd_softc *sc) { - struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = ic->ic_ifp; - struct zyd_softc *sc = ifp->if_softc; + struct usb2_device_request req; + size_t size; + u_char *fw; + uint8_t stat; + uint16_t addr; - 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); + 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); + } + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = ZYD_DOWNLOADREQ; + USETW(req.wIndex, 0); + + addr = ZYD_FIRMWARE_START_ADDR; + while (size > 0) { /* - * Caller supplied explicit parameters to use in - * sending the frame. + * 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? */ - zyd_tx_mgt(sc, m, ni); /* XXX zyd_tx_raw() */ + const int mlen = min(size, 64); + + DPRINTF(sc, ZYD_DEBUG_FW, + "loading firmware block: len=%d, addr=0x%x\n", mlen, addr); + + USETW(req.wValue, addr); + USETW(req.wLength, mlen); + if (zyd_do_request(sc, &req, fw) != 0) + return (EIO); + + addr += mlen / 2; + fw += mlen; + size -= mlen; } - mtx_unlock(&sc->sc_mtx); - return (0); + + /* 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); + + sc->sc_flags |= ZYD_FLAG_FWLOADED; + + return (stat & 0x80) ? (EIO) : (0); } -static struct ieee80211vap * -zyd_get_vap(struct zyd_softc *sc) +static void +zyd_newassoc(struct ieee80211_node *ni, int isnew) { - struct ifnet *ifp; - struct ieee80211com *ic; + struct ieee80211vap *vap = ni->ni_vap; - 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); + ieee80211_amrr_node_init(&ZYD_VAP(vap)->amrr, &ZYD_NODE(ni)->amn, ni); } + +static void +zyd_scan_start(struct ieee80211com *ic) +{ + struct zyd_softc *sc = ic->ic_ifp->if_softc; + + 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_scan_end(struct ieee80211com *ic) +{ + struct zyd_softc *sc = ic->ic_ifp->if_softc; + + 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_set_channel(struct ieee80211com *ic) +{ + struct zyd_softc *sc = ic->ic_ifp->if_softc; + + 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_scantask(struct usb2_proc_msg *pm) +{ + 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; + + ZYD_LOCK_ASSERT(sc, MA_OWNED); + + switch (sc->sc_scan_action) { + case ZYD_SCAN_START: + /* want broadcast address while scanning */ + zyd_set_bssid(sc, ifp->if_broadcastaddr); + break; + + case ZYD_SET_CHANNEL: + zyd_set_chan(sc, ic->ic_curchan); + break; + + default: /* ZYD_SCAN_END */ + /* restore previous bssid */ + zyd_set_bssid(sc, sc->sc_bssid); + break; + } +} + +static void +zyd_queue_command(struct zyd_softc *sc, usb2_proc_callback_t *fn, + struct usb2_proc_msg *t0, struct usb2_proc_msg *t1) +{ + struct zyd_task *task; + + ZYD_LOCK_ASSERT(sc, MA_OWNED); + + if (usb2_proc_is_gone(&sc->sc_tq)) { + DPRINTF(sc, ZYD_DEBUG_STATE, "proc is gone\n"); + return; /* nothing to do */ + } + /* + * 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); + + /* Setup callback and softc pointers */ + task->hdr.pm_callback = fn; + task->sc = sc; + + /* + * Init and stop must be synchronous! + */ + if ((fn == zyd_init_task) || (fn == zyd_stop_task)) + usb2_proc_mwait(&sc->sc_tq, t0, t1); +} + +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 } +}; + +static driver_t zyd_driver = { + "zyd", + zyd_methods, + sizeof(struct zyd_softc) +}; + +static devclass_t zyd_devclass; + +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); diff --git a/sys/dev/usb2/wlan/if_zydfw.h b/sys/dev/usb2/wlan/if_zydfw.h index 3c176e45576..46f5c2aba75 100644 --- a/sys/dev/usb2/wlan/if_zydfw.h +++ b/sys/dev/usb2/wlan/if_zydfw.h @@ -26,7 +26,7 @@ /* $FreeBSD$ */ -static const uint8_t zd1211_firmware[] = { +uint8_t zd1211_firmware[] = { 0x08, 0x91, 0xFF, 0xED, 0x09, 0x93, 0x1E, 0xEE, 0xD1, 0x94, 0x11, 0xEE, 0x88, 0xD4, 0xD1, 0x96, 0xD1, 0x98, 0x5C, 0x99, 0x5C, 0x99, 0x4C, 0x99, @@ -672,9 +672,9 @@ static const uint8_t zd1211_firmware[] = { /* * current zd1211b firmware version. */ -#define ZD1211B_FIRMWARE_VER 4705 +#define ZD1211B_FIRMWARE_VER 4705 -static const uint8_t zd1211b_firmware[] = { +uint8_t zd1211b_firmware[] = { 0x08, 0x91, 0xff, 0xed, 0x09, 0x93, 0x1e, 0xee, 0xd1, 0x94, 0x11, 0xee, 0x88, 0xd4, 0xd1, 0x96, 0xd1, 0x98, 0x5c, 0x99, 0x5c, 0x99, 0x4c, 0x99, 0x04, 0x9d, 0xd1, 0x98, 0xd1, 0x9a, 0x03, 0xee, 0xf4, diff --git a/sys/dev/usb2/wlan/if_zydreg.h b/sys/dev/usb2/wlan/if_zydreg.h index 2c7d90c3991..8ef34e35472 100644 --- a/sys/dev/usb2/wlan/if_zydreg.h +++ b/sys/dev/usb2/wlan/if_zydreg.h @@ -23,403 +23,403 @@ * ZyDAS ZD1211/ZD1211B USB WLAN driver. */ -#define ZYD_CR_GPI_EN 0x9418 -#define ZYD_CR_RADIO_PD 0x942c -#define ZYD_CR_RF2948_PD 0x942c -#define ZYD_CR_EN_PS_MANUAL_AGC 0x943c -#define ZYD_CR_CONFIG_PHILIPS 0x9440 -#define ZYD_CR_I2C_WRITE 0x9444 -#define ZYD_CR_SA2400_SER_RP 0x9448 -#define ZYD_CR_RADIO_PE 0x9458 -#define ZYD_CR_RST_BUS_MASTER 0x945c -#define ZYD_CR_RFCFG 0x9464 -#define ZYD_CR_HSTSCHG 0x946c -#define ZYD_CR_PHY_ON 0x9474 -#define ZYD_CR_RX_DELAY 0x9478 -#define ZYD_CR_RX_PE_DELAY 0x947c -#define ZYD_CR_GPIO_1 0x9490 -#define ZYD_CR_GPIO_2 0x9494 -#define ZYD_CR_EnZYD_CRyBufMux 0x94a8 -#define ZYD_CR_PS_CTRL 0x9500 -#define ZYD_CR_ADDA_PWR_DWN 0x9504 -#define ZYD_CR_ADDA_MBIAS_WT 0x9508 -#define ZYD_CR_INTERRUPT 0x9510 -#define ZYD_CR_MAC_PS_STATE 0x950c -#define ZYD_CR_ATIM_WND_PERIOD 0x951c -#define ZYD_CR_BCN_INTERVAL 0x9520 -#define ZYD_CR_PRE_TBTT 0x9524 +#define ZYD_CR_GPI_EN 0x9418 +#define ZYD_CR_RADIO_PD 0x942c +#define ZYD_CR_RF2948_PD 0x942c +#define ZYD_CR_EN_PS_MANUAL_AGC 0x943c +#define ZYD_CR_CONFIG_PHILIPS 0x9440 +#define ZYD_CR_I2C_WRITE 0x9444 +#define ZYD_CR_SA2400_SER_RP 0x9448 +#define ZYD_CR_RADIO_PE 0x9458 +#define ZYD_CR_RST_BUS_MASTER 0x945c +#define ZYD_CR_RFCFG 0x9464 +#define ZYD_CR_HSTSCHG 0x946c +#define ZYD_CR_PHY_ON 0x9474 +#define ZYD_CR_RX_DELAY 0x9478 +#define ZYD_CR_RX_PE_DELAY 0x947c +#define ZYD_CR_GPIO_1 0x9490 +#define ZYD_CR_GPIO_2 0x9494 +#define ZYD_CR_EnZYD_CRyBufMux 0x94a8 +#define ZYD_CR_PS_CTRL 0x9500 +#define ZYD_CR_ADDA_PWR_DWN 0x9504 +#define ZYD_CR_ADDA_MBIAS_WT 0x9508 +#define ZYD_CR_INTERRUPT 0x9510 +#define ZYD_CR_MAC_PS_STATE 0x950c +#define ZYD_CR_ATIM_WND_PERIOD 0x951c +#define ZYD_CR_BCN_INTERVAL 0x9520 +#define ZYD_CR_PRE_TBTT 0x9524 /* * MAC registers. */ -#define ZYD_MAC_MACADRL 0x9610 /* MAC address (low) */ -#define ZYD_MAC_MACADRH 0x9614 /* MAC address (high) */ -#define ZYD_MAC_BSSADRL 0x9618 /* BSS address (low) */ -#define ZYD_MAC_BSSADRH 0x961c /* BSS address (high) */ -#define ZYD_MAC_BCNCFG 0x9620 /* BCN configuration */ -#define ZYD_MAC_GHTBL 0x9624 /* Group hash table (low) */ -#define ZYD_MAC_GHTBH 0x9628 /* Group hash table (high) */ -#define ZYD_MAC_RX_TIMEOUT 0x962c /* Rx timeout value */ -#define ZYD_MAC_BAS_RATE 0x9630 /* Basic rate setting */ -#define ZYD_MAC_MAN_RATE 0x9634 /* Mandatory rate setting */ -#define ZYD_MAC_RTSCTSRATE 0x9638 /* RTS CTS rate */ -#define ZYD_MAC_BACKOFF_PROTECT 0x963c /* Backoff protection */ -#define ZYD_MAC_RX_THRESHOLD 0x9640 /* Rx threshold */ -#define ZYD_MAC_TX_PE_CONTROL 0x9644 /* Tx_PE control */ -#define ZYD_MAC_AFTER_PNP 0x9648 /* After PnP */ -#define ZYD_MAC_RX_PE_DELAY 0x964c /* Rx_pe delay */ -#define ZYD_MAC_RX_ADDR2_L 0x9650 /* RX address2 (low) */ -#define ZYD_MAC_RX_ADDR2_H 0x9654 /* RX address2 (high) */ -#define ZYD_MAC_SIFS_ACK_TIME 0x9658 /* Dynamic SIFS ack time */ -#define ZYD_MAC_PHY_DELAY 0x9660 /* PHY delay */ -#define ZYD_MAC_PHY_DELAY2 0x966c /* PHY delay */ -#define ZYD_MAC_BCNFIFO 0x9670 /* Beacon FIFO I/O port */ -#define ZYD_MAC_SNIFFER 0x9674 /* Sniffer on/off */ -#define ZYD_MAC_ENCRYPTION_TYPE 0x9678 /* Encryption type */ -#define ZYD_MAC_RETRY 0x967c /* Retry time */ -#define ZYD_MAC_MISC 0x9680 /* Misc */ -#define ZYD_MAC_STMACHINESTAT 0x9684 /* State machine status */ -#define ZYD_MAC_TX_UNDERRUN_CNT 0x9688 /* TX underrun counter */ -#define ZYD_MAC_RXFILTER 0x968c /* Send to host settings */ -#define ZYD_MAC_ACK_EXT 0x9690 /* Acknowledge extension */ -#define ZYD_MAC_BCNFIFOST 0x9694 /* BCN FIFO set and status */ -#define ZYD_MAC_DIFS_EIFS_SIFS 0x9698 /* DIFS, EIFS & SIFS settings */ -#define ZYD_MAC_RX_TIMEOUT_CNT 0x969c /* RX timeout count */ -#define ZYD_MAC_RX_TOTAL_FRAME 0x96a0 /* RX total frame count */ -#define ZYD_MAC_RX_CRC32_CNT 0x96a4 /* RX CRC32 frame count */ -#define ZYD_MAC_RX_CRC16_CNT 0x96a8 /* RX CRC16 frame count */ -#define ZYD_MAC_RX_UDEC 0x96ac /* RX unicast decr. error count */ -#define ZYD_MAC_RX_OVERRUN_CNT 0x96b0 /* RX FIFO overrun count */ -#define ZYD_MAC_RX_MDEC 0x96bc /* RX multicast decr. err. cnt. */ -#define ZYD_MAC_NAV_TCR 0x96c4 /* NAV timer count read */ -#define ZYD_MAC_BACKOFF_ST_RD 0x96c8 /* Backoff status read */ -#define ZYD_MAC_DM_RETRY_CNT_RD 0x96cc /* DM retry count read */ -#define ZYD_MAC_RX_ACR 0x96d0 /* RX arbitration count read */ -#define ZYD_MAC_TX_CCR 0x96d4 /* Tx complete count read */ -#define ZYD_MAC_TCB_ADDR 0x96e8 /* Current PCI process TCP addr */ -#define ZYD_MAC_RCB_ADDR 0x96ec /* Next RCB address */ -#define ZYD_MAC_CONT_WIN_LIMIT 0x96f0 /* Contention window limit */ -#define ZYD_MAC_TX_PKT 0x96f4 /* Tx total packet count read */ -#define ZYD_MAC_DL_CTRL 0x96f8 /* Download control */ -#define ZYD_MAC_CAM_MODE 0x9700 /* CAM: Continuous Access Mode */ -#define ZYD_MACB_TXPWR_CTL1 0x9b00 -#define ZYD_MACB_TXPWR_CTL2 0x9b04 -#define ZYD_MACB_TXPWR_CTL3 0x9b08 -#define ZYD_MACB_TXPWR_CTL4 0x9b0c -#define ZYD_MACB_AIFS_CTL1 0x9b10 -#define ZYD_MACB_AIFS_CTL2 0x9b14 -#define ZYD_MACB_TXOP 0x9b20 -#define ZYD_MACB_MAX_RETRY 0x9b28 +#define ZYD_MAC_MACADRL 0x9610 /* MAC address (low) */ +#define ZYD_MAC_MACADRH 0x9614 /* MAC address (high) */ +#define ZYD_MAC_BSSADRL 0x9618 /* BSS address (low) */ +#define ZYD_MAC_BSSADRH 0x961c /* BSS address (high) */ +#define ZYD_MAC_BCNCFG 0x9620 /* BCN configuration */ +#define ZYD_MAC_GHTBL 0x9624 /* Group hash table (low) */ +#define ZYD_MAC_GHTBH 0x9628 /* Group hash table (high) */ +#define ZYD_MAC_RX_TIMEOUT 0x962c /* Rx timeout value */ +#define ZYD_MAC_BAS_RATE 0x9630 /* Basic rate setting */ +#define ZYD_MAC_MAN_RATE 0x9634 /* Mandatory rate setting */ +#define ZYD_MAC_RTSCTSRATE 0x9638 /* RTS CTS rate */ +#define ZYD_MAC_BACKOFF_PROTECT 0x963c /* Backoff protection */ +#define ZYD_MAC_RX_THRESHOLD 0x9640 /* Rx threshold */ +#define ZYD_MAC_TX_PE_CONTROL 0x9644 /* Tx_PE control */ +#define ZYD_MAC_AFTER_PNP 0x9648 /* After PnP */ +#define ZYD_MAC_RX_PE_DELAY 0x964c /* Rx_pe delay */ +#define ZYD_MAC_RX_ADDR2_L 0x9650 /* RX address2 (low) */ +#define ZYD_MAC_RX_ADDR2_H 0x9654 /* RX address2 (high) */ +#define ZYD_MAC_SIFS_ACK_TIME 0x9658 /* Dynamic SIFS ack time */ +#define ZYD_MAC_PHY_DELAY 0x9660 /* PHY delay */ +#define ZYD_MAC_PHY_DELAY2 0x966c /* PHY delay */ +#define ZYD_MAC_BCNFIFO 0x9670 /* Beacon FIFO I/O port */ +#define ZYD_MAC_SNIFFER 0x9674 /* Sniffer on/off */ +#define ZYD_MAC_ENCRYPTION_TYPE 0x9678 /* Encryption type */ +#define ZYD_MAC_RETRY 0x967c /* Retry time */ +#define ZYD_MAC_MISC 0x9680 /* Misc */ +#define ZYD_MAC_STMACHINESTAT 0x9684 /* State machine status */ +#define ZYD_MAC_TX_UNDERRUN_CNT 0x9688 /* TX underrun counter */ +#define ZYD_MAC_RXFILTER 0x968c /* Send to host settings */ +#define ZYD_MAC_ACK_EXT 0x9690 /* Acknowledge extension */ +#define ZYD_MAC_BCNFIFOST 0x9694 /* BCN FIFO set and status */ +#define ZYD_MAC_DIFS_EIFS_SIFS 0x9698 /* DIFS, EIFS & SIFS settings */ +#define ZYD_MAC_RX_TIMEOUT_CNT 0x969c /* RX timeout count */ +#define ZYD_MAC_RX_TOTAL_FRAME 0x96a0 /* RX total frame count */ +#define ZYD_MAC_RX_CRC32_CNT 0x96a4 /* RX CRC32 frame count */ +#define ZYD_MAC_RX_CRC16_CNT 0x96a8 /* RX CRC16 frame count */ +#define ZYD_MAC_RX_UDEC 0x96ac /* RX unicast decr. error count */ +#define ZYD_MAC_RX_OVERRUN_CNT 0x96b0 /* RX FIFO overrun count */ +#define ZYD_MAC_RX_MDEC 0x96bc /* RX multicast decr. err. cnt. */ +#define ZYD_MAC_NAV_TCR 0x96c4 /* NAV timer count read */ +#define ZYD_MAC_BACKOFF_ST_RD 0x96c8 /* Backoff status read */ +#define ZYD_MAC_DM_RETRY_CNT_RD 0x96cc /* DM retry count read */ +#define ZYD_MAC_RX_ACR 0x96d0 /* RX arbitration count read */ +#define ZYD_MAC_TX_CCR 0x96d4 /* Tx complete count read */ +#define ZYD_MAC_TCB_ADDR 0x96e8 /* Current PCI process TCP addr */ +#define ZYD_MAC_RCB_ADDR 0x96ec /* Next RCB address */ +#define ZYD_MAC_CONT_WIN_LIMIT 0x96f0 /* Contention window limit */ +#define ZYD_MAC_TX_PKT 0x96f4 /* Tx total packet count read */ +#define ZYD_MAC_DL_CTRL 0x96f8 /* Download control */ +#define ZYD_MAC_CAM_MODE 0x9700 /* CAM: Continuous Access Mode */ +#define ZYD_MACB_TXPWR_CTL1 0x9b00 +#define ZYD_MACB_TXPWR_CTL2 0x9b04 +#define ZYD_MACB_TXPWR_CTL3 0x9b08 +#define ZYD_MACB_TXPWR_CTL4 0x9b0c +#define ZYD_MACB_AIFS_CTL1 0x9b10 +#define ZYD_MACB_AIFS_CTL2 0x9b14 +#define ZYD_MACB_TXOP 0x9b20 +#define ZYD_MACB_MAX_RETRY 0x9b28 /* * Miscellanous registers. */ -#define ZYD_FIRMWARE_START_ADDR 0xee00 -#define ZYD_FIRMWARE_BASE_ADDR 0xee1d /* Firmware base address */ +#define ZYD_FIRMWARE_START_ADDR 0xee00 +#define ZYD_FIRMWARE_BASE_ADDR 0xee1d /* Firmware base address */ /* * EEPROM registers. */ -#define ZYD_EEPROM_START_HEAD 0xf800 /* EEPROM start */ -#define ZYD_EEPROM_SUBID 0xf817 -#define ZYD_EEPROM_POD 0xf819 -#define ZYD_EEPROM_MAC_ADDR_P1 0xf81b /* Part 1 of the MAC address */ -#define ZYD_EEPROM_MAC_ADDR_P2 0xf81d /* Part 2 of the MAC address */ -#define ZYD_EEPROM_PWR_CAL 0xf81f /* Calibration */ -#define ZYD_EEPROM_PWR_INT 0xf827 /* Calibration */ -#define ZYD_EEPROM_ALLOWEDCHAN 0xf82f /* Allowed CH mask, 1 bit each */ -#define ZYD_EEPROM_DEVICE_VER 0xf837 /* Device version */ -#define ZYD_EEPROM_PHY_REG 0xf83c /* PHY registers */ -#define ZYD_EEPROM_36M_CAL 0xf83f /* Calibration */ -#define ZYD_EEPROM_11A_INT 0xf847 /* Interpolation */ -#define ZYD_EEPROM_48M_CAL 0xf84f /* Calibration */ -#define ZYD_EEPROM_48M_INT 0xf857 /* Interpolation */ -#define ZYD_EEPROM_54M_CAL 0xf85f /* Calibration */ -#define ZYD_EEPROM_54M_INT 0xf867 /* Interpolation */ +#define ZYD_EEPROM_START_HEAD 0xf800 /* EEPROM start */ +#define ZYD_EEPROM_SUBID 0xf817 +#define ZYD_EEPROM_POD 0xf819 +#define ZYD_EEPROM_MAC_ADDR_P1 0xf81b /* Part 1 of the MAC address */ +#define ZYD_EEPROM_MAC_ADDR_P2 0xf81d /* Part 2 of the MAC address */ +#define ZYD_EEPROM_PWR_CAL 0xf81f /* Calibration */ +#define ZYD_EEPROM_PWR_INT 0xf827 /* Calibration */ +#define ZYD_EEPROM_ALLOWEDCHAN 0xf82f /* Allowed CH mask, 1 bit each */ +#define ZYD_EEPROM_DEVICE_VER 0xf837 /* Device version */ +#define ZYD_EEPROM_PHY_REG 0xf83c /* PHY registers */ +#define ZYD_EEPROM_36M_CAL 0xf83f /* Calibration */ +#define ZYD_EEPROM_11A_INT 0xf847 /* Interpolation */ +#define ZYD_EEPROM_48M_CAL 0xf84f /* Calibration */ +#define ZYD_EEPROM_48M_INT 0xf857 /* Interpolation */ +#define ZYD_EEPROM_54M_CAL 0xf85f /* Calibration */ +#define ZYD_EEPROM_54M_INT 0xf867 /* Interpolation */ /* * Firmware registers offsets (relative to fwbase). */ -#define ZYD_FW_FIRMWARE_REV 0x0000 /* Firmware version */ -#define ZYD_FW_USB_SPEED 0x0001 /* USB speed (!=0 if highspeed) */ -#define ZYD_FW_FIX_TX_RATE 0x0002 /* Fixed TX rate */ -#define ZYD_FW_LINK_STATUS 0x0003 -#define ZYD_FW_SOFT_RESET 0x0004 -#define ZYD_FW_FLASH_CHK 0x0005 +#define ZYD_FW_FIRMWARE_REV 0x0000 /* Firmware version */ +#define ZYD_FW_USB_SPEED 0x0001 /* USB speed (!=0 if highspeed) */ +#define ZYD_FW_FIX_TX_RATE 0x0002 /* Fixed TX rate */ +#define ZYD_FW_LINK_STATUS 0x0003 +#define ZYD_FW_SOFT_RESET 0x0004 +#define ZYD_FW_FLASH_CHK 0x0005 /* possible flags for register ZYD_FW_LINK_STATUS */ -#define ZYD_LED1 (1 << 8) -#define ZYD_LED2 (1 << 9) +#define ZYD_LED1 (1 << 8) +#define ZYD_LED2 (1 << 9) /* * RF IDs. */ -#define ZYD_RF_UW2451 0x2 /* not supported yet */ -#define ZYD_RF_UCHIP 0x3 /* not supported yet */ -#define ZYD_RF_AL2230 0x4 -#define ZYD_RF_AL7230B 0x5 -#define ZYD_RF_THETA 0x6 /* not supported yet */ -#define ZYD_RF_AL2210 0x7 -#define ZYD_RF_MAXIM_NEW 0x8 -#define ZYD_RF_GCT 0x9 -#define ZYD_RF_AL2230S 0xa -#define ZYD_RF_RALINK 0xb /* not supported yet */ -#define ZYD_RF_INTERSIL 0xc /* not supported yet */ -#define ZYD_RF_RFMD 0xd -#define ZYD_RF_MAXIM_NEW2 0xe -#define ZYD_RF_PHILIPS 0xf /* not supported yet */ +#define ZYD_RF_UW2451 0x2 /* not supported yet */ +#define ZYD_RF_UCHIP 0x3 /* not supported yet */ +#define ZYD_RF_AL2230 0x4 +#define ZYD_RF_AL7230B 0x5 +#define ZYD_RF_THETA 0x6 /* not supported yet */ +#define ZYD_RF_AL2210 0x7 +#define ZYD_RF_MAXIM_NEW 0x8 +#define ZYD_RF_GCT 0x9 +#define ZYD_RF_AL2230S 0xa /* not supported yet */ +#define ZYD_RF_RALINK 0xb /* not supported yet */ +#define ZYD_RF_INTERSIL 0xc /* not supported yet */ +#define ZYD_RF_RFMD 0xd +#define ZYD_RF_MAXIM_NEW2 0xe +#define ZYD_RF_PHILIPS 0xf /* not supported yet */ /* * PHY registers (8 bits, not documented). */ -#define ZYD_CR0 0x9000 -#define ZYD_CR1 0x9004 -#define ZYD_CR2 0x9008 -#define ZYD_CR3 0x900c -#define ZYD_CR5 0x9010 -#define ZYD_CR6 0x9014 -#define ZYD_CR7 0x9018 -#define ZYD_CR8 0x901c -#define ZYD_CR4 0x9020 -#define ZYD_CR9 0x9024 -#define ZYD_CR10 0x9028 -#define ZYD_CR11 0x902c -#define ZYD_CR12 0x9030 -#define ZYD_CR13 0x9034 -#define ZYD_CR14 0x9038 -#define ZYD_CR15 0x903c -#define ZYD_CR16 0x9040 -#define ZYD_CR17 0x9044 -#define ZYD_CR18 0x9048 -#define ZYD_CR19 0x904c -#define ZYD_CR20 0x9050 -#define ZYD_CR21 0x9054 -#define ZYD_CR22 0x9058 -#define ZYD_CR23 0x905c -#define ZYD_CR24 0x9060 -#define ZYD_CR25 0x9064 -#define ZYD_CR26 0x9068 -#define ZYD_CR27 0x906c -#define ZYD_CR28 0x9070 -#define ZYD_CR29 0x9074 -#define ZYD_CR30 0x9078 -#define ZYD_CR31 0x907c -#define ZYD_CR32 0x9080 -#define ZYD_CR33 0x9084 -#define ZYD_CR34 0x9088 -#define ZYD_CR35 0x908c -#define ZYD_CR36 0x9090 -#define ZYD_CR37 0x9094 -#define ZYD_CR38 0x9098 -#define ZYD_CR39 0x909c -#define ZYD_CR40 0x90a0 -#define ZYD_CR41 0x90a4 -#define ZYD_CR42 0x90a8 -#define ZYD_CR43 0x90ac -#define ZYD_CR44 0x90b0 -#define ZYD_CR45 0x90b4 -#define ZYD_CR46 0x90b8 -#define ZYD_CR47 0x90bc -#define ZYD_CR48 0x90c0 -#define ZYD_CR49 0x90c4 -#define ZYD_CR50 0x90c8 -#define ZYD_CR51 0x90cc -#define ZYD_CR52 0x90d0 -#define ZYD_CR53 0x90d4 -#define ZYD_CR54 0x90d8 -#define ZYD_CR55 0x90dc -#define ZYD_CR56 0x90e0 -#define ZYD_CR57 0x90e4 -#define ZYD_CR58 0x90e8 -#define ZYD_CR59 0x90ec -#define ZYD_CR60 0x90f0 -#define ZYD_CR61 0x90f4 -#define ZYD_CR62 0x90f8 -#define ZYD_CR63 0x90fc -#define ZYD_CR64 0x9100 -#define ZYD_CR65 0x9104 -#define ZYD_CR66 0x9108 -#define ZYD_CR67 0x910c -#define ZYD_CR68 0x9110 -#define ZYD_CR69 0x9114 -#define ZYD_CR70 0x9118 -#define ZYD_CR71 0x911c -#define ZYD_CR72 0x9120 -#define ZYD_CR73 0x9124 -#define ZYD_CR74 0x9128 -#define ZYD_CR75 0x912c -#define ZYD_CR76 0x9130 -#define ZYD_CR77 0x9134 -#define ZYD_CR78 0x9138 -#define ZYD_CR79 0x913c -#define ZYD_CR80 0x9140 -#define ZYD_CR81 0x9144 -#define ZYD_CR82 0x9148 -#define ZYD_CR83 0x914c -#define ZYD_CR84 0x9150 -#define ZYD_CR85 0x9154 -#define ZYD_CR86 0x9158 -#define ZYD_CR87 0x915c -#define ZYD_CR88 0x9160 -#define ZYD_CR89 0x9164 -#define ZYD_CR90 0x9168 -#define ZYD_CR91 0x916c -#define ZYD_CR92 0x9170 -#define ZYD_CR93 0x9174 -#define ZYD_CR94 0x9178 -#define ZYD_CR95 0x917c -#define ZYD_CR96 0x9180 -#define ZYD_CR97 0x9184 -#define ZYD_CR98 0x9188 -#define ZYD_CR99 0x918c -#define ZYD_CR100 0x9190 -#define ZYD_CR101 0x9194 -#define ZYD_CR102 0x9198 -#define ZYD_CR103 0x919c -#define ZYD_CR104 0x91a0 -#define ZYD_CR105 0x91a4 -#define ZYD_CR106 0x91a8 -#define ZYD_CR107 0x91ac -#define ZYD_CR108 0x91b0 -#define ZYD_CR109 0x91b4 -#define ZYD_CR110 0x91b8 -#define ZYD_CR111 0x91bc -#define ZYD_CR112 0x91c0 -#define ZYD_CR113 0x91c4 -#define ZYD_CR114 0x91c8 -#define ZYD_CR115 0x91cc -#define ZYD_CR116 0x91d0 -#define ZYD_CR117 0x91d4 -#define ZYD_CR118 0x91d8 -#define ZYD_CR119 0x91dc -#define ZYD_CR120 0x91e0 -#define ZYD_CR121 0x91e4 -#define ZYD_CR122 0x91e8 -#define ZYD_CR123 0x91ec -#define ZYD_CR124 0x91f0 -#define ZYD_CR125 0x91f4 -#define ZYD_CR126 0x91f8 -#define ZYD_CR127 0x91fc -#define ZYD_CR128 0x9200 -#define ZYD_CR129 0x9204 -#define ZYD_CR130 0x9208 -#define ZYD_CR131 0x920c -#define ZYD_CR132 0x9210 -#define ZYD_CR133 0x9214 -#define ZYD_CR134 0x9218 -#define ZYD_CR135 0x921c -#define ZYD_CR136 0x9220 -#define ZYD_CR137 0x9224 -#define ZYD_CR138 0x9228 -#define ZYD_CR139 0x922c -#define ZYD_CR140 0x9230 -#define ZYD_CR141 0x9234 -#define ZYD_CR142 0x9238 -#define ZYD_CR143 0x923c -#define ZYD_CR144 0x9240 -#define ZYD_CR145 0x9244 -#define ZYD_CR146 0x9248 -#define ZYD_CR147 0x924c -#define ZYD_CR148 0x9250 -#define ZYD_CR149 0x9254 -#define ZYD_CR150 0x9258 -#define ZYD_CR151 0x925c -#define ZYD_CR152 0x9260 -#define ZYD_CR153 0x9264 -#define ZYD_CR154 0x9268 -#define ZYD_CR155 0x926c -#define ZYD_CR156 0x9270 -#define ZYD_CR157 0x9274 -#define ZYD_CR158 0x9278 -#define ZYD_CR159 0x927c -#define ZYD_CR160 0x9280 -#define ZYD_CR161 0x9284 -#define ZYD_CR162 0x9288 -#define ZYD_CR163 0x928c -#define ZYD_CR164 0x9290 -#define ZYD_CR165 0x9294 -#define ZYD_CR166 0x9298 -#define ZYD_CR167 0x929c -#define ZYD_CR168 0x92a0 -#define ZYD_CR169 0x92a4 -#define ZYD_CR170 0x92a8 -#define ZYD_CR171 0x92ac -#define ZYD_CR172 0x92b0 -#define ZYD_CR173 0x92b4 -#define ZYD_CR174 0x92b8 -#define ZYD_CR175 0x92bc -#define ZYD_CR176 0x92c0 -#define ZYD_CR177 0x92c4 -#define ZYD_CR178 0x92c8 -#define ZYD_CR179 0x92cc -#define ZYD_CR180 0x92d0 -#define ZYD_CR181 0x92d4 -#define ZYD_CR182 0x92d8 -#define ZYD_CR183 0x92dc -#define ZYD_CR184 0x92e0 -#define ZYD_CR185 0x92e4 -#define ZYD_CR186 0x92e8 -#define ZYD_CR187 0x92ec -#define ZYD_CR188 0x92f0 -#define ZYD_CR189 0x92f4 -#define ZYD_CR190 0x92f8 -#define ZYD_CR191 0x92fc -#define ZYD_CR192 0x9300 -#define ZYD_CR193 0x9304 -#define ZYD_CR194 0x9308 -#define ZYD_CR195 0x930c -#define ZYD_CR196 0x9310 -#define ZYD_CR197 0x9314 -#define ZYD_CR198 0x9318 -#define ZYD_CR199 0x931c -#define ZYD_CR200 0x9320 -#define ZYD_CR201 0x9324 -#define ZYD_CR202 0x9328 -#define ZYD_CR203 0x932c -#define ZYD_CR204 0x9330 -#define ZYD_CR205 0x9334 -#define ZYD_CR206 0x9338 -#define ZYD_CR207 0x933c -#define ZYD_CR208 0x9340 -#define ZYD_CR209 0x9344 -#define ZYD_CR210 0x9348 -#define ZYD_CR211 0x934c -#define ZYD_CR212 0x9350 -#define ZYD_CR213 0x9354 -#define ZYD_CR214 0x9358 -#define ZYD_CR215 0x935c -#define ZYD_CR216 0x9360 -#define ZYD_CR217 0x9364 -#define ZYD_CR218 0x9368 -#define ZYD_CR219 0x936c -#define ZYD_CR220 0x9370 -#define ZYD_CR221 0x9374 -#define ZYD_CR222 0x9378 -#define ZYD_CR223 0x937c -#define ZYD_CR224 0x9380 -#define ZYD_CR225 0x9384 -#define ZYD_CR226 0x9388 -#define ZYD_CR227 0x938c -#define ZYD_CR228 0x9390 -#define ZYD_CR229 0x9394 -#define ZYD_CR230 0x9398 -#define ZYD_CR231 0x939c -#define ZYD_CR232 0x93a0 -#define ZYD_CR233 0x93a4 -#define ZYD_CR234 0x93a8 -#define ZYD_CR235 0x93ac -#define ZYD_CR236 0x93b0 -#define ZYD_CR240 0x93c0 -#define ZYD_CR241 0x93c4 -#define ZYD_CR242 0x93c8 -#define ZYD_CR243 0x93cc -#define ZYD_CR244 0x93d0 -#define ZYD_CR245 0x93d4 -#define ZYD_CR251 0x93ec -#define ZYD_CR252 0x93f0 -#define ZYD_CR253 0x93f4 -#define ZYD_CR254 0x93f8 -#define ZYD_CR255 0x93fc +#define ZYD_CR0 0x9000 +#define ZYD_CR1 0x9004 +#define ZYD_CR2 0x9008 +#define ZYD_CR3 0x900c +#define ZYD_CR5 0x9010 +#define ZYD_CR6 0x9014 +#define ZYD_CR7 0x9018 +#define ZYD_CR8 0x901c +#define ZYD_CR4 0x9020 +#define ZYD_CR9 0x9024 +#define ZYD_CR10 0x9028 +#define ZYD_CR11 0x902c +#define ZYD_CR12 0x9030 +#define ZYD_CR13 0x9034 +#define ZYD_CR14 0x9038 +#define ZYD_CR15 0x903c +#define ZYD_CR16 0x9040 +#define ZYD_CR17 0x9044 +#define ZYD_CR18 0x9048 +#define ZYD_CR19 0x904c +#define ZYD_CR20 0x9050 +#define ZYD_CR21 0x9054 +#define ZYD_CR22 0x9058 +#define ZYD_CR23 0x905c +#define ZYD_CR24 0x9060 +#define ZYD_CR25 0x9064 +#define ZYD_CR26 0x9068 +#define ZYD_CR27 0x906c +#define ZYD_CR28 0x9070 +#define ZYD_CR29 0x9074 +#define ZYD_CR30 0x9078 +#define ZYD_CR31 0x907c +#define ZYD_CR32 0x9080 +#define ZYD_CR33 0x9084 +#define ZYD_CR34 0x9088 +#define ZYD_CR35 0x908c +#define ZYD_CR36 0x9090 +#define ZYD_CR37 0x9094 +#define ZYD_CR38 0x9098 +#define ZYD_CR39 0x909c +#define ZYD_CR40 0x90a0 +#define ZYD_CR41 0x90a4 +#define ZYD_CR42 0x90a8 +#define ZYD_CR43 0x90ac +#define ZYD_CR44 0x90b0 +#define ZYD_CR45 0x90b4 +#define ZYD_CR46 0x90b8 +#define ZYD_CR47 0x90bc +#define ZYD_CR48 0x90c0 +#define ZYD_CR49 0x90c4 +#define ZYD_CR50 0x90c8 +#define ZYD_CR51 0x90cc +#define ZYD_CR52 0x90d0 +#define ZYD_CR53 0x90d4 +#define ZYD_CR54 0x90d8 +#define ZYD_CR55 0x90dc +#define ZYD_CR56 0x90e0 +#define ZYD_CR57 0x90e4 +#define ZYD_CR58 0x90e8 +#define ZYD_CR59 0x90ec +#define ZYD_CR60 0x90f0 +#define ZYD_CR61 0x90f4 +#define ZYD_CR62 0x90f8 +#define ZYD_CR63 0x90fc +#define ZYD_CR64 0x9100 +#define ZYD_CR65 0x9104 +#define ZYD_CR66 0x9108 +#define ZYD_CR67 0x910c +#define ZYD_CR68 0x9110 +#define ZYD_CR69 0x9114 +#define ZYD_CR70 0x9118 +#define ZYD_CR71 0x911c +#define ZYD_CR72 0x9120 +#define ZYD_CR73 0x9124 +#define ZYD_CR74 0x9128 +#define ZYD_CR75 0x912c +#define ZYD_CR76 0x9130 +#define ZYD_CR77 0x9134 +#define ZYD_CR78 0x9138 +#define ZYD_CR79 0x913c +#define ZYD_CR80 0x9140 +#define ZYD_CR81 0x9144 +#define ZYD_CR82 0x9148 +#define ZYD_CR83 0x914c +#define ZYD_CR84 0x9150 +#define ZYD_CR85 0x9154 +#define ZYD_CR86 0x9158 +#define ZYD_CR87 0x915c +#define ZYD_CR88 0x9160 +#define ZYD_CR89 0x9164 +#define ZYD_CR90 0x9168 +#define ZYD_CR91 0x916c +#define ZYD_CR92 0x9170 +#define ZYD_CR93 0x9174 +#define ZYD_CR94 0x9178 +#define ZYD_CR95 0x917c +#define ZYD_CR96 0x9180 +#define ZYD_CR97 0x9184 +#define ZYD_CR98 0x9188 +#define ZYD_CR99 0x918c +#define ZYD_CR100 0x9190 +#define ZYD_CR101 0x9194 +#define ZYD_CR102 0x9198 +#define ZYD_CR103 0x919c +#define ZYD_CR104 0x91a0 +#define ZYD_CR105 0x91a4 +#define ZYD_CR106 0x91a8 +#define ZYD_CR107 0x91ac +#define ZYD_CR108 0x91b0 +#define ZYD_CR109 0x91b4 +#define ZYD_CR110 0x91b8 +#define ZYD_CR111 0x91bc +#define ZYD_CR112 0x91c0 +#define ZYD_CR113 0x91c4 +#define ZYD_CR114 0x91c8 +#define ZYD_CR115 0x91cc +#define ZYD_CR116 0x91d0 +#define ZYD_CR117 0x91d4 +#define ZYD_CR118 0x91d8 +#define ZYD_CR119 0x91dc +#define ZYD_CR120 0x91e0 +#define ZYD_CR121 0x91e4 +#define ZYD_CR122 0x91e8 +#define ZYD_CR123 0x91ec +#define ZYD_CR124 0x91f0 +#define ZYD_CR125 0x91f4 +#define ZYD_CR126 0x91f8 +#define ZYD_CR127 0x91fc +#define ZYD_CR128 0x9200 +#define ZYD_CR129 0x9204 +#define ZYD_CR130 0x9208 +#define ZYD_CR131 0x920c +#define ZYD_CR132 0x9210 +#define ZYD_CR133 0x9214 +#define ZYD_CR134 0x9218 +#define ZYD_CR135 0x921c +#define ZYD_CR136 0x9220 +#define ZYD_CR137 0x9224 +#define ZYD_CR138 0x9228 +#define ZYD_CR139 0x922c +#define ZYD_CR140 0x9230 +#define ZYD_CR141 0x9234 +#define ZYD_CR142 0x9238 +#define ZYD_CR143 0x923c +#define ZYD_CR144 0x9240 +#define ZYD_CR145 0x9244 +#define ZYD_CR146 0x9248 +#define ZYD_CR147 0x924c +#define ZYD_CR148 0x9250 +#define ZYD_CR149 0x9254 +#define ZYD_CR150 0x9258 +#define ZYD_CR151 0x925c +#define ZYD_CR152 0x9260 +#define ZYD_CR153 0x9264 +#define ZYD_CR154 0x9268 +#define ZYD_CR155 0x926c +#define ZYD_CR156 0x9270 +#define ZYD_CR157 0x9274 +#define ZYD_CR158 0x9278 +#define ZYD_CR159 0x927c +#define ZYD_CR160 0x9280 +#define ZYD_CR161 0x9284 +#define ZYD_CR162 0x9288 +#define ZYD_CR163 0x928c +#define ZYD_CR164 0x9290 +#define ZYD_CR165 0x9294 +#define ZYD_CR166 0x9298 +#define ZYD_CR167 0x929c +#define ZYD_CR168 0x92a0 +#define ZYD_CR169 0x92a4 +#define ZYD_CR170 0x92a8 +#define ZYD_CR171 0x92ac +#define ZYD_CR172 0x92b0 +#define ZYD_CR173 0x92b4 +#define ZYD_CR174 0x92b8 +#define ZYD_CR175 0x92bc +#define ZYD_CR176 0x92c0 +#define ZYD_CR177 0x92c4 +#define ZYD_CR178 0x92c8 +#define ZYD_CR179 0x92cc +#define ZYD_CR180 0x92d0 +#define ZYD_CR181 0x92d4 +#define ZYD_CR182 0x92d8 +#define ZYD_CR183 0x92dc +#define ZYD_CR184 0x92e0 +#define ZYD_CR185 0x92e4 +#define ZYD_CR186 0x92e8 +#define ZYD_CR187 0x92ec +#define ZYD_CR188 0x92f0 +#define ZYD_CR189 0x92f4 +#define ZYD_CR190 0x92f8 +#define ZYD_CR191 0x92fc +#define ZYD_CR192 0x9300 +#define ZYD_CR193 0x9304 +#define ZYD_CR194 0x9308 +#define ZYD_CR195 0x930c +#define ZYD_CR196 0x9310 +#define ZYD_CR197 0x9314 +#define ZYD_CR198 0x9318 +#define ZYD_CR199 0x931c +#define ZYD_CR200 0x9320 +#define ZYD_CR201 0x9324 +#define ZYD_CR202 0x9328 +#define ZYD_CR203 0x932c +#define ZYD_CR204 0x9330 +#define ZYD_CR205 0x9334 +#define ZYD_CR206 0x9338 +#define ZYD_CR207 0x933c +#define ZYD_CR208 0x9340 +#define ZYD_CR209 0x9344 +#define ZYD_CR210 0x9348 +#define ZYD_CR211 0x934c +#define ZYD_CR212 0x9350 +#define ZYD_CR213 0x9354 +#define ZYD_CR214 0x9358 +#define ZYD_CR215 0x935c +#define ZYD_CR216 0x9360 +#define ZYD_CR217 0x9364 +#define ZYD_CR218 0x9368 +#define ZYD_CR219 0x936c +#define ZYD_CR220 0x9370 +#define ZYD_CR221 0x9374 +#define ZYD_CR222 0x9378 +#define ZYD_CR223 0x937c +#define ZYD_CR224 0x9380 +#define ZYD_CR225 0x9384 +#define ZYD_CR226 0x9388 +#define ZYD_CR227 0x938c +#define ZYD_CR228 0x9390 +#define ZYD_CR229 0x9394 +#define ZYD_CR230 0x9398 +#define ZYD_CR231 0x939c +#define ZYD_CR232 0x93a0 +#define ZYD_CR233 0x93a4 +#define ZYD_CR234 0x93a8 +#define ZYD_CR235 0x93ac +#define ZYD_CR236 0x93b0 +#define ZYD_CR240 0x93c0 +#define ZYD_CR241 0x93c4 +#define ZYD_CR242 0x93c8 +#define ZYD_CR243 0x93cc +#define ZYD_CR244 0x93d0 +#define ZYD_CR245 0x93d4 +#define ZYD_CR251 0x93ec +#define ZYD_CR252 0x93f0 +#define ZYD_CR253 0x93f4 +#define ZYD_CR254 0x93f8 +#define ZYD_CR255 0x93fc /* copied nearly verbatim from the Linux driver rewrite */ #define ZYD_DEF_PHY \ @@ -485,7 +485,7 @@ { ZYD_CR203, 0x30 }, { 0, 0} \ } -#define ZYD_DEF_PHYB \ +#define ZYD_DEF_PHYB \ { \ { ZYD_CR0, 0x14 }, { ZYD_CR1, 0x06 }, { ZYD_CR2, 0x26 }, \ { ZYD_CR3, 0x38 }, { ZYD_CR4, 0x80 }, { ZYD_CR9, 0xe0 }, \ @@ -536,7 +536,7 @@ { 0, 0 } \ } -#define ZYD_RFMD_PHY \ +#define ZYD_RFMD_PHY \ { \ { ZYD_CR2, 0x1e }, { ZYD_CR9, 0x20 }, { ZYD_CR10, 0x89 }, \ { ZYD_CR11, 0x00 }, { ZYD_CR15, 0xd0 }, { ZYD_CR17, 0x68 }, \ @@ -565,14 +565,14 @@ { ZYD_CR150, 0x10 }, { ZYD_CR169, 0xbb }, { ZYD_CR170, 0xbb } \ } -#define ZYD_RFMD_RF \ +#define ZYD_RFMD_RF \ { \ 0x000007, 0x07dd43, 0x080959, 0x0e6666, 0x116a57, 0x17dd43, \ 0x1819f9, 0x1e6666, 0x214554, 0x25e7fa, 0x27fffa, 0x294128, \ 0x2c0000, 0x300000, 0x340000, 0x381e0f, 0x6c180f \ } -#define ZYD_RFMD_CHANTABLE \ +#define ZYD_RFMD_CHANTABLE \ { \ { 0x181979, 0x1e6666 }, \ { 0x181989, 0x1e6666 }, \ @@ -590,7 +590,7 @@ { 0x181a60, 0x1c0000 } \ } -#define ZYD_AL2230_PHY \ +#define ZYD_AL2230_PHY \ { \ { ZYD_CR15, 0x20 }, { ZYD_CR23, 0x40 }, { ZYD_CR24, 0x20 }, \ { ZYD_CR26, 0x11 }, { ZYD_CR28, 0x3e }, { ZYD_CR29, 0x00 }, \ @@ -613,7 +613,7 @@ { ZYD_CR138, 0x28 }, { ZYD_CR203, 0x06 } \ } -#define ZYD_AL2230_PHY_B \ +#define ZYD_AL2230_PHY_B \ { \ { ZYD_CR10, 0x89 }, { ZYD_CR15, 0x20 }, { ZYD_CR17, 0x2B }, \ { ZYD_CR23, 0x40 }, { ZYD_CR24, 0x20 }, { ZYD_CR26, 0x93 }, \ @@ -638,17 +638,17 @@ { ZYD_CR252, 0x34 }, { ZYD_CR253, 0x34 } \ } -#define ZYD_AL2230_PHY_PART1 \ +#define ZYD_AL2230_PHY_PART1 \ { \ { ZYD_CR240, 0x57 }, { ZYD_CR9, 0xe0 } \ } -#define ZYD_AL2230_PHY_PART2 \ +#define ZYD_AL2230_PHY_PART2 \ { \ { ZYD_CR251, 0x2f }, { ZYD_CR251, 0x7f }, \ } -#define ZYD_AL2230_PHY_PART3 \ +#define ZYD_AL2230_PHY_PART3 \ { \ { ZYD_CR128, 0x14 }, { ZYD_CR129, 0x12 }, { ZYD_CR130, 0x10 }, \ } @@ -668,46 +668,46 @@ { ZYD_CR203, 0x06 }, { ZYD_CR240, 0x80 }, \ } -#define ZYD_AL2230_RF_PART1 \ +#define ZYD_AL2230_RF_PART1 \ { \ 0x03f790, 0x033331, 0x00000d, 0x0b3331, 0x03b812, 0x00fff3 \ } -#define ZYD_AL2230_RF_PART2 \ +#define ZYD_AL2230_RF_PART2 \ { \ 0x000da4, 0x0f4dc5, 0x0805b6, 0x011687, 0x000688, 0x0403b9, \ 0x00dbba, 0x00099b, 0x0bdffc, 0x00000d, 0x00500f \ } -#define ZYD_AL2230_RF_PART3 \ +#define ZYD_AL2230_RF_PART3 \ { \ 0x00d00f, 0x004c0f, 0x00540f, 0x00700f, 0x00500f \ } -#define ZYD_AL2230_RF_B \ +#define ZYD_AL2230_RF_B \ { \ 0x03f790, 0x033331, 0x00000d, 0x0b3331, 0x03b812, 0x00fff3, \ 0x0005a4, 0x0f4dc5, 0x0805b6, 0x0146c7, 0x000688, 0x0403b9, \ 0x00dbba, 0x00099b, 0x0bdffc, 0x00000d, 0x00580f \ } -#define ZYD_AL2230_RF_B_PART1 \ +#define ZYD_AL2230_RF_B_PART1 \ { \ 0x8cccd0, 0x481dc0, 0xcfff00, 0x25a000 \ } -#define ZYD_AL2230_RF_B_PART2 \ +#define ZYD_AL2230_RF_B_PART2 \ { \ 0x25a000, 0xa3b2f0, 0x6da010, 0xe36280, 0x116000, 0x9dc020, \ 0x5ddb00, 0xd99000, 0x3ffbd0, 0xb00000, 0xf01a00 \ } -#define ZYD_AL2230_RF_B_PART3 \ +#define ZYD_AL2230_RF_B_PART3 \ { \ 0xf01b00, 0xf01e00, 0xf01a00 \ } -#define ZYD_AL2230_CHANTABLE \ +#define ZYD_AL2230_CHANTABLE \ { \ { 0x03f790, 0x033331, 0x00000d }, \ { 0x03f790, 0x0b3331, 0x00000d }, \ @@ -725,7 +725,7 @@ { 0x03e7c0, 0x066661, 0x00000d } \ } -#define ZYD_AL2230_CHANTABLE_B \ +#define ZYD_AL2230_CHANTABLE_B \ { \ { 0x09efc0, 0x8cccc0, 0xb00000 }, \ { 0x09efc0, 0x8cccd0, 0xb00000 }, \ @@ -743,7 +743,7 @@ { 0x03e7c0, 0x866660, 0xb00000 } \ } -#define ZYD_AL7230B_PHY_1 \ +#define ZYD_AL7230B_PHY_1 \ { \ { ZYD_CR240, 0x57 }, { ZYD_CR15, 0x20 }, { ZYD_CR23, 0x40 }, \ { ZYD_CR24, 0x20 }, { ZYD_CR26, 0x11 }, { ZYD_CR28, 0x3e }, \ @@ -766,36 +766,36 @@ { ZYD_CR251, 0x2f } \ } -#define ZYD_AL7230B_PHY_2 \ +#define ZYD_AL7230B_PHY_2 \ { \ { ZYD_CR251, 0x3f }, { ZYD_CR128, 0x14 }, { ZYD_CR129, 0x12 }, \ { ZYD_CR130, 0x10 }, { ZYD_CR38, 0x38 }, { ZYD_CR136, 0xdf } \ } -#define ZYD_AL7230B_PHY_3 \ +#define ZYD_AL7230B_PHY_3 \ { \ { ZYD_CR203, 0x06 }, { ZYD_CR240, 0x80 } \ } -#define ZYD_AL7230B_RF_1 \ +#define ZYD_AL7230B_RF_1 \ { \ 0x09ec04, 0x8cccc8, 0x4ff821, 0xc5fbfc, 0x21ebfe, 0xafd401, \ 0x6cf56a, 0xe04073, 0x193d76, 0x9dd844, 0x500007, 0xd8c010, \ 0x3c9000, 0xbfffff, 0x700000, 0xf15d58 \ } -#define ZYD_AL7230B_RF_2 \ +#define ZYD_AL7230B_RF_2 \ { \ 0xf15d59, 0xf15d5c, 0xf15d58 \ } -#define ZYD_AL7230B_RF_SETCHANNEL \ +#define ZYD_AL7230B_RF_SETCHANNEL \ { \ 0x4ff821, 0xc5fbfc, 0x21ebfe, 0xafd401, 0x6cf56a, 0xe04073, \ 0x193d76, 0x9dd844, 0x500007, 0xd8c010, 0x3c9000, 0xf15d58 \ } -#define ZYD_AL7230B_CHANTABLE \ +#define ZYD_AL7230B_CHANTABLE \ { \ { 0x09ec00, 0x8cccc8 }, \ { 0x09ec00, 0x8cccd8 }, \ @@ -813,7 +813,7 @@ { 0x03ec00, 0x866660 } \ } -#define ZYD_AL2210_PHY \ +#define ZYD_AL2210_PHY \ { \ { ZYD_CR9, 0xe0 }, { ZYD_CR10, 0x91 }, { ZYD_CR12, 0x90 }, \ { ZYD_CR15, 0xd0 }, { ZYD_CR16, 0x40 }, { ZYD_CR17, 0x58 }, \ @@ -825,20 +825,20 @@ { ZYD_CR127, 0x03 } \ } -#define ZYD_AL2210_RF \ +#define ZYD_AL2210_RF \ { \ 0x2396c0, 0x00fcb1, 0x358132, 0x0108b3, 0xc77804, 0x456415, \ 0xff2226, 0x806667, 0x7860f8, 0xbb01c9, 0x00000a, 0x00000b \ } -#define ZYD_AL2210_CHANTABLE \ +#define ZYD_AL2210_CHANTABLE \ { \ 0x0196c0, 0x019710, 0x019760, 0x0197b0, 0x019800, 0x019850, \ 0x0198a0, 0x0198f0, 0x019940, 0x019990, 0x0199e0, 0x019a30, \ 0x019a80, 0x019b40 \ } -#define ZYD_GCT_PHY \ +#define ZYD_GCT_PHY \ { \ { ZYD_CR47, 0x1e }, { ZYD_CR15, 0xdc }, { ZYD_CR113, 0xc0 }, \ { ZYD_CR20, 0x0c }, { ZYD_CR17, 0x65 }, { ZYD_CR34, 0x04 }, \ @@ -848,7 +848,7 @@ { ZYD_CR64, 0x80 }, { ZYD_CR33, 0x28 }, { ZYD_CR38, 0x30 } \ } -#define ZYD_GCT_RF \ +#define ZYD_GCT_RF \ { \ 0x1f0000, 0x1f0000, 0x1f0200, 0x1f0600, 0x1f8600, 0x1f8600, \ 0x002050, 0x1f8000, 0x1f8200, 0x1f8600, 0x1c0000, 0x10c458, \ @@ -859,14 +859,14 @@ 0x150000, 0x0c7000, 0x150800, 0x150000 \ } -#define ZYD_GCT_CHANTABLE \ +#define ZYD_GCT_CHANTABLE \ { \ 0x1a0000, 0x1a8000, 0x1a4000, 0x1ac000, 0x1a2000, 0x1aa000, \ 0x1a6000, 0x1ae000, 0x1a1000, 0x1a9000, 0x1a5000, 0x1ad000, \ 0x1a3000, 0x1ab000 \ } -#define ZYD_MAXIM_PHY \ +#define ZYD_MAXIM_PHY \ { \ { ZYD_CR23, 0x40 }, { ZYD_CR15, 0x20 }, { ZYD_CR28, 0x3e }, \ { ZYD_CR29, 0x00 }, { ZYD_CR26, 0x11 }, { ZYD_CR44, 0x33 }, \ @@ -893,14 +893,14 @@ { ZYD_CR150, 0x0d } \ } -#define ZYD_MAXIM_RF \ +#define ZYD_MAXIM_RF \ { \ 0x00ccd4, 0x030a03, 0x000400, 0x000ca1, 0x010072, 0x018645, \ 0x004006, 0x0000a7, 0x008258, 0x003fc9, 0x00040a, 0x00000b, \ 0x00026c \ } -#define ZYD_MAXIM_CHANTABLE \ +#define ZYD_MAXIM_CHANTABLE \ { \ { 0x0ccd4, 0x30a03 }, \ { 0x22224, 0x00a13 }, \ @@ -918,7 +918,7 @@ { 0x199a4, 0x20a53 } \ } -#define ZYD_MAXIM2_PHY \ +#define ZYD_MAXIM2_PHY \ { \ { ZYD_CR23, 0x40 }, { ZYD_CR15, 0x20 }, { ZYD_CR28, 0x3e }, \ { ZYD_CR29, 0x00 }, { ZYD_CR26, 0x11 }, { ZYD_CR44, 0x33 }, \ @@ -945,19 +945,19 @@ { ZYD_CR120, 0x4f }, { ZYD_CR121, 0x06 }, { ZYD_CR122, 0xfe } \ } -#define ZYD_MAXIM2_RF \ +#define ZYD_MAXIM2_RF \ { \ 0x33334, 0x10a03, 0x00400, 0x00ca1, 0x10072, 0x18645, 0x04006, \ 0x000a7, 0x08258, 0x03fc9, 0x0040a, 0x0000b, 0x0026c \ } -#define ZYD_MAXIM2_CHANTABLE_F \ +#define ZYD_MAXIM2_CHANTABLE_F \ { \ 0x33334, 0x08884, 0x1ddd4, 0x33334, 0x08884, 0x1ddd4, 0x33334, \ 0x08884, 0x1ddd4, 0x33334, 0x08884, 0x1ddd4, 0x33334, 0x26664 \ } -#define ZYD_MAXIM2_CHANTABLE \ +#define ZYD_MAXIM2_CHANTABLE \ { \ { 0x33334, 0x10a03 }, \ { 0x08884, 0x20a13 }, \ @@ -978,207 +978,228 @@ /* * Control pipe requests. */ -#define ZYD_DOWNLOADREQ 0x30 -#define ZYD_DOWNLOADSTS 0x31 -#define ZYD_READFWDATAREQ 0x32 +#define ZYD_DOWNLOADREQ 0x30 +#define ZYD_DOWNLOADSTS 0x31 +#define ZYD_READFWDATAREQ 0x32 /* possible values for register ZYD_CR_INTERRUPT */ -#define ZYD_HWINT_MASK 0x004f0000 +#define ZYD_HWINT_MASK 0x004f0000 /* possible values for register ZYD_MAC_MISC */ -#define ZYD_UNLOCK_PHY_REGS 0x80 +#define ZYD_UNLOCK_PHY_REGS 0x80 /* possible values for register ZYD_MAC_ENCRYPTION_TYPE */ -#define ZYD_ENC_SNIFFER 8 +#define ZYD_ENC_SNIFFER 8 /* flags for register ZYD_MAC_RXFILTER */ -#define ZYD_FILTER_ASS_REQ (1 << 0) -#define ZYD_FILTER_ASS_RSP (1 << 1) -#define ZYD_FILTER_REASS_REQ (1 << 2) -#define ZYD_FILTER_REASS_RSP (1 << 3) -#define ZYD_FILTER_PRB_REQ (1 << 4) -#define ZYD_FILTER_PRB_RSP (1 << 5) -#define ZYD_FILTER_BCN (1 << 8) -#define ZYD_FILTER_ATIM (1 << 9) -#define ZYD_FILTER_DEASS (1 << 10) -#define ZYD_FILTER_AUTH (1 << 11) -#define ZYD_FILTER_DEAUTH (1 << 12) -#define ZYD_FILTER_PS_POLL (1 << 26) -#define ZYD_FILTER_RTS (1 << 27) -#define ZYD_FILTER_CTS (1 << 28) -#define ZYD_FILTER_ACK (1 << 29) -#define ZYD_FILTER_CFE (1 << 30) -#define ZYD_FILTER_CFE_A (1 << 31) +#define ZYD_FILTER_ASS_REQ (1 << 0) +#define ZYD_FILTER_ASS_RSP (1 << 1) +#define ZYD_FILTER_REASS_REQ (1 << 2) +#define ZYD_FILTER_REASS_RSP (1 << 3) +#define ZYD_FILTER_PRB_REQ (1 << 4) +#define ZYD_FILTER_PRB_RSP (1 << 5) +#define ZYD_FILTER_BCN (1 << 8) +#define ZYD_FILTER_ATIM (1 << 9) +#define ZYD_FILTER_DEASS (1 << 10) +#define ZYD_FILTER_AUTH (1 << 11) +#define ZYD_FILTER_DEAUTH (1 << 12) +#define ZYD_FILTER_PS_POLL (1 << 26) +#define ZYD_FILTER_RTS (1 << 27) +#define ZYD_FILTER_CTS (1 << 28) +#define ZYD_FILTER_ACK (1 << 29) +#define ZYD_FILTER_CFE (1 << 30) +#define ZYD_FILTER_CFE_A (1 << 31) /* helpers for register ZYD_MAC_RXFILTER */ -#define ZYD_FILTER_MONITOR 0xffffffff -#define ZYD_FILTER_BSS \ - (ZYD_FILTER_ASS_REQ | ZYD_FILTER_ASS_RSP | \ - ZYD_FILTER_REASS_REQ | ZYD_FILTER_REASS_RSP | \ - ZYD_FILTER_PRB_REQ | ZYD_FILTER_PRB_RSP | \ - (0x3 << 6) | \ - ZYD_FILTER_BCN | ZYD_FILTER_ATIM | ZYD_FILTER_DEASS | \ - ZYD_FILTER_AUTH | ZYD_FILTER_DEAUTH | \ - (0x7 << 13) | \ - ZYD_FILTER_PS_POLL | ZYD_FILTER_ACK) -#define ZYD_FILTER_HOSTAP \ +#define ZYD_FILTER_MONITOR 0xffffffff +#define ZYD_FILTER_BSS \ + (ZYD_FILTER_ASS_REQ | ZYD_FILTER_ASS_RSP | \ + ZYD_FILTER_REASS_REQ | ZYD_FILTER_REASS_RSP | \ + ZYD_FILTER_PRB_REQ | ZYD_FILTER_PRB_RSP | \ + (0x3 << 6) | \ + ZYD_FILTER_BCN | ZYD_FILTER_ATIM | ZYD_FILTER_DEASS | \ + ZYD_FILTER_AUTH | ZYD_FILTER_DEAUTH | \ + (0x7 << 13) | \ + ZYD_FILTER_PS_POLL | ZYD_FILTER_ACK) +#define ZYD_FILTER_HOSTAP \ (ZYD_FILTER_ASS_REQ | ZYD_FILTER_REASS_REQ | \ ZYD_FILTER_PRB_REQ | ZYD_FILTER_DEASS | ZYD_FILTER_AUTH | \ ZYD_FILTER_DEAUTH | ZYD_FILTER_PS_POLL) struct zyd_tx_desc { - uint8_t phy; -#define ZYD_TX_PHY_SIGNAL(x) ((x) & 0xf) -#define ZYD_TX_PHY_OFDM (1 << 4) -#define ZYD_TX_PHY_SHPREAMBLE (1 << 5)/* CCK */ -#define ZYD_TX_PHY_5GHZ (1 << 5)/* OFDM */ - - uint16_t len; - uint8_t flags; -#define ZYD_TX_FLAG_BACKOFF (1 << 0) -#define ZYD_TX_FLAG_MULTICAST (1 << 1) -#define ZYD_TX_FLAG_TYPE(x) (((x) & 0x3) << 2) -#define ZYD_TX_TYPE_DATA 0 -#define ZYD_TX_TYPE_PS_POLL 1 -#define ZYD_TX_TYPE_MGMT 2 -#define ZYD_TX_TYPE_CTL 3 -#define ZYD_TX_FLAG_WAKEUP (1 << 4) -#define ZYD_TX_FLAG_RTS (1 << 5) -#define ZYD_TX_FLAG_ENCRYPT (1 << 6) -#define ZYD_TX_FLAG_CTS_TO_SELF (1 << 7) - - uint16_t pktlen; - uint16_t plcp_length; - uint8_t plcp_service; -#define ZYD_PLCP_LENGEXT 0x80 - - uint16_t nextlen; + uint8_t phy; +#define ZYD_TX_PHY_SIGNAL(x) ((x) & 0xf) +#define ZYD_TX_PHY_OFDM (1 << 4) +#define ZYD_TX_PHY_SHPREAMBLE (1 << 5) /* CCK */ +#define ZYD_TX_PHY_5GHZ (1 << 5) /* OFDM */ + uint16_t len; + uint8_t flags; +#define ZYD_TX_FLAG_BACKOFF (1 << 0) +#define ZYD_TX_FLAG_MULTICAST (1 << 1) +#define ZYD_TX_FLAG_TYPE(x) (((x) & 0x3) << 2) +#define ZYD_TX_TYPE_DATA 0 +#define ZYD_TX_TYPE_PS_POLL 1 +#define ZYD_TX_TYPE_MGMT 2 +#define ZYD_TX_TYPE_CTL 3 +#define ZYD_TX_FLAG_WAKEUP (1 << 4) +#define ZYD_TX_FLAG_RTS (1 << 5) +#define ZYD_TX_FLAG_ENCRYPT (1 << 6) +#define ZYD_TX_FLAG_CTS_TO_SELF (1 << 7) + uint16_t pktlen; + uint16_t plcp_length; + uint8_t plcp_service; +#define ZYD_PLCP_LENGEXT 0x80 + uint16_t nextlen; } __packed; struct zyd_plcphdr { - uint8_t signal; - uint8_t reserved[2]; - uint16_t service; /* unaligned! */ + uint8_t signal; + uint8_t reserved[2]; + uint16_t service; /* unaligned! */ } __packed; struct zyd_rx_stat { - uint8_t signal_cck; - uint8_t rssi; - uint8_t signal_ofdm; - uint8_t cipher; -#define ZYD_RX_CIPHER_WEP64 1 -#define ZYD_RX_CIPHER_TKIP 2 -#define ZYD_RX_CIPHER_AES 4 -#define ZYD_RX_CIPHER_WEP128 5 -#define ZYD_RX_CIPHER_WEP256 6 -#define ZYD_RX_CIPHER_WEP \ + uint8_t signal_cck; + uint8_t rssi; + uint8_t signal_ofdm; + uint8_t cipher; +#define ZYD_RX_CIPHER_WEP64 1 +#define ZYD_RX_CIPHER_TKIP 2 +#define ZYD_RX_CIPHER_AES 4 +#define ZYD_RX_CIPHER_WEP128 5 +#define ZYD_RX_CIPHER_WEP256 6 +#define ZYD_RX_CIPHER_WEP \ (ZYD_RX_CIPHER_WEP64 | ZYD_RX_CIPHER_WEP128 | ZYD_RX_CIPHER_WEP256) - - uint8_t flags; -#define ZYD_RX_OFDM (1 << 0) -#define ZYD_RX_TIMEOUT (1 << 1) -#define ZYD_RX_OVERRUN (1 << 2) -#define ZYD_RX_DECRYPTERR (1 << 3) -#define ZYD_RX_BADCRC32 (1 << 4) -#define ZYD_RX_NOT2ME (1 << 5) -#define ZYD_RX_BADCRC16 (1 << 6) -#define ZYD_RX_ERROR (1 << 7) + uint8_t flags; +#define ZYD_RX_OFDM (1 << 0) +#define ZYD_RX_TIMEOUT (1 << 1) +#define ZYD_RX_OVERRUN (1 << 2) +#define ZYD_RX_DECRYPTERR (1 << 3) +#define ZYD_RX_BADCRC32 (1 << 4) +#define ZYD_RX_NOT2ME (1 << 5) +#define ZYD_RX_BADCRC16 (1 << 6) +#define ZYD_RX_ERROR (1 << 7) } __packed; /* this structure may be unaligned */ struct zyd_rx_desc { -#define ZYD_MAX_RXFRAMECNT 3 - uWord len[ZYD_MAX_RXFRAMECNT]; - uWord tag; -#define ZYD_TAG_MULTIFRAME 0x697e +#define ZYD_MAX_RXFRAMECNT 3 + uWord len[ZYD_MAX_RXFRAMECNT]; + uWord tag; +#define ZYD_TAG_MULTIFRAME 0x697e } __packed; /* I2C bus alike */ -struct zyd_rfwrite { - uint16_t code; - uint16_t width; - uint16_t bit[32]; -#define ZYD_RF_IF_LE (1 << 1) -#define ZYD_RF_CLK (1 << 2) -#define ZYD_RF_DATA (1 << 3) +struct zyd_rfwrite_cmd { + uint16_t code; + uint16_t width; + uint16_t bit[32]; +#define ZYD_RF_IF_LE (1 << 1) +#define ZYD_RF_CLK (1 << 2) +#define ZYD_RF_DATA (1 << 3) } __packed; struct zyd_cmd { - uint16_t code; -#define ZYD_CMD_IOWR 0x0021 /* write HMAC or PHY register */ -#define ZYD_CMD_IORD 0x0022 /* read HMAC or PHY register */ -#define ZYD_CMD_RFCFG 0x0023 /* write RF register */ -#define ZYD_NOTIF_IORD 0x9001 /* response for ZYD_CMD_IORD */ -#define ZYD_NOTIF_MACINTR 0x9001 /* interrupt notification */ -#define ZYD_NOTIF_RETRYSTATUS 0xa001 /* Tx retry notification */ - - uint8_t data[64]; + uint16_t code; +#define ZYD_CMD_IOWR 0x0021 /* write HMAC or PHY register */ +#define ZYD_CMD_IORD 0x0022 /* read HMAC or PHY register */ +#define ZYD_CMD_RFCFG 0x0023 /* write RF register */ +#define ZYD_NOTIF_IORD 0x9001 /* response for ZYD_CMD_IORD */ +#define ZYD_NOTIF_MACINTR 0x9001 /* interrupt notification */ +#define ZYD_NOTIF_RETRYSTATUS 0xa001 /* Tx retry notification */ + uint8_t data[64]; } __packed; /* structure for command ZYD_CMD_IOWR */ struct zyd_pair { - uint16_t reg; + uint16_t reg; /* helpers macros to read/write 32-bit registers */ -#define ZYD_REG32_LO(reg) (reg) -#define ZYD_REG32_HI(reg) \ +#define ZYD_REG32_LO(reg) (reg) +#define ZYD_REG32_HI(reg) \ ((reg) + ((((reg) & 0xf000) == 0x9000) ? 2 : 1)) - - uint16_t val; + uint16_t val; } __packed; /* structure for notification ZYD_NOTIF_RETRYSTATUS */ struct zyd_notif_retry { - uint16_t rate; - uint8_t macaddr[IEEE80211_ADDR_LEN]; - uint16_t count; + uint16_t rate; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint16_t count; } __packed; -#define ZYD_HW_PADDING 10 /* bytes */ +#define ZYD_CONFIG_INDEX 0 +#define ZYD_IFACE_INDEX 0 -#define ZYD_CONFIG_INDEX 0 -#define ZYD_IFACE_INDEX 0 +#define ZYD_INTR_TIMEOUT 1000 +#define ZYD_TX_TIMEOUT 10000 -#define ZYD_INTR_TIMEOUT 1000 -#define ZYD_TX_TIMEOUT 10000 - -#define ZYD_MAX_TXBUFSZ \ +#define ZYD_MAX_TXBUFSZ \ (sizeof(struct zyd_tx_desc) + MCLBYTES) - -#define ZYD_MIN_FRAGSZ \ +#define ZYD_MIN_FRAGSZ \ (sizeof(struct zyd_plcphdr) + IEEE80211_MIN_LEN + \ sizeof(struct zyd_rx_stat)) -#define ZYX_MAX_RXBUFSZ \ +#define ZYD_MIN_RXBUFSZ ZYD_MIN_FRAGSZ +#define ZYX_MAX_RXBUFSZ \ ((sizeof (struct zyd_plcphdr) + IEEE80211_MAX_LEN + \ sizeof (struct zyd_rx_stat)) * ZYD_MAX_RXFRAMECNT + \ sizeof (struct zyd_rx_desc)) +#define ZYD_TX_DESC_SIZE (sizeof (struct zyd_tx_desc)) - -#define ZYD_CMD_FLAG_READ (1 << 0) +#define ZYD_RX_LIST_CNT 1 +#define ZYD_TX_LIST_CNT 5 +#define ZYD_CMD_FLAG_READ (1 << 0) +#define ZYD_CMD_FLAG_SENT (1 << 1) /* quickly determine if a given rate is CCK or OFDM */ -#define ZYD_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) +#define ZYD_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) struct zyd_phy_pair { - uint16_t reg; - uint8_t val; + uint16_t reg; + uint8_t val; }; struct zyd_mac_pair { - uint16_t reg; - uint32_t val; + uint16_t reg; + uint32_t val; }; +struct zyd_task { + struct usb2_proc_msg hdr; + struct zyd_softc *sc; +}; + +struct zyd_tx_data { + STAILQ_ENTRY(zyd_tx_data) next; + struct zyd_softc *sc; + struct zyd_tx_desc desc; + struct mbuf *m; + struct ieee80211_node *ni; + int rate; +}; +typedef STAILQ_HEAD(, zyd_tx_data) zyd_txdhead; + +struct zyd_rx_data { + struct mbuf *m; + int rssi; +}; + +struct zyd_node { + struct ieee80211_node ni; /* must be the first */ + struct ieee80211_amrr_node amn; +}; +#define ZYD_NODE(ni) ((struct zyd_node *)(ni)) + struct zyd_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; - uint8_t wr_flags; - uint8_t wr_rate; - uint16_t wr_chan_freq; - uint16_t wr_chan_flags; - int8_t wr_antsignal; - int8_t wr_antnoise; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + int8_t wr_antsignal; + int8_t wr_antnoise; } __packed; -#define ZYD_RX_RADIOTAP_PRESENT \ +#define ZYD_RX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ @@ -1187,171 +1208,131 @@ struct zyd_rx_radiotap_header { struct zyd_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; - uint8_t wt_flags; - uint8_t wt_rate; - uint16_t wt_chan_freq; - uint16_t wt_chan_flags; + uint8_t wt_flags; + uint8_t wt_rate; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; } __packed; -#define ZYD_TX_RADIOTAP_PRESENT \ +#define ZYD_TX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL)) -struct zyd_softc; /* forward declaration */ +struct zyd_softc; /* forward declaration */ struct zyd_rf { /* RF methods */ - void (*cfg_init_hw) (struct zyd_softc *, struct zyd_rf *); - void (*cfg_switch_radio) (struct zyd_softc *, uint8_t on); - void (*cfg_set_channel) (struct zyd_softc *, struct zyd_rf *, uint8_t); - void (*cfg_bandedge6) (struct zyd_softc *, struct zyd_rf *, uint8_t); - - uint8_t width; + int (*init)(struct zyd_rf *); + int (*switch_radio)(struct zyd_rf *, int); + int (*set_channel)(struct zyd_rf *, uint8_t); + int (*bandedge6)(struct zyd_rf *, + struct ieee80211_channel *); + /* RF attributes */ + struct zyd_softc *rf_sc; /* back-pointer */ + int width; }; -struct zyd_ifq { - struct mbuf *ifq_head; - struct mbuf *ifq_tail; - uint16_t ifq_len; +struct zyd_rq { + struct zyd_cmd *cmd; + const uint16_t *idata; + struct zyd_pair *odata; + int ilen; + int olen; + int flags; + STAILQ_ENTRY(zyd_rq) rq; }; -struct zyd_node { - struct ieee80211_node ni; - struct ieee80211_amrr_node amn; -}; - -#define ZYD_NODE(ni) ((struct zyd_node *)(ni)) - struct zyd_vap { - struct ieee80211vap vap; - struct ieee80211_beacon_offsets bo; - struct ieee80211_amrr amrr; - - int (*newstate) (struct ieee80211vap *, - enum ieee80211_state, int); -}; - -#define ZYD_VAP(vap) ((struct zyd_vap *)(vap)) - -struct zyd_config_copy_chan { - uint32_t chan_to_ieee; - enum ieee80211_phymode chan_to_mode; - uint16_t ic_freq; - uint8_t chan_is_5ghz:1; - uint8_t chan_is_2ghz:1; - uint8_t chan_is_b:1; - uint8_t chan_is_a:1; - uint8_t chan_is_g:1; - uint8_t unused:3; -}; - -struct zyd_config_copy_bss { - uint16_t ni_intval; - uint8_t ni_bssid[IEEE80211_ADDR_LEN]; - uint8_t fixed_rate_none; -}; - -struct zyd_config_copy { - struct zyd_config_copy_chan ic_curchan; - struct zyd_config_copy_chan ic_bsschan; - struct zyd_config_copy_bss iv_bss; - - enum ieee80211_opmode ic_opmode; - - uint32_t ic_flags; - uint32_t if_flags; - - uint32_t zyd_multi_low; - uint32_t zyd_multi_high; - - uint16_t ic_txpowlimit; - uint16_t ic_curmode; - - uint8_t ic_myaddr[IEEE80211_ADDR_LEN]; - uint8_t if_broadcastaddr[IEEE80211_ADDR_LEN]; + struct ieee80211vap vap; + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); + struct ieee80211_amrr amrr; }; +#define ZYD_VAP(vap) ((struct zyd_vap *)(vap)) enum { - ZYD_BULK_DT_WR, - ZYD_BULK_DT_RD, - ZYD_BULK_CS_WR, - ZYD_BULK_CS_RD, - ZYD_INTR_DT_WR, - ZYD_INTR_DT_RD, - ZYD_INTR_CS_WR, - ZYD_INTR_CS_RD, - ZYD_N_TRANSFER = 8, + ZYD_BULK_WR, + ZYD_BULK_RD, + ZYD_INTR_WR, + ZYD_INTR_RD, + ZYD_N_TRANSFER = 4, }; struct zyd_softc { - struct ifnet *sc_ifp; + struct ifnet *sc_ifp; + device_t sc_dev; + struct usb2_device *sc_udev; + struct usb2_process sc_tq; - struct zyd_rf sc_rf; - struct usb2_callout sc_watchdog; - struct mtx sc_mtx; - struct usb2_config_td sc_config_td; - struct zyd_rx_radiotap_header sc_rxtap; - struct zyd_tx_radiotap_header sc_txtap; - struct zyd_cmd sc_intr_ibuf; - struct zyd_cmd sc_intr_obuf; - struct zyd_tx_desc sc_tx_desc; - struct zyd_ifq sc_tx_queue; - struct cv sc_intr_cv; + struct usb2_xfer *sc_xfer[ZYD_N_TRANSFER]; - struct usb2_device *sc_udev; - struct usb2_xfer *sc_xfer[ZYD_N_TRANSFER]; - const struct ieee80211_rate_table *sc_rates; + enum ieee80211_state sc_state; + int sc_arg; + int sc_flags; +#define ZYD_FLAG_FWLOADED (1 << 0) +#define ZYD_FLAG_INITONCE (1 << 1) +#define ZYD_FLAG_INITDONE (1 << 2) + int sc_if_flags; - enum ieee80211_state sc_ns_state; - uint32_t sc_rxtap_len; - uint32_t sc_txtap_len; - uint32_t sc_unit; - uint32_t sc_atim_wnd; - uint32_t sc_pre_tbtt; - uint32_t sc_bcn_int; + struct zyd_task sc_synctask[2]; + struct zyd_task sc_mcasttask[2]; + struct zyd_task sc_scantask[2]; + int sc_scan_action; +#define ZYD_SCAN_START 0 +#define ZYD_SCAN_END 1 +#define ZYD_SET_CHANNEL 2 + struct zyd_task sc_task[2]; - int sc_ns_arg; + struct zyd_rf sc_rf; - uint16_t sc_firmware_base; - uint16_t sc_fw_ver; - uint16_t sc_fwbase; - uint16_t sc_fw_rev; + STAILQ_HEAD(, zyd_rq) sc_rtx; + STAILQ_HEAD(, zyd_rq) sc_rqh; - uint8_t sc_intr_iwakeup; - uint8_t sc_intr_owakeup; - uint8_t sc_intr_ilen; - uint8_t sc_intr_olen; - uint8_t sc_regdomain; - uint8_t sc_mac_rev; - uint8_t sc_rf_rev; - uint8_t sc_pa_rev; - uint8_t sc_al2230s; - uint8_t sc_cckgain; - uint8_t sc_bandedge6; - uint8_t sc_newphy; - uint8_t sc_ledtype; - uint8_t sc_txled; - uint8_t sc_fix_cr157; - uint8_t sc_pwr_cal[14]; - uint8_t sc_pwr_int[14]; - uint8_t sc_ofdm36_cal[14]; - uint8_t sc_ofdm48_cal[14]; - uint8_t sc_ofdm54_cal[14]; + uint8_t sc_bssid[IEEE80211_ADDR_LEN]; + uint16_t sc_fwbase; + uint8_t sc_regdomain; + uint8_t sc_macrev; + uint16_t sc_fwrev; + uint8_t sc_rfrev; + uint8_t sc_parev; + uint8_t sc_al2230s; + uint8_t sc_bandedge6; + uint8_t sc_newphy; + uint8_t sc_cckgain; + uint8_t sc_fix_cr157; + uint8_t sc_ledtype; + uint8_t sc_txled; - uint8_t sc_flags; -#define ZYD_FLAG_INTR_READ_STALL 0x01 -#define ZYD_FLAG_INTR_WRITE_STALL 0x02 -#define ZYD_FLAG_BULK_READ_STALL 0x04 -#define ZYD_FLAG_BULK_WRITE_STALL 0x08 -#define ZYD_FLAG_TX_BEACON 0x10 -#define ZYD_FLAG_HL_READY 0x20 -#define ZYD_FLAG_LL_READY 0x40 -#define ZYD_FLAG_WAIT_COMMAND 0x80 + uint32_t sc_atim_wnd; + uint32_t sc_pre_tbtt; + uint32_t sc_bcn_int; - uint8_t sc_amrr_timer; + uint8_t sc_pwrcal[14]; + uint8_t sc_pwrint[14]; + uint8_t sc_ofdm36_cal[14]; + uint8_t sc_ofdm48_cal[14]; + uint8_t sc_ofdm54_cal[14]; - uint8_t sc_myaddr[IEEE80211_ADDR_LEN]; + struct mtx sc_mtx; + struct cv sc_intr_cv; + struct zyd_tx_data tx_data[ZYD_TX_LIST_CNT]; + zyd_txdhead tx_q; + zyd_txdhead tx_free; + int tx_nfree; + struct zyd_rx_desc sc_rx_desc; + struct zyd_rx_data sc_rx_data[ZYD_MAX_RXFRAMECNT]; + int sc_rx_count; - char sc_name[16]; + struct zyd_cmd sc_ibuf; + + struct zyd_rx_radiotap_header sc_rxtap; + int sc_rxtap_len; + struct zyd_tx_radiotap_header sc_txtap; + int sc_txtap_len; }; + +#define ZYD_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define ZYD_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define ZYD_LOCK_ASSERT(sc, t) mtx_assert(&(sc)->sc_mtx, t) +