if_zyd.c revision 184610
1184610Salfred/*	$OpenBSD: if_zyd.c,v 1.52 2007/02/11 00:08:04 jsg Exp $	*/
2184610Salfred/*	$NetBSD: if_zyd.c,v 1.7 2007/06/21 04:04:29 kiyohara Exp $	*/
3184610Salfred/*	$FreeBSD: head/sys/dev/usb2/wlan/if_zyd2.c 184610 2008-11-04 02:31:03Z alfred $	*/
4184610Salfred
5184610Salfred/*-
6184610Salfred * Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr>
7184610Salfred * Copyright (c) 2006 by Florian Stoehr <ich@florian-stoehr.de>
8184610Salfred *
9184610Salfred * Permission to use, copy, modify, and distribute this software for any
10184610Salfred * purpose with or without fee is hereby granted, provided that the above
11184610Salfred * copyright notice and this permission notice appear in all copies.
12184610Salfred *
13184610Salfred * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14184610Salfred * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15184610Salfred * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16184610Salfred * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17184610Salfred * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18184610Salfred * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19184610Salfred * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20184610Salfred */
21184610Salfred
22184610Salfred#include <sys/cdefs.h>
23184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/wlan/if_zyd2.c 184610 2008-11-04 02:31:03Z alfred $");
24184610Salfred
25184610Salfred/*
26184610Salfred * ZyDAS ZD1211/ZD1211B USB WLAN driver
27184610Salfred *
28184610Salfred * NOTE: all function names beginning like "zyd_cfg_" can only
29184610Salfred * be called from within the config thread function !
30184610Salfred */
31184610Salfred
32184610Salfred#include <dev/usb2/include/usb2_devid.h>
33184610Salfred#include <dev/usb2/include/usb2_standard.h>
34184610Salfred#include <dev/usb2/include/usb2_mfunc.h>
35184610Salfred#include <dev/usb2/include/usb2_error.h>
36184610Salfred
37184610Salfred#define	usb2_config_td_cc zyd_config_copy
38184610Salfred#define	usb2_config_td_softc zyd_softc
39184610Salfred
40184610Salfred#define	USB_DEBUG_VAR zyd_debug
41184610Salfred
42184610Salfred#include <dev/usb2/core/usb2_core.h>
43184610Salfred#include <dev/usb2/core/usb2_lookup.h>
44184610Salfred#include <dev/usb2/core/usb2_process.h>
45184610Salfred#include <dev/usb2/core/usb2_config_td.h>
46184610Salfred#include <dev/usb2/core/usb2_debug.h>
47184610Salfred#include <dev/usb2/core/usb2_request.h>
48184610Salfred#include <dev/usb2/core/usb2_busdma.h>
49184610Salfred#include <dev/usb2/core/usb2_util.h>
50184610Salfred
51184610Salfred#include <dev/usb2/wlan/usb2_wlan.h>
52184610Salfred#include <dev/usb2/wlan/if_zyd2_reg.h>
53184610Salfred#include <dev/usb2/wlan/if_zyd2_fw.h>
54184610Salfred
55184610Salfred#if USB_DEBUG
56184610Salfredstatic int zyd_debug = 0;
57184610Salfred
58184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, zyd, CTLFLAG_RW, 0, "USB zyd");
59184610SalfredSYSCTL_INT(_hw_usb2_zyd, OID_AUTO, debug, CTLFLAG_RW, &zyd_debug, 0,
60184610Salfred    "zyd debug level");
61184610Salfred#endif
62184610Salfred
63184610Salfred#undef INDEXES
64184610Salfred#define	INDEXES(a) (sizeof(a) / sizeof((a)[0]))
65184610Salfred
66184610Salfredstatic device_probe_t zyd_probe;
67184610Salfredstatic device_attach_t zyd_attach;
68184610Salfredstatic device_detach_t zyd_detach;
69184610Salfred
70184610Salfredstatic usb2_callback_t zyd_intr_read_clear_stall_callback;
71184610Salfredstatic usb2_callback_t zyd_intr_read_callback;
72184610Salfredstatic usb2_callback_t zyd_intr_write_clear_stall_callback;
73184610Salfredstatic usb2_callback_t zyd_intr_write_callback;
74184610Salfredstatic usb2_callback_t zyd_bulk_read_clear_stall_callback;
75184610Salfredstatic usb2_callback_t zyd_bulk_read_callback;
76184610Salfredstatic usb2_callback_t zyd_bulk_write_clear_stall_callback;
77184610Salfredstatic usb2_callback_t zyd_bulk_write_callback;
78184610Salfred
79184610Salfredstatic usb2_config_td_command_t zyd_cfg_first_time_setup;
80184610Salfredstatic usb2_config_td_command_t zyd_cfg_update_promisc;
81184610Salfredstatic usb2_config_td_command_t zyd_cfg_set_chan;
82184610Salfredstatic usb2_config_td_command_t zyd_cfg_pre_init;
83184610Salfredstatic usb2_config_td_command_t zyd_cfg_init;
84184610Salfredstatic usb2_config_td_command_t zyd_cfg_pre_stop;
85184610Salfredstatic usb2_config_td_command_t zyd_cfg_stop;
86184610Salfredstatic usb2_config_td_command_t zyd_config_copy;
87184610Salfredstatic usb2_config_td_command_t zyd_cfg_scan_start;
88184610Salfredstatic usb2_config_td_command_t zyd_cfg_scan_end;
89184610Salfredstatic usb2_config_td_command_t zyd_cfg_set_rxfilter;
90184610Salfredstatic usb2_config_td_command_t zyd_cfg_amrr_timeout;
91184610Salfred
92184610Salfredstatic uint8_t zyd_plcp2ieee(uint8_t signal, uint8_t isofdm);
93184610Salfredstatic void zyd_cfg_usbrequest(struct zyd_softc *sc, struct usb2_device_request *req, uint8_t *data);
94184610Salfredstatic void zyd_cfg_usb2_intr_read(struct zyd_softc *sc, void *data, uint32_t size);
95184610Salfredstatic void zyd_cfg_usb2_intr_write(struct zyd_softc *sc, const void *data, uint16_t code, uint32_t size);
96184610Salfredstatic void zyd_cfg_read16(struct zyd_softc *sc, uint16_t addr, uint16_t *value);
97184610Salfredstatic void zyd_cfg_read32(struct zyd_softc *sc, uint16_t addr, uint32_t *value);
98184610Salfredstatic void zyd_cfg_write16(struct zyd_softc *sc, uint16_t addr, uint16_t value);
99184610Salfredstatic void zyd_cfg_write32(struct zyd_softc *sc, uint16_t addr, uint32_t value);
100184610Salfredstatic void zyd_cfg_rfwrite(struct zyd_softc *sc, uint32_t value);
101184610Salfredstatic uint8_t zyd_cfg_uploadfirmware(struct zyd_softc *sc, const uint8_t *fw_ptr, uint32_t fw_len);
102184610Salfredstatic void zyd_cfg_lock_phy(struct zyd_softc *sc);
103184610Salfredstatic void zyd_cfg_unlock_phy(struct zyd_softc *sc);
104184610Salfredstatic void zyd_cfg_set_beacon_interval(struct zyd_softc *sc, uint32_t interval);
105184610Salfredstatic const char *zyd_rf_name(uint8_t type);
106184610Salfredstatic void zyd_cfg_rf_rfmd_init(struct zyd_softc *sc, struct zyd_rf *rf);
107184610Salfredstatic void zyd_cfg_rf_rfmd_switch_radio(struct zyd_softc *sc, uint8_t onoff);
108184610Salfredstatic void zyd_cfg_rf_rfmd_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, uint8_t channel);
109184610Salfredstatic void zyd_cfg_rf_al2230_switch_radio(struct zyd_softc *sc, uint8_t onoff);
110184610Salfredstatic void zyd_cfg_rf_al2230_init(struct zyd_softc *sc, struct zyd_rf *rf);
111184610Salfredstatic void zyd_cfg_rf_al2230_init_b(struct zyd_softc *sc, struct zyd_rf *rf);
112184610Salfredstatic void zyd_cfg_rf_al2230_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, uint8_t channel);
113184610Salfredstatic uint8_t zyd_cfg_rf_init_hw(struct zyd_softc *sc, struct zyd_rf *rf);
114184610Salfredstatic uint8_t zyd_cfg_hw_init(struct zyd_softc *sc);
115184610Salfredstatic void zyd_cfg_set_mac_addr(struct zyd_softc *sc, const uint8_t *addr);
116184610Salfredstatic void zyd_cfg_switch_radio(struct zyd_softc *sc, uint8_t onoff);
117184610Salfredstatic void zyd_cfg_set_bssid(struct zyd_softc *sc, uint8_t *addr);
118184610Salfredstatic void zyd_start_cb(struct ifnet *ifp);
119184610Salfredstatic void zyd_init_cb(void *arg);
120184610Salfredstatic int zyd_ioctl_cb(struct ifnet *ifp, u_long command, caddr_t data);
121184610Salfredstatic void zyd_watchdog(void *arg);
122184610Salfredstatic void zyd_end_of_commands(struct zyd_softc *sc);
123184610Salfredstatic void zyd_newassoc_cb(struct ieee80211_node *ni, int isnew);
124184610Salfredstatic void zyd_scan_start_cb(struct ieee80211com *ic);
125184610Salfredstatic void zyd_scan_end_cb(struct ieee80211com *ic);
126184610Salfredstatic void zyd_set_channel_cb(struct ieee80211com *ic);
127184610Salfredstatic void zyd_cfg_set_led(struct zyd_softc *sc, uint32_t which, uint8_t on);
128184610Salfredstatic 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]);
129184610Salfredstatic void zyd_vap_delete(struct ieee80211vap *);
130184610Salfredstatic struct ieee80211_node *zyd_node_alloc_cb(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]);
131184610Salfredstatic void zyd_cfg_set_run(struct zyd_softc *sc, struct usb2_config_td_cc *cc);
132184610Salfredstatic void zyd_fill_write_queue(struct zyd_softc *sc);
133184610Salfredstatic void zyd_tx_clean_queue(struct zyd_softc *sc);
134184610Salfredstatic void zyd_tx_freem(struct mbuf *m);
135184610Salfredstatic void zyd_tx_mgt(struct zyd_softc *sc, struct mbuf *m, struct ieee80211_node *ni);
136184610Salfredstatic struct ieee80211vap *zyd_get_vap(struct zyd_softc *sc);
137184610Salfredstatic void zyd_tx_data(struct zyd_softc *sc, struct mbuf *m, struct ieee80211_node *ni);
138184610Salfredstatic int zyd_raw_xmit_cb(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params);
139184610Salfredstatic void zyd_setup_desc_and_tx(struct zyd_softc *sc, struct mbuf *m, uint16_t rate);
140184610Salfredstatic int zyd_newstate_cb(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg);
141184610Salfredstatic void zyd_cfg_amrr_start(struct zyd_softc *sc);
142184610Salfredstatic void zyd_update_mcast_cb(struct ifnet *ifp);
143184610Salfredstatic void zyd_update_promisc_cb(struct ifnet *ifp);
144184610Salfred
145184610Salfredstatic const struct zyd_phy_pair zyd_def_phy[] = ZYD_DEF_PHY;
146184610Salfredstatic const struct zyd_phy_pair zyd_def_phyB[] = ZYD_DEF_PHYB;
147184610Salfred
148184610Salfred/* various supported device vendors/products */
149184610Salfred#define	ZYD_ZD1211	0
150184610Salfred#define	ZYD_ZD1211B	1
151184610Salfred
152184610Salfredstatic const struct usb2_device_id zyd_devs[] = {
153184610Salfred	/* ZYD_ZD1211 */
154184610Salfred	{USB_VPI(USB_VENDOR_3COM2, USB_PRODUCT_3COM2_3CRUSB10075, ZYD_ZD1211)},
155184610Salfred	{USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_WL54, ZYD_ZD1211)},
156184610Salfred	{USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_WL159G, ZYD_ZD1211)},
157184610Salfred	{USB_VPI(USB_VENDOR_CYBERTAN, USB_PRODUCT_CYBERTAN_TG54USB, ZYD_ZD1211)},
158184610Salfred	{USB_VPI(USB_VENDOR_DRAYTEK, USB_PRODUCT_DRAYTEK_VIGOR550, ZYD_ZD1211)},
159184610Salfred	{USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54GD, ZYD_ZD1211)},
160184610Salfred	{USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54GZL, ZYD_ZD1211)},
161184610Salfred	{USB_VPI(USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GWUS54GZ, ZYD_ZD1211)},
162184610Salfred	{USB_VPI(USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GWUS54MINI, ZYD_ZD1211)},
163184610Salfred	{USB_VPI(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_XG760A, ZYD_ZD1211)},
164184610Salfred	{USB_VPI(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_NUB8301, ZYD_ZD1211)},
165184610Salfred	{USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL113, ZYD_ZD1211)},
166184610Salfred	{USB_VPI(USB_VENDOR_SWEEX, USB_PRODUCT_SWEEX_ZD1211, ZYD_ZD1211)},
167184610Salfred	{USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_QUICKWLAN, ZYD_ZD1211)},
168184610Salfred	{USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZD1211_1, ZYD_ZD1211)},
169184610Salfred	{USB_VPI(USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZD1211_2, ZYD_ZD1211)},
170184610Salfred	{USB_VPI(USB_VENDOR_TWINMOS, USB_PRODUCT_TWINMOS_G240, ZYD_ZD1211)},
171184610Salfred	{USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_ALL0298V2, ZYD_ZD1211)},
172184610Salfred	{USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UB_A, ZYD_ZD1211)},
173184610Salfred	{USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UB, ZYD_ZD1211)},
174184610Salfred	{USB_VPI(USB_VENDOR_WISTRONNEWEB, USB_PRODUCT_WISTRONNEWEB_UR055G, ZYD_ZD1211)},
175184610Salfred	{USB_VPI(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_ZD1211, ZYD_ZD1211)},
176184610Salfred	{USB_VPI(USB_VENDOR_ZYDAS, USB_PRODUCT_ZYDAS_ZD1211, ZYD_ZD1211)},
177184610Salfred	{USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_AG225H, ZYD_ZD1211)},
178184610Salfred	{USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_ZYAIRG220, ZYD_ZD1211)},
179184610Salfred	{USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G200V2, ZYD_ZD1211)},
180184610Salfred	{USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G202, ZYD_ZD1211)},
181184610Salfred	/* ZYD_ZD1211B */
182184610Salfred	{USB_VPI(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SMCWUSBG, ZYD_ZD1211B)},
183184610Salfred	{USB_VPI(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_ZD1211B, ZYD_ZD1211B)},
184184610Salfred	{USB_VPI(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_A9T_WIFI, ZYD_ZD1211B)},
185184610Salfred	{USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050_V4000, ZYD_ZD1211B)},
186184610Salfred	{USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_ZD1211B, ZYD_ZD1211B)},
187184610Salfred	{USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSBF54G, ZYD_ZD1211B)},
188184610Salfred	{USB_VPI(USB_VENDOR_FIBERLINE, USB_PRODUCT_FIBERLINE_WL430U, ZYD_ZD1211B)},
189184610Salfred	{USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54L, ZYD_ZD1211B)},
190184610Salfred	{USB_VPI(USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_SNU5600, ZYD_ZD1211B)},
191184610Salfred	{USB_VPI(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US54GXS, ZYD_ZD1211B)},
192184610Salfred	{USB_VPI(USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_XG76NA, ZYD_ZD1211B)},
193184610Salfred	{USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_ZD1211B, ZYD_ZD1211B)},
194184610Salfred	{USB_VPI(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UBC1, ZYD_ZD1211B)},
195184610Salfred	{USB_VPI(USB_VENDOR_USR, USB_PRODUCT_USR_USR5423, ZYD_ZD1211B)},
196184610Salfred	{USB_VPI(USB_VENDOR_VTECH, USB_PRODUCT_VTECH_ZD1211B, ZYD_ZD1211B)},
197184610Salfred	{USB_VPI(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_ZD1211B, ZYD_ZD1211B)},
198184610Salfred	{USB_VPI(USB_VENDOR_ZYDAS, USB_PRODUCT_ZYDAS_ZD1211B, ZYD_ZD1211B)},
199184610Salfred	{USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_M202, ZYD_ZD1211B)},
200184610Salfred	{USB_VPI(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_G220V2, ZYD_ZD1211B)},
201184610Salfred};
202184610Salfred
203184610Salfredstatic const struct usb2_config zyd_config[ZYD_N_TRANSFER] = {
204184610Salfred	[ZYD_TR_BULK_DT_WR] = {
205184610Salfred		.type = UE_BULK,
206184610Salfred		.endpoint = UE_ADDR_ANY,
207184610Salfred		.direction = UE_DIR_OUT,
208184610Salfred		.mh.bufsize = ZYD_MAX_TXBUFSZ,
209184610Salfred		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
210184610Salfred		.mh.callback = &zyd_bulk_write_callback,
211184610Salfred		.ep_index = 0,
212184610Salfred		.mh.timeout = 10000,	/* 10 seconds */
213184610Salfred	},
214184610Salfred
215184610Salfred	[ZYD_TR_BULK_DT_RD] = {
216184610Salfred		.type = UE_BULK,
217184610Salfred		.endpoint = UE_ADDR_ANY,
218184610Salfred		.direction = UE_DIR_IN,
219184610Salfred		.mh.bufsize = ZYX_MAX_RXBUFSZ,
220184610Salfred		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
221184610Salfred		.mh.callback = &zyd_bulk_read_callback,
222184610Salfred		.ep_index = 0,
223184610Salfred	},
224184610Salfred
225184610Salfred	[ZYD_TR_BULK_CS_WR] = {
226184610Salfred		.type = UE_CONTROL,
227184610Salfred		.endpoint = 0x00,	/* Control pipe */
228184610Salfred		.direction = UE_DIR_ANY,
229184610Salfred		.mh.bufsize = sizeof(struct usb2_device_request),
230184610Salfred		.mh.flags = {},
231184610Salfred		.mh.callback = &zyd_bulk_write_clear_stall_callback,
232184610Salfred		.mh.timeout = 1000,	/* 1 second */
233184610Salfred		.mh.interval = 50,	/* 50ms */
234184610Salfred	},
235184610Salfred
236184610Salfred	[ZYD_TR_BULK_CS_RD] = {
237184610Salfred		.type = UE_CONTROL,
238184610Salfred		.endpoint = 0x00,	/* Control pipe */
239184610Salfred		.direction = UE_DIR_ANY,
240184610Salfred		.mh.bufsize = sizeof(struct usb2_device_request),
241184610Salfred		.mh.flags = {},
242184610Salfred		.mh.callback = &zyd_bulk_read_clear_stall_callback,
243184610Salfred		.mh.timeout = 1000,	/* 1 second */
244184610Salfred		.mh.interval = 50,	/* 50ms */
245184610Salfred	},
246184610Salfred
247184610Salfred	[ZYD_TR_INTR_DT_WR] = {
248184610Salfred		.type = UE_BULK_INTR,
249184610Salfred		.endpoint = UE_ADDR_ANY,
250184610Salfred		.direction = UE_DIR_OUT,
251184610Salfred		.mh.bufsize = sizeof(struct zyd_cmd),
252184610Salfred		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
253184610Salfred		.mh.callback = &zyd_intr_write_callback,
254184610Salfred		.mh.timeout = 1000,	/* 1 second */
255184610Salfred		.ep_index = 1,
256184610Salfred	},
257184610Salfred
258184610Salfred	[ZYD_TR_INTR_DT_RD] = {
259184610Salfred		.type = UE_BULK_INTR,
260184610Salfred		.endpoint = UE_ADDR_ANY,
261184610Salfred		.direction = UE_DIR_IN,
262184610Salfred		.mh.bufsize = sizeof(struct zyd_cmd),
263184610Salfred		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
264184610Salfred		.mh.callback = &zyd_intr_read_callback,
265184610Salfred		.ep_index = 1,
266184610Salfred	},
267184610Salfred
268184610Salfred	[ZYD_TR_INTR_CS_WR] = {
269184610Salfred		.type = UE_CONTROL,
270184610Salfred		.endpoint = 0x00,	/* Control pipe */
271184610Salfred		.direction = UE_DIR_ANY,
272184610Salfred		.mh.bufsize = sizeof(struct usb2_device_request),
273184610Salfred		.mh.flags = {},
274184610Salfred		.mh.callback = &zyd_intr_write_clear_stall_callback,
275184610Salfred		.mh.timeout = 1000,	/* 1 second */
276184610Salfred		.mh.interval = 50,	/* 50ms */
277184610Salfred	},
278184610Salfred
279184610Salfred	[ZYD_TR_INTR_CS_RD] = {
280184610Salfred		.type = UE_CONTROL,
281184610Salfred		.endpoint = 0x00,	/* Control pipe */
282184610Salfred		.direction = UE_DIR_ANY,
283184610Salfred		.mh.bufsize = sizeof(struct usb2_device_request),
284184610Salfred		.mh.flags = {},
285184610Salfred		.mh.callback = &zyd_intr_read_clear_stall_callback,
286184610Salfred		.mh.timeout = 1000,	/* 1 second */
287184610Salfred		.mh.interval = 50,	/* 50ms */
288184610Salfred	},
289184610Salfred};
290184610Salfred
291184610Salfredstatic devclass_t zyd_devclass;
292184610Salfred
293184610Salfredstatic device_method_t zyd_methods[] = {
294184610Salfred	DEVMETHOD(device_probe, zyd_probe),
295184610Salfred	DEVMETHOD(device_attach, zyd_attach),
296184610Salfred	DEVMETHOD(device_detach, zyd_detach),
297184610Salfred	{0, 0}
298184610Salfred};
299184610Salfred
300184610Salfredstatic driver_t zyd_driver = {
301184610Salfred	.name = "zyd",
302184610Salfred	.methods = zyd_methods,
303184610Salfred	.size = sizeof(struct zyd_softc),
304184610Salfred};
305184610Salfred
306184610SalfredDRIVER_MODULE(zyd, ushub, zyd_driver, zyd_devclass, NULL, 0);
307184610SalfredMODULE_DEPEND(zyd, usb2_wlan, 1, 1, 1);
308184610SalfredMODULE_DEPEND(zyd, usb2_core, 1, 1, 1);
309184610SalfredMODULE_DEPEND(zyd, wlan, 1, 1, 1);
310184610SalfredMODULE_DEPEND(zyd, wlan_amrr, 1, 1, 1);
311184610Salfred
312184610Salfredstatic uint8_t
313184610Salfredzyd_plcp2ieee(uint8_t signal, uint8_t isofdm)
314184610Salfred{
315184610Salfred	if (isofdm) {
316184610Salfred		static const uint8_t ofdmrates[16] =
317184610Salfred		{0, 0, 0, 0, 0, 0, 0, 96, 48, 24, 12, 108, 72, 36, 18};
318184610Salfred
319184610Salfred		return ofdmrates[signal & 0xf];
320184610Salfred	} else {
321184610Salfred		static const uint8_t cckrates[16] =
322184610Salfred		{0, 0, 0, 0, 4, 0, 0, 11, 0, 0, 2, 0, 0, 0, 22, 0};
323184610Salfred
324184610Salfred		return cckrates[signal & 0xf];
325184610Salfred	}
326184610Salfred}
327184610Salfred
328184610Salfred/*
329184610Salfred * USB request basic wrapper
330184610Salfred */
331184610Salfredstatic void
332184610Salfredzyd_cfg_usbrequest(struct zyd_softc *sc, struct usb2_device_request *req, uint8_t *data)
333184610Salfred{
334184610Salfred	usb2_error_t err;
335184610Salfred	uint16_t length;
336184610Salfred
337184610Salfred	if (usb2_config_td_is_gone(&sc->sc_config_td)) {
338184610Salfred		goto error;
339184610Salfred	}
340184610Salfred	err = usb2_do_request_flags
341184610Salfred	    (sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 1000);
342184610Salfred
343184610Salfred	if (err) {
344184610Salfred
345184610Salfred		DPRINTFN(0, "%s: device request failed, err=%s "
346184610Salfred		    "(ignored)\n", sc->sc_name, usb2_errstr(err));
347184610Salfred
348184610Salfrederror:
349184610Salfred		length = UGETW(req->wLength);
350184610Salfred
351184610Salfred		if ((req->bmRequestType & UT_READ) && length) {
352184610Salfred			bzero(data, length);
353184610Salfred		}
354184610Salfred	}
355184610Salfred	return;
356184610Salfred}
357184610Salfred
358184610Salfredstatic void
359184610Salfredzyd_intr_read_clear_stall_callback(struct usb2_xfer *xfer)
360184610Salfred{
361184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
362184610Salfred	struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_TR_INTR_DT_RD];
363184610Salfred
364184610Salfred	if (usb2_clear_stall_callback(xfer, xfer_other)) {
365184610Salfred		DPRINTF("stall cleared\n");
366184610Salfred		sc->sc_flags &= ~ZYD_FLAG_INTR_READ_STALL;
367184610Salfred		usb2_transfer_start(xfer_other);
368184610Salfred	}
369184610Salfred	return;
370184610Salfred}
371184610Salfred
372184610Salfred/*
373184610Salfred * Callback handler for interrupt transfer
374184610Salfred */
375184610Salfredstatic void
376184610Salfredzyd_intr_read_callback(struct usb2_xfer *xfer)
377184610Salfred{
378184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
379184610Salfred	struct zyd_cmd *cmd = &sc->sc_intr_ibuf;
380184610Salfred	uint32_t actlen;
381184610Salfred
382184610Salfred	switch (USB_GET_STATE(xfer)) {
383184610Salfred	case USB_ST_TRANSFERRED:
384184610Salfred
385184610Salfred		actlen = xfer->actlen;
386184610Salfred
387184610Salfred		DPRINTFN(3, "length=%d\n", actlen);
388184610Salfred
389184610Salfred		if (actlen > sizeof(sc->sc_intr_ibuf)) {
390184610Salfred			actlen = sizeof(sc->sc_intr_ibuf);
391184610Salfred		}
392184610Salfred		usb2_copy_out(xfer->frbuffers, 0,
393184610Salfred		    &sc->sc_intr_ibuf, actlen);
394184610Salfred
395184610Salfred		switch (cmd->code) {
396184610Salfred		case htole16(ZYD_NOTIF_RETRYSTATUS):
397184610Salfred			goto handle_notif_retrystatus;
398184610Salfred		case htole16(ZYD_NOTIF_IORD):
399184610Salfred			goto handle_notif_iord;
400184610Salfred		default:
401184610Salfred			DPRINTFN(2, "unknown indication: 0x%04x\n",
402184610Salfred			    le16toh(cmd->code));
403184610Salfred		}
404184610Salfred
405184610Salfred		/* fallthrough */
406184610Salfred
407184610Salfred	case USB_ST_SETUP:
408184610Salfredtr_setup:
409184610Salfred		if (sc->sc_flags & ZYD_FLAG_INTR_READ_STALL) {
410184610Salfred			usb2_transfer_start(sc->sc_xfer[ZYD_TR_INTR_CS_RD]);
411184610Salfred			break;
412184610Salfred		}
413184610Salfred		xfer->frlengths[0] = xfer->max_data_length;
414184610Salfred		usb2_start_hardware(xfer);
415184610Salfred		break;
416184610Salfred
417184610Salfred	default:			/* Error */
418184610Salfred		DPRINTFN(3, "error = %s\n",
419184610Salfred		    usb2_errstr(xfer->error));
420184610Salfred
421184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
422184610Salfred			/* try to clear stall first */
423184610Salfred			sc->sc_flags |= ZYD_FLAG_INTR_READ_STALL;
424184610Salfred			usb2_transfer_start(sc->sc_xfer[ZYD_TR_INTR_CS_RD]);
425184610Salfred		}
426184610Salfred		break;
427184610Salfred	}
428184610Salfred	return;
429184610Salfred
430184610Salfredhandle_notif_retrystatus:{
431184610Salfred
432184610Salfred		struct zyd_notif_retry *retry = (void *)(cmd->data);
433184610Salfred		struct ifnet *ifp = sc->sc_ifp;
434184610Salfred		struct ieee80211vap *vap;
435184610Salfred		struct ieee80211_node *ni;
436184610Salfred
437184610Salfred		DPRINTF("retry intr: rate=0x%x "
438184610Salfred		    "addr=%02x:%02x:%02x:%02x:%02x:%02x count=%d (0x%x)\n",
439184610Salfred		    le16toh(retry->rate), retry->macaddr[0], retry->macaddr[1],
440184610Salfred		    retry->macaddr[2], retry->macaddr[3], retry->macaddr[4],
441184610Salfred		    retry->macaddr[5], le16toh(retry->count) & 0xff,
442184610Salfred		    le16toh(retry->count));
443184610Salfred
444184610Salfred		vap = zyd_get_vap(sc);
445184610Salfred		if ((vap != NULL) && (sc->sc_amrr_timer)) {
446184610Salfred			/*
447184610Salfred			 * Find the node to which the packet was sent
448184610Salfred			 * and update its retry statistics.  In BSS
449184610Salfred			 * mode, this node is the AP we're associated
450184610Salfred			 * to so no lookup is actually needed.
451184610Salfred			 */
452184610Salfred			ni = ieee80211_find_txnode(vap, retry->macaddr);
453184610Salfred			if (ni != NULL) {
454184610Salfred				ieee80211_amrr_tx_complete(&ZYD_NODE(ni)->amn,
455184610Salfred				    IEEE80211_AMRR_FAILURE, 1);
456184610Salfred				ieee80211_free_node(ni);
457184610Salfred			}
458184610Salfred		}
459184610Salfred		if (retry->count & htole16(0x100)) {
460184610Salfred			ifp->if_oerrors++;	/* too many retries */
461184610Salfred		}
462184610Salfred		goto tr_setup;
463184610Salfred	}
464184610Salfred
465184610Salfredhandle_notif_iord:
466184610Salfred
467184610Salfred	if (*(uint16_t *)cmd->data == htole16(ZYD_CR_INTERRUPT)) {
468184610Salfred		goto tr_setup;		/* HMAC interrupt */
469184610Salfred	}
470184610Salfred	if (actlen < 4) {
471184610Salfred		DPRINTFN(0, "too short, %u bytes\n", actlen);
472184610Salfred		goto tr_setup;		/* too short */
473184610Salfred	}
474184610Salfred	actlen -= 4;
475184610Salfred
476184610Salfred	sc->sc_intr_ilen = actlen;
477184610Salfred
478184610Salfred	if (sc->sc_intr_iwakeup) {
479184610Salfred		sc->sc_intr_iwakeup = 0;
480184610Salfred		usb2_cv_signal(&sc->sc_intr_cv);
481184610Salfred	} else {
482184610Salfred		sc->sc_intr_iwakeup = 1;
483184610Salfred	}
484184610Salfred	/*
485184610Salfred	 * We pause reading data from the interrupt endpoint until the
486184610Salfred	 * data has been picked up!
487184610Salfred	 */
488184610Salfred	return;
489184610Salfred}
490184610Salfred
491184610Salfred/*
492184610Salfred * Interrupt call reply transfer, read
493184610Salfred */
494184610Salfredstatic void
495184610Salfredzyd_cfg_usb2_intr_read(struct zyd_softc *sc, void *data, uint32_t size)
496184610Salfred{
497184610Salfred	uint16_t actlen;
498184610Salfred	uint16_t x;
499184610Salfred
500184610Salfred	if (size > sizeof(sc->sc_intr_ibuf.data)) {
501184610Salfred		DPRINTFN(0, "truncating transfer size!\n");
502184610Salfred		size = sizeof(sc->sc_intr_ibuf.data);
503184610Salfred	}
504184610Salfred	if (usb2_config_td_is_gone(&sc->sc_config_td)) {
505184610Salfred		bzero(data, size);
506184610Salfred		goto done;
507184610Salfred	}
508184610Salfred	if (sc->sc_intr_iwakeup) {
509184610Salfred		DPRINTF("got data already!\n");
510184610Salfred		sc->sc_intr_iwakeup = 0;
511184610Salfred		goto skip0;
512184610Salfred	}
513184610Salfredrepeat:
514184610Salfred	sc->sc_intr_iwakeup = 1;
515184610Salfred
516184610Salfred	while (sc->sc_intr_iwakeup) {
517184610Salfred
518184610Salfred		/* wait for data */
519184610Salfred
520184610Salfred		usb2_transfer_start(sc->sc_xfer[ZYD_TR_INTR_DT_RD]);
521184610Salfred
522184610Salfred		if (usb2_cv_timedwait(&sc->sc_intr_cv,
523184610Salfred		    &sc->sc_mtx, hz / 2)) {
524184610Salfred			/* should not happen */
525184610Salfred		}
526184610Salfred		if (usb2_config_td_is_gone(&sc->sc_config_td)) {
527184610Salfred			bzero(data, size);
528184610Salfred			goto done;
529184610Salfred		}
530184610Salfred	}
531184610Salfredskip0:
532184610Salfred	if (size != sc->sc_intr_ilen) {
533184610Salfred		DPRINTFN(0, "unexpected length %u != %u\n",
534184610Salfred		    size, sc->sc_intr_ilen);
535184610Salfred		goto repeat;
536184610Salfred	}
537184610Salfred	actlen = sc->sc_intr_ilen;
538184610Salfred	actlen /= 4;
539184610Salfred
540184610Salfred	/* verify register values */
541184610Salfred	for (x = 0; x != actlen; x++) {
542184610Salfred		if (sc->sc_intr_obuf.data[(2 * x)] !=
543184610Salfred		    sc->sc_intr_ibuf.data[(4 * x)]) {
544184610Salfred			/* invalid register */
545184610Salfred			DPRINTFN(0, "Invalid register (1) at %u!\n", x);
546184610Salfred			goto repeat;
547184610Salfred		}
548184610Salfred		if (sc->sc_intr_obuf.data[(2 * x) + 1] !=
549184610Salfred		    sc->sc_intr_ibuf.data[(4 * x) + 1]) {
550184610Salfred			/* invalid register */
551184610Salfred			DPRINTFN(0, "Invalid register (2) at %u!\n", x);
552184610Salfred			goto repeat;
553184610Salfred		}
554184610Salfred	}
555184610Salfred
556184610Salfred	bcopy(sc->sc_intr_ibuf.data, data, size);
557184610Salfred
558184610Salfred	/*
559184610Salfred	 * We have fetched the data from the shared buffer and it is
560184610Salfred	 * safe to restart the interrupt transfer!
561184610Salfred	 */
562184610Salfred	usb2_transfer_start(sc->sc_xfer[ZYD_TR_INTR_DT_RD]);
563184610Salfreddone:
564184610Salfred	return;
565184610Salfred}
566184610Salfred
567184610Salfredstatic void
568184610Salfredzyd_intr_write_clear_stall_callback(struct usb2_xfer *xfer)
569184610Salfred{
570184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
571184610Salfred	struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_TR_INTR_DT_WR];
572184610Salfred
573184610Salfred	if (usb2_clear_stall_callback(xfer, xfer_other)) {
574184610Salfred		DPRINTF("stall cleared\n");
575184610Salfred		sc->sc_flags &= ~ZYD_FLAG_INTR_WRITE_STALL;
576184610Salfred		usb2_transfer_start(xfer_other);
577184610Salfred	}
578184610Salfred	return;
579184610Salfred}
580184610Salfred
581184610Salfredstatic void
582184610Salfredzyd_intr_write_callback(struct usb2_xfer *xfer)
583184610Salfred{
584184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
585184610Salfred
586184610Salfred	switch (USB_GET_STATE(xfer)) {
587184610Salfred	case USB_ST_TRANSFERRED:
588184610Salfred		DPRINTFN(3, "length=%d\n", xfer->actlen);
589184610Salfred		goto wakeup;
590184610Salfred
591184610Salfred	case USB_ST_SETUP:
592184610Salfred
593184610Salfred		if (sc->sc_flags & ZYD_FLAG_INTR_WRITE_STALL) {
594184610Salfred			usb2_transfer_start(sc->sc_xfer[ZYD_TR_INTR_CS_WR]);
595184610Salfred			goto wakeup;
596184610Salfred		}
597184610Salfred		if (sc->sc_intr_owakeup) {
598184610Salfred			usb2_copy_in(xfer->frbuffers, 0, &sc->sc_intr_obuf,
599184610Salfred			    sc->sc_intr_olen);
600184610Salfred
601184610Salfred			xfer->frlengths[0] = sc->sc_intr_olen;
602184610Salfred			usb2_start_hardware(xfer);
603184610Salfred		}
604184610Salfred		break;
605184610Salfred
606184610Salfred	default:			/* Error */
607184610Salfred		DPRINTFN(3, "error = %s\n",
608184610Salfred		    usb2_errstr(xfer->error));
609184610Salfred
610184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
611184610Salfred			/* try to clear stall first */
612184610Salfred			sc->sc_flags |= ZYD_FLAG_INTR_WRITE_STALL;
613184610Salfred			usb2_transfer_start(sc->sc_xfer[ZYD_TR_INTR_CS_WR]);
614184610Salfred		}
615184610Salfred		goto wakeup;
616184610Salfred	}
617184610Salfred	return;
618184610Salfred
619184610Salfredwakeup:
620184610Salfred	if (sc->sc_intr_owakeup) {
621184610Salfred		sc->sc_intr_owakeup = 0;
622184610Salfred		usb2_cv_signal(&sc->sc_intr_cv);
623184610Salfred	}
624184610Salfred	return;
625184610Salfred}
626184610Salfred
627184610Salfred/*
628184610Salfred * Interrupt transfer, write.
629184610Salfred *
630184610Salfred * Not always an "interrupt transfer". If operating in
631184610Salfred * full speed mode, EP4 is bulk out, not interrupt out.
632184610Salfred */
633184610Salfredstatic void
634184610Salfredzyd_cfg_usb2_intr_write(struct zyd_softc *sc, const void *data,
635184610Salfred    uint16_t code, uint32_t size)
636184610Salfred{
637184610Salfred	if (size > sizeof(sc->sc_intr_obuf.data)) {
638184610Salfred		DPRINTFN(0, "truncating transfer size!\n");
639184610Salfred		size = sizeof(sc->sc_intr_obuf.data);
640184610Salfred	}
641184610Salfred	if (usb2_config_td_is_gone(&sc->sc_config_td)) {
642184610Salfred		goto done;
643184610Salfred	}
644184610Salfred	sc->sc_intr_olen = size + 2;
645184610Salfred	sc->sc_intr_owakeup = 1;
646184610Salfred
647184610Salfred	sc->sc_intr_obuf.code = htole16(code);
648184610Salfred	bcopy(data, sc->sc_intr_obuf.data, size);
649184610Salfred
650184610Salfred	usb2_transfer_start(sc->sc_xfer[ZYD_TR_INTR_DT_WR]);
651184610Salfred
652184610Salfred	while (sc->sc_intr_owakeup) {
653184610Salfred		if (usb2_cv_timedwait(&sc->sc_intr_cv,
654184610Salfred		    &sc->sc_mtx, hz / 2)) {
655184610Salfred			/* should not happen */
656184610Salfred		}
657184610Salfred		if (usb2_config_td_is_gone(&sc->sc_config_td)) {
658184610Salfred			sc->sc_intr_owakeup = 0;
659184610Salfred			goto done;
660184610Salfred		}
661184610Salfred	}
662184610Salfreddone:
663184610Salfred	return;
664184610Salfred}
665184610Salfred
666184610Salfredstatic void
667184610Salfredzyd_cfg_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, uint16_t ilen,
668184610Salfred    void *odata, uint16_t olen, uint16_t flags)
669184610Salfred{
670184610Salfred	zyd_cfg_usb2_intr_write(sc, idata, code, ilen);
671184610Salfred
672184610Salfred	if (flags & ZYD_CMD_FLAG_READ) {
673184610Salfred		zyd_cfg_usb2_intr_read(sc, odata, olen);
674184610Salfred	}
675184610Salfred	return;
676184610Salfred}
677184610Salfred
678184610Salfredstatic void
679184610Salfredzyd_cfg_read16(struct zyd_softc *sc, uint16_t addr, uint16_t *value)
680184610Salfred{
681184610Salfred	struct zyd_pair tmp[1];
682184610Salfred
683184610Salfred	addr = htole16(addr);
684184610Salfred	zyd_cfg_cmd(sc, ZYD_CMD_IORD, &addr, sizeof(addr),
685184610Salfred	    tmp, sizeof(tmp), ZYD_CMD_FLAG_READ);
686184610Salfred	*value = le16toh(tmp[0].val);
687184610Salfred	return;
688184610Salfred}
689184610Salfred
690184610Salfredstatic void
691184610Salfredzyd_cfg_read32(struct zyd_softc *sc, uint16_t addr, uint32_t *value)
692184610Salfred{
693184610Salfred	struct zyd_pair tmp[2];
694184610Salfred	uint16_t regs[2];
695184610Salfred
696184610Salfred	regs[0] = ZYD_REG32_HI(addr);
697184610Salfred	regs[1] = ZYD_REG32_LO(addr);
698184610Salfred	regs[0] = htole16(regs[0]);
699184610Salfred	regs[1] = htole16(regs[1]);
700184610Salfred
701184610Salfred	zyd_cfg_cmd(sc, ZYD_CMD_IORD, regs, sizeof(regs),
702184610Salfred	    tmp, sizeof(tmp), ZYD_CMD_FLAG_READ);
703184610Salfred	*value = (le16toh(tmp[0].val) << 16) | le16toh(tmp[1].val);
704184610Salfred	return;
705184610Salfred}
706184610Salfred
707184610Salfredstatic void
708184610Salfredzyd_cfg_write16(struct zyd_softc *sc, uint16_t reg, uint16_t val)
709184610Salfred{
710184610Salfred	struct zyd_pair pair[1];
711184610Salfred
712184610Salfred	pair[0].reg = htole16(reg);
713184610Salfred	pair[0].val = htole16(val);
714184610Salfred
715184610Salfred	zyd_cfg_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0);
716184610Salfred	return;
717184610Salfred}
718184610Salfred
719184610Salfredstatic void
720184610Salfredzyd_cfg_write32(struct zyd_softc *sc, uint16_t reg, uint32_t val)
721184610Salfred{
722184610Salfred	struct zyd_pair pair[2];
723184610Salfred
724184610Salfred	pair[0].reg = htole16(ZYD_REG32_HI(reg));
725184610Salfred	pair[0].val = htole16(val >> 16);
726184610Salfred	pair[1].reg = htole16(ZYD_REG32_LO(reg));
727184610Salfred	pair[1].val = htole16(val & 0xffff);
728184610Salfred
729184610Salfred	zyd_cfg_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0);
730184610Salfred	return;
731184610Salfred}
732184610Salfred
733184610Salfred/*------------------------------------------------------------------------*
734184610Salfred *	zyd_cfg_rfwrite - write RF registers
735184610Salfred *------------------------------------------------------------------------*/
736184610Salfredstatic void
737184610Salfredzyd_cfg_rfwrite(struct zyd_softc *sc, uint32_t value)
738184610Salfred{
739184610Salfred	struct zyd_rf *rf = &sc->sc_rf;
740184610Salfred	struct zyd_rfwrite req;
741184610Salfred	uint16_t cr203;
742184610Salfred	uint16_t i;
743184610Salfred
744184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &cr203);
745184610Salfred	cr203 &= ~(ZYD_RF_IF_LE | ZYD_RF_CLK | ZYD_RF_DATA);
746184610Salfred
747184610Salfred	req.code = htole16(2);
748184610Salfred	req.width = htole16(rf->width);
749184610Salfred	for (i = 0; i != rf->width; i++) {
750184610Salfred		req.bit[i] = htole16(cr203);
751184610Salfred		if (value & (1 << (rf->width - 1 - i)))
752184610Salfred			req.bit[i] |= htole16(ZYD_RF_DATA);
753184610Salfred	}
754184610Salfred	zyd_cfg_cmd(sc, ZYD_CMD_RFCFG, &req, 4 + (2 * rf->width), NULL, 0, 0);
755184610Salfred	return;
756184610Salfred}
757184610Salfred
758184610Salfredstatic void
759184610Salfredzyd_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
760184610Salfred{
761184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
762184610Salfred	struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_TR_BULK_DT_RD];
763184610Salfred
764184610Salfred	if (usb2_clear_stall_callback(xfer, xfer_other)) {
765184610Salfred		DPRINTF("stall cleared\n");
766184610Salfred		sc->sc_flags &= ~ZYD_FLAG_BULK_READ_STALL;
767184610Salfred		usb2_transfer_start(xfer_other);
768184610Salfred	}
769184610Salfred	return;
770184610Salfred}
771184610Salfred
772184610Salfredstatic void
773184610Salfredzyd_bulk_read_callback_sub(struct usb2_xfer *xfer, struct zyd_ifq *mq,
774184610Salfred    uint32_t offset, uint16_t len)
775184610Salfred{
776184610Salfred	enum {
777184610Salfred		ZYD_OVERHEAD = (ZYD_HW_PADDING + IEEE80211_CRC_LEN),
778184610Salfred	};
779184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
780184610Salfred	struct ifnet *ifp = sc->sc_ifp;
781184610Salfred	struct zyd_plcphdr plcp;
782184610Salfred	struct zyd_rx_stat stat;
783184610Salfred	struct mbuf *m;
784184610Salfred
785184610Salfred	if (len < ZYD_OVERHEAD) {
786184610Salfred		DPRINTF("frame too "
787184610Salfred		    "short (length=%d)\n", len);
788184610Salfred		ifp->if_ierrors++;
789184610Salfred		return;
790184610Salfred	}
791184610Salfred	usb2_copy_out(xfer->frbuffers, offset, &plcp, sizeof(plcp));
792184610Salfred	usb2_copy_out(xfer->frbuffers, offset + len - sizeof(stat),
793184610Salfred	    &stat, sizeof(stat));
794184610Salfred
795184610Salfred	if (stat.flags & ZYD_RX_ERROR) {
796184610Salfred		DPRINTF("RX status indicated "
797184610Salfred		    "error (0x%02x)\n", stat.flags);
798184610Salfred		ifp->if_ierrors++;
799184610Salfred		return;
800184610Salfred	}
801184610Salfred	/* compute actual frame length */
802184610Salfred	len -= ZYD_OVERHEAD;
803184610Salfred
804184610Salfred	/* allocate a mbuf to store the frame */
805184610Salfred	if (len > MCLBYTES) {
806184610Salfred		DPRINTF("too large frame, "
807184610Salfred		    "%u bytes\n", len);
808184610Salfred		return;
809184610Salfred	} else if (len > MHLEN)
810184610Salfred		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
811184610Salfred	else
812184610Salfred		m = m_gethdr(M_DONTWAIT, MT_DATA);
813184610Salfred
814184610Salfred	if (m == NULL) {
815184610Salfred		DPRINTF("could not allocate rx mbuf\n");
816184610Salfred		ifp->if_ierrors++;
817184610Salfred		return;
818184610Salfred	}
819184610Salfred	m->m_pkthdr.rcvif = ifp;
820184610Salfred	m->m_pkthdr.len = len;
821184610Salfred	m->m_len = len;
822184610Salfred
823184610Salfred	usb2_copy_out(xfer->frbuffers, offset +
824184610Salfred	    sizeof(plcp), m->m_data, len);
825184610Salfred
826184610Salfred	if (bpf_peers_present(ifp->if_bpf)) {
827184610Salfred		struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap;
828184610Salfred
829184610Salfred		tap->wr_flags = 0;
830184610Salfred		if (stat.flags & (ZYD_RX_BADCRC16 | ZYD_RX_BADCRC32))
831184610Salfred			tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;
832184610Salfred		/* XXX toss, no way to express errors */
833184610Salfred		if (stat.flags & ZYD_RX_DECRYPTERR)
834184610Salfred			tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;
835184610Salfred		tap->wr_rate =
836184610Salfred		    zyd_plcp2ieee(plcp.signal, stat.flags & ZYD_RX_OFDM);
837184610Salfred		tap->wr_antsignal = stat.rssi + -95;
838184610Salfred		tap->wr_antnoise = -95;	/* XXX */
839184610Salfred
840184610Salfred		bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m);
841184610Salfred	}
842184610Salfred	if (sizeof(m->m_hdr.pad) > 0) {
843184610Salfred		m->m_hdr.pad[0] = stat.rssi;	/* XXX hack */
844184610Salfred	}
845184610Salfred	_IF_ENQUEUE(mq, m);
846184610Salfred
847184610Salfred	return;
848184610Salfred}
849184610Salfred
850184610Salfredstatic void
851184610Salfredzyd_bulk_read_callback(struct usb2_xfer *xfer)
852184610Salfred{
853184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
854184610Salfred	struct ifnet *ifp = sc->sc_ifp;
855184610Salfred	struct ieee80211com *ic = ifp->if_l2com;
856184610Salfred	struct ieee80211_node *ni;
857184610Salfred	struct zyd_rx_desc rx_desc;
858184610Salfred	struct zyd_ifq mq = {NULL, NULL, 0};
859184610Salfred	struct mbuf *m;
860184610Salfred	uint32_t offset;
861184610Salfred	uint16_t len16;
862184610Salfred	uint8_t x;
863184610Salfred	uint8_t rssi;
864184610Salfred	int8_t nf;
865184610Salfred
866184610Salfred	switch (USB_GET_STATE(xfer)) {
867184610Salfred	case USB_ST_TRANSFERRED:
868184610Salfred
869184610Salfred		if (xfer->actlen < MAX(sizeof(rx_desc), ZYD_MIN_FRAGSZ)) {
870184610Salfred			DPRINTFN(0, "xfer too short, %d bytes\n", xfer->actlen);
871184610Salfred			ifp->if_ierrors++;
872184610Salfred			goto tr_setup;
873184610Salfred		}
874184610Salfred		usb2_copy_out(xfer->frbuffers, xfer->actlen - sizeof(rx_desc),
875184610Salfred		    &rx_desc, sizeof(rx_desc));
876184610Salfred
877184610Salfred		if (UGETW(rx_desc.tag) == ZYD_TAG_MULTIFRAME) {
878184610Salfred
879184610Salfred			offset = 0;
880184610Salfred
881184610Salfred			DPRINTFN(4, "received multi-frame transfer, "
882184610Salfred			    "%u bytes\n", xfer->actlen);
883184610Salfred
884184610Salfred			for (x = 0; x < ZYD_MAX_RXFRAMECNT; x++) {
885184610Salfred				len16 = UGETW(rx_desc.len[x]);
886184610Salfred
887184610Salfred				if ((len16 == 0) || (len16 > xfer->actlen)) {
888184610Salfred					break;
889184610Salfred				}
890184610Salfred				zyd_bulk_read_callback_sub(xfer, &mq, offset, len16);
891184610Salfred
892184610Salfred				/*
893184610Salfred				 * next frame is aligned on a 32-bit
894184610Salfred				 * boundary
895184610Salfred				 */
896184610Salfred				len16 = (len16 + 3) & ~3;
897184610Salfred				offset += len16;
898184610Salfred				if (len16 > xfer->actlen) {
899184610Salfred					break;
900184610Salfred				}
901184610Salfred				xfer->actlen -= len16;
902184610Salfred			}
903184610Salfred		} else {
904184610Salfred			DPRINTFN(4, "received single-frame transfer, "
905184610Salfred			    "%u bytes\n", xfer->actlen);
906184610Salfred			zyd_bulk_read_callback_sub(xfer, &mq, 0, xfer->actlen);
907184610Salfred		}
908184610Salfred
909184610Salfred	case USB_ST_SETUP:
910184610Salfredtr_setup:
911184610Salfred		DPRINTF("setup\n");
912184610Salfred
913184610Salfred		if (sc->sc_flags & ZYD_FLAG_BULK_READ_STALL) {
914184610Salfred			usb2_transfer_start(sc->sc_xfer[ZYD_TR_BULK_CS_RD]);
915184610Salfred		} else {
916184610Salfred			xfer->frlengths[0] = xfer->max_data_length;
917184610Salfred			usb2_start_hardware(xfer);
918184610Salfred		}
919184610Salfred
920184610Salfred		/*
921184610Salfred		 * At the end of a USB callback it is always safe to unlock
922184610Salfred		 * the private mutex of a device! That is why we do the
923184610Salfred		 * "ieee80211_input" here, and not some lines up!
924184610Salfred		 */
925184610Salfred		if (mq.ifq_head) {
926184610Salfred
927184610Salfred			mtx_unlock(&sc->sc_mtx);
928184610Salfred
929184610Salfred			while (1) {
930184610Salfred
931184610Salfred				_IF_DEQUEUE(&mq, m);
932184610Salfred
933184610Salfred				if (m == NULL)
934184610Salfred					break;
935184610Salfred
936184610Salfred				rssi = m->m_hdr.pad[0];	/* XXX hack */
937184610Salfred
938184610Salfred				rssi = (rssi > 63) ? 127 : 2 * rssi;
939184610Salfred				nf = -95;	/* XXX */
940184610Salfred
941184610Salfred				ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *));
942184610Salfred				if (ni != NULL) {
943184610Salfred					if (ieee80211_input(ni, m, rssi, nf, 0)) {
944184610Salfred						/* ignore */
945184610Salfred					}
946184610Salfred					ieee80211_free_node(ni);
947184610Salfred				} else {
948184610Salfred					if (ieee80211_input_all(ic, m, rssi, nf, 0)) {
949184610Salfred						/* ignore */
950184610Salfred					}
951184610Salfred				}
952184610Salfred			}
953184610Salfred
954184610Salfred			mtx_lock(&sc->sc_mtx);
955184610Salfred		}
956184610Salfred		break;
957184610Salfred
958184610Salfred	default:			/* Error */
959184610Salfred		DPRINTF("frame error: %s\n", usb2_errstr(xfer->error));
960184610Salfred
961184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
962184610Salfred			/* try to clear stall first */
963184610Salfred			sc->sc_flags |= ZYD_FLAG_BULK_READ_STALL;
964184610Salfred			usb2_transfer_start(sc->sc_xfer[ZYD_TR_BULK_CS_RD]);
965184610Salfred		}
966184610Salfred		break;
967184610Salfred	}
968184610Salfred	return;
969184610Salfred}
970184610Salfred
971184610Salfred/*------------------------------------------------------------------------*
972184610Salfred *	zyd_cfg_uploadfirmware
973184610Salfred * Returns:
974184610Salfred *    0: Success
975184610Salfred * Else: Failure
976184610Salfred *------------------------------------------------------------------------*/
977184610Salfredstatic uint8_t
978184610Salfredzyd_cfg_uploadfirmware(struct zyd_softc *sc, const uint8_t *fw_ptr,
979184610Salfred    uint32_t fw_len)
980184610Salfred{
981184610Salfred	struct usb2_device_request req;
982184610Salfred	uint16_t temp;
983184610Salfred	uint16_t addr;
984184610Salfred	uint8_t stat;
985184610Salfred
986184610Salfred	DPRINTF("firmware %p size=%u\n", fw_ptr, fw_len);
987184610Salfred
988184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
989184610Salfred	req.bRequest = ZYD_DOWNLOADREQ;
990184610Salfred	USETW(req.wIndex, 0);
991184610Salfred
992184610Salfred	temp = 64;
993184610Salfred
994184610Salfred	addr = ZYD_FIRMWARE_START_ADDR;
995184610Salfred	while (fw_len > 0) {
996184610Salfred
997184610Salfred		if (fw_len < 64) {
998184610Salfred			temp = fw_len;
999184610Salfred		}
1000184610Salfred		DPRINTF("firmware block: fw_len=%u\n", fw_len);
1001184610Salfred
1002184610Salfred		USETW(req.wValue, addr);
1003184610Salfred		USETW(req.wLength, temp);
1004184610Salfred
1005184610Salfred		zyd_cfg_usbrequest(sc, &req,
1006184610Salfred		    USB_ADD_BYTES(fw_ptr, 0));
1007184610Salfred
1008184610Salfred		addr += (temp / 2);
1009184610Salfred		fw_len -= temp;
1010184610Salfred		fw_ptr += temp;
1011184610Salfred	}
1012184610Salfred
1013184610Salfred	/* check whether the upload succeeded */
1014184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1015184610Salfred	req.bRequest = ZYD_DOWNLOADSTS;
1016184610Salfred	USETW(req.wValue, 0);
1017184610Salfred	USETW(req.wIndex, 0);
1018184610Salfred	USETW(req.wLength, sizeof(stat));
1019184610Salfred
1020184610Salfred	zyd_cfg_usbrequest(sc, &req, &stat);
1021184610Salfred
1022184610Salfred	return ((stat & 0x80) ? 1 : 0);
1023184610Salfred}
1024184610Salfred
1025184610Salfred/*
1026184610Salfred * Driver OS interface
1027184610Salfred */
1028184610Salfred
1029184610Salfred/*
1030184610Salfred * Probe for a ZD1211-containing product
1031184610Salfred */
1032184610Salfredstatic int
1033184610Salfredzyd_probe(device_t dev)
1034184610Salfred{
1035184610Salfred	struct usb2_attach_arg *uaa = device_get_ivars(dev);
1036184610Salfred
1037184610Salfred	if (uaa->usb2_mode != USB_MODE_HOST) {
1038184610Salfred		return (ENXIO);
1039184610Salfred	}
1040184610Salfred	if (uaa->info.bConfigIndex != 0) {
1041184610Salfred		return (ENXIO);
1042184610Salfred	}
1043184610Salfred	if (uaa->info.bIfaceIndex != ZYD_IFACE_INDEX) {
1044184610Salfred		return (ENXIO);
1045184610Salfred	}
1046184610Salfred	return (usb2_lookup_id_by_uaa(zyd_devs, sizeof(zyd_devs), uaa));
1047184610Salfred}
1048184610Salfred
1049184610Salfred/*
1050184610Salfred * Attach the interface. Allocate softc structures, do
1051184610Salfred * setup and ethernet/BPF attach.
1052184610Salfred */
1053184610Salfredstatic int
1054184610Salfredzyd_attach(device_t dev)
1055184610Salfred{
1056184610Salfred	struct usb2_attach_arg *uaa = device_get_ivars(dev);
1057184610Salfred	struct zyd_softc *sc = device_get_softc(dev);
1058184610Salfred	int error;
1059184610Salfred	uint8_t iface_index;
1060184610Salfred
1061184610Salfred	if (sc == NULL) {
1062184610Salfred		return (ENOMEM);
1063184610Salfred	}
1064184610Salfred	if (uaa->info.bcdDevice < 0x4330) {
1065184610Salfred		device_printf(dev, "device version mismatch: 0x%X "
1066184610Salfred		    "(only >= 43.30 supported)\n",
1067184610Salfred		    uaa->info.bcdDevice);
1068184610Salfred		return (EINVAL);
1069184610Salfred	}
1070184610Salfred	device_set_usb2_desc(dev);
1071184610Salfred
1072184610Salfred	snprintf(sc->sc_name, sizeof(sc->sc_name), "%s",
1073184610Salfred	    device_get_nameunit(dev));
1074184610Salfred
1075184610Salfred	sc->sc_unit = device_get_unit(dev);
1076184610Salfred	sc->sc_udev = uaa->device;
1077184610Salfred	sc->sc_mac_rev = USB_GET_DRIVER_INFO(uaa);
1078184610Salfred
1079184610Salfred	mtx_init(&sc->sc_mtx, "zyd lock", MTX_NETWORK_LOCK,
1080184610Salfred	    MTX_DEF | MTX_RECURSE);
1081184610Salfred
1082184610Salfred	usb2_cv_init(&sc->sc_intr_cv, "IWAIT");
1083184610Salfred
1084184610Salfred	usb2_callout_init_mtx(&sc->sc_watchdog,
1085184610Salfred	    &sc->sc_mtx, CALLOUT_RETURNUNLOCKED);
1086184610Salfred
1087184610Salfred	/*
1088184610Salfred	 * Endpoint 1 = Bulk out (512b @ high speed / 64b @ full speed)
1089184610Salfred	 * Endpoint 2 = Bulk in  (512b @ high speed / 64b @ full speed)
1090184610Salfred	 * Endpoint 3 = Intr in (64b)
1091184610Salfred	 * Endpoint 4 = Intr out @ high speed / bulk out @ full speed (64b)
1092184610Salfred	 */
1093184610Salfred	iface_index = ZYD_IFACE_INDEX;
1094184610Salfred	error = usb2_transfer_setup(uaa->device, &iface_index,
1095184610Salfred	    sc->sc_xfer, zyd_config, ZYD_N_TRANSFER, sc, &sc->sc_mtx);
1096184610Salfred	if (error) {
1097184610Salfred		device_printf(dev, "could not allocate USB "
1098184610Salfred		    "transfers: %s\n", usb2_errstr(error));
1099184610Salfred		goto detach;
1100184610Salfred	}
1101184610Salfred	error = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_mtx,
1102184610Salfred	    &zyd_end_of_commands, sizeof(struct usb2_config_td_cc), 16);
1103184610Salfred	if (error) {
1104184610Salfred		device_printf(dev, "could not setup config "
1105184610Salfred		    "thread!\n");
1106184610Salfred		goto detach;
1107184610Salfred	}
1108184610Salfred	mtx_lock(&sc->sc_mtx);
1109184610Salfred
1110184610Salfred	/* start setup */
1111184610Salfred
1112184610Salfred	usb2_config_td_queue_command
1113184610Salfred	    (&sc->sc_config_td, NULL, &zyd_cfg_first_time_setup, 0, 0);
1114184610Salfred
1115184610Salfred	/* start watchdog (will exit mutex) */
1116184610Salfred
1117184610Salfred	zyd_watchdog(sc);
1118184610Salfred
1119184610Salfred	return (0);
1120184610Salfred
1121184610Salfreddetach:
1122184610Salfred	zyd_detach(dev);
1123184610Salfred	return (ENXIO);
1124184610Salfred}
1125184610Salfred
1126184610Salfred/*
1127184610Salfred * Lock PHY registers
1128184610Salfred */
1129184610Salfredstatic void
1130184610Salfredzyd_cfg_lock_phy(struct zyd_softc *sc)
1131184610Salfred{
1132184610Salfred	uint32_t temp;
1133184610Salfred
1134184610Salfred	zyd_cfg_read32(sc, ZYD_MAC_MISC, &temp);
1135184610Salfred	temp &= ~ZYD_UNLOCK_PHY_REGS;
1136184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_MISC, temp);
1137184610Salfred}
1138184610Salfred
1139184610Salfred/*
1140184610Salfred * Unlock PHY registers
1141184610Salfred */
1142184610Salfredstatic void
1143184610Salfredzyd_cfg_unlock_phy(struct zyd_softc *sc)
1144184610Salfred{
1145184610Salfred	uint32_t temp;
1146184610Salfred
1147184610Salfred	zyd_cfg_read32(sc, ZYD_MAC_MISC, &temp);
1148184610Salfred	temp |= ZYD_UNLOCK_PHY_REGS;
1149184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_MISC, temp);
1150184610Salfred}
1151184610Salfred
1152184610Salfredstatic void
1153184610Salfredzyd_cfg_set_beacon_interval(struct zyd_softc *sc, uint32_t bintval)
1154184610Salfred{
1155184610Salfred	/* XXX this is probably broken.. */
1156184610Salfred	zyd_cfg_write32(sc, ZYD_CR_ATIM_WND_PERIOD, bintval - 2);
1157184610Salfred	zyd_cfg_write32(sc, ZYD_CR_PRE_TBTT, bintval - 1);
1158184610Salfred	zyd_cfg_write32(sc, ZYD_CR_BCN_INTERVAL, bintval);
1159184610Salfred	return;
1160184610Salfred}
1161184610Salfred
1162184610Salfred/*
1163184610Salfred * Get RF name
1164184610Salfred */
1165184610Salfredstatic const char *
1166184610Salfredzyd_rf_name(uint8_t type)
1167184610Salfred{
1168184610Salfred	static const char *const zyd_rfs[] = {
1169184610Salfred		"unknown", "unknown", "UW2451", "UCHIP", "AL2230",
1170184610Salfred		"AL7230B", "THETA", "AL2210", "MAXIM_NEW", "GCT",
1171184610Salfred		"PV2000", "RALINK", "INTERSIL", "RFMD", "MAXIM_NEW2",
1172184610Salfred		"PHILIPS"
1173184610Salfred	};
1174184610Salfred
1175184610Salfred	return (zyd_rfs[(type > 15) ? 0 : type]);
1176184610Salfred}
1177184610Salfred
1178184610Salfred/*
1179184610Salfred * RF driver: Init for RFMD chip
1180184610Salfred */
1181184610Salfredstatic void
1182184610Salfredzyd_cfg_rf_rfmd_init(struct zyd_softc *sc, struct zyd_rf *rf)
1183184610Salfred{
1184184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_RFMD_PHY;
1185184610Salfred	static const uint32_t rfini[] = ZYD_RFMD_RF;
1186184610Salfred	uint32_t i;
1187184610Salfred
1188184610Salfred	/* init RF-dependent PHY registers */
1189184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1190184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1191184610Salfred	}
1192184610Salfred
1193184610Salfred	/* init RFMD radio */
1194184610Salfred	for (i = 0; i != INDEXES(rfini); i++) {
1195184610Salfred		zyd_cfg_rfwrite(sc, rfini[i]);
1196184610Salfred	}
1197184610Salfred	return;
1198184610Salfred}
1199184610Salfred
1200184610Salfred/*
1201184610Salfred * RF driver: Switch radio on/off for RFMD chip
1202184610Salfred */
1203184610Salfredstatic void
1204184610Salfredzyd_cfg_rf_rfmd_switch_radio(struct zyd_softc *sc, uint8_t on)
1205184610Salfred{
1206184610Salfred	zyd_cfg_write16(sc, ZYD_CR10, on ? 0x89 : 0x15);
1207184610Salfred	zyd_cfg_write16(sc, ZYD_CR11, on ? 0x00 : 0x81);
1208184610Salfred	return;
1209184610Salfred}
1210184610Salfred
1211184610Salfred/*
1212184610Salfred * RF driver: Channel setting for RFMD chip
1213184610Salfred */
1214184610Salfredstatic void
1215184610Salfredzyd_cfg_rf_rfmd_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
1216184610Salfred    uint8_t channel)
1217184610Salfred{
1218184610Salfred	static const struct {
1219184610Salfred		uint32_t r1, r2;
1220184610Salfred	}      rfprog[] = ZYD_RFMD_CHANTABLE;
1221184610Salfred
1222184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1);
1223184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2);
1224184610Salfred	return;
1225184610Salfred}
1226184610Salfred
1227184610Salfred/*
1228184610Salfred * RF driver: Switch radio on/off for AL2230 chip
1229184610Salfred */
1230184610Salfredstatic void
1231184610Salfredzyd_cfg_rf_al2230_switch_radio(struct zyd_softc *sc, uint8_t on)
1232184610Salfred{
1233184610Salfred	uint8_t on251 = (sc->sc_mac_rev == ZYD_ZD1211) ? 0x3f : 0x7f;
1234184610Salfred
1235184610Salfred	zyd_cfg_write16(sc, ZYD_CR11, on ? 0x00 : 0x04);
1236184610Salfred	zyd_cfg_write16(sc, ZYD_CR251, on ? on251 : 0x2f);
1237184610Salfred	return;
1238184610Salfred}
1239184610Salfred
1240184610Salfred/*
1241184610Salfred * RF driver: Init for AL2230 chip
1242184610Salfred */
1243184610Salfredstatic void
1244184610Salfredzyd_cfg_rf_al2230_init(struct zyd_softc *sc, struct zyd_rf *rf)
1245184610Salfred{
1246184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY;
1247184610Salfred	static const uint32_t rfini[] = ZYD_AL2230_RF;
1248184610Salfred	uint32_t i;
1249184610Salfred
1250184610Salfred	/* init RF-dependent PHY registers */
1251184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1252184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1253184610Salfred	}
1254184610Salfred
1255184610Salfred	/* init AL2230 radio */
1256184610Salfred	for (i = 0; i != INDEXES(rfini); i++) {
1257184610Salfred		zyd_cfg_rfwrite(sc, rfini[i]);
1258184610Salfred	}
1259184610Salfred	return;
1260184610Salfred}
1261184610Salfred
1262184610Salfredstatic void
1263184610Salfredzyd_cfg_rf_al2230_init_b(struct zyd_softc *sc, struct zyd_rf *rf)
1264184610Salfred{
1265184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY_B;
1266184610Salfred	static const uint32_t rfini[] = ZYD_AL2230_RF_B;
1267184610Salfred	uint32_t i;
1268184610Salfred
1269184610Salfred	/* init RF-dependent PHY registers */
1270184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1271184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1272184610Salfred	}
1273184610Salfred
1274184610Salfred	/* init AL2230 radio */
1275184610Salfred	for (i = 0; i != INDEXES(rfini); i++) {
1276184610Salfred		zyd_cfg_rfwrite(sc, rfini[i]);
1277184610Salfred	}
1278184610Salfred	return;
1279184610Salfred}
1280184610Salfred
1281184610Salfred/*
1282184610Salfred * RF driver: Channel setting for AL2230 chip
1283184610Salfred */
1284184610Salfredstatic void
1285184610Salfredzyd_cfg_rf_al2230_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
1286184610Salfred    uint8_t channel)
1287184610Salfred{
1288184610Salfred	static const struct {
1289184610Salfred		uint32_t r1, r2, r3;
1290184610Salfred	}      rfprog[] = ZYD_AL2230_CHANTABLE;
1291184610Salfred
1292184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1);
1293184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2);
1294184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r3);
1295184610Salfred
1296184610Salfred	zyd_cfg_write16(sc, ZYD_CR138, 0x28);
1297184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, 0x06);
1298184610Salfred	return;
1299184610Salfred}
1300184610Salfred
1301184610Salfred/*
1302184610Salfred * AL7230B RF methods.
1303184610Salfred */
1304184610Salfredstatic void
1305184610Salfredzyd_cfg_rf_al7230b_switch_radio(struct zyd_softc *sc, uint8_t on)
1306184610Salfred{
1307184610Salfred	zyd_cfg_write16(sc, ZYD_CR11, on ? 0x00 : 0x04);
1308184610Salfred	zyd_cfg_write16(sc, ZYD_CR251, on ? 0x3f : 0x2f);
1309184610Salfred	return;
1310184610Salfred}
1311184610Salfred
1312184610Salfredstatic void
1313184610Salfredzyd_cfg_rf_al7230b_init(struct zyd_softc *sc, struct zyd_rf *rf)
1314184610Salfred{
1315184610Salfred	static const struct zyd_phy_pair phyini_1[] = ZYD_AL7230B_PHY_1;
1316184610Salfred	static const struct zyd_phy_pair phyini_2[] = ZYD_AL7230B_PHY_2;
1317184610Salfred	static const struct zyd_phy_pair phyini_3[] = ZYD_AL7230B_PHY_3;
1318184610Salfred	static const uint32_t rfini_1[] = ZYD_AL7230B_RF_1;
1319184610Salfred	static const uint32_t rfini_2[] = ZYD_AL7230B_RF_2;
1320184610Salfred	uint32_t i;
1321184610Salfred
1322184610Salfred	/* for AL7230B, PHY and RF need to be initialized in "phases" */
1323184610Salfred
1324184610Salfred	/* init RF-dependent PHY registers, part one */
1325184610Salfred	for (i = 0; i != INDEXES(phyini_1); i++) {
1326184610Salfred		zyd_cfg_write16(sc, phyini_1[i].reg, phyini_1[i].val);
1327184610Salfred	}
1328184610Salfred	/* init AL7230B radio, part one */
1329184610Salfred	for (i = 0; i != INDEXES(rfini_1); i++) {
1330184610Salfred		zyd_cfg_rfwrite(sc, rfini_1[i]);
1331184610Salfred	}
1332184610Salfred	/* init RF-dependent PHY registers, part two */
1333184610Salfred	for (i = 0; i != INDEXES(phyini_2); i++) {
1334184610Salfred		zyd_cfg_write16(sc, phyini_2[i].reg, phyini_2[i].val);
1335184610Salfred	}
1336184610Salfred	/* init AL7230B radio, part two */
1337184610Salfred	for (i = 0; i != INDEXES(rfini_2); i++) {
1338184610Salfred		zyd_cfg_rfwrite(sc, rfini_2[i]);
1339184610Salfred	}
1340184610Salfred	/* init RF-dependent PHY registers, part three */
1341184610Salfred	for (i = 0; i != INDEXES(phyini_3); i++) {
1342184610Salfred		zyd_cfg_write16(sc, phyini_3[i].reg, phyini_3[i].val);
1343184610Salfred	}
1344184610Salfred	return;
1345184610Salfred}
1346184610Salfred
1347184610Salfredstatic void
1348184610Salfredzyd_cfg_rf_al7230b_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
1349184610Salfred    uint8_t channel)
1350184610Salfred{
1351184610Salfred	static const struct {
1352184610Salfred		uint32_t r1, r2;
1353184610Salfred	}      rfprog[] = ZYD_AL7230B_CHANTABLE;
1354184610Salfred	static const uint32_t rfsc[] = ZYD_AL7230B_RF_SETCHANNEL;
1355184610Salfred	uint32_t i;
1356184610Salfred
1357184610Salfred	zyd_cfg_write16(sc, ZYD_CR240, 0x57);
1358184610Salfred	zyd_cfg_write16(sc, ZYD_CR251, 0x2f);
1359184610Salfred
1360184610Salfred	for (i = 0; i != INDEXES(rfsc); i++) {
1361184610Salfred		zyd_cfg_rfwrite(sc, rfsc[i]);
1362184610Salfred	}
1363184610Salfred
1364184610Salfred	zyd_cfg_write16(sc, ZYD_CR128, 0x14);
1365184610Salfred	zyd_cfg_write16(sc, ZYD_CR129, 0x12);
1366184610Salfred	zyd_cfg_write16(sc, ZYD_CR130, 0x10);
1367184610Salfred	zyd_cfg_write16(sc, ZYD_CR38, 0x38);
1368184610Salfred	zyd_cfg_write16(sc, ZYD_CR136, 0xdf);
1369184610Salfred
1370184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1);
1371184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2);
1372184610Salfred	zyd_cfg_rfwrite(sc, 0x3c9000);
1373184610Salfred
1374184610Salfred	zyd_cfg_write16(sc, ZYD_CR251, 0x3f);
1375184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, 0x06);
1376184610Salfred	zyd_cfg_write16(sc, ZYD_CR240, 0x08);
1377184610Salfred
1378184610Salfred	return;
1379184610Salfred}
1380184610Salfred
1381184610Salfred/*
1382184610Salfred * AL2210 RF methods.
1383184610Salfred */
1384184610Salfredstatic void
1385184610Salfredzyd_cfg_rf_al2210_switch_radio(struct zyd_softc *sc, uint8_t on)
1386184610Salfred{
1387184610Salfred
1388184610Salfred}
1389184610Salfred
1390184610Salfredstatic void
1391184610Salfredzyd_cfg_rf_al2210_init(struct zyd_softc *sc, struct zyd_rf *rf)
1392184610Salfred{
1393184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_AL2210_PHY;
1394184610Salfred	static const uint32_t rfini[] = ZYD_AL2210_RF;
1395184610Salfred	uint32_t tmp;
1396184610Salfred	uint32_t i;
1397184610Salfred
1398184610Salfred	zyd_cfg_write32(sc, ZYD_CR18, 2);
1399184610Salfred
1400184610Salfred	/* init RF-dependent PHY registers */
1401184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1402184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1403184610Salfred	}
1404184610Salfred	/* init AL2210 radio */
1405184610Salfred	for (i = 0; i != INDEXES(rfini); i++) {
1406184610Salfred		zyd_cfg_rfwrite(sc, rfini[i]);
1407184610Salfred	}
1408184610Salfred	zyd_cfg_write16(sc, ZYD_CR47, 0x1e);
1409184610Salfred	zyd_cfg_read32(sc, ZYD_CR_RADIO_PD, &tmp);
1410184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp & ~1);
1411184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp | 1);
1412184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x05);
1413184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x00);
1414184610Salfred	zyd_cfg_write16(sc, ZYD_CR47, 0x1e);
1415184610Salfred	zyd_cfg_write32(sc, ZYD_CR18, 3);
1416184610Salfred
1417184610Salfred	return;
1418184610Salfred}
1419184610Salfred
1420184610Salfredstatic void
1421184610Salfredzyd_cfg_rf_al2210_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
1422184610Salfred    uint8_t channel)
1423184610Salfred{
1424184610Salfred	static const uint32_t rfprog[] = ZYD_AL2210_CHANTABLE;
1425184610Salfred	uint32_t tmp;
1426184610Salfred
1427184610Salfred	zyd_cfg_write32(sc, ZYD_CR18, 2);
1428184610Salfred	zyd_cfg_write16(sc, ZYD_CR47, 0x1e);
1429184610Salfred	zyd_cfg_read32(sc, ZYD_CR_RADIO_PD, &tmp);
1430184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp & ~1);
1431184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp | 1);
1432184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x05);
1433184610Salfred
1434184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x00);
1435184610Salfred	zyd_cfg_write16(sc, ZYD_CR47, 0x1e);
1436184610Salfred
1437184610Salfred	/* actually set the channel */
1438184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1]);
1439184610Salfred
1440184610Salfred	zyd_cfg_write32(sc, ZYD_CR18, 3);
1441184610Salfred	return;
1442184610Salfred}
1443184610Salfred
1444184610Salfred/*
1445184610Salfred * GCT RF methods.
1446184610Salfred */
1447184610Salfredstatic void
1448184610Salfredzyd_cfg_rf_gct_switch_radio(struct zyd_softc *sc, uint8_t on)
1449184610Salfred{
1450184610Salfred	/* vendor driver does nothing for this RF chip */
1451184610Salfred
1452184610Salfred	return;
1453184610Salfred}
1454184610Salfred
1455184610Salfredstatic void
1456184610Salfredzyd_cfg_rf_gct_init(struct zyd_softc *sc, struct zyd_rf *rf)
1457184610Salfred{
1458184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_GCT_PHY;
1459184610Salfred	static const uint32_t rfini[] = ZYD_GCT_RF;
1460184610Salfred	uint32_t i;
1461184610Salfred
1462184610Salfred	/* init RF-dependent PHY registers */
1463184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1464184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1465184610Salfred	}
1466184610Salfred	/* init cgt radio */
1467184610Salfred	for (i = 0; i != INDEXES(rfini); i++) {
1468184610Salfred		zyd_cfg_rfwrite(sc, rfini[i]);
1469184610Salfred	}
1470184610Salfred	return;
1471184610Salfred}
1472184610Salfred
1473184610Salfredstatic void
1474184610Salfredzyd_cfg_rf_gct_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
1475184610Salfred    uint8_t channel)
1476184610Salfred{
1477184610Salfred	static const uint32_t rfprog[] = ZYD_GCT_CHANTABLE;
1478184610Salfred
1479184610Salfred	zyd_cfg_rfwrite(sc, 0x1c0000);
1480184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1]);
1481184610Salfred	zyd_cfg_rfwrite(sc, 0x1c0008);
1482184610Salfred
1483184610Salfred	return;
1484184610Salfred}
1485184610Salfred
1486184610Salfred/*
1487184610Salfred * Maxim RF methods.
1488184610Salfred */
1489184610Salfredstatic void
1490184610Salfredzyd_cfg_rf_maxim_switch_radio(struct zyd_softc *sc, uint8_t on)
1491184610Salfred{
1492184610Salfred	/* vendor driver does nothing for this RF chip */
1493184610Salfred
1494184610Salfred	return;
1495184610Salfred}
1496184610Salfred
1497184610Salfredstatic void
1498184610Salfredzyd_cfg_rf_maxim_init(struct zyd_softc *sc, struct zyd_rf *rf)
1499184610Salfred{
1500184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_MAXIM_PHY;
1501184610Salfred	static const uint32_t rfini[] = ZYD_MAXIM_RF;
1502184610Salfred	uint16_t tmp;
1503184610Salfred	uint32_t i;
1504184610Salfred
1505184610Salfred	/* init RF-dependent PHY registers */
1506184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1507184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1508184610Salfred	}
1509184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &tmp);
1510184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, tmp & ~(1 << 4));
1511184610Salfred
1512184610Salfred	/* init maxim radio */
1513184610Salfred	for (i = 0; i != INDEXES(rfini); i++) {
1514184610Salfred		zyd_cfg_rfwrite(sc, rfini[i]);
1515184610Salfred	}
1516184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &tmp);
1517184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4));
1518184610Salfred
1519184610Salfred	return;
1520184610Salfred}
1521184610Salfred
1522184610Salfredstatic void
1523184610Salfredzyd_cfg_rf_maxim_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
1524184610Salfred    uint8_t channel)
1525184610Salfred{
1526184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_MAXIM_PHY;
1527184610Salfred	static const uint32_t rfini[] = ZYD_MAXIM_RF;
1528184610Salfred	static const struct {
1529184610Salfred		uint32_t r1, r2;
1530184610Salfred	}      rfprog[] = ZYD_MAXIM_CHANTABLE;
1531184610Salfred	uint16_t tmp;
1532184610Salfred	uint32_t i;
1533184610Salfred
1534184610Salfred	/*
1535184610Salfred	 * Do the same as we do when initializing it, except for the channel
1536184610Salfred	 * values coming from the two channel tables.
1537184610Salfred	 */
1538184610Salfred
1539184610Salfred	/* init RF-dependent PHY registers */
1540184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1541184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1542184610Salfred	}
1543184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &tmp);
1544184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, tmp & ~(1 << 4));
1545184610Salfred
1546184610Salfred	/* first two values taken from the chantables */
1547184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1);
1548184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2);
1549184610Salfred
1550184610Salfred	/* init maxim radio - skipping the two first values */
1551184610Salfred	if (INDEXES(rfini) > 2) {
1552184610Salfred		for (i = 2; i != INDEXES(rfini); i++) {
1553184610Salfred			zyd_cfg_rfwrite(sc, rfini[i]);
1554184610Salfred		}
1555184610Salfred	}
1556184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &tmp);
1557184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4));
1558184610Salfred
1559184610Salfred	return;
1560184610Salfred}
1561184610Salfred
1562184610Salfred/*
1563184610Salfred * Maxim2 RF methods.
1564184610Salfred */
1565184610Salfredstatic void
1566184610Salfredzyd_cfg_rf_maxim2_switch_radio(struct zyd_softc *sc, uint8_t on)
1567184610Salfred{
1568184610Salfred	/* vendor driver does nothing for this RF chip */
1569184610Salfred	return;
1570184610Salfred}
1571184610Salfred
1572184610Salfredstatic void
1573184610Salfredzyd_cfg_rf_maxim2_init(struct zyd_softc *sc, struct zyd_rf *rf)
1574184610Salfred{
1575184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY;
1576184610Salfred	static const uint32_t rfini[] = ZYD_MAXIM2_RF;
1577184610Salfred	uint16_t tmp;
1578184610Salfred	uint32_t i;
1579184610Salfred
1580184610Salfred	/* init RF-dependent PHY registers */
1581184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1582184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1583184610Salfred	}
1584184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &tmp);
1585184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, tmp & ~(1 << 4));
1586184610Salfred
1587184610Salfred	/* init maxim2 radio */
1588184610Salfred	for (i = 0; i != INDEXES(rfini); i++) {
1589184610Salfred		zyd_cfg_rfwrite(sc, rfini[i]);
1590184610Salfred	}
1591184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &tmp);
1592184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4));
1593184610Salfred	return;
1594184610Salfred}
1595184610Salfred
1596184610Salfredstatic void
1597184610Salfredzyd_cfg_rf_maxim2_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
1598184610Salfred    uint8_t channel)
1599184610Salfred{
1600184610Salfred	static const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY;
1601184610Salfred	static const uint32_t rfini[] = ZYD_MAXIM2_RF;
1602184610Salfred	static const struct {
1603184610Salfred		uint32_t r1, r2;
1604184610Salfred	}      rfprog[] = ZYD_MAXIM2_CHANTABLE;
1605184610Salfred	uint16_t tmp;
1606184610Salfred	uint32_t i;
1607184610Salfred
1608184610Salfred	/*
1609184610Salfred	 * Do the same as we do when initializing it, except for the channel
1610184610Salfred	 * values coming from the two channel tables.
1611184610Salfred	 */
1612184610Salfred
1613184610Salfred	/* init RF-dependent PHY registers */
1614184610Salfred	for (i = 0; i != INDEXES(phyini); i++) {
1615184610Salfred		zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
1616184610Salfred	}
1617184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &tmp);
1618184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, tmp & ~(1 << 4));
1619184610Salfred
1620184610Salfred	/* first two values taken from the chantables */
1621184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1);
1622184610Salfred	zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2);
1623184610Salfred
1624184610Salfred	/* init maxim2 radio - skipping the two first values */
1625184610Salfred	if (INDEXES(rfini) > 2) {
1626184610Salfred		for (i = 2; i != INDEXES(rfini); i++) {
1627184610Salfred			zyd_cfg_rfwrite(sc, rfini[i]);
1628184610Salfred		}
1629184610Salfred	}
1630184610Salfred	zyd_cfg_read16(sc, ZYD_CR203, &tmp);
1631184610Salfred	zyd_cfg_write16(sc, ZYD_CR203, tmp | (1 << 4));
1632184610Salfred	return;
1633184610Salfred}
1634184610Salfred
1635184610Salfred/*
1636184610Salfred * Assign drivers and init the RF
1637184610Salfred */
1638184610Salfredstatic uint8_t
1639184610Salfredzyd_cfg_rf_init_hw(struct zyd_softc *sc, struct zyd_rf *rf)
1640184610Salfred{
1641184610Salfred	;				/* fix for indent */
1642184610Salfred
1643184610Salfred	switch (sc->sc_rf_rev) {
1644184610Salfred	case ZYD_RF_RFMD:
1645184610Salfred		rf->cfg_init_hw = zyd_cfg_rf_rfmd_init;
1646184610Salfred		rf->cfg_switch_radio = zyd_cfg_rf_rfmd_switch_radio;
1647184610Salfred		rf->cfg_set_channel = zyd_cfg_rf_rfmd_set_channel;
1648184610Salfred		rf->width = 24;		/* 24-bit RF values */
1649184610Salfred		break;
1650184610Salfred	case ZYD_RF_AL2230:
1651184610Salfred		if (sc->sc_mac_rev == ZYD_ZD1211B)
1652184610Salfred			rf->cfg_init_hw = zyd_cfg_rf_al2230_init_b;
1653184610Salfred		else
1654184610Salfred			rf->cfg_init_hw = zyd_cfg_rf_al2230_init;
1655184610Salfred		rf->cfg_switch_radio = zyd_cfg_rf_al2230_switch_radio;
1656184610Salfred		rf->cfg_set_channel = zyd_cfg_rf_al2230_set_channel;
1657184610Salfred		rf->width = 24;		/* 24-bit RF values */
1658184610Salfred		break;
1659184610Salfred	case ZYD_RF_AL7230B:
1660184610Salfred		rf->cfg_init_hw = zyd_cfg_rf_al7230b_init;
1661184610Salfred		rf->cfg_switch_radio = zyd_cfg_rf_al7230b_switch_radio;
1662184610Salfred		rf->cfg_set_channel = zyd_cfg_rf_al7230b_set_channel;
1663184610Salfred		rf->width = 24;		/* 24-bit RF values */
1664184610Salfred		break;
1665184610Salfred	case ZYD_RF_AL2210:
1666184610Salfred		rf->cfg_init_hw = zyd_cfg_rf_al2210_init;
1667184610Salfred		rf->cfg_switch_radio = zyd_cfg_rf_al2210_switch_radio;
1668184610Salfred		rf->cfg_set_channel = zyd_cfg_rf_al2210_set_channel;
1669184610Salfred		rf->width = 24;		/* 24-bit RF values */
1670184610Salfred		break;
1671184610Salfred	case ZYD_RF_GCT:
1672184610Salfred		rf->cfg_init_hw = zyd_cfg_rf_gct_init;
1673184610Salfred		rf->cfg_switch_radio = zyd_cfg_rf_gct_switch_radio;
1674184610Salfred		rf->cfg_set_channel = zyd_cfg_rf_gct_set_channel;
1675184610Salfred		rf->width = 21;		/* 21-bit RF values */
1676184610Salfred		break;
1677184610Salfred	case ZYD_RF_MAXIM_NEW:
1678184610Salfred		rf->cfg_init_hw = zyd_cfg_rf_maxim_init;
1679184610Salfred		rf->cfg_switch_radio = zyd_cfg_rf_maxim_switch_radio;
1680184610Salfred		rf->cfg_set_channel = zyd_cfg_rf_maxim_set_channel;
1681184610Salfred		rf->width = 18;		/* 18-bit RF values */
1682184610Salfred		break;
1683184610Salfred	case ZYD_RF_MAXIM_NEW2:
1684184610Salfred		rf->cfg_init_hw = zyd_cfg_rf_maxim2_init;
1685184610Salfred		rf->cfg_switch_radio = zyd_cfg_rf_maxim2_switch_radio;
1686184610Salfred		rf->cfg_set_channel = zyd_cfg_rf_maxim2_set_channel;
1687184610Salfred		rf->width = 18;		/* 18-bit RF values */
1688184610Salfred		break;
1689184610Salfred	default:
1690184610Salfred		DPRINTFN(0, "%s: Sorry, radio %s is not supported yet\n",
1691184610Salfred		    sc->sc_name, zyd_rf_name(sc->sc_rf_rev));
1692184610Salfred		return (1);
1693184610Salfred	}
1694184610Salfred
1695184610Salfred	zyd_cfg_lock_phy(sc);
1696184610Salfred	(rf->cfg_init_hw) (sc, rf);
1697184610Salfred	zyd_cfg_unlock_phy(sc);
1698184610Salfred
1699184610Salfred	return (0);			/* success */
1700184610Salfred}
1701184610Salfred
1702184610Salfred/*
1703184610Salfred * Init the hardware
1704184610Salfred */
1705184610Salfredstatic uint8_t
1706184610Salfredzyd_cfg_hw_init(struct zyd_softc *sc)
1707184610Salfred{
1708184610Salfred	const struct zyd_phy_pair *phyp;
1709184610Salfred	uint32_t tmp;
1710184610Salfred
1711184610Salfred	/* specify that the plug and play is finished */
1712184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_AFTER_PNP, 1);
1713184610Salfred
1714184610Salfred	zyd_cfg_read16(sc, ZYD_FIRMWARE_BASE_ADDR, &sc->sc_firmware_base);
1715184610Salfred	DPRINTF("firmware base address=0x%04x\n", sc->sc_firmware_base);
1716184610Salfred
1717184610Salfred	/* retrieve firmware revision number */
1718184610Salfred	zyd_cfg_read16(sc, sc->sc_firmware_base + ZYD_FW_FIRMWARE_REV, &sc->sc_fw_rev);
1719184610Salfred
1720184610Salfred	zyd_cfg_write32(sc, ZYD_CR_GPI_EN, 0);
1721184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_CONT_WIN_LIMIT, 0x7f043f);
1722184610Salfred
1723184610Salfred	/* disable interrupts */
1724184610Salfred	zyd_cfg_write32(sc, ZYD_CR_INTERRUPT, 0);
1725184610Salfred
1726184610Salfred	/* PHY init */
1727184610Salfred	zyd_cfg_lock_phy(sc);
1728184610Salfred	phyp = (sc->sc_mac_rev == ZYD_ZD1211B) ? zyd_def_phyB : zyd_def_phy;
1729184610Salfred	for (; phyp->reg != 0; phyp++) {
1730184610Salfred		zyd_cfg_write16(sc, phyp->reg, phyp->val);
1731184610Salfred	}
1732184610Salfred	if (sc->sc_fix_cr157) {
1733184610Salfred		zyd_cfg_read32(sc, ZYD_EEPROM_PHY_REG, &tmp);
1734184610Salfred		zyd_cfg_write32(sc, ZYD_CR157, tmp >> 8);
1735184610Salfred	}
1736184610Salfred	zyd_cfg_unlock_phy(sc);
1737184610Salfred
1738184610Salfred	/* HMAC init */
1739184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_ACK_EXT, 0x00000020);
1740184610Salfred	zyd_cfg_write32(sc, ZYD_CR_ADDA_MBIAS_WT, 0x30000808);
1741184610Salfred
1742184610Salfred	if (sc->sc_mac_rev == ZYD_ZD1211) {
1743184610Salfred		zyd_cfg_write32(sc, ZYD_MAC_RETRY, 0x00000002);
1744184610Salfred	} else {
1745184610Salfred		zyd_cfg_write32(sc, ZYD_MACB_MAX_RETRY, 0x02020202);
1746184610Salfred		zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL4, 0x007f003f);
1747184610Salfred		zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL3, 0x007f003f);
1748184610Salfred		zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL2, 0x003f001f);
1749184610Salfred		zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL1, 0x001f000f);
1750184610Salfred		zyd_cfg_write32(sc, ZYD_MACB_AIFS_CTL1, 0x00280028);
1751184610Salfred		zyd_cfg_write32(sc, ZYD_MACB_AIFS_CTL2, 0x008C003C);
1752184610Salfred		zyd_cfg_write32(sc, ZYD_MACB_TXOP, 0x01800824);
1753184610Salfred	}
1754184610Salfred
1755184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_SNIFFER, 0x00000000);
1756184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_RXFILTER, 0x00000000);
1757184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_GHTBL, 0x00000000);
1758184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_GHTBH, 0x80000000);
1759184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_MISC, 0x000000a4);
1760184610Salfred	zyd_cfg_write32(sc, ZYD_CR_ADDA_PWR_DWN, 0x0000007f);
1761184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_BCNCFG, 0x00f00401);
1762184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_PHY_DELAY2, 0x00000000);
1763184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_ACK_EXT, 0x00000080);
1764184610Salfred	zyd_cfg_write32(sc, ZYD_CR_ADDA_PWR_DWN, 0x00000000);
1765184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_SIFS_ACK_TIME, 0x00000100);
1766184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_DIFS_EIFS_SIFS, 0x0547c032);
1767184610Salfred	zyd_cfg_write32(sc, ZYD_CR_RX_PE_DELAY, 0x00000070);
1768184610Salfred	zyd_cfg_write32(sc, ZYD_CR_PS_CTRL, 0x10000000);
1769184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_RTSCTSRATE, 0x02030203);
1770184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0640);
1771184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_BACKOFF_PROTECT, 0x00000114);
1772184610Salfred
1773184610Salfred	/* init beacon interval to 100ms */
1774184610Salfred	zyd_cfg_set_beacon_interval(sc, 100);
1775184610Salfred
1776184610Salfred	return (0);			/* success */
1777184610Salfred}
1778184610Salfred
1779184610Salfred/*
1780184610Salfred * Read information from EEPROM
1781184610Salfred */
1782184610Salfredstatic void
1783184610Salfredzyd_cfg_read_eeprom(struct zyd_softc *sc)
1784184610Salfred{
1785184610Salfred	uint32_t tmp;
1786184610Salfred	uint16_t i;
1787184610Salfred	uint16_t val;
1788184610Salfred
1789184610Salfred	/* read MAC address */
1790184610Salfred	zyd_cfg_read32(sc, ZYD_EEPROM_MAC_ADDR_P1, &tmp);
1791184610Salfred	sc->sc_myaddr[0] = tmp & 0xff;
1792184610Salfred	sc->sc_myaddr[1] = tmp >> 8;
1793184610Salfred	sc->sc_myaddr[2] = tmp >> 16;
1794184610Salfred	sc->sc_myaddr[3] = tmp >> 24;
1795184610Salfred	zyd_cfg_read32(sc, ZYD_EEPROM_MAC_ADDR_P2, &tmp);
1796184610Salfred	sc->sc_myaddr[4] = tmp & 0xff;
1797184610Salfred	sc->sc_myaddr[5] = tmp >> 8;
1798184610Salfred
1799184610Salfred	zyd_cfg_read32(sc, ZYD_EEPROM_POD, &tmp);
1800184610Salfred	sc->sc_rf_rev = tmp & 0x0f;
1801184610Salfred	sc->sc_fix_cr47 = (tmp >> 8) & 0x01;
1802184610Salfred	sc->sc_fix_cr157 = (tmp >> 13) & 0x01;
1803184610Salfred	sc->sc_pa_rev = (tmp >> 16) & 0x0f;
1804184610Salfred
1805184610Salfred	/* read regulatory domain (currently unused) */
1806184610Salfred	zyd_cfg_read32(sc, ZYD_EEPROM_SUBID, &tmp);
1807184610Salfred	sc->sc_regdomain = tmp >> 16;
1808184610Salfred	DPRINTF("regulatory domain %x\n", sc->sc_regdomain);
1809184610Salfred
1810184610Salfred	/* read Tx power calibration tables */
1811184610Salfred	for (i = 0; i < 7; i++) {
1812184610Salfred		zyd_cfg_read16(sc, ZYD_EEPROM_PWR_CAL + i, &val);
1813184610Salfred		sc->sc_pwr_cal[(i * 2)] = val >> 8;
1814184610Salfred		sc->sc_pwr_cal[(i * 2) + 1] = val & 0xff;
1815184610Salfred
1816184610Salfred		zyd_cfg_read16(sc, ZYD_EEPROM_PWR_INT + i, &val);
1817184610Salfred		sc->sc_pwr_int[(i * 2)] = val >> 8;
1818184610Salfred		sc->sc_pwr_int[(i * 2) + 1] = val & 0xff;
1819184610Salfred
1820184610Salfred		zyd_cfg_read16(sc, ZYD_EEPROM_36M_CAL + i, &val);
1821184610Salfred		sc->sc_ofdm36_cal[(i * 2)] = val >> 8;
1822184610Salfred		sc->sc_ofdm36_cal[(i * 2) + 1] = val & 0xff;
1823184610Salfred
1824184610Salfred		zyd_cfg_read16(sc, ZYD_EEPROM_48M_CAL + i, &val);
1825184610Salfred		sc->sc_ofdm48_cal[(i * 2)] = val >> 8;
1826184610Salfred		sc->sc_ofdm48_cal[(i * 2) + 1] = val & 0xff;
1827184610Salfred
1828184610Salfred		zyd_cfg_read16(sc, ZYD_EEPROM_54M_CAL + i, &val);
1829184610Salfred		sc->sc_ofdm54_cal[(i * 2)] = val >> 8;
1830184610Salfred		sc->sc_ofdm54_cal[(i * 2) + 1] = val & 0xff;
1831184610Salfred	}
1832184610Salfred	return;
1833184610Salfred}
1834184610Salfred
1835184610Salfredstatic void
1836184610Salfredzyd_cfg_set_mac_addr(struct zyd_softc *sc, const uint8_t *addr)
1837184610Salfred{
1838184610Salfred	uint32_t tmp;
1839184610Salfred
1840184610Salfred	tmp = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
1841184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_MACADRL, tmp);
1842184610Salfred
1843184610Salfred	tmp = (addr[5] << 8) | addr[4];
1844184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_MACADRH, tmp);
1845184610Salfred	return;
1846184610Salfred}
1847184610Salfred
1848184610Salfred/*
1849184610Salfred * Switch radio on/off
1850184610Salfred */
1851184610Salfredstatic void
1852184610Salfredzyd_cfg_switch_radio(struct zyd_softc *sc, uint8_t onoff)
1853184610Salfred{
1854184610Salfred	zyd_cfg_lock_phy(sc);
1855184610Salfred	(sc->sc_rf.cfg_switch_radio) (sc, onoff);
1856184610Salfred	zyd_cfg_unlock_phy(sc);
1857184610Salfred
1858184610Salfred	return;
1859184610Salfred}
1860184610Salfred
1861184610Salfred/*
1862184610Salfred * Set BSSID
1863184610Salfred */
1864184610Salfredstatic void
1865184610Salfredzyd_cfg_set_bssid(struct zyd_softc *sc, uint8_t *addr)
1866184610Salfred{
1867184610Salfred	uint32_t tmp;
1868184610Salfred
1869184610Salfred	tmp = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
1870184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_BSSADRL, tmp);
1871184610Salfred
1872184610Salfred	tmp = (addr[5] << 8) | addr[4];
1873184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_BSSADRH, tmp);
1874184610Salfred	return;
1875184610Salfred}
1876184610Salfred
1877184610Salfred/*
1878184610Salfred * Complete the attach process
1879184610Salfred */
1880184610Salfredstatic void
1881184610Salfredzyd_cfg_first_time_setup(struct zyd_softc *sc,
1882184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
1883184610Salfred{
1884184610Salfred	struct usb2_config_descriptor *cd;
1885184610Salfred	struct ieee80211com *ic;
1886184610Salfred	struct ifnet *ifp;
1887184610Salfred	const uint8_t *fw_ptr;
1888184610Salfred	uint32_t fw_len;
1889184610Salfred	uint8_t bands;
1890184610Salfred	usb2_error_t err;
1891184610Salfred
1892184610Salfred	/* setup RX tap header */
1893184610Salfred	sc->sc_rxtap_len = sizeof(sc->sc_rxtap);
1894184610Salfred	sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
1895184610Salfred	sc->sc_rxtap.wr_ihdr.it_present = htole32(ZYD_RX_RADIOTAP_PRESENT);
1896184610Salfred
1897184610Salfred	/* setup TX tap header */
1898184610Salfred	sc->sc_txtap_len = sizeof(sc->sc_txtap);
1899184610Salfred	sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
1900184610Salfred	sc->sc_txtap.wt_ihdr.it_present = htole32(ZYD_TX_RADIOTAP_PRESENT);
1901184610Salfred
1902184610Salfred	if (sc->sc_mac_rev == ZYD_ZD1211) {
1903184610Salfred		fw_ptr = zd1211_firmware;
1904184610Salfred		fw_len = sizeof(zd1211_firmware);
1905184610Salfred	} else {
1906184610Salfred		fw_ptr = zd1211b_firmware;
1907184610Salfred		fw_len = sizeof(zd1211b_firmware);
1908184610Salfred	}
1909184610Salfred
1910184610Salfred	if (zyd_cfg_uploadfirmware(sc, fw_ptr, fw_len)) {
1911184610Salfred		DPRINTFN(0, "%s: could not "
1912184610Salfred		    "upload firmware!\n", sc->sc_name);
1913184610Salfred		return;
1914184610Salfred	}
1915184610Salfred	cd = usb2_get_config_descriptor(sc->sc_udev);
1916184610Salfred
1917184610Salfred	/* reset device */
1918184610Salfred	err = usb2_req_set_config(sc->sc_udev, &sc->sc_mtx,
1919184610Salfred	    cd->bConfigurationValue);
1920184610Salfred	if (err) {
1921184610Salfred		DPRINTF("reset failed (ignored)\n");
1922184610Salfred	}
1923184610Salfred	/* Read MAC and other stuff rom EEPROM */
1924184610Salfred	zyd_cfg_read_eeprom(sc);
1925184610Salfred
1926184610Salfred	/* Init hardware */
1927184610Salfred	if (zyd_cfg_hw_init(sc)) {
1928184610Salfred		DPRINTFN(0, "%s: HW init failed!\n", sc->sc_name);
1929184610Salfred		return;
1930184610Salfred	}
1931184610Salfred	/* Now init the RF chip */
1932184610Salfred	if (zyd_cfg_rf_init_hw(sc, &sc->sc_rf)) {
1933184610Salfred		DPRINTFN(0, "%s: RF init failed!\n", sc->sc_name);
1934184610Salfred		return;
1935184610Salfred	}
1936184610Salfred	printf("%s: HMAC ZD1211%s, FW %02x.%02x, RF %s, PA %x, address %02x:%02x:%02x:%02x:%02x:%02x\n",
1937184610Salfred	    sc->sc_name, (sc->sc_mac_rev == ZYD_ZD1211) ? "" : "B",
1938184610Salfred	    sc->sc_fw_rev >> 8, sc->sc_fw_rev & 0xff, zyd_rf_name(sc->sc_rf_rev),
1939184610Salfred	    sc->sc_pa_rev, sc->sc_myaddr[0],
1940184610Salfred	    sc->sc_myaddr[1], sc->sc_myaddr[2],
1941184610Salfred	    sc->sc_myaddr[3], sc->sc_myaddr[4],
1942184610Salfred	    sc->sc_myaddr[5]);
1943184610Salfred
1944184610Salfred	mtx_unlock(&sc->sc_mtx);
1945184610Salfred
1946184610Salfred	ifp = if_alloc(IFT_IEEE80211);
1947184610Salfred
1948184610Salfred	mtx_lock(&sc->sc_mtx);
1949184610Salfred
1950184610Salfred	if (ifp == NULL) {
1951184610Salfred		DPRINTFN(0, "%s: could not if_alloc()!\n",
1952184610Salfred		    sc->sc_name);
1953184610Salfred		goto done;
1954184610Salfred	}
1955184610Salfred	sc->sc_evilhack = ifp;
1956184610Salfred	sc->sc_ifp = ifp;
1957184610Salfred	ic = ifp->if_l2com;
1958184610Salfred
1959184610Salfred	ifp->if_softc = sc;
1960184610Salfred	if_initname(ifp, "zyd", sc->sc_unit);
1961184610Salfred	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1962184610Salfred	ifp->if_init = &zyd_init_cb;
1963184610Salfred	ifp->if_ioctl = &zyd_ioctl_cb;
1964184610Salfred	ifp->if_start = &zyd_start_cb;
1965184610Salfred	ifp->if_watchdog = NULL;
1966184610Salfred	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
1967184610Salfred	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
1968184610Salfred	IFQ_SET_READY(&ifp->if_snd);
1969184610Salfred
1970184610Salfred	bcopy(sc->sc_myaddr, ic->ic_myaddr, sizeof(ic->ic_myaddr));
1971184610Salfred
1972184610Salfred	ic->ic_ifp = ifp;
1973184610Salfred	ic->ic_phytype = IEEE80211_T_OFDM;
1974184610Salfred	ic->ic_opmode = IEEE80211_M_STA;
1975184610Salfred
1976184610Salfred	/* Set device capabilities */
1977184610Salfred	ic->ic_caps =
1978184610Salfred	    IEEE80211_C_STA		/* station mode supported */
1979184610Salfred	    | IEEE80211_C_MONITOR	/* monitor mode */
1980184610Salfred	    | IEEE80211_C_SHPREAMBLE	/* short preamble supported */
1981184610Salfred	    | IEEE80211_C_SHSLOT	/* short slot time supported */
1982184610Salfred	    | IEEE80211_C_BGSCAN	/* capable of bg scanning */
1983184610Salfred	    | IEEE80211_C_WPA		/* 802.11i */
1984184610Salfred	    ;
1985184610Salfred
1986184610Salfred	bands = 0;
1987184610Salfred	setbit(&bands, IEEE80211_MODE_11B);
1988184610Salfred	setbit(&bands, IEEE80211_MODE_11G);
1989184610Salfred	ieee80211_init_channels(ic, NULL, &bands);
1990184610Salfred
1991184610Salfred	mtx_unlock(&sc->sc_mtx);
1992184610Salfred
1993184610Salfred	ieee80211_ifattach(ic);
1994184610Salfred
1995184610Salfred	mtx_lock(&sc->sc_mtx);
1996184610Salfred
1997184610Salfred	ic->ic_node_alloc = &zyd_node_alloc_cb;
1998184610Salfred	ic->ic_raw_xmit = &zyd_raw_xmit_cb;
1999184610Salfred	ic->ic_newassoc = &zyd_newassoc_cb;
2000184610Salfred
2001184610Salfred	ic->ic_scan_start = &zyd_scan_start_cb;
2002184610Salfred	ic->ic_scan_end = &zyd_scan_end_cb;
2003184610Salfred	ic->ic_set_channel = &zyd_set_channel_cb;
2004184610Salfred	ic->ic_vap_create = &zyd_vap_create;
2005184610Salfred	ic->ic_vap_delete = &zyd_vap_delete;
2006184610Salfred	ic->ic_update_mcast = &zyd_update_mcast_cb;
2007184610Salfred	ic->ic_update_promisc = &zyd_update_promisc_cb;
2008184610Salfred
2009184610Salfred	sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan);
2010184610Salfred
2011184610Salfred	mtx_unlock(&sc->sc_mtx);
2012184610Salfred
2013184610Salfred	bpfattach(ifp, DLT_IEEE802_11_RADIO,
2014184610Salfred	    sizeof(struct ieee80211_frame) +
2015184610Salfred	    sizeof(sc->sc_txtap));
2016184610Salfred
2017184610Salfred	mtx_lock(&sc->sc_mtx);
2018184610Salfred
2019184610Salfred	if (bootverbose) {
2020184610Salfred		ieee80211_announce(ic);
2021184610Salfred	}
2022184610Salfred	usb2_transfer_start(sc->sc_xfer[ZYD_TR_INTR_DT_RD]);
2023184610Salfreddone:
2024184610Salfred	return;
2025184610Salfred}
2026184610Salfred
2027184610Salfred/*
2028184610Salfred * Detach device
2029184610Salfred */
2030184610Salfredstatic int
2031184610Salfredzyd_detach(device_t dev)
2032184610Salfred{
2033184610Salfred	struct zyd_softc *sc = device_get_softc(dev);
2034184610Salfred	struct ieee80211com *ic;
2035184610Salfred	struct ifnet *ifp;
2036184610Salfred
2037184610Salfred	usb2_config_td_drain(&sc->sc_config_td);
2038184610Salfred
2039184610Salfred	mtx_lock(&sc->sc_mtx);
2040184610Salfred
2041184610Salfred	usb2_callout_stop(&sc->sc_watchdog);
2042184610Salfred
2043184610Salfred	zyd_cfg_pre_stop(sc, NULL, 0);
2044184610Salfred
2045184610Salfred	ifp = sc->sc_ifp;
2046184610Salfred	ic = ifp->if_l2com;
2047184610Salfred
2048184610Salfred	mtx_unlock(&sc->sc_mtx);
2049184610Salfred
2050184610Salfred	/* stop all USB transfers first */
2051184610Salfred	usb2_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER);
2052184610Salfred
2053184610Salfred	/* get rid of any late children */
2054184610Salfred	bus_generic_detach(dev);
2055184610Salfred
2056184610Salfred	if (ifp) {
2057184610Salfred		bpfdetach(ifp);
2058184610Salfred		ieee80211_ifdetach(ic);
2059184610Salfred		if_free(ifp);
2060184610Salfred	}
2061184610Salfred	usb2_config_td_unsetup(&sc->sc_config_td);
2062184610Salfred
2063184610Salfred	usb2_callout_drain(&sc->sc_watchdog);
2064184610Salfred
2065184610Salfred	usb2_cv_destroy(&sc->sc_intr_cv);
2066184610Salfred
2067184610Salfred	mtx_destroy(&sc->sc_mtx);
2068184610Salfred
2069184610Salfred	return (0);
2070184610Salfred}
2071184610Salfred
2072184610Salfredstatic void
2073184610Salfredzyd_cfg_newstate(struct zyd_softc *sc,
2074184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2075184610Salfred{
2076184610Salfred	struct ifnet *ifp = sc->sc_ifp;
2077184610Salfred	struct ieee80211com *ic = ifp->if_l2com;
2078184610Salfred	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2079184610Salfred	struct zyd_vap *uvp = ZYD_VAP(vap);
2080184610Salfred	enum ieee80211_state ostate;
2081184610Salfred	enum ieee80211_state nstate;
2082184610Salfred	int arg;
2083184610Salfred
2084184610Salfred	ostate = vap->iv_state;
2085184610Salfred	nstate = sc->sc_ns_state;
2086184610Salfred	arg = sc->sc_ns_arg;
2087184610Salfred
2088184610Salfred	switch (nstate) {
2089184610Salfred	case IEEE80211_S_INIT:
2090184610Salfred		break;
2091184610Salfred
2092184610Salfred	case IEEE80211_S_RUN:
2093184610Salfred		zyd_cfg_set_run(sc, cc);
2094184610Salfred		break;
2095184610Salfred
2096184610Salfred	default:
2097184610Salfred		break;
2098184610Salfred	}
2099184610Salfred
2100184610Salfred	mtx_unlock(&sc->sc_mtx);
2101184610Salfred	IEEE80211_LOCK(ic);
2102184610Salfred	uvp->newstate(vap, nstate, arg);
2103184610Salfred	if (vap->iv_newstate_cb != NULL)
2104184610Salfred		vap->iv_newstate_cb(vap, nstate, arg);
2105184610Salfred	IEEE80211_UNLOCK(ic);
2106184610Salfred	mtx_lock(&sc->sc_mtx);
2107184610Salfred	return;
2108184610Salfred}
2109184610Salfred
2110184610Salfredstatic void
2111184610Salfredzyd_cfg_set_run(struct zyd_softc *sc,
2112184610Salfred    struct usb2_config_td_cc *cc)
2113184610Salfred{
2114184610Salfred	zyd_cfg_set_chan(sc, cc, 0);
2115184610Salfred
2116184610Salfred	if (cc->ic_opmode != IEEE80211_M_MONITOR) {
2117184610Salfred		/* turn link LED on */
2118184610Salfred		zyd_cfg_set_led(sc, ZYD_LED1, 1);
2119184610Salfred
2120184610Salfred		/* make data LED blink upon Tx */
2121184610Salfred		zyd_cfg_write32(sc, sc->sc_firmware_base + ZYD_FW_LINK_STATUS, 1);
2122184610Salfred
2123184610Salfred		zyd_cfg_set_bssid(sc, cc->iv_bss.ni_bssid);
2124184610Salfred	}
2125184610Salfred	if (cc->iv_bss.fixed_rate_none) {
2126184610Salfred		/* enable automatic rate adaptation */
2127184610Salfred		zyd_cfg_amrr_start(sc);
2128184610Salfred	}
2129184610Salfred	return;
2130184610Salfred}
2131184610Salfred
2132184610Salfredstatic int
2133184610Salfredzyd_newstate_cb(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2134184610Salfred{
2135184610Salfred	struct zyd_vap *uvp = ZYD_VAP(vap);
2136184610Salfred	struct ieee80211com *ic = vap->iv_ic;
2137184610Salfred	struct zyd_softc *sc = ic->ic_ifp->if_softc;
2138184610Salfred
2139184610Salfred	DPRINTF("setting new state: %d\n", nstate);
2140184610Salfred
2141184610Salfred	mtx_lock(&sc->sc_mtx);
2142184610Salfred	if (usb2_config_td_is_gone(&sc->sc_config_td)) {
2143184610Salfred		mtx_unlock(&sc->sc_mtx);
2144184610Salfred		/* Special case which happens at detach. */
2145184610Salfred		if (nstate == IEEE80211_S_INIT) {
2146184610Salfred			(uvp->newstate) (vap, nstate, arg);
2147184610Salfred		}
2148184610Salfred		return (0);		/* nothing to do */
2149184610Salfred	}
2150184610Salfred	/* store next state */
2151184610Salfred	sc->sc_ns_state = nstate;
2152184610Salfred	sc->sc_ns_arg = arg;
2153184610Salfred
2154184610Salfred	/* stop timers */
2155184610Salfred	sc->sc_amrr_timer = 0;
2156184610Salfred
2157184610Salfred	/*
2158184610Salfred	 * USB configuration can only be done from the USB configuration
2159184610Salfred	 * thread:
2160184610Salfred	 */
2161184610Salfred	usb2_config_td_queue_command
2162184610Salfred	    (&sc->sc_config_td, &zyd_config_copy,
2163184610Salfred	    &zyd_cfg_newstate, 0, 0);
2164184610Salfred
2165184610Salfred	mtx_unlock(&sc->sc_mtx);
2166184610Salfred
2167184610Salfred	return EINPROGRESS;
2168184610Salfred}
2169184610Salfred
2170184610Salfredstatic void
2171184610Salfredzyd_cfg_update_promisc(struct zyd_softc *sc,
2172184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2173184610Salfred{
2174184610Salfred	uint32_t low;
2175184610Salfred	uint32_t high;
2176184610Salfred
2177184610Salfred	if ((cc->ic_opmode == IEEE80211_M_MONITOR) ||
2178184610Salfred	    (cc->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) {
2179184610Salfred		low = 0xffffffff;
2180184610Salfred		high = 0xffffffff;
2181184610Salfred	} else {
2182184610Salfred		low = cc->zyd_multi_low;
2183184610Salfred		high = cc->zyd_multi_high;
2184184610Salfred	}
2185184610Salfred
2186184610Salfred	/* reprogram multicast global hash table */
2187184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_GHTBL, low);
2188184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_GHTBH, high);
2189184610Salfred	return;
2190184610Salfred}
2191184610Salfred
2192184610Salfred/*
2193184610Salfred * Rate-to-bit-converter (Field "rate" in zyd_controlsetformat)
2194184610Salfred */
2195184610Salfredstatic uint8_t
2196184610Salfredzyd_plcp_signal(uint8_t rate)
2197184610Salfred{
2198184610Salfred	;				/* fix for indent */
2199184610Salfred
2200184610Salfred	switch (rate) {
2201184610Salfred		/* CCK rates (NB: not IEEE std, device-specific) */
2202184610Salfred	case 2:
2203184610Salfred		return (0x0);
2204184610Salfred	case 4:
2205184610Salfred		return (0x1);
2206184610Salfred	case 11:
2207184610Salfred		return (0x2);
2208184610Salfred	case 22:
2209184610Salfred		return (0x3);
2210184610Salfred
2211184610Salfred		/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
2212184610Salfred	case 12:
2213184610Salfred		return (0xb);
2214184610Salfred	case 18:
2215184610Salfred		return (0xf);
2216184610Salfred	case 24:
2217184610Salfred		return (0xa);
2218184610Salfred	case 36:
2219184610Salfred		return (0xe);
2220184610Salfred	case 48:
2221184610Salfred		return (0x9);
2222184610Salfred	case 72:
2223184610Salfred		return (0xd);
2224184610Salfred	case 96:
2225184610Salfred		return (0x8);
2226184610Salfred	case 108:
2227184610Salfred		return (0xc);
2228184610Salfred
2229184610Salfred		/* XXX unsupported/unknown rate */
2230184610Salfred	default:
2231184610Salfred		return (0xff);
2232184610Salfred	}
2233184610Salfred}
2234184610Salfred
2235184610Salfredstatic void
2236184610Salfredzyd_std_command(struct ieee80211com *ic, usb2_config_td_command_t *func)
2237184610Salfred{
2238184610Salfred	struct zyd_softc *sc = ic->ic_ifp->if_softc;
2239184610Salfred
2240184610Salfred	mtx_lock(&sc->sc_mtx);
2241184610Salfred
2242184610Salfred	sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan);
2243184610Salfred
2244184610Salfred	usb2_config_td_queue_command
2245184610Salfred	    (&sc->sc_config_td, &zyd_config_copy, func, 0, 0);
2246184610Salfred
2247184610Salfred	mtx_unlock(&sc->sc_mtx);
2248184610Salfred
2249184610Salfred	return;
2250184610Salfred}
2251184610Salfred
2252184610Salfredstatic void
2253184610Salfredzyd_scan_start_cb(struct ieee80211com *ic)
2254184610Salfred{
2255184610Salfred	zyd_std_command(ic, &zyd_cfg_scan_start);
2256184610Salfred	return;
2257184610Salfred}
2258184610Salfred
2259184610Salfredstatic void
2260184610Salfredzyd_scan_end_cb(struct ieee80211com *ic)
2261184610Salfred{
2262184610Salfred	zyd_std_command(ic, &zyd_cfg_scan_end);
2263184610Salfred	return;
2264184610Salfred}
2265184610Salfred
2266184610Salfredstatic void
2267184610Salfredzyd_set_channel_cb(struct ieee80211com *ic)
2268184610Salfred{
2269184610Salfred	zyd_std_command(ic, &zyd_cfg_set_chan);
2270184610Salfred	return;
2271184610Salfred}
2272184610Salfred
2273184610Salfred/*========================================================================*
2274184610Salfred * configure sub-routines, zyd_cfg_xxx
2275184610Salfred *========================================================================*/
2276184610Salfred
2277184610Salfredstatic void
2278184610Salfredzyd_cfg_scan_start(struct zyd_softc *sc,
2279184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2280184610Salfred{
2281184610Salfred	zyd_cfg_set_bssid(sc, cc->if_broadcastaddr);
2282184610Salfred	return;
2283184610Salfred}
2284184610Salfred
2285184610Salfredstatic void
2286184610Salfredzyd_cfg_scan_end(struct zyd_softc *sc,
2287184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2288184610Salfred{
2289184610Salfred	zyd_cfg_set_bssid(sc, cc->iv_bss.ni_bssid);
2290184610Salfred	return;
2291184610Salfred}
2292184610Salfred
2293184610Salfredstatic void
2294184610Salfredzyd_cfg_set_chan(struct zyd_softc *sc,
2295184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2296184610Salfred{
2297184610Salfred	uint32_t chan;
2298184610Salfred	uint32_t tmp;
2299184610Salfred
2300184610Salfred	chan = cc->ic_curchan.chan_to_ieee;
2301184610Salfred
2302184610Salfred	DPRINTF("Will try %d\n", chan);
2303184610Salfred
2304184610Salfred	if ((chan == 0) || (chan == IEEE80211_CHAN_ANY)) {
2305184610Salfred		DPRINTF("0 or ANY, exiting\n");
2306184610Salfred		return;
2307184610Salfred	}
2308184610Salfred	zyd_cfg_lock_phy(sc);
2309184610Salfred
2310184610Salfred	(sc->sc_rf.cfg_set_channel) (sc, &sc->sc_rf, chan);
2311184610Salfred
2312184610Salfred	/* update Tx power */
2313184610Salfred	zyd_cfg_write16(sc, ZYD_CR31, sc->sc_pwr_int[chan - 1]);
2314184610Salfred
2315184610Salfred	if (sc->sc_mac_rev == ZYD_ZD1211B) {
2316184610Salfred		zyd_cfg_write16(sc, ZYD_CR67, sc->sc_ofdm36_cal[chan - 1]);
2317184610Salfred		zyd_cfg_write16(sc, ZYD_CR66, sc->sc_ofdm48_cal[chan - 1]);
2318184610Salfred		zyd_cfg_write16(sc, ZYD_CR65, sc->sc_ofdm54_cal[chan - 1]);
2319184610Salfred
2320184610Salfred		zyd_cfg_write16(sc, ZYD_CR68, sc->sc_pwr_cal[chan - 1]);
2321184610Salfred
2322184610Salfred		zyd_cfg_write16(sc, ZYD_CR69, 0x28);
2323184610Salfred		zyd_cfg_write16(sc, ZYD_CR69, 0x2a);
2324184610Salfred	}
2325184610Salfred	if (sc->sc_fix_cr47) {
2326184610Salfred		/* set CCK baseband gain from EEPROM */
2327184610Salfred		zyd_cfg_read32(sc, ZYD_EEPROM_PHY_REG, &tmp);
2328184610Salfred		zyd_cfg_write16(sc, ZYD_CR47, tmp & 0xff);
2329184610Salfred	}
2330184610Salfred	zyd_cfg_write32(sc, ZYD_CR_CONFIG_PHILIPS, 0);
2331184610Salfred
2332184610Salfred	zyd_cfg_unlock_phy(sc);
2333184610Salfred
2334184610Salfred	sc->sc_rxtap.wr_chan_freq =
2335184610Salfred	    sc->sc_txtap.wt_chan_freq =
2336184610Salfred	    htole16(cc->ic_curchan.ic_freq);
2337184610Salfred
2338184610Salfred	sc->sc_rxtap.wr_chan_flags =
2339184610Salfred	    sc->sc_txtap.wt_chan_flags =
2340184610Salfred	    htole16(cc->ic_flags);
2341184610Salfred
2342184610Salfred	return;
2343184610Salfred}
2344184610Salfred
2345184610Salfred/*
2346184610Salfred * Interface: init
2347184610Salfred */
2348184610Salfred
2349184610Salfred/* immediate configuration */
2350184610Salfred
2351184610Salfredstatic void
2352184610Salfredzyd_cfg_pre_init(struct zyd_softc *sc,
2353184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2354184610Salfred{
2355184610Salfred	struct ifnet *ifp = sc->sc_ifp;
2356184610Salfred	struct ieee80211com *ic = ifp->if_l2com;
2357184610Salfred
2358184610Salfred	zyd_cfg_pre_stop(sc, cc, 0);
2359184610Salfred
2360184610Salfred	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2361184610Salfred
2362184610Salfred	sc->sc_flags |= ZYD_FLAG_HL_READY;
2363184610Salfred
2364184610Salfred	IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
2365184610Salfred
2366184610Salfred	return;
2367184610Salfred}
2368184610Salfred
2369184610Salfred/* delayed configuration */
2370184610Salfred
2371184610Salfredstatic void
2372184610Salfredzyd_cfg_init(struct zyd_softc *sc,
2373184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2374184610Salfred{
2375184610Salfred	zyd_cfg_stop(sc, cc, 0);
2376184610Salfred
2377184610Salfred	/* Do initial setup */
2378184610Salfred
2379184610Salfred	zyd_cfg_set_mac_addr(sc, cc->ic_myaddr);
2380184610Salfred
2381184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_ENCRYPTION_TYPE, ZYD_ENC_SNIFFER);
2382184610Salfred
2383184610Salfred	/* promiscuous mode */
2384184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_SNIFFER,
2385184610Salfred	    (cc->ic_opmode == IEEE80211_M_MONITOR) ? 1 : 0);
2386184610Salfred
2387184610Salfred	/* multicast setup */
2388184610Salfred	zyd_cfg_update_promisc(sc, cc, refcount);
2389184610Salfred
2390184610Salfred	zyd_cfg_set_rxfilter(sc, cc, refcount);
2391184610Salfred
2392184610Salfred	/* switch radio transmitter ON */
2393184610Salfred	zyd_cfg_switch_radio(sc, 1);
2394184610Salfred
2395184610Salfred	/* XXX wrong, can't set here */
2396184610Salfred	/* set basic rates */
2397184610Salfred	if (cc->ic_curmode == IEEE80211_MODE_11B)
2398184610Salfred		zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0x0003);
2399184610Salfred	else if (cc->ic_curmode == IEEE80211_MODE_11A)
2400184610Salfred		zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0x1500);
2401184610Salfred	else				/* assumes 802.11b/g */
2402184610Salfred		zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0x000f);
2403184610Salfred
2404184610Salfred	/* set mandatory rates */
2405184610Salfred	if (cc->ic_curmode == IEEE80211_MODE_11B)
2406184610Salfred		zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x000f);
2407184610Salfred	else if (cc->ic_curmode == IEEE80211_MODE_11A)
2408184610Salfred		zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x1500);
2409184610Salfred	else				/* assumes 802.11b/g */
2410184610Salfred		zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x150f);
2411184610Salfred
2412184610Salfred	/* set default BSS channel */
2413184610Salfred	zyd_cfg_set_chan(sc, cc, 0);
2414184610Salfred
2415184610Salfred	/* enable interrupts */
2416184610Salfred	zyd_cfg_write32(sc, ZYD_CR_INTERRUPT, ZYD_HWINT_MASK);
2417184610Salfred
2418184610Salfred	/* make sure that the transfers get started */
2419184610Salfred	sc->sc_flags |= (
2420184610Salfred	    ZYD_FLAG_BULK_READ_STALL |
2421184610Salfred	    ZYD_FLAG_BULK_WRITE_STALL |
2422184610Salfred	    ZYD_FLAG_LL_READY);
2423184610Salfred
2424184610Salfred	if ((sc->sc_flags & ZYD_FLAG_LL_READY) &&
2425184610Salfred	    (sc->sc_flags & ZYD_FLAG_HL_READY)) {
2426184610Salfred		struct ifnet *ifp = sc->sc_ifp;
2427184610Salfred		struct ieee80211com *ic = ifp->if_l2com;
2428184610Salfred
2429184610Salfred		/*
2430184610Salfred		 * start the USB transfers, if not already started:
2431184610Salfred		 */
2432184610Salfred		usb2_transfer_start(sc->sc_xfer[1]);
2433184610Salfred		usb2_transfer_start(sc->sc_xfer[0]);
2434184610Salfred
2435184610Salfred		/*
2436184610Salfred		 * start IEEE802.11 layer
2437184610Salfred		 */
2438184610Salfred		mtx_unlock(&sc->sc_mtx);
2439184610Salfred		ieee80211_start_all(ic);
2440184610Salfred		mtx_lock(&sc->sc_mtx);
2441184610Salfred	}
2442184610Salfred	return;
2443184610Salfred}
2444184610Salfred
2445184610Salfred/* immediate configuration */
2446184610Salfred
2447184610Salfredstatic void
2448184610Salfredzyd_cfg_pre_stop(struct zyd_softc *sc,
2449184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2450184610Salfred{
2451184610Salfred	struct ifnet *ifp = sc->sc_ifp;
2452184610Salfred
2453184610Salfred	if (cc) {
2454184610Salfred		/* copy the needed configuration */
2455184610Salfred		zyd_config_copy(sc, cc, refcount);
2456184610Salfred	}
2457184610Salfred	if (ifp) {
2458184610Salfred		/* clear flags */
2459184610Salfred		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2460184610Salfred	}
2461184610Salfred	sc->sc_flags &= ~(ZYD_FLAG_HL_READY |
2462184610Salfred	    ZYD_FLAG_LL_READY);
2463184610Salfred
2464184610Salfred	/*
2465184610Salfred	 * stop all the transfers, if not already stopped:
2466184610Salfred	 */
2467184610Salfred	usb2_transfer_stop(sc->sc_xfer[ZYD_TR_BULK_DT_WR]);
2468184610Salfred	usb2_transfer_stop(sc->sc_xfer[ZYD_TR_BULK_DT_RD]);
2469184610Salfred	usb2_transfer_stop(sc->sc_xfer[ZYD_TR_BULK_CS_WR]);
2470184610Salfred	usb2_transfer_stop(sc->sc_xfer[ZYD_TR_BULK_CS_RD]);
2471184610Salfred
2472184610Salfred	/* clean up transmission */
2473184610Salfred	zyd_tx_clean_queue(sc);
2474184610Salfred	return;
2475184610Salfred}
2476184610Salfred
2477184610Salfred/* delayed configuration */
2478184610Salfred
2479184610Salfredstatic void
2480184610Salfredzyd_cfg_stop(struct zyd_softc *sc,
2481184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2482184610Salfred{
2483184610Salfred	/* switch radio transmitter OFF */
2484184610Salfred	zyd_cfg_switch_radio(sc, 0);
2485184610Salfred
2486184610Salfred	/* disable Rx */
2487184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_RXFILTER, 0);
2488184610Salfred
2489184610Salfred	/* disable interrupts */
2490184610Salfred	zyd_cfg_write32(sc, ZYD_CR_INTERRUPT, 0);
2491184610Salfred
2492184610Salfred	return;
2493184610Salfred}
2494184610Salfred
2495184610Salfredstatic void
2496184610Salfredzyd_update_mcast_cb(struct ifnet *ifp)
2497184610Salfred{
2498184610Salfred	struct zyd_softc *sc = ifp->if_softc;
2499184610Salfred
2500184610Salfred	mtx_lock(&sc->sc_mtx);
2501184610Salfred	usb2_config_td_queue_command
2502184610Salfred	    (&sc->sc_config_td, &zyd_config_copy,
2503184610Salfred	    &zyd_cfg_update_promisc, 0, 0);
2504184610Salfred	mtx_unlock(&sc->sc_mtx);
2505184610Salfred	return;
2506184610Salfred}
2507184610Salfred
2508184610Salfredstatic void
2509184610Salfredzyd_update_promisc_cb(struct ifnet *ifp)
2510184610Salfred{
2511184610Salfred	struct zyd_softc *sc = ifp->if_softc;
2512184610Salfred
2513184610Salfred	mtx_lock(&sc->sc_mtx);
2514184610Salfred	usb2_config_td_queue_command
2515184610Salfred	    (&sc->sc_config_td, &zyd_config_copy,
2516184610Salfred	    &zyd_cfg_update_promisc, 0, 0);
2517184610Salfred	mtx_unlock(&sc->sc_mtx);
2518184610Salfred	return;
2519184610Salfred}
2520184610Salfred
2521184610Salfredstatic void
2522184610Salfredzyd_cfg_set_rxfilter(struct zyd_softc *sc,
2523184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2524184610Salfred{
2525184610Salfred	uint32_t rxfilter;
2526184610Salfred
2527184610Salfred	switch (cc->ic_opmode) {
2528184610Salfred	case IEEE80211_M_STA:
2529184610Salfred		rxfilter = ZYD_FILTER_BSS;
2530184610Salfred		break;
2531184610Salfred	case IEEE80211_M_IBSS:
2532184610Salfred	case IEEE80211_M_HOSTAP:
2533184610Salfred		rxfilter = ZYD_FILTER_HOSTAP;
2534184610Salfred		break;
2535184610Salfred	case IEEE80211_M_MONITOR:
2536184610Salfred		rxfilter = ZYD_FILTER_MONITOR;
2537184610Salfred		break;
2538184610Salfred	default:
2539184610Salfred		/* should not get there */
2540184610Salfred		return;
2541184610Salfred	}
2542184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_RXFILTER, rxfilter);
2543184610Salfred	return;
2544184610Salfred}
2545184610Salfred
2546184610Salfredstatic void
2547184610Salfredzyd_cfg_set_led(struct zyd_softc *sc, uint32_t which, uint8_t on)
2548184610Salfred{
2549184610Salfred	uint32_t tmp;
2550184610Salfred
2551184610Salfred	zyd_cfg_read32(sc, ZYD_MAC_TX_PE_CONTROL, &tmp);
2552184610Salfred	if (on)
2553184610Salfred		tmp |= which;
2554184610Salfred	else
2555184610Salfred		tmp &= ~which;
2556184610Salfred
2557184610Salfred	zyd_cfg_write32(sc, ZYD_MAC_TX_PE_CONTROL, tmp);
2558184610Salfred	return;
2559184610Salfred}
2560184610Salfred
2561184610Salfredstatic void
2562184610Salfredzyd_start_cb(struct ifnet *ifp)
2563184610Salfred{
2564184610Salfred	struct zyd_softc *sc = ifp->if_softc;
2565184610Salfred
2566184610Salfred	mtx_lock(&sc->sc_mtx);
2567184610Salfred	usb2_transfer_start(sc->sc_xfer[ZYD_TR_BULK_DT_WR]);
2568184610Salfred	mtx_unlock(&sc->sc_mtx);
2569184610Salfred	return;
2570184610Salfred}
2571184610Salfred
2572184610Salfredstatic void
2573184610Salfredzyd_bulk_write_clear_stall_callback(struct usb2_xfer *xfer)
2574184610Salfred{
2575184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
2576184610Salfred	struct usb2_xfer *xfer_other = sc->sc_xfer[ZYD_TR_BULK_DT_WR];
2577184610Salfred
2578184610Salfred	if (usb2_clear_stall_callback(xfer, xfer_other)) {
2579184610Salfred		DPRINTF("stall cleared\n");
2580184610Salfred		sc->sc_flags &= ~ZYD_FLAG_BULK_WRITE_STALL;
2581184610Salfred		usb2_transfer_start(xfer_other);
2582184610Salfred	}
2583184610Salfred	return;
2584184610Salfred}
2585184610Salfred
2586184610Salfred/*
2587184610Salfred * We assume that "m->m_pkthdr.rcvif" is pointing to the "ni" that
2588184610Salfred * should be freed, when "zyd_setup_desc_and_tx" is called.
2589184610Salfred */
2590184610Salfredstatic void
2591184610Salfredzyd_setup_desc_and_tx(struct zyd_softc *sc, struct mbuf *m,
2592184610Salfred    uint16_t rate)
2593184610Salfred{
2594184610Salfred	struct ifnet *ifp = sc->sc_ifp;
2595184610Salfred	struct ieee80211com *ic = ifp->if_l2com;
2596184610Salfred	struct mbuf *mm;
2597184610Salfred	enum ieee80211_phytype phytype;
2598184610Salfred	uint16_t len;
2599184610Salfred	uint16_t totlen;
2600184610Salfred	uint16_t pktlen;
2601184610Salfred	uint8_t remainder;
2602184610Salfred
2603184610Salfred	if (sc->sc_tx_queue.ifq_len >= IFQ_MAXLEN) {
2604184610Salfred		/* free packet */
2605184610Salfred		zyd_tx_freem(m);
2606184610Salfred		ifp->if_oerrors++;
2607184610Salfred		return;
2608184610Salfred	}
2609184610Salfred	if (!((sc->sc_flags & ZYD_FLAG_LL_READY) &&
2610184610Salfred	    (sc->sc_flags & ZYD_FLAG_HL_READY))) {
2611184610Salfred		/* free packet */
2612184610Salfred		zyd_tx_freem(m);
2613184610Salfred		ifp->if_oerrors++;
2614184610Salfred		return;
2615184610Salfred	}
2616184610Salfred	if (rate < 2) {
2617184610Salfred		DPRINTF("rate < 2!\n");
2618184610Salfred
2619184610Salfred		/* avoid division by zero */
2620184610Salfred		rate = 2;
2621184610Salfred	}
2622184610Salfred	ic->ic_lastdata = ticks;
2623184610Salfred
2624184610Salfred	if (bpf_peers_present(ifp->if_bpf)) {
2625184610Salfred		struct zyd_tx_radiotap_header *tap = &sc->sc_txtap;
2626184610Salfred
2627184610Salfred		tap->wt_flags = 0;
2628184610Salfred		tap->wt_rate = rate;
2629184610Salfred		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
2630184610Salfred		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
2631184610Salfred
2632184610Salfred		bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m);
2633184610Salfred	}
2634184610Salfred	len = m->m_pkthdr.len;
2635184610Salfred	totlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
2636184610Salfred	phytype = ieee80211_rate2phytype(sc->sc_rates, rate);
2637184610Salfred
2638184610Salfred	sc->sc_tx_desc.len = htole16(totlen);
2639184610Salfred	sc->sc_tx_desc.phy = zyd_plcp_signal(rate);
2640184610Salfred	if (phytype == IEEE80211_T_OFDM) {
2641184610Salfred		sc->sc_tx_desc.phy |= ZYD_TX_PHY_OFDM;
2642184610Salfred		if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
2643184610Salfred			sc->sc_tx_desc.phy |= ZYD_TX_PHY_5GHZ;
2644184610Salfred	} else if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
2645184610Salfred		sc->sc_tx_desc.phy |= ZYD_TX_PHY_SHPREAMBLE;
2646184610Salfred
2647184610Salfred	/* actual transmit length (XXX why +10?) */
2648184610Salfred	pktlen = sizeof(struct zyd_tx_desc) + 10;
2649184610Salfred	if (sc->sc_mac_rev == ZYD_ZD1211)
2650184610Salfred		pktlen += totlen;
2651184610Salfred	sc->sc_tx_desc.pktlen = htole16(pktlen);
2652184610Salfred
2653184610Salfred	sc->sc_tx_desc.plcp_length = ((16 * totlen) + rate - 1) / rate;
2654184610Salfred	sc->sc_tx_desc.plcp_service = 0;
2655184610Salfred	if (rate == 22) {
2656184610Salfred		remainder = (16 * totlen) % 22;
2657184610Salfred		if ((remainder != 0) && (remainder < 7))
2658184610Salfred			sc->sc_tx_desc.plcp_service |= ZYD_PLCP_LENGEXT;
2659184610Salfred	}
2660184610Salfred	if (sizeof(sc->sc_tx_desc) > MHLEN) {
2661184610Salfred		DPRINTF("No room for header structure!\n");
2662184610Salfred		zyd_tx_freem(m);
2663184610Salfred		return;
2664184610Salfred	}
2665184610Salfred	mm = m_gethdr(M_NOWAIT, MT_DATA);
2666184610Salfred	if (mm == NULL) {
2667184610Salfred		DPRINTF("Could not allocate header mbuf!\n");
2668184610Salfred		zyd_tx_freem(m);
2669184610Salfred		return;
2670184610Salfred	}
2671184610Salfred	bcopy(&sc->sc_tx_desc, mm->m_data, sizeof(sc->sc_tx_desc));
2672184610Salfred	mm->m_len = sizeof(sc->sc_tx_desc);
2673184610Salfred
2674184610Salfred	mm->m_next = m;
2675184610Salfred	mm->m_pkthdr.len = mm->m_len + m->m_pkthdr.len;
2676184610Salfred	mm->m_pkthdr.rcvif = NULL;
2677184610Salfred
2678184610Salfred	/* start write transfer, if not started */
2679184610Salfred	_IF_ENQUEUE(&sc->sc_tx_queue, mm);
2680184610Salfred
2681184610Salfred	usb2_transfer_start(sc->sc_xfer[0]);
2682184610Salfred	return;
2683184610Salfred}
2684184610Salfred
2685184610Salfredstatic void
2686184610Salfredzyd_bulk_write_callback(struct usb2_xfer *xfer)
2687184610Salfred{
2688184610Salfred	struct zyd_softc *sc = xfer->priv_sc;
2689184610Salfred	struct ifnet *ifp = sc->sc_ifp;
2690184610Salfred	struct mbuf *m;
2691184610Salfred	uint16_t temp_len;
2692184610Salfred
2693184610Salfred	DPRINTF("\n");
2694184610Salfred
2695184610Salfred	switch (USB_GET_STATE(xfer)) {
2696184610Salfred	case USB_ST_TRANSFERRED:
2697184610Salfred		DPRINTFN(11, "transfer complete\n");
2698184610Salfred
2699184610Salfred		ifp->if_opackets++;
2700184610Salfred
2701184610Salfred	case USB_ST_SETUP:
2702184610Salfred		if (sc->sc_flags & ZYD_FLAG_BULK_WRITE_STALL) {
2703184610Salfred			usb2_transfer_start(sc->sc_xfer[ZYD_TR_BULK_CS_WR]);
2704184610Salfred			DPRINTFN(11, "write stalled\n");
2705184610Salfred			break;
2706184610Salfred		}
2707184610Salfred		if (sc->sc_flags & ZYD_FLAG_WAIT_COMMAND) {
2708184610Salfred			/*
2709184610Salfred			 * don't send anything while a command is pending !
2710184610Salfred			 */
2711184610Salfred			DPRINTFN(11, "wait command\n");
2712184610Salfred			break;
2713184610Salfred		}
2714184610Salfred		zyd_fill_write_queue(sc);
2715184610Salfred
2716184610Salfred		_IF_DEQUEUE(&sc->sc_tx_queue, m);
2717184610Salfred
2718184610Salfred		if (m) {
2719184610Salfred			if (m->m_pkthdr.len > ZYD_MAX_TXBUFSZ) {
2720184610Salfred				DPRINTFN(0, "data overflow, %u bytes\n",
2721184610Salfred				    m->m_pkthdr.len);
2722184610Salfred				m->m_pkthdr.len = ZYD_MAX_TXBUFSZ;
2723184610Salfred			}
2724184610Salfred			usb2_m_copy_in(xfer->frbuffers, 0,
2725184610Salfred			    m, 0, m->m_pkthdr.len);
2726184610Salfred
2727184610Salfred			/* get transfer length */
2728184610Salfred			temp_len = m->m_pkthdr.len;
2729184610Salfred
2730184610Salfred			DPRINTFN(11, "sending frame len=%u xferlen=%u\n",
2731184610Salfred			    m->m_pkthdr.len, temp_len);
2732184610Salfred
2733184610Salfred			xfer->frlengths[0] = temp_len;
2734184610Salfred
2735184610Salfred			usb2_start_hardware(xfer);
2736184610Salfred
2737184610Salfred			/* free mbuf and node */
2738184610Salfred			zyd_tx_freem(m);
2739184610Salfred		}
2740184610Salfred		break;
2741184610Salfred
2742184610Salfred	default:			/* Error */
2743184610Salfred		DPRINTFN(11, "transfer error, %s\n",
2744184610Salfred		    usb2_errstr(xfer->error));
2745184610Salfred
2746184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
2747184610Salfred			/* try to clear stall first */
2748184610Salfred			sc->sc_flags |= ZYD_FLAG_BULK_WRITE_STALL;
2749184610Salfred			usb2_transfer_start(sc->sc_xfer[ZYD_TR_BULK_CS_WR]);
2750184610Salfred		}
2751184610Salfred		ifp->if_oerrors++;
2752184610Salfred		break;
2753184610Salfred	}
2754184610Salfred	return;
2755184610Salfred}
2756184610Salfred
2757184610Salfredstatic void
2758184610Salfredzyd_init_cb(void *arg)
2759184610Salfred{
2760184610Salfred	struct zyd_softc *sc = arg;
2761184610Salfred
2762184610Salfred	mtx_lock(&sc->sc_mtx);
2763184610Salfred	usb2_config_td_queue_command
2764184610Salfred	    (&sc->sc_config_td, &zyd_cfg_pre_init,
2765184610Salfred	    &zyd_cfg_init, 0, 0);
2766184610Salfred	mtx_unlock(&sc->sc_mtx);
2767184610Salfred
2768184610Salfred	return;
2769184610Salfred}
2770184610Salfred
2771184610Salfredstatic int
2772184610Salfredzyd_ioctl_cb(struct ifnet *ifp, u_long cmd, caddr_t data)
2773184610Salfred{
2774184610Salfred	struct zyd_softc *sc = ifp->if_softc;
2775184610Salfred	struct ieee80211com *ic = ifp->if_l2com;
2776184610Salfred	int error;
2777184610Salfred
2778184610Salfred	switch (cmd) {
2779184610Salfred	case SIOCSIFFLAGS:
2780184610Salfred		mtx_lock(&sc->sc_mtx);
2781184610Salfred		if (ifp->if_flags & IFF_UP) {
2782184610Salfred			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2783184610Salfred				usb2_config_td_queue_command
2784184610Salfred				    (&sc->sc_config_td, &zyd_cfg_pre_init,
2785184610Salfred				    &zyd_cfg_init, 0, 0);
2786184610Salfred			}
2787184610Salfred		} else {
2788184610Salfred			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2789184610Salfred				usb2_config_td_queue_command
2790184610Salfred				    (&sc->sc_config_td, &zyd_cfg_pre_stop,
2791184610Salfred				    &zyd_cfg_stop, 0, 0);
2792184610Salfred			}
2793184610Salfred		}
2794184610Salfred		mtx_unlock(&sc->sc_mtx);
2795184610Salfred		error = 0;
2796184610Salfred		break;
2797184610Salfred
2798184610Salfred	case SIOCGIFMEDIA:
2799184610Salfred	case SIOCADDMULTI:
2800184610Salfred	case SIOCDELMULTI:
2801184610Salfred		error = ifmedia_ioctl(ifp, (void *)data, &ic->ic_media, cmd);
2802184610Salfred		break;
2803184610Salfred
2804184610Salfred	default:
2805184610Salfred		error = ether_ioctl(ifp, cmd, data);
2806184610Salfred		break;
2807184610Salfred	}
2808184610Salfred	return (error);
2809184610Salfred}
2810184610Salfred
2811184610Salfredstatic void
2812184610Salfredzyd_watchdog(void *arg)
2813184610Salfred{
2814184610Salfred	struct zyd_softc *sc = arg;
2815184610Salfred
2816184610Salfred	mtx_assert(&sc->sc_mtx, MA_OWNED);
2817184610Salfred
2818184610Salfred	if (sc->sc_amrr_timer) {
2819184610Salfred		usb2_config_td_queue_command
2820184610Salfred		    (&sc->sc_config_td, NULL,
2821184610Salfred		    &zyd_cfg_amrr_timeout, 0, 0);
2822184610Salfred	}
2823184610Salfred	usb2_callout_reset(&sc->sc_watchdog,
2824184610Salfred	    hz, &zyd_watchdog, sc);
2825184610Salfred
2826184610Salfred	mtx_unlock(&sc->sc_mtx);
2827184610Salfred
2828184610Salfred	return;
2829184610Salfred}
2830184610Salfred
2831184610Salfredstatic void
2832184610Salfredzyd_config_copy_chan(struct zyd_config_copy_chan *cc,
2833184610Salfred    struct ieee80211com *ic, struct ieee80211_channel *c)
2834184610Salfred{
2835184610Salfred	if (!c)
2836184610Salfred		return;
2837184610Salfred	cc->chan_to_ieee =
2838184610Salfred	    ieee80211_chan2ieee(ic, c);
2839184610Salfred	if (c != IEEE80211_CHAN_ANYC) {
2840184610Salfred		cc->chan_to_mode =
2841184610Salfred		    ieee80211_chan2mode(c);
2842184610Salfred		cc->ic_freq = c->ic_freq;
2843184610Salfred		if (IEEE80211_IS_CHAN_B(c))
2844184610Salfred			cc->chan_is_b = 1;
2845184610Salfred		if (IEEE80211_IS_CHAN_A(c))
2846184610Salfred			cc->chan_is_a = 1;
2847184610Salfred		if (IEEE80211_IS_CHAN_2GHZ(c))
2848184610Salfred			cc->chan_is_2ghz = 1;
2849184610Salfred		if (IEEE80211_IS_CHAN_5GHZ(c))
2850184610Salfred			cc->chan_is_5ghz = 1;
2851184610Salfred		if (IEEE80211_IS_CHAN_ANYG(c))
2852184610Salfred			cc->chan_is_g = 1;
2853184610Salfred	}
2854184610Salfred	return;
2855184610Salfred}
2856184610Salfred
2857184610Salfredstatic void
2858184610Salfredzyd_config_copy(struct zyd_softc *sc,
2859184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2860184610Salfred{
2861184610Salfred	const struct ieee80211_txparam *tp;
2862184610Salfred	struct ieee80211vap *vap;
2863184610Salfred	struct ifmultiaddr *ifma;
2864184610Salfred	struct ieee80211_node *ni;
2865184610Salfred	struct ieee80211com *ic;
2866184610Salfred	struct ifnet *ifp;
2867184610Salfred
2868184610Salfred	bzero(cc, sizeof(*cc));
2869184610Salfred
2870184610Salfred	ifp = sc->sc_ifp;
2871184610Salfred	if (ifp) {
2872184610Salfred		cc->if_flags = ifp->if_flags;
2873184610Salfred		bcopy(ifp->if_broadcastaddr, cc->if_broadcastaddr,
2874184610Salfred		    sizeof(cc->if_broadcastaddr));
2875184610Salfred
2876184610Salfred		cc->zyd_multi_low = 0x00000000;
2877184610Salfred		cc->zyd_multi_high = 0x80000000;
2878184610Salfred
2879184610Salfred		IF_ADDR_LOCK(ifp);
2880184610Salfred		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2881184610Salfred			uint8_t v;
2882184610Salfred
2883184610Salfred			if (ifma->ifma_addr->sa_family != AF_LINK)
2884184610Salfred				continue;
2885184610Salfred			v = ((uint8_t *)LLADDR((struct sockaddr_dl *)
2886184610Salfred			    ifma->ifma_addr))[5] >> 2;
2887184610Salfred			if (v < 32)
2888184610Salfred				cc->zyd_multi_low |= 1 << v;
2889184610Salfred			else
2890184610Salfred				cc->zyd_multi_high |= 1 << (v - 32);
2891184610Salfred		}
2892184610Salfred		IF_ADDR_UNLOCK(ifp);
2893184610Salfred
2894184610Salfred		ic = ifp->if_l2com;
2895184610Salfred		if (ic) {
2896184610Salfred			zyd_config_copy_chan(&cc->ic_curchan, ic, ic->ic_curchan);
2897184610Salfred			zyd_config_copy_chan(&cc->ic_bsschan, ic, ic->ic_bsschan);
2898184610Salfred			vap = TAILQ_FIRST(&ic->ic_vaps);
2899184610Salfred			if (vap) {
2900184610Salfred				ni = vap->iv_bss;
2901184610Salfred				if (ni) {
2902184610Salfred					cc->iv_bss.ni_intval = ni->ni_intval;
2903184610Salfred					bcopy(ni->ni_bssid, cc->iv_bss.ni_bssid,
2904184610Salfred					    sizeof(cc->iv_bss.ni_bssid));
2905184610Salfred				}
2906184610Salfred				tp = vap->iv_txparms + cc->ic_bsschan.chan_to_mode;
2907184610Salfred				if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) {
2908184610Salfred					cc->iv_bss.fixed_rate_none = 1;
2909184610Salfred				}
2910184610Salfred			}
2911184610Salfred			cc->ic_opmode = ic->ic_opmode;
2912184610Salfred			cc->ic_flags = ic->ic_flags;
2913184610Salfred			cc->ic_txpowlimit = ic->ic_txpowlimit;
2914184610Salfred			cc->ic_curmode = ic->ic_curmode;
2915184610Salfred
2916184610Salfred			bcopy(ic->ic_myaddr, cc->ic_myaddr,
2917184610Salfred			    sizeof(cc->ic_myaddr));
2918184610Salfred		}
2919184610Salfred	}
2920184610Salfred	sc->sc_flags |= ZYD_FLAG_WAIT_COMMAND;
2921184610Salfred	return;
2922184610Salfred}
2923184610Salfred
2924184610Salfredstatic void
2925184610Salfredzyd_end_of_commands(struct zyd_softc *sc)
2926184610Salfred{
2927184610Salfred	sc->sc_flags &= ~ZYD_FLAG_WAIT_COMMAND;
2928184610Salfred
2929184610Salfred	/* start write transfer, if not started */
2930184610Salfred	usb2_transfer_start(sc->sc_xfer[0]);
2931184610Salfred	return;
2932184610Salfred}
2933184610Salfred
2934184610Salfredstatic void
2935184610Salfredzyd_newassoc_cb(struct ieee80211_node *ni, int isnew)
2936184610Salfred{
2937184610Salfred	struct ieee80211vap *vap = ni->ni_vap;
2938184610Salfred
2939184610Salfred	ieee80211_amrr_node_init(&ZYD_VAP(vap)->amrr, &ZYD_NODE(ni)->amn, ni);
2940184610Salfred	return;
2941184610Salfred}
2942184610Salfred
2943184610Salfredstatic void
2944184610Salfredzyd_cfg_amrr_timeout(struct zyd_softc *sc,
2945184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
2946184610Salfred{
2947184610Salfred	struct ieee80211vap *vap;
2948184610Salfred	struct ieee80211_node *ni;
2949184610Salfred
2950184610Salfred	vap = zyd_get_vap(sc);
2951184610Salfred	if (vap == NULL) {
2952184610Salfred		return;
2953184610Salfred	}
2954184610Salfred	ni = vap->iv_bss;
2955184610Salfred	if (ni == NULL) {
2956184610Salfred		return;
2957184610Salfred	}
2958184610Salfred	if ((sc->sc_flags & ZYD_FLAG_LL_READY) &&
2959184610Salfred	    (sc->sc_flags & ZYD_FLAG_HL_READY)) {
2960184610Salfred
2961184610Salfred		if (sc->sc_amrr_timer) {
2962184610Salfred
2963184610Salfred			if (ieee80211_amrr_choose(ni, &ZYD_NODE(ni)->amn)) {
2964184610Salfred				/* ignore */
2965184610Salfred			}
2966184610Salfred		}
2967184610Salfred	}
2968184610Salfred	return;
2969184610Salfred}
2970184610Salfred
2971184610Salfredstatic void
2972184610Salfredzyd_cfg_amrr_start(struct zyd_softc *sc)
2973184610Salfred{
2974184610Salfred	struct ieee80211vap *vap;
2975184610Salfred	struct ieee80211_node *ni;
2976184610Salfred
2977184610Salfred	vap = zyd_get_vap(sc);
2978184610Salfred
2979184610Salfred	if (vap == NULL) {
2980184610Salfred		return;
2981184610Salfred	}
2982184610Salfred	ni = vap->iv_bss;
2983184610Salfred	if (ni == NULL) {
2984184610Salfred		return;
2985184610Salfred	}
2986184610Salfred	/* init AMRR */
2987184610Salfred
2988184610Salfred	ieee80211_amrr_node_init(&ZYD_VAP(vap)->amrr, &ZYD_NODE(ni)->amn, ni);
2989184610Salfred
2990184610Salfred	/* enable AMRR timer */
2991184610Salfred
2992184610Salfred	sc->sc_amrr_timer = 1;
2993184610Salfred	return;
2994184610Salfred}
2995184610Salfred
2996184610Salfredstatic struct ieee80211vap *
2997184610Salfredzyd_vap_create(struct ieee80211com *ic,
2998184610Salfred    const char name[IFNAMSIZ], int unit, int opmode, int flags,
2999184610Salfred    const uint8_t bssid[IEEE80211_ADDR_LEN],
3000184610Salfred    const uint8_t mac[IEEE80211_ADDR_LEN])
3001184610Salfred{
3002184610Salfred	struct zyd_vap *zvp;
3003184610Salfred	struct ieee80211vap *vap;
3004184610Salfred	struct zyd_softc *sc = ic->ic_ifp->if_softc;
3005184610Salfred
3006184610Salfred	/* Need to sync with config thread: */
3007184610Salfred	mtx_lock(&sc->sc_mtx);
3008184610Salfred	if (usb2_config_td_sync(&sc->sc_config_td)) {
3009184610Salfred		mtx_unlock(&sc->sc_mtx);
3010184610Salfred		/* config thread is gone */
3011184610Salfred		return (NULL);
3012184610Salfred	}
3013184610Salfred	mtx_unlock(&sc->sc_mtx);
3014184610Salfred
3015184610Salfred	if (!TAILQ_EMPTY(&ic->ic_vaps))	/* only one at a time */
3016184610Salfred		return NULL;
3017184610Salfred	zvp = (struct zyd_vap *)malloc(sizeof(struct zyd_vap),
3018184610Salfred	    M_80211_VAP, M_NOWAIT | M_ZERO);
3019184610Salfred	if (zvp == NULL)
3020184610Salfred		return NULL;
3021184610Salfred	vap = &zvp->vap;
3022184610Salfred	/* enable s/w bmiss handling for sta mode */
3023184610Salfred	ieee80211_vap_setup(ic, vap, name, unit, opmode,
3024184610Salfred	    flags | IEEE80211_CLONE_NOBEACONS, bssid, mac);
3025184610Salfred
3026184610Salfred	/* override state transition machine */
3027184610Salfred	zvp->newstate = vap->iv_newstate;
3028184610Salfred	vap->iv_newstate = &zyd_newstate_cb;
3029184610Salfred
3030184610Salfred	ieee80211_amrr_init(&zvp->amrr, vap,
3031184610Salfred	    IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
3032184610Salfred	    IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
3033184610Salfred	    1000 /* 1 sec */ );
3034184610Salfred
3035184610Salfred	/* complete setup */
3036184610Salfred	ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status);
3037184610Salfred	ic->ic_opmode = opmode;
3038184610Salfred
3039184610Salfred	return (vap);
3040184610Salfred}
3041184610Salfred
3042184610Salfredstatic void
3043184610Salfredzyd_vap_delete(struct ieee80211vap *vap)
3044184610Salfred{
3045184610Salfred	struct zyd_vap *zvp = ZYD_VAP(vap);
3046184610Salfred	struct zyd_softc *sc = vap->iv_ic->ic_ifp->if_softc;
3047184610Salfred
3048184610Salfred	/* Need to sync with config thread: */
3049184610Salfred	mtx_lock(&sc->sc_mtx);
3050184610Salfred	if (usb2_config_td_sync(&sc->sc_config_td)) {
3051184610Salfred		/* ignore */
3052184610Salfred	}
3053184610Salfred	mtx_unlock(&sc->sc_mtx);
3054184610Salfred
3055184610Salfred	ieee80211_amrr_cleanup(&zvp->amrr);
3056184610Salfred	ieee80211_vap_detach(vap);
3057184610Salfred	free(zvp, M_80211_VAP);
3058184610Salfred	return;
3059184610Salfred}
3060184610Salfred
3061184610Salfred/* ARGUSED */
3062184610Salfredstatic struct ieee80211_node *
3063184610Salfredzyd_node_alloc_cb(struct ieee80211vap *vap __unused,
3064184610Salfred    const uint8_t mac[IEEE80211_ADDR_LEN] __unused)
3065184610Salfred{
3066184610Salfred	struct zyd_node *zn;
3067184610Salfred
3068184610Salfred	zn = malloc(sizeof(struct zyd_node), M_80211_NODE, M_NOWAIT | M_ZERO);
3069184610Salfred	return ((zn != NULL) ? &zn->ni : NULL);
3070184610Salfred}
3071184610Salfred
3072184610Salfredstatic void
3073184610Salfredzyd_fill_write_queue(struct zyd_softc *sc)
3074184610Salfred{
3075184610Salfred	struct ifnet *ifp = sc->sc_ifp;
3076184610Salfred	struct ieee80211_node *ni;
3077184610Salfred	struct mbuf *m;
3078184610Salfred
3079184610Salfred	/*
3080184610Salfred	 * We only fill up half of the queue with data frames. The rest is
3081184610Salfred	 * reserved for other kinds of frames.
3082184610Salfred	 */
3083184610Salfred
3084184610Salfred	while (sc->sc_tx_queue.ifq_len < (IFQ_MAXLEN / 2)) {
3085184610Salfred
3086184610Salfred		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
3087184610Salfred		if (m == NULL)
3088184610Salfred			break;
3089184610Salfred
3090184610Salfred		ni = (void *)(m->m_pkthdr.rcvif);
3091184610Salfred		m = ieee80211_encap(ni, m);
3092184610Salfred		if (m == NULL) {
3093184610Salfred			ieee80211_free_node(ni);
3094184610Salfred			continue;
3095184610Salfred		}
3096184610Salfred		zyd_tx_data(sc, m, ni);
3097184610Salfred	}
3098184610Salfred	return;
3099184610Salfred}
3100184610Salfred
3101184610Salfredstatic void
3102184610Salfredzyd_tx_clean_queue(struct zyd_softc *sc)
3103184610Salfred{
3104184610Salfred	struct mbuf *m;
3105184610Salfred
3106184610Salfred	for (;;) {
3107184610Salfred		_IF_DEQUEUE(&sc->sc_tx_queue, m);
3108184610Salfred
3109184610Salfred		if (!m) {
3110184610Salfred			break;
3111184610Salfred		}
3112184610Salfred		zyd_tx_freem(m);
3113184610Salfred	}
3114184610Salfred
3115184610Salfred	return;
3116184610Salfred}
3117184610Salfred
3118184610Salfredstatic void
3119184610Salfredzyd_tx_freem(struct mbuf *m)
3120184610Salfred{
3121184610Salfred	struct ieee80211_node *ni;
3122184610Salfred
3123184610Salfred	while (m) {
3124184610Salfred		ni = (void *)(m->m_pkthdr.rcvif);
3125184610Salfred		if (!ni) {
3126184610Salfred			m = m_free(m);
3127184610Salfred			continue;
3128184610Salfred		}
3129184610Salfred		if (m->m_flags & M_TXCB) {
3130184610Salfred			ieee80211_process_callback(ni, m, 0);
3131184610Salfred		}
3132184610Salfred		m_freem(m);
3133184610Salfred		ieee80211_free_node(ni);
3134184610Salfred
3135184610Salfred		break;
3136184610Salfred	}
3137184610Salfred	return;
3138184610Salfred}
3139184610Salfred
3140184610Salfredstatic void
3141184610Salfredzyd_tx_mgt(struct zyd_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3142184610Salfred{
3143184610Salfred	struct ieee80211vap *vap = ni->ni_vap;
3144184610Salfred	struct ieee80211com *ic = ni->ni_ic;
3145184610Salfred	const struct ieee80211_txparam *tp;
3146184610Salfred	struct ieee80211_frame *wh;
3147184610Salfred	struct ieee80211_key *k;
3148184610Salfred	uint16_t totlen;
3149184610Salfred	uint16_t rate;
3150184610Salfred
3151184610Salfred	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
3152184610Salfred	rate = tp->mgmtrate;
3153184610Salfred
3154184610Salfred	wh = mtod(m, struct ieee80211_frame *);
3155184610Salfred	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3156184610Salfred		k = ieee80211_crypto_encap(ni, m);
3157184610Salfred		if (k == NULL) {
3158184610Salfred			m_freem(m);
3159184610Salfred			ieee80211_free_node(ni);
3160184610Salfred			return;
3161184610Salfred		}
3162184610Salfred		wh = mtod(m, struct ieee80211_frame *);
3163184610Salfred	}
3164184610Salfred	/* fill Tx descriptor */
3165184610Salfred
3166184610Salfred	sc->sc_tx_desc.flags = ZYD_TX_FLAG_BACKOFF;
3167184610Salfred	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3168184610Salfred		/* get total length */
3169184610Salfred		totlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3170184610Salfred		/* multicast frames are not sent at OFDM rates in 802.11b/g */
3171184610Salfred		if (totlen > vap->iv_rtsthreshold) {
3172184610Salfred			sc->sc_tx_desc.flags |= ZYD_TX_FLAG_RTS;
3173184610Salfred		} else if (ZYD_RATE_IS_OFDM(rate) &&
3174184610Salfred		    (ic->ic_flags & IEEE80211_F_USEPROT)) {
3175184610Salfred			if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
3176184610Salfred				sc->sc_tx_desc.flags |= ZYD_TX_FLAG_CTS_TO_SELF;
3177184610Salfred			else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
3178184610Salfred				sc->sc_tx_desc.flags |= ZYD_TX_FLAG_RTS;
3179184610Salfred		}
3180184610Salfred	} else
3181184610Salfred		sc->sc_tx_desc.flags |= ZYD_TX_FLAG_MULTICAST;
3182184610Salfred
3183184610Salfred	if ((wh->i_fc[0] &
3184184610Salfred	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3185184610Salfred	    (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_PS_POLL))
3186184610Salfred		sc->sc_tx_desc.flags |= ZYD_TX_FLAG_TYPE(ZYD_TX_TYPE_PS_POLL);
3187184610Salfred
3188184610Salfred	m->m_pkthdr.rcvif = (void *)ni;
3189184610Salfred	zyd_setup_desc_and_tx(sc, m, rate);
3190184610Salfred	return;
3191184610Salfred}
3192184610Salfred
3193184610Salfredstatic void
3194184610Salfredzyd_tx_data(struct zyd_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3195184610Salfred{
3196184610Salfred	struct ieee80211vap *vap = ni->ni_vap;
3197184610Salfred	struct ieee80211com *ic = ni->ni_ic;
3198184610Salfred	const struct ieee80211_txparam *tp;
3199184610Salfred	struct ieee80211_frame *wh;
3200184610Salfred	struct ieee80211_key *k;
3201184610Salfred	uint16_t rate;
3202184610Salfred
3203184610Salfred	wh = mtod(m, struct ieee80211_frame *);
3204184610Salfred
3205184610Salfred	sc->sc_tx_desc.flags = ZYD_TX_FLAG_BACKOFF;
3206184610Salfred	tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
3207184610Salfred	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3208184610Salfred		rate = tp->mcastrate;
3209184610Salfred		sc->sc_tx_desc.flags |= ZYD_TX_FLAG_MULTICAST;
3210184610Salfred	} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
3211184610Salfred		rate = tp->ucastrate;
3212184610Salfred	} else
3213184610Salfred		rate = ni->ni_txrate;
3214184610Salfred
3215184610Salfred	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3216184610Salfred		k = ieee80211_crypto_encap(ni, m);
3217184610Salfred		if (k == NULL) {
3218184610Salfred			m_freem(m);
3219184610Salfred			ieee80211_free_node(ni);
3220184610Salfred			return;
3221184610Salfred		}
3222184610Salfred		/* packet header may have moved, reset our local pointer */
3223184610Salfred		wh = mtod(m, struct ieee80211_frame *);
3224184610Salfred	}
3225184610Salfred	/* fill Tx descriptor */
3226184610Salfred
3227184610Salfred	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3228184610Salfred		uint16_t totlen;
3229184610Salfred
3230184610Salfred		totlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3231184610Salfred
3232184610Salfred		/* multicast frames are not sent at OFDM rates in 802.11b/g */
3233184610Salfred		if (totlen > vap->iv_rtsthreshold) {
3234184610Salfred			sc->sc_tx_desc.flags |= ZYD_TX_FLAG_RTS;
3235184610Salfred		} else if (ZYD_RATE_IS_OFDM(rate) &&
3236184610Salfred		    (ic->ic_flags & IEEE80211_F_USEPROT)) {
3237184610Salfred			if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
3238184610Salfred				sc->sc_tx_desc.flags |= ZYD_TX_FLAG_CTS_TO_SELF;
3239184610Salfred			else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
3240184610Salfred				sc->sc_tx_desc.flags |= ZYD_TX_FLAG_RTS;
3241184610Salfred		}
3242184610Salfred	}
3243184610Salfred	if ((wh->i_fc[0] &
3244184610Salfred	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3245184610Salfred	    (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_PS_POLL))
3246184610Salfred		sc->sc_tx_desc.flags |= ZYD_TX_FLAG_TYPE(ZYD_TX_TYPE_PS_POLL);
3247184610Salfred
3248184610Salfred	m->m_pkthdr.rcvif = (void *)ni;
3249184610Salfred	zyd_setup_desc_and_tx(sc, m, rate);
3250184610Salfred	return;
3251184610Salfred}
3252184610Salfred
3253184610Salfredstatic int
3254184610Salfredzyd_raw_xmit_cb(struct ieee80211_node *ni, struct mbuf *m,
3255184610Salfred    const struct ieee80211_bpf_params *params)
3256184610Salfred{
3257184610Salfred	struct ieee80211com *ic = ni->ni_ic;
3258184610Salfred	struct ifnet *ifp = ic->ic_ifp;
3259184610Salfred	struct zyd_softc *sc = ifp->if_softc;
3260184610Salfred
3261184610Salfred	mtx_lock(&sc->sc_mtx);
3262184610Salfred	if (params == NULL) {
3263184610Salfred		/*
3264184610Salfred		 * Legacy path; interpret frame contents to decide
3265184610Salfred		 * precisely how to send the frame.
3266184610Salfred		 */
3267184610Salfred		zyd_tx_mgt(sc, m, ni);
3268184610Salfred	} else {
3269184610Salfred		/*
3270184610Salfred		 * Caller supplied explicit parameters to use in
3271184610Salfred		 * sending the frame.
3272184610Salfred		 */
3273184610Salfred		zyd_tx_mgt(sc, m, ni);	/* XXX zyd_tx_raw() */
3274184610Salfred	}
3275184610Salfred	mtx_unlock(&sc->sc_mtx);
3276184610Salfred	return (0);
3277184610Salfred}
3278184610Salfred
3279184610Salfredstatic struct ieee80211vap *
3280184610Salfredzyd_get_vap(struct zyd_softc *sc)
3281184610Salfred{
3282184610Salfred	struct ifnet *ifp;
3283184610Salfred	struct ieee80211com *ic;
3284184610Salfred
3285184610Salfred	if (sc == NULL) {
3286184610Salfred		return NULL;
3287184610Salfred	}
3288184610Salfred	ifp = sc->sc_ifp;
3289184610Salfred	if (ifp == NULL) {
3290184610Salfred		return NULL;
3291184610Salfred	}
3292184610Salfred	ic = ifp->if_l2com;
3293184610Salfred	if (ic == NULL) {
3294184610Salfred		return NULL;
3295184610Salfred	}
3296184610Salfred	return TAILQ_FIRST(&ic->ic_vaps);
3297184610Salfred}
3298