Commit | Line | Data |
---|---|---|
12bd3c8b SW |
1 | /* $OpenBSD: if_zyd.c,v 1.52 2007/02/11 00:08:04 jsg Exp $ */ |
2 | /* $NetBSD: if_zyd.c,v 1.7 2007/06/21 04:04:29 kiyohara Exp $ */ | |
3 | /* $FreeBSD$ */ | |
4 | ||
5 | /*- | |
6 | * Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr> | |
7 | * Copyright (c) 2006 by Florian Stoehr <ich@florian-stoehr.de> | |
8 | * | |
9 | * Permission to use, copy, modify, and distribute this software for any | |
10 | * purpose with or without fee is hereby granted, provided that the above | |
11 | * copyright notice and this permission notice appear in all copies. | |
12 | * | |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
20 | */ | |
21 | ||
12bd3c8b SW |
22 | /* |
23 | * ZyDAS ZD1211/ZD1211B USB WLAN driver. | |
24 | */ | |
25 | ||
26 | #include <sys/param.h> | |
27 | #include <sys/sockio.h> | |
28 | #include <sys/sysctl.h> | |
29 | #include <sys/lock.h> | |
30 | #include <sys/mutex.h> | |
31 | #include <sys/condvar.h> | |
32 | #include <sys/mbuf.h> | |
33 | #include <sys/kernel.h> | |
34 | #include <sys/socket.h> | |
35 | #include <sys/systm.h> | |
36 | #include <sys/malloc.h> | |
37 | #include <sys/module.h> | |
38 | #include <sys/bus.h> | |
39 | #include <sys/endian.h> | |
40 | #include <sys/kdb.h> | |
41 | ||
42 | #include <machine/bus.h> | |
43 | #include <machine/resource.h> | |
44 | #include <sys/rman.h> | |
45 | ||
46 | #include <net/bpf.h> | |
47 | #include <net/if.h> | |
48 | #include <net/if_arp.h> | |
49 | #include <net/ethernet.h> | |
50 | #include <net/if_dl.h> | |
51 | #include <net/if_media.h> | |
52 | #include <net/if_types.h> | |
53 | ||
54 | #ifdef INET | |
55 | #include <netinet/in.h> | |
56 | #include <netinet/in_systm.h> | |
57 | #include <netinet/in_var.h> | |
58 | #include <netinet/if_ether.h> | |
59 | #include <netinet/ip.h> | |
60 | #endif | |
61 | ||
62 | #include <net80211/ieee80211_var.h> | |
63 | #include <net80211/ieee80211_regdomain.h> | |
64 | #include <net80211/ieee80211_radiotap.h> | |
65 | #include <net80211/ieee80211_ratectl.h> | |
66 | ||
67 | #include <dev/usb/usb.h> | |
68 | #include <dev/usb/usbdi.h> | |
69 | #include <dev/usb/usbdi_util.h> | |
70 | #include "usbdevs.h" | |
71 | ||
72 | #include <dev/usb/wlan/if_zydreg.h> | |
73 | #include <dev/usb/wlan/if_zydfw.h> | |
74 | ||
75 | #ifdef USB_DEBUG | |
76 | static int zyd_debug = 0; | |
77 | ||
78 | static SYSCTL_NODE(_hw_usb, OID_AUTO, zyd, CTLFLAG_RW, 0, "USB zyd"); | |
79 | SYSCTL_INT(_hw_usb_zyd, OID_AUTO, debug, CTLFLAG_RW, &zyd_debug, 0, | |
80 | "zyd debug level"); | |
81 | ||
82 | enum { | |
83 | ZYD_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ | |
84 | ZYD_DEBUG_RECV = 0x00000002, /* basic recv operation */ | |
85 | ZYD_DEBUG_RESET = 0x00000004, /* reset processing */ | |
86 | ZYD_DEBUG_INIT = 0x00000008, /* device init */ | |
87 | ZYD_DEBUG_TX_PROC = 0x00000010, /* tx ISR proc */ | |
88 | ZYD_DEBUG_RX_PROC = 0x00000020, /* rx ISR proc */ | |
89 | ZYD_DEBUG_STATE = 0x00000040, /* 802.11 state transitions */ | |
90 | ZYD_DEBUG_STAT = 0x00000080, /* statistic */ | |
91 | ZYD_DEBUG_FW = 0x00000100, /* firmware */ | |
92 | ZYD_DEBUG_CMD = 0x00000200, /* fw commands */ | |
93 | ZYD_DEBUG_ANY = 0xffffffff | |
94 | }; | |
95 | #define DPRINTF(sc, m, fmt, ...) do { \ | |
96 | if (zyd_debug & (m)) \ | |
97 | printf("%s: " fmt, __func__, ## __VA_ARGS__); \ | |
98 | } while (0) | |
99 | #else | |
100 | #define DPRINTF(sc, m, fmt, ...) do { \ | |
101 | (void) sc; \ | |
102 | } while (0) | |
103 | #endif | |
104 | ||
105 | #define zyd_do_request(sc,req,data) \ | |
106 | usbd_do_request_flags((sc)->sc_udev, &(sc)->sc_mtx, req, data, 0, NULL, 5000) | |
107 | ||
108 | static device_probe_t zyd_match; | |
109 | static device_attach_t zyd_attach; | |
110 | static device_detach_t zyd_detach; | |
111 | ||
112 | static usb_callback_t zyd_intr_read_callback; | |
113 | static usb_callback_t zyd_intr_write_callback; | |
114 | static usb_callback_t zyd_bulk_read_callback; | |
115 | static usb_callback_t zyd_bulk_write_callback; | |
116 | ||
117 | static struct ieee80211vap *zyd_vap_create(struct ieee80211com *, | |
118 | const char [IFNAMSIZ], int, enum ieee80211_opmode, int, | |
119 | const uint8_t [IEEE80211_ADDR_LEN], | |
120 | const uint8_t [IEEE80211_ADDR_LEN]); | |
121 | static void zyd_vap_delete(struct ieee80211vap *); | |
122 | static void zyd_tx_free(struct zyd_tx_data *, int); | |
123 | static void zyd_setup_tx_list(struct zyd_softc *); | |
124 | static void zyd_unsetup_tx_list(struct zyd_softc *); | |
125 | static int zyd_newstate(struct ieee80211vap *, enum ieee80211_state, int); | |
126 | static int zyd_cmd(struct zyd_softc *, uint16_t, const void *, int, | |
127 | void *, int, int); | |
128 | static int zyd_read16(struct zyd_softc *, uint16_t, uint16_t *); | |
129 | static int zyd_read32(struct zyd_softc *, uint16_t, uint32_t *); | |
130 | static int zyd_write16(struct zyd_softc *, uint16_t, uint16_t); | |
131 | static int zyd_write32(struct zyd_softc *, uint16_t, uint32_t); | |
132 | static int zyd_rfwrite(struct zyd_softc *, uint32_t); | |
133 | static int zyd_lock_phy(struct zyd_softc *); | |
134 | static int zyd_unlock_phy(struct zyd_softc *); | |
135 | static int zyd_rf_attach(struct zyd_softc *, uint8_t); | |
136 | static const char *zyd_rf_name(uint8_t); | |
137 | static int zyd_hw_init(struct zyd_softc *); | |
138 | static int zyd_read_pod(struct zyd_softc *); | |
139 | static int zyd_read_eeprom(struct zyd_softc *); | |
140 | static int zyd_get_macaddr(struct zyd_softc *); | |
141 | static int zyd_set_macaddr(struct zyd_softc *, const uint8_t *); | |
142 | static int zyd_set_bssid(struct zyd_softc *, const uint8_t *); | |
143 | static int zyd_switch_radio(struct zyd_softc *, int); | |
144 | static int zyd_set_led(struct zyd_softc *, int, int); | |
145 | static void zyd_set_multi(struct zyd_softc *); | |
146 | static void zyd_update_mcast(struct ifnet *); | |
147 | static int zyd_set_rxfilter(struct zyd_softc *); | |
148 | static void zyd_set_chan(struct zyd_softc *, struct ieee80211_channel *); | |
149 | static int zyd_set_beacon_interval(struct zyd_softc *, int); | |
150 | static void zyd_rx_data(struct usb_xfer *, int, uint16_t); | |
151 | static int zyd_tx_start(struct zyd_softc *, struct mbuf *, | |
152 | struct ieee80211_node *); | |
153 | static void zyd_start(struct ifnet *); | |
154 | static int zyd_raw_xmit(struct ieee80211_node *, struct mbuf *, | |
155 | const struct ieee80211_bpf_params *); | |
156 | static int zyd_ioctl(struct ifnet *, u_long, caddr_t); | |
157 | static void zyd_init_locked(struct zyd_softc *); | |
158 | static void zyd_init(void *); | |
159 | static void zyd_stop(struct zyd_softc *); | |
160 | static int zyd_loadfirmware(struct zyd_softc *); | |
161 | static void zyd_scan_start(struct ieee80211com *); | |
162 | static void zyd_scan_end(struct ieee80211com *); | |
163 | static void zyd_set_channel(struct ieee80211com *); | |
164 | static int zyd_rfmd_init(struct zyd_rf *); | |
165 | static int zyd_rfmd_switch_radio(struct zyd_rf *, int); | |
166 | static int zyd_rfmd_set_channel(struct zyd_rf *, uint8_t); | |
167 | static int zyd_al2230_init(struct zyd_rf *); | |
168 | static int zyd_al2230_switch_radio(struct zyd_rf *, int); | |
169 | static int zyd_al2230_set_channel(struct zyd_rf *, uint8_t); | |
170 | static int zyd_al2230_set_channel_b(struct zyd_rf *, uint8_t); | |
171 | static int zyd_al2230_init_b(struct zyd_rf *); | |
172 | static int zyd_al7230B_init(struct zyd_rf *); | |
173 | static int zyd_al7230B_switch_radio(struct zyd_rf *, int); | |
174 | static int zyd_al7230B_set_channel(struct zyd_rf *, uint8_t); | |
175 | static int zyd_al2210_init(struct zyd_rf *); | |
176 | static int zyd_al2210_switch_radio(struct zyd_rf *, int); | |
177 | static int zyd_al2210_set_channel(struct zyd_rf *, uint8_t); | |
178 | static int zyd_gct_init(struct zyd_rf *); | |
179 | static int zyd_gct_switch_radio(struct zyd_rf *, int); | |
180 | static int zyd_gct_set_channel(struct zyd_rf *, uint8_t); | |
181 | static int zyd_gct_mode(struct zyd_rf *); | |
182 | static int zyd_gct_set_channel_synth(struct zyd_rf *, int, int); | |
183 | static int zyd_gct_write(struct zyd_rf *, uint16_t); | |
184 | static int zyd_gct_txgain(struct zyd_rf *, uint8_t); | |
185 | static int zyd_maxim2_init(struct zyd_rf *); | |
186 | static int zyd_maxim2_switch_radio(struct zyd_rf *, int); | |
187 | static int zyd_maxim2_set_channel(struct zyd_rf *, uint8_t); | |
188 | ||
189 | static const struct zyd_phy_pair zyd_def_phy[] = ZYD_DEF_PHY; | |
190 | static const struct zyd_phy_pair zyd_def_phyB[] = ZYD_DEF_PHYB; | |
191 | ||
192 | /* various supported device vendors/products */ | |
193 | #define ZYD_ZD1211 0 | |
194 | #define ZYD_ZD1211B 1 | |
195 | ||
196 | #define ZYD_ZD1211_DEV(v,p) \ | |
197 | { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, ZYD_ZD1211) } | |
198 | #define ZYD_ZD1211B_DEV(v,p) \ | |
199 | { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, ZYD_ZD1211B) } | |
200 | static const STRUCT_USB_HOST_ID zyd_devs[] = { | |
201 | /* ZYD_ZD1211 */ | |
202 | ZYD_ZD1211_DEV(3COM2, 3CRUSB10075), | |
203 | ZYD_ZD1211_DEV(ABOCOM, WL54), | |
204 | ZYD_ZD1211_DEV(ASUS, WL159G), | |
205 | ZYD_ZD1211_DEV(CYBERTAN, TG54USB), | |
206 | ZYD_ZD1211_DEV(DRAYTEK, VIGOR550), | |
207 | ZYD_ZD1211_DEV(PLANEX2, GWUS54GD), | |
208 | ZYD_ZD1211_DEV(PLANEX2, GWUS54GZL), | |
209 | ZYD_ZD1211_DEV(PLANEX3, GWUS54GZ), | |
210 | ZYD_ZD1211_DEV(PLANEX3, GWUS54MINI), | |
211 | ZYD_ZD1211_DEV(SAGEM, XG760A), | |
212 | ZYD_ZD1211_DEV(SENAO, NUB8301), | |
213 | ZYD_ZD1211_DEV(SITECOMEU, WL113), | |
214 | ZYD_ZD1211_DEV(SWEEX, ZD1211), | |
215 | ZYD_ZD1211_DEV(TEKRAM, QUICKWLAN), | |
216 | ZYD_ZD1211_DEV(TEKRAM, ZD1211_1), | |
217 | ZYD_ZD1211_DEV(TEKRAM, ZD1211_2), | |
218 | ZYD_ZD1211_DEV(TWINMOS, G240), | |
219 | ZYD_ZD1211_DEV(UMEDIA, ALL0298V2), | |
220 | ZYD_ZD1211_DEV(UMEDIA, TEW429UB_A), | |
221 | ZYD_ZD1211_DEV(UMEDIA, TEW429UB), | |
222 | ZYD_ZD1211_DEV(WISTRONNEWEB, UR055G), | |
223 | ZYD_ZD1211_DEV(ZCOM, ZD1211), | |
224 | ZYD_ZD1211_DEV(ZYDAS, ZD1211), | |
225 | ZYD_ZD1211_DEV(ZYXEL, AG225H), | |
226 | ZYD_ZD1211_DEV(ZYXEL, ZYAIRG220), | |
227 | ZYD_ZD1211_DEV(ZYXEL, G200V2), | |
228 | /* ZYD_ZD1211B */ | |
229 | ZYD_ZD1211B_DEV(ACCTON, SMCWUSBG_NF), | |
230 | ZYD_ZD1211B_DEV(ACCTON, SMCWUSBG), | |
231 | ZYD_ZD1211B_DEV(ACCTON, ZD1211B), | |
232 | ZYD_ZD1211B_DEV(ASUS, A9T_WIFI), | |
233 | ZYD_ZD1211B_DEV(BELKIN, F5D7050_V4000), | |
234 | ZYD_ZD1211B_DEV(BELKIN, ZD1211B), | |
235 | ZYD_ZD1211B_DEV(CISCOLINKSYS, WUSBF54G), | |
236 | ZYD_ZD1211B_DEV(FIBERLINE, WL430U), | |
237 | ZYD_ZD1211B_DEV(MELCO, KG54L), | |
238 | ZYD_ZD1211B_DEV(PHILIPS, SNU5600), | |
239 | ZYD_ZD1211B_DEV(PLANEX2, GW_US54GXS), | |
240 | ZYD_ZD1211B_DEV(SAGEM, XG76NA), | |
241 | ZYD_ZD1211B_DEV(SITECOMEU, ZD1211B), | |
242 | ZYD_ZD1211B_DEV(UMEDIA, TEW429UBC1), | |
243 | ZYD_ZD1211B_DEV(USR, USR5423), | |
244 | ZYD_ZD1211B_DEV(VTECH, ZD1211B), | |
245 | ZYD_ZD1211B_DEV(ZCOM, ZD1211B), | |
246 | ZYD_ZD1211B_DEV(ZYDAS, ZD1211B), | |
247 | ZYD_ZD1211B_DEV(ZYXEL, M202), | |
248 | ZYD_ZD1211B_DEV(ZYXEL, G202), | |
249 | ZYD_ZD1211B_DEV(ZYXEL, G220V2) | |
250 | }; | |
251 | ||
252 | static const struct usb_config zyd_config[ZYD_N_TRANSFER] = { | |
253 | [ZYD_BULK_WR] = { | |
254 | .type = UE_BULK, | |
255 | .endpoint = UE_ADDR_ANY, | |
256 | .direction = UE_DIR_OUT, | |
257 | .bufsize = ZYD_MAX_TXBUFSZ, | |
258 | .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, | |
259 | .callback = zyd_bulk_write_callback, | |
260 | .ep_index = 0, | |
261 | .timeout = 10000, /* 10 seconds */ | |
262 | }, | |
263 | [ZYD_BULK_RD] = { | |
264 | .type = UE_BULK, | |
265 | .endpoint = UE_ADDR_ANY, | |
266 | .direction = UE_DIR_IN, | |
267 | .bufsize = ZYX_MAX_RXBUFSZ, | |
268 | .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, | |
269 | .callback = zyd_bulk_read_callback, | |
270 | .ep_index = 0, | |
271 | }, | |
272 | [ZYD_INTR_WR] = { | |
273 | .type = UE_BULK_INTR, | |
274 | .endpoint = UE_ADDR_ANY, | |
275 | .direction = UE_DIR_OUT, | |
276 | .bufsize = sizeof(struct zyd_cmd), | |
277 | .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, | |
278 | .callback = zyd_intr_write_callback, | |
279 | .timeout = 1000, /* 1 second */ | |
280 | .ep_index = 1, | |
281 | }, | |
282 | [ZYD_INTR_RD] = { | |
283 | .type = UE_INTERRUPT, | |
284 | .endpoint = UE_ADDR_ANY, | |
285 | .direction = UE_DIR_IN, | |
286 | .bufsize = sizeof(struct zyd_cmd), | |
287 | .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, | |
288 | .callback = zyd_intr_read_callback, | |
289 | }, | |
290 | }; | |
291 | #define zyd_read16_m(sc, val, data) do { \ | |
292 | error = zyd_read16(sc, val, data); \ | |
293 | if (error != 0) \ | |
294 | goto fail; \ | |
295 | } while (0) | |
296 | #define zyd_write16_m(sc, val, data) do { \ | |
297 | error = zyd_write16(sc, val, data); \ | |
298 | if (error != 0) \ | |
299 | goto fail; \ | |
300 | } while (0) | |
301 | #define zyd_read32_m(sc, val, data) do { \ | |
302 | error = zyd_read32(sc, val, data); \ | |
303 | if (error != 0) \ | |
304 | goto fail; \ | |
305 | } while (0) | |
306 | #define zyd_write32_m(sc, val, data) do { \ | |
307 | error = zyd_write32(sc, val, data); \ | |
308 | if (error != 0) \ | |
309 | goto fail; \ | |
310 | } while (0) | |
311 | ||
312 | static int | |
313 | zyd_match(device_t dev) | |
314 | { | |
315 | struct usb_attach_arg *uaa = device_get_ivars(dev); | |
316 | ||
317 | if (uaa->usb_mode != USB_MODE_HOST) | |
318 | return (ENXIO); | |
319 | if (uaa->info.bConfigIndex != ZYD_CONFIG_INDEX) | |
320 | return (ENXIO); | |
321 | if (uaa->info.bIfaceIndex != ZYD_IFACE_INDEX) | |
322 | return (ENXIO); | |
323 | ||
324 | return (usbd_lookup_id_by_uaa(zyd_devs, sizeof(zyd_devs), uaa)); | |
325 | } | |
326 | ||
327 | static int | |
328 | zyd_attach(device_t dev) | |
329 | { | |
330 | struct usb_attach_arg *uaa = device_get_ivars(dev); | |
331 | struct zyd_softc *sc = device_get_softc(dev); | |
332 | struct ifnet *ifp; | |
333 | struct ieee80211com *ic; | |
334 | uint8_t iface_index, bands; | |
335 | int error; | |
336 | ||
337 | if (uaa->info.bcdDevice < 0x4330) { | |
338 | device_printf(dev, "device version mismatch: 0x%X " | |
339 | "(only >= 43.30 supported)\n", | |
340 | uaa->info.bcdDevice); | |
341 | return (EINVAL); | |
342 | } | |
343 | ||
344 | device_set_usb_desc(dev); | |
345 | sc->sc_dev = dev; | |
346 | sc->sc_udev = uaa->device; | |
347 | sc->sc_macrev = USB_GET_DRIVER_INFO(uaa); | |
348 | ||
349 | mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), | |
350 | MTX_NETWORK_LOCK, MTX_DEF); | |
351 | STAILQ_INIT(&sc->sc_rqh); | |
352 | ||
353 | iface_index = ZYD_IFACE_INDEX; | |
354 | error = usbd_transfer_setup(uaa->device, | |
355 | &iface_index, sc->sc_xfer, zyd_config, | |
356 | ZYD_N_TRANSFER, sc, &sc->sc_mtx); | |
357 | if (error) { | |
358 | device_printf(dev, "could not allocate USB transfers, " | |
359 | "err=%s\n", usbd_errstr(error)); | |
360 | goto detach; | |
361 | } | |
362 | ||
363 | ZYD_LOCK(sc); | |
364 | if ((error = zyd_get_macaddr(sc)) != 0) { | |
365 | device_printf(sc->sc_dev, "could not read EEPROM\n"); | |
366 | ZYD_UNLOCK(sc); | |
367 | goto detach; | |
368 | } | |
369 | ZYD_UNLOCK(sc); | |
370 | ||
371 | ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); | |
372 | if (ifp == NULL) { | |
373 | device_printf(sc->sc_dev, "can not if_alloc()\n"); | |
374 | goto detach; | |
375 | } | |
376 | ifp->if_softc = sc; | |
377 | if_initname(ifp, "zyd", device_get_unit(sc->sc_dev)); | |
378 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |
379 | ifp->if_init = zyd_init; | |
380 | ifp->if_ioctl = zyd_ioctl; | |
381 | ifp->if_start = zyd_start; | |
382 | IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |
383 | IFQ_SET_READY(&ifp->if_snd); | |
384 | ||
385 | ic = ifp->if_l2com; | |
386 | ic->ic_ifp = ifp; | |
387 | ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ | |
388 | ic->ic_opmode = IEEE80211_M_STA; | |
389 | ||
390 | /* set device capabilities */ | |
391 | ic->ic_caps = | |
392 | IEEE80211_C_STA /* station mode */ | |
393 | | IEEE80211_C_MONITOR /* monitor mode */ | |
394 | | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | |
395 | | IEEE80211_C_SHSLOT /* short slot time supported */ | |
396 | | IEEE80211_C_BGSCAN /* capable of bg scanning */ | |
397 | | IEEE80211_C_WPA /* 802.11i */ | |
398 | ; | |
399 | ||
400 | bands = 0; | |
401 | setbit(&bands, IEEE80211_MODE_11B); | |
402 | setbit(&bands, IEEE80211_MODE_11G); | |
403 | ieee80211_init_channels(ic, NULL, &bands); | |
404 | ||
405 | ieee80211_ifattach(ic, sc->sc_bssid); | |
406 | ic->ic_raw_xmit = zyd_raw_xmit; | |
407 | ic->ic_scan_start = zyd_scan_start; | |
408 | ic->ic_scan_end = zyd_scan_end; | |
409 | ic->ic_set_channel = zyd_set_channel; | |
410 | ||
411 | ic->ic_vap_create = zyd_vap_create; | |
412 | ic->ic_vap_delete = zyd_vap_delete; | |
413 | ic->ic_update_mcast = zyd_update_mcast; | |
414 | ic->ic_update_promisc = zyd_update_mcast; | |
415 | ||
416 | ieee80211_radiotap_attach(ic, | |
417 | &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), | |
418 | ZYD_TX_RADIOTAP_PRESENT, | |
419 | &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), | |
420 | ZYD_RX_RADIOTAP_PRESENT); | |
421 | ||
422 | if (bootverbose) | |
423 | ieee80211_announce(ic); | |
424 | ||
425 | return (0); | |
426 | ||
427 | detach: | |
428 | zyd_detach(dev); | |
429 | return (ENXIO); /* failure */ | |
430 | } | |
431 | ||
432 | static int | |
433 | zyd_detach(device_t dev) | |
434 | { | |
435 | struct zyd_softc *sc = device_get_softc(dev); | |
436 | struct ifnet *ifp = sc->sc_ifp; | |
437 | struct ieee80211com *ic; | |
438 | ||
439 | /* stop all USB transfers */ | |
440 | usbd_transfer_unsetup(sc->sc_xfer, ZYD_N_TRANSFER); | |
441 | ||
442 | /* free TX list, if any */ | |
443 | zyd_unsetup_tx_list(sc); | |
444 | ||
445 | if (ifp) { | |
446 | ic = ifp->if_l2com; | |
447 | ieee80211_ifdetach(ic); | |
448 | if_free(ifp); | |
449 | } | |
450 | mtx_destroy(&sc->sc_mtx); | |
451 | ||
452 | return (0); | |
453 | } | |
454 | ||
455 | static struct ieee80211vap * | |
456 | zyd_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, | |
457 | enum ieee80211_opmode opmode, int flags, | |
458 | const uint8_t bssid[IEEE80211_ADDR_LEN], | |
459 | const uint8_t mac[IEEE80211_ADDR_LEN]) | |
460 | { | |
461 | struct zyd_vap *zvp; | |
462 | struct ieee80211vap *vap; | |
463 | ||
464 | if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ | |
465 | return (NULL); | |
466 | zvp = (struct zyd_vap *) malloc(sizeof(struct zyd_vap), | |
f6807fa3 | 467 | M_80211_VAP, M_WAITOK | M_ZERO); |
12bd3c8b SW |
468 | if (zvp == NULL) |
469 | return (NULL); | |
470 | vap = &zvp->vap; | |
471 | /* enable s/w bmiss handling for sta mode */ | |
472 | ieee80211_vap_setup(ic, vap, name, unit, opmode, | |
473 | flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); | |
474 | ||
475 | /* override state transition machine */ | |
476 | zvp->newstate = vap->iv_newstate; | |
477 | vap->iv_newstate = zyd_newstate; | |
478 | ||
479 | ieee80211_ratectl_init(vap); | |
480 | ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); | |
481 | ||
482 | /* complete setup */ | |
483 | ieee80211_vap_attach(vap, ieee80211_media_change, | |
484 | ieee80211_media_status); | |
485 | ic->ic_opmode = opmode; | |
486 | return (vap); | |
487 | } | |
488 | ||
489 | static void | |
490 | zyd_vap_delete(struct ieee80211vap *vap) | |
491 | { | |
492 | struct zyd_vap *zvp = ZYD_VAP(vap); | |
493 | ||
494 | ieee80211_ratectl_deinit(vap); | |
495 | ieee80211_vap_detach(vap); | |
496 | free(zvp, M_80211_VAP); | |
497 | } | |
498 | ||
499 | static void | |
500 | zyd_tx_free(struct zyd_tx_data *data, int txerr) | |
501 | { | |
502 | struct zyd_softc *sc = data->sc; | |
503 | ||
504 | if (data->m != NULL) { | |
505 | if (data->m->m_flags & M_TXCB) | |
506 | ieee80211_process_callback(data->ni, data->m, | |
507 | txerr ? ETIMEDOUT : 0); | |
508 | m_freem(data->m); | |
509 | data->m = NULL; | |
510 | ||
511 | ieee80211_free_node(data->ni); | |
512 | data->ni = NULL; | |
513 | } | |
514 | STAILQ_INSERT_TAIL(&sc->tx_free, data, next); | |
515 | sc->tx_nfree++; | |
516 | } | |
517 | ||
518 | static void | |
519 | zyd_setup_tx_list(struct zyd_softc *sc) | |
520 | { | |
521 | struct zyd_tx_data *data; | |
522 | int i; | |
523 | ||
524 | sc->tx_nfree = 0; | |
525 | STAILQ_INIT(&sc->tx_q); | |
526 | STAILQ_INIT(&sc->tx_free); | |
527 | ||
528 | for (i = 0; i < ZYD_TX_LIST_CNT; i++) { | |
529 | data = &sc->tx_data[i]; | |
530 | ||
531 | data->sc = sc; | |
532 | STAILQ_INSERT_TAIL(&sc->tx_free, data, next); | |
533 | sc->tx_nfree++; | |
534 | } | |
535 | } | |
536 | ||
537 | static void | |
538 | zyd_unsetup_tx_list(struct zyd_softc *sc) | |
539 | { | |
540 | struct zyd_tx_data *data; | |
541 | int i; | |
542 | ||
543 | /* make sure any subsequent use of the queues will fail */ | |
544 | sc->tx_nfree = 0; | |
545 | STAILQ_INIT(&sc->tx_q); | |
546 | STAILQ_INIT(&sc->tx_free); | |
547 | ||
548 | /* free up all node references and mbufs */ | |
549 | for (i = 0; i < ZYD_TX_LIST_CNT; i++) { | |
550 | data = &sc->tx_data[i]; | |
551 | ||
552 | if (data->m != NULL) { | |
553 | m_freem(data->m); | |
554 | data->m = NULL; | |
555 | } | |
556 | if (data->ni != NULL) { | |
557 | ieee80211_free_node(data->ni); | |
558 | data->ni = NULL; | |
559 | } | |
560 | } | |
561 | } | |
562 | ||
563 | static int | |
564 | zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | |
565 | { | |
566 | struct zyd_vap *zvp = ZYD_VAP(vap); | |
567 | struct ieee80211com *ic = vap->iv_ic; | |
568 | struct zyd_softc *sc = ic->ic_ifp->if_softc; | |
569 | int error; | |
570 | ||
571 | DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, | |
572 | ieee80211_state_name[vap->iv_state], | |
573 | ieee80211_state_name[nstate]); | |
574 | ||
575 | IEEE80211_UNLOCK(ic); | |
576 | ZYD_LOCK(sc); | |
577 | switch (nstate) { | |
578 | case IEEE80211_S_AUTH: | |
579 | zyd_set_chan(sc, ic->ic_curchan); | |
580 | break; | |
581 | case IEEE80211_S_RUN: | |
582 | if (vap->iv_opmode == IEEE80211_M_MONITOR) | |
583 | break; | |
584 | ||
585 | /* turn link LED on */ | |
586 | error = zyd_set_led(sc, ZYD_LED1, 1); | |
587 | if (error != 0) | |
588 | break; | |
589 | ||
590 | /* make data LED blink upon Tx */ | |
591 | zyd_write32_m(sc, sc->sc_fwbase + ZYD_FW_LINK_STATUS, 1); | |
592 | ||
593 | IEEE80211_ADDR_COPY(sc->sc_bssid, vap->iv_bss->ni_bssid); | |
594 | zyd_set_bssid(sc, sc->sc_bssid); | |
595 | break; | |
596 | default: | |
597 | break; | |
598 | } | |
599 | fail: | |
600 | ZYD_UNLOCK(sc); | |
601 | IEEE80211_LOCK(ic); | |
602 | return (zvp->newstate(vap, nstate, arg)); | |
603 | } | |
604 | ||
605 | /* | |
606 | * Callback handler for interrupt transfer | |
607 | */ | |
608 | static void | |
609 | zyd_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) | |
610 | { | |
611 | struct zyd_softc *sc = usbd_xfer_softc(xfer); | |
612 | struct ifnet *ifp = sc->sc_ifp; | |
613 | struct ieee80211com *ic = ifp->if_l2com; | |
614 | struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); | |
615 | struct ieee80211_node *ni; | |
616 | struct zyd_cmd *cmd = &sc->sc_ibuf; | |
617 | struct usb_page_cache *pc; | |
618 | int datalen; | |
619 | int actlen; | |
23abaded | 620 | char hexstr[HEX_NCPYLEN(64)]; |
12bd3c8b SW |
621 | |
622 | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | |
623 | ||
624 | switch (USB_GET_STATE(xfer)) { | |
625 | case USB_ST_TRANSFERRED: | |
626 | pc = usbd_xfer_get_frame(xfer, 0); | |
627 | usbd_copy_out(pc, 0, cmd, sizeof(*cmd)); | |
628 | ||
629 | switch (le16toh(cmd->code)) { | |
630 | case ZYD_NOTIF_RETRYSTATUS: | |
631 | { | |
632 | struct zyd_notif_retry *retry = | |
633 | (struct zyd_notif_retry *)cmd->data; | |
634 | ||
635 | DPRINTF(sc, ZYD_DEBUG_TX_PROC, | |
636 | "retry intr: rate=0x%x addr=%s count=%d (0x%x)\n", | |
637 | le16toh(retry->rate), ether_sprintf(retry->macaddr), | |
638 | le16toh(retry->count)&0xff, le16toh(retry->count)); | |
639 | ||
640 | /* | |
641 | * Find the node to which the packet was sent and | |
642 | * update its retry statistics. In BSS mode, this node | |
643 | * is the AP we're associated to so no lookup is | |
644 | * actually needed. | |
645 | */ | |
646 | ni = ieee80211_find_txnode(vap, retry->macaddr); | |
647 | if (ni != NULL) { | |
648 | int retrycnt = | |
649 | (int)(le16toh(retry->count) & 0xff); | |
650 | ||
651 | ieee80211_ratectl_tx_complete(vap, ni, | |
652 | IEEE80211_RATECTL_TX_FAILURE, | |
653 | &retrycnt, NULL); | |
654 | ieee80211_free_node(ni); | |
655 | } | |
656 | if (le16toh(retry->count) & 0x100) | |
657 | ifp->if_oerrors++; /* too many retries */ | |
658 | break; | |
659 | } | |
660 | case ZYD_NOTIF_IORD: | |
661 | { | |
662 | struct zyd_rq *rqp; | |
663 | ||
664 | if (le16toh(*(uint16_t *)cmd->data) == ZYD_CR_INTERRUPT) | |
665 | break; /* HMAC interrupt */ | |
666 | ||
667 | datalen = actlen - sizeof(cmd->code); | |
668 | datalen -= 2; /* XXX: padding? */ | |
669 | ||
670 | STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) { | |
671 | int i, cnt; | |
672 | ||
673 | if (rqp->olen != datalen) | |
674 | continue; | |
675 | cnt = rqp->olen / sizeof(struct zyd_pair); | |
676 | for (i = 0; i < cnt; i++) { | |
677 | if (*(((const uint16_t *)rqp->idata) + i) != | |
678 | (((struct zyd_pair *)cmd->data) + i)->reg) | |
679 | break; | |
680 | } | |
681 | if (i != cnt) | |
682 | continue; | |
683 | /* copy answer into caller-supplied buffer */ | |
684 | memcpy(rqp->odata, cmd->data, rqp->olen); | |
685 | DPRINTF(sc, ZYD_DEBUG_CMD, | |
23abaded AHJ |
686 | "command %p complete, data = %s \n", |
687 | rqp, hexncpy(rqp->odata, rqp->olen, hexstr, | |
688 | HEX_NCPYLEN(rqp->olen), ":")); | |
12bd3c8b SW |
689 | wakeup(rqp); /* wakeup caller */ |
690 | break; | |
691 | } | |
692 | if (rqp == NULL) { | |
693 | device_printf(sc->sc_dev, | |
23abaded AHJ |
694 | "unexpected IORD notification %s\n", |
695 | hexncpy(cmd->data, datalen, hexstr, | |
696 | HEX_NCPYLEN(datalen), ":")); | |
12bd3c8b SW |
697 | } |
698 | break; | |
699 | } | |
700 | default: | |
701 | device_printf(sc->sc_dev, "unknown notification %x\n", | |
702 | le16toh(cmd->code)); | |
703 | } | |
704 | ||
705 | /* FALLTHROUGH */ | |
706 | case USB_ST_SETUP: | |
707 | tr_setup: | |
708 | usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); | |
709 | usbd_transfer_submit(xfer); | |
710 | break; | |
711 | ||
712 | default: /* Error */ | |
713 | DPRINTF(sc, ZYD_DEBUG_CMD, "error = %s\n", | |
714 | usbd_errstr(error)); | |
715 | ||
716 | if (error != USB_ERR_CANCELLED) { | |
717 | /* try to clear stall first */ | |
718 | usbd_xfer_set_stall(xfer); | |
719 | goto tr_setup; | |
720 | } | |
721 | break; | |
722 | } | |
723 | } | |
724 | ||
725 | static void | |
726 | zyd_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) | |
727 | { | |
728 | struct zyd_softc *sc = usbd_xfer_softc(xfer); | |
729 | struct zyd_rq *rqp, *cmd; | |
730 | struct usb_page_cache *pc; | |
731 | ||
732 | switch (USB_GET_STATE(xfer)) { | |
733 | case USB_ST_TRANSFERRED: | |
734 | cmd = usbd_xfer_get_priv(xfer); | |
735 | DPRINTF(sc, ZYD_DEBUG_CMD, "command %p transferred\n", cmd); | |
736 | STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) { | |
737 | /* Ensure the cached rq pointer is still valid */ | |
738 | if (rqp == cmd && | |
739 | (rqp->flags & ZYD_CMD_FLAG_READ) == 0) | |
740 | wakeup(rqp); /* wakeup caller */ | |
741 | } | |
742 | ||
743 | /* FALLTHROUGH */ | |
744 | case USB_ST_SETUP: | |
745 | tr_setup: | |
746 | STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) { | |
747 | if (rqp->flags & ZYD_CMD_FLAG_SENT) | |
748 | continue; | |
749 | ||
750 | pc = usbd_xfer_get_frame(xfer, 0); | |
751 | usbd_copy_in(pc, 0, rqp->cmd, rqp->ilen); | |
752 | ||
753 | usbd_xfer_set_frame_len(xfer, 0, rqp->ilen); | |
754 | usbd_xfer_set_priv(xfer, rqp); | |
755 | rqp->flags |= ZYD_CMD_FLAG_SENT; | |
756 | usbd_transfer_submit(xfer); | |
757 | break; | |
758 | } | |
759 | break; | |
760 | ||
761 | default: /* Error */ | |
762 | DPRINTF(sc, ZYD_DEBUG_ANY, "error = %s\n", | |
763 | usbd_errstr(error)); | |
764 | ||
765 | if (error != USB_ERR_CANCELLED) { | |
766 | /* try to clear stall first */ | |
767 | usbd_xfer_set_stall(xfer); | |
768 | goto tr_setup; | |
769 | } | |
770 | break; | |
771 | } | |
772 | } | |
773 | ||
774 | static int | |
775 | zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen, | |
776 | void *odata, int olen, int flags) | |
777 | { | |
778 | struct zyd_cmd cmd; | |
779 | struct zyd_rq rq; | |
780 | int error; | |
23abaded AHJ |
781 | #ifdef USB_DEBUG |
782 | char hexstr[HEX_NCPYLEN(64)]; | |
783 | #endif | |
12bd3c8b SW |
784 | |
785 | if (ilen > sizeof(cmd.data)) | |
786 | return (EINVAL); | |
787 | ||
788 | cmd.code = htole16(code); | |
789 | memcpy(cmd.data, idata, ilen); | |
23abaded AHJ |
790 | DPRINTF(sc, ZYD_DEBUG_CMD, "sending cmd %p = %s\n", &rq, |
791 | hexncpy(idata, ilen, hexstr, HEX_NCPYLEN(ilen), ":")); | |
12bd3c8b SW |
792 | |
793 | rq.cmd = &cmd; | |
794 | rq.idata = idata; | |
795 | rq.odata = odata; | |
796 | rq.ilen = sizeof(uint16_t) + ilen; | |
797 | rq.olen = olen; | |
798 | rq.flags = flags; | |
799 | STAILQ_INSERT_TAIL(&sc->sc_rqh, &rq, rq); | |
800 | usbd_transfer_start(sc->sc_xfer[ZYD_INTR_RD]); | |
801 | usbd_transfer_start(sc->sc_xfer[ZYD_INTR_WR]); | |
802 | ||
803 | /* wait at most one second for command reply */ | |
804 | error = mtx_sleep(&rq, &sc->sc_mtx, 0 , "zydcmd", hz); | |
805 | if (error) | |
806 | device_printf(sc->sc_dev, "command timeout\n"); | |
807 | STAILQ_REMOVE(&sc->sc_rqh, &rq, zyd_rq, rq); | |
808 | DPRINTF(sc, ZYD_DEBUG_CMD, "finsihed cmd %p, error = %d \n", | |
809 | &rq, error); | |
810 | ||
811 | return (error); | |
812 | } | |
813 | ||
814 | static int | |
815 | zyd_read16(struct zyd_softc *sc, uint16_t reg, uint16_t *val) | |
816 | { | |
817 | struct zyd_pair tmp; | |
818 | int error; | |
819 | ||
820 | reg = htole16(reg); | |
821 | error = zyd_cmd(sc, ZYD_CMD_IORD, ®, sizeof(reg), &tmp, sizeof(tmp), | |
822 | ZYD_CMD_FLAG_READ); | |
823 | if (error == 0) | |
824 | *val = le16toh(tmp.val); | |
825 | return (error); | |
826 | } | |
827 | ||
828 | static int | |
829 | zyd_read32(struct zyd_softc *sc, uint16_t reg, uint32_t *val) | |
830 | { | |
831 | struct zyd_pair tmp[2]; | |
832 | uint16_t regs[2]; | |
833 | int error; | |
834 | ||
835 | regs[0] = htole16(ZYD_REG32_HI(reg)); | |
836 | regs[1] = htole16(ZYD_REG32_LO(reg)); | |
837 | error = zyd_cmd(sc, ZYD_CMD_IORD, regs, sizeof(regs), tmp, sizeof(tmp), | |
838 | ZYD_CMD_FLAG_READ); | |
839 | if (error == 0) | |
840 | *val = le16toh(tmp[0].val) << 16 | le16toh(tmp[1].val); | |
841 | return (error); | |
842 | } | |
843 | ||
844 | static int | |
845 | zyd_write16(struct zyd_softc *sc, uint16_t reg, uint16_t val) | |
846 | { | |
847 | struct zyd_pair pair; | |
848 | ||
849 | pair.reg = htole16(reg); | |
850 | pair.val = htole16(val); | |
851 | ||
852 | return zyd_cmd(sc, ZYD_CMD_IOWR, &pair, sizeof(pair), NULL, 0, 0); | |
853 | } | |
854 | ||
855 | static int | |
856 | zyd_write32(struct zyd_softc *sc, uint16_t reg, uint32_t val) | |
857 | { | |
858 | struct zyd_pair pair[2]; | |
859 | ||
860 | pair[0].reg = htole16(ZYD_REG32_HI(reg)); | |
861 | pair[0].val = htole16(val >> 16); | |
862 | pair[1].reg = htole16(ZYD_REG32_LO(reg)); | |
863 | pair[1].val = htole16(val & 0xffff); | |
864 | ||
865 | return zyd_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0); | |
866 | } | |
867 | ||
868 | static int | |
869 | zyd_rfwrite(struct zyd_softc *sc, uint32_t val) | |
870 | { | |
871 | struct zyd_rf *rf = &sc->sc_rf; | |
872 | struct zyd_rfwrite_cmd req; | |
873 | uint16_t cr203; | |
874 | int error, i; | |
875 | ||
876 | zyd_read16_m(sc, ZYD_CR203, &cr203); | |
877 | cr203 &= ~(ZYD_RF_IF_LE | ZYD_RF_CLK | ZYD_RF_DATA); | |
878 | ||
879 | req.code = htole16(2); | |
880 | req.width = htole16(rf->width); | |
881 | for (i = 0; i < rf->width; i++) { | |
882 | req.bit[i] = htole16(cr203); | |
883 | if (val & (1 << (rf->width - 1 - i))) | |
884 | req.bit[i] |= htole16(ZYD_RF_DATA); | |
885 | } | |
886 | error = zyd_cmd(sc, ZYD_CMD_RFCFG, &req, 4 + 2 * rf->width, NULL, 0, 0); | |
887 | fail: | |
888 | return (error); | |
889 | } | |
890 | ||
891 | static int | |
892 | zyd_rfwrite_cr(struct zyd_softc *sc, uint32_t val) | |
893 | { | |
894 | int error; | |
895 | ||
896 | zyd_write16_m(sc, ZYD_CR244, (val >> 16) & 0xff); | |
897 | zyd_write16_m(sc, ZYD_CR243, (val >> 8) & 0xff); | |
898 | zyd_write16_m(sc, ZYD_CR242, (val >> 0) & 0xff); | |
899 | fail: | |
900 | return (error); | |
901 | } | |
902 | ||
903 | static int | |
904 | zyd_lock_phy(struct zyd_softc *sc) | |
905 | { | |
906 | int error; | |
907 | uint32_t tmp; | |
908 | ||
909 | zyd_read32_m(sc, ZYD_MAC_MISC, &tmp); | |
910 | tmp &= ~ZYD_UNLOCK_PHY_REGS; | |
911 | zyd_write32_m(sc, ZYD_MAC_MISC, tmp); | |
912 | fail: | |
913 | return (error); | |
914 | } | |
915 | ||
916 | static int | |
917 | zyd_unlock_phy(struct zyd_softc *sc) | |
918 | { | |
919 | int error; | |
920 | uint32_t tmp; | |
921 | ||
922 | zyd_read32_m(sc, ZYD_MAC_MISC, &tmp); | |
923 | tmp |= ZYD_UNLOCK_PHY_REGS; | |
924 | zyd_write32_m(sc, ZYD_MAC_MISC, tmp); | |
925 | fail: | |
926 | return (error); | |
927 | } | |
928 | ||
929 | /* | |
930 | * RFMD RF methods. | |
931 | */ | |
932 | static int | |
933 | zyd_rfmd_init(struct zyd_rf *rf) | |
934 | { | |
935 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
936 | struct zyd_softc *sc = rf->rf_sc; | |
937 | static const struct zyd_phy_pair phyini[] = ZYD_RFMD_PHY; | |
938 | static const uint32_t rfini[] = ZYD_RFMD_RF; | |
939 | int i, error; | |
940 | ||
941 | /* init RF-dependent PHY registers */ | |
942 | for (i = 0; i < N(phyini); i++) { | |
943 | zyd_write16_m(sc, phyini[i].reg, phyini[i].val); | |
944 | } | |
945 | ||
946 | /* init RFMD radio */ | |
947 | for (i = 0; i < N(rfini); i++) { | |
948 | if ((error = zyd_rfwrite(sc, rfini[i])) != 0) | |
949 | return (error); | |
950 | } | |
951 | fail: | |
952 | return (error); | |
953 | #undef N | |
954 | } | |
955 | ||
956 | static int | |
957 | zyd_rfmd_switch_radio(struct zyd_rf *rf, int on) | |
958 | { | |
959 | int error; | |
960 | struct zyd_softc *sc = rf->rf_sc; | |
961 | ||
962 | zyd_write16_m(sc, ZYD_CR10, on ? 0x89 : 0x15); | |
963 | zyd_write16_m(sc, ZYD_CR11, on ? 0x00 : 0x81); | |
964 | fail: | |
965 | return (error); | |
966 | } | |
967 | ||
968 | static int | |
969 | zyd_rfmd_set_channel(struct zyd_rf *rf, uint8_t chan) | |
970 | { | |
971 | int error; | |
972 | struct zyd_softc *sc = rf->rf_sc; | |
973 | static const struct { | |
974 | uint32_t r1, r2; | |
975 | } rfprog[] = ZYD_RFMD_CHANTABLE; | |
976 | ||
977 | error = zyd_rfwrite(sc, rfprog[chan - 1].r1); | |
978 | if (error != 0) | |
979 | goto fail; | |
980 | error = zyd_rfwrite(sc, rfprog[chan - 1].r2); | |
981 | if (error != 0) | |
982 | goto fail; | |
983 | ||
984 | fail: | |
985 | return (error); | |
986 | } | |
987 | ||
988 | /* | |
989 | * AL2230 RF methods. | |
990 | */ | |
991 | static int | |
992 | zyd_al2230_init(struct zyd_rf *rf) | |
993 | { | |
994 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
995 | struct zyd_softc *sc = rf->rf_sc; | |
996 | static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY; | |
997 | static const struct zyd_phy_pair phy2230s[] = ZYD_AL2230S_PHY_INIT; | |
998 | static const struct zyd_phy_pair phypll[] = { | |
999 | { ZYD_CR251, 0x2f }, { ZYD_CR251, 0x3f }, | |
1000 | { ZYD_CR138, 0x28 }, { ZYD_CR203, 0x06 } | |
1001 | }; | |
1002 | static const uint32_t rfini1[] = ZYD_AL2230_RF_PART1; | |
1003 | static const uint32_t rfini2[] = ZYD_AL2230_RF_PART2; | |
1004 | static const uint32_t rfini3[] = ZYD_AL2230_RF_PART3; | |
1005 | int i, error; | |
1006 | ||
1007 | /* init RF-dependent PHY registers */ | |
1008 | for (i = 0; i < N(phyini); i++) | |
1009 | zyd_write16_m(sc, phyini[i].reg, phyini[i].val); | |
1010 | ||
1011 | if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) { | |
1012 | for (i = 0; i < N(phy2230s); i++) | |
1013 | zyd_write16_m(sc, phy2230s[i].reg, phy2230s[i].val); | |
1014 | } | |
1015 | ||
1016 | /* init AL2230 radio */ | |
1017 | for (i = 0; i < N(rfini1); i++) { | |
1018 | error = zyd_rfwrite(sc, rfini1[i]); | |
1019 | if (error != 0) | |
1020 | goto fail; | |
1021 | } | |
1022 | ||
1023 | if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) | |
1024 | error = zyd_rfwrite(sc, 0x000824); | |
1025 | else | |
1026 | error = zyd_rfwrite(sc, 0x0005a4); | |
1027 | if (error != 0) | |
1028 | goto fail; | |
1029 | ||
1030 | for (i = 0; i < N(rfini2); i++) { | |
1031 | error = zyd_rfwrite(sc, rfini2[i]); | |
1032 | if (error != 0) | |
1033 | goto fail; | |
1034 | } | |
1035 | ||
1036 | for (i = 0; i < N(phypll); i++) | |
1037 | zyd_write16_m(sc, phypll[i].reg, phypll[i].val); | |
1038 | ||
1039 | for (i = 0; i < N(rfini3); i++) { | |
1040 | error = zyd_rfwrite(sc, rfini3[i]); | |
1041 | if (error != 0) | |
1042 | goto fail; | |
1043 | } | |
1044 | fail: | |
1045 | return (error); | |
1046 | #undef N | |
1047 | } | |
1048 | ||
1049 | static int | |
1050 | zyd_al2230_fini(struct zyd_rf *rf) | |
1051 | { | |
1052 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1053 | int error, i; | |
1054 | struct zyd_softc *sc = rf->rf_sc; | |
1055 | static const struct zyd_phy_pair phy[] = ZYD_AL2230_PHY_FINI_PART1; | |
1056 | ||
1057 | for (i = 0; i < N(phy); i++) | |
1058 | zyd_write16_m(sc, phy[i].reg, phy[i].val); | |
1059 | ||
1060 | if (sc->sc_newphy != 0) | |
1061 | zyd_write16_m(sc, ZYD_CR9, 0xe1); | |
1062 | ||
1063 | zyd_write16_m(sc, ZYD_CR203, 0x6); | |
1064 | fail: | |
1065 | return (error); | |
1066 | #undef N | |
1067 | } | |
1068 | ||
1069 | static int | |
1070 | zyd_al2230_init_b(struct zyd_rf *rf) | |
1071 | { | |
1072 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1073 | struct zyd_softc *sc = rf->rf_sc; | |
1074 | static const struct zyd_phy_pair phy1[] = ZYD_AL2230_PHY_PART1; | |
1075 | static const struct zyd_phy_pair phy2[] = ZYD_AL2230_PHY_PART2; | |
1076 | static const struct zyd_phy_pair phy3[] = ZYD_AL2230_PHY_PART3; | |
1077 | static const struct zyd_phy_pair phy2230s[] = ZYD_AL2230S_PHY_INIT; | |
1078 | static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY_B; | |
1079 | static const uint32_t rfini_part1[] = ZYD_AL2230_RF_B_PART1; | |
1080 | static const uint32_t rfini_part2[] = ZYD_AL2230_RF_B_PART2; | |
1081 | static const uint32_t rfini_part3[] = ZYD_AL2230_RF_B_PART3; | |
1082 | static const uint32_t zyd_al2230_chtable[][3] = ZYD_AL2230_CHANTABLE; | |
1083 | int i, error; | |
1084 | ||
1085 | for (i = 0; i < N(phy1); i++) | |
1086 | zyd_write16_m(sc, phy1[i].reg, phy1[i].val); | |
1087 | ||
1088 | /* init RF-dependent PHY registers */ | |
1089 | for (i = 0; i < N(phyini); i++) | |
1090 | zyd_write16_m(sc, phyini[i].reg, phyini[i].val); | |
1091 | ||
1092 | if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) { | |
1093 | for (i = 0; i < N(phy2230s); i++) | |
1094 | zyd_write16_m(sc, phy2230s[i].reg, phy2230s[i].val); | |
1095 | } | |
1096 | ||
1097 | for (i = 0; i < 3; i++) { | |
1098 | error = zyd_rfwrite_cr(sc, zyd_al2230_chtable[0][i]); | |
1099 | if (error != 0) | |
1100 | return (error); | |
1101 | } | |
1102 | ||
1103 | for (i = 0; i < N(rfini_part1); i++) { | |
1104 | error = zyd_rfwrite_cr(sc, rfini_part1[i]); | |
1105 | if (error != 0) | |
1106 | return (error); | |
1107 | } | |
1108 | ||
1109 | if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) | |
1110 | error = zyd_rfwrite(sc, 0x241000); | |
1111 | else | |
1112 | error = zyd_rfwrite(sc, 0x25a000); | |
1113 | if (error != 0) | |
1114 | goto fail; | |
1115 | ||
1116 | for (i = 0; i < N(rfini_part2); i++) { | |
1117 | error = zyd_rfwrite_cr(sc, rfini_part2[i]); | |
1118 | if (error != 0) | |
1119 | return (error); | |
1120 | } | |
1121 | ||
1122 | for (i = 0; i < N(phy2); i++) | |
1123 | zyd_write16_m(sc, phy2[i].reg, phy2[i].val); | |
1124 | ||
1125 | for (i = 0; i < N(rfini_part3); i++) { | |
1126 | error = zyd_rfwrite_cr(sc, rfini_part3[i]); | |
1127 | if (error != 0) | |
1128 | return (error); | |
1129 | } | |
1130 | ||
1131 | for (i = 0; i < N(phy3); i++) | |
1132 | zyd_write16_m(sc, phy3[i].reg, phy3[i].val); | |
1133 | ||
1134 | error = zyd_al2230_fini(rf); | |
1135 | fail: | |
1136 | return (error); | |
1137 | #undef N | |
1138 | } | |
1139 | ||
1140 | static int | |
1141 | zyd_al2230_switch_radio(struct zyd_rf *rf, int on) | |
1142 | { | |
1143 | struct zyd_softc *sc = rf->rf_sc; | |
1144 | int error, on251 = (sc->sc_macrev == ZYD_ZD1211) ? 0x3f : 0x7f; | |
1145 | ||
1146 | zyd_write16_m(sc, ZYD_CR11, on ? 0x00 : 0x04); | |
1147 | zyd_write16_m(sc, ZYD_CR251, on ? on251 : 0x2f); | |
1148 | fail: | |
1149 | return (error); | |
1150 | } | |
1151 | ||
1152 | static int | |
1153 | zyd_al2230_set_channel(struct zyd_rf *rf, uint8_t chan) | |
1154 | { | |
1155 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1156 | int error, i; | |
1157 | struct zyd_softc *sc = rf->rf_sc; | |
1158 | static const struct zyd_phy_pair phy1[] = { | |
1159 | { ZYD_CR138, 0x28 }, { ZYD_CR203, 0x06 }, | |
1160 | }; | |
1161 | static const struct { | |
1162 | uint32_t r1, r2, r3; | |
1163 | } rfprog[] = ZYD_AL2230_CHANTABLE; | |
1164 | ||
1165 | error = zyd_rfwrite(sc, rfprog[chan - 1].r1); | |
1166 | if (error != 0) | |
1167 | goto fail; | |
1168 | error = zyd_rfwrite(sc, rfprog[chan - 1].r2); | |
1169 | if (error != 0) | |
1170 | goto fail; | |
1171 | error = zyd_rfwrite(sc, rfprog[chan - 1].r3); | |
1172 | if (error != 0) | |
1173 | goto fail; | |
1174 | ||
1175 | for (i = 0; i < N(phy1); i++) | |
1176 | zyd_write16_m(sc, phy1[i].reg, phy1[i].val); | |
1177 | fail: | |
1178 | return (error); | |
1179 | #undef N | |
1180 | } | |
1181 | ||
1182 | static int | |
1183 | zyd_al2230_set_channel_b(struct zyd_rf *rf, uint8_t chan) | |
1184 | { | |
1185 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1186 | int error, i; | |
1187 | struct zyd_softc *sc = rf->rf_sc; | |
1188 | static const struct zyd_phy_pair phy1[] = ZYD_AL2230_PHY_PART1; | |
1189 | static const struct { | |
1190 | uint32_t r1, r2, r3; | |
1191 | } rfprog[] = ZYD_AL2230_CHANTABLE_B; | |
1192 | ||
1193 | for (i = 0; i < N(phy1); i++) | |
1194 | zyd_write16_m(sc, phy1[i].reg, phy1[i].val); | |
1195 | ||
1196 | error = zyd_rfwrite_cr(sc, rfprog[chan - 1].r1); | |
1197 | if (error != 0) | |
1198 | goto fail; | |
1199 | error = zyd_rfwrite_cr(sc, rfprog[chan - 1].r2); | |
1200 | if (error != 0) | |
1201 | goto fail; | |
1202 | error = zyd_rfwrite_cr(sc, rfprog[chan - 1].r3); | |
1203 | if (error != 0) | |
1204 | goto fail; | |
1205 | error = zyd_al2230_fini(rf); | |
1206 | fail: | |
1207 | return (error); | |
1208 | #undef N | |
1209 | } | |
1210 | ||
1211 | #define ZYD_AL2230_PHY_BANDEDGE6 \ | |
1212 | { \ | |
1213 | { ZYD_CR128, 0x14 }, { ZYD_CR129, 0x12 }, { ZYD_CR130, 0x10 }, \ | |
1214 | { ZYD_CR47, 0x1e } \ | |
1215 | } | |
1216 | ||
1217 | static int | |
1218 | zyd_al2230_bandedge6(struct zyd_rf *rf, struct ieee80211_channel *c) | |
1219 | { | |
1220 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1221 | int error = 0, i; | |
1222 | struct zyd_softc *sc = rf->rf_sc; | |
1223 | struct ifnet *ifp = sc->sc_ifp; | |
1224 | struct ieee80211com *ic = ifp->if_l2com; | |
1225 | struct zyd_phy_pair r[] = ZYD_AL2230_PHY_BANDEDGE6; | |
1226 | int chan = ieee80211_chan2ieee(ic, c); | |
1227 | ||
1228 | if (chan == 1 || chan == 11) | |
1229 | r[0].val = 0x12; | |
1230 | ||
1231 | for (i = 0; i < N(r); i++) | |
1232 | zyd_write16_m(sc, r[i].reg, r[i].val); | |
1233 | fail: | |
1234 | return (error); | |
1235 | #undef N | |
1236 | } | |
1237 | ||
1238 | /* | |
1239 | * AL7230B RF methods. | |
1240 | */ | |
1241 | static int | |
1242 | zyd_al7230B_init(struct zyd_rf *rf) | |
1243 | { | |
1244 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1245 | struct zyd_softc *sc = rf->rf_sc; | |
1246 | static const struct zyd_phy_pair phyini_1[] = ZYD_AL7230B_PHY_1; | |
1247 | static const struct zyd_phy_pair phyini_2[] = ZYD_AL7230B_PHY_2; | |
1248 | static const struct zyd_phy_pair phyini_3[] = ZYD_AL7230B_PHY_3; | |
1249 | static const uint32_t rfini_1[] = ZYD_AL7230B_RF_1; | |
1250 | static const uint32_t rfini_2[] = ZYD_AL7230B_RF_2; | |
1251 | int i, error; | |
1252 | ||
1253 | /* for AL7230B, PHY and RF need to be initialized in "phases" */ | |
1254 | ||
1255 | /* init RF-dependent PHY registers, part one */ | |
1256 | for (i = 0; i < N(phyini_1); i++) | |
1257 | zyd_write16_m(sc, phyini_1[i].reg, phyini_1[i].val); | |
1258 | ||
1259 | /* init AL7230B radio, part one */ | |
1260 | for (i = 0; i < N(rfini_1); i++) { | |
1261 | if ((error = zyd_rfwrite(sc, rfini_1[i])) != 0) | |
1262 | return (error); | |
1263 | } | |
1264 | /* init RF-dependent PHY registers, part two */ | |
1265 | for (i = 0; i < N(phyini_2); i++) | |
1266 | zyd_write16_m(sc, phyini_2[i].reg, phyini_2[i].val); | |
1267 | ||
1268 | /* init AL7230B radio, part two */ | |
1269 | for (i = 0; i < N(rfini_2); i++) { | |
1270 | if ((error = zyd_rfwrite(sc, rfini_2[i])) != 0) | |
1271 | return (error); | |
1272 | } | |
1273 | /* init RF-dependent PHY registers, part three */ | |
1274 | for (i = 0; i < N(phyini_3); i++) | |
1275 | zyd_write16_m(sc, phyini_3[i].reg, phyini_3[i].val); | |
1276 | fail: | |
1277 | return (error); | |
1278 | #undef N | |
1279 | } | |
1280 | ||
1281 | static int | |
1282 | zyd_al7230B_switch_radio(struct zyd_rf *rf, int on) | |
1283 | { | |
1284 | int error; | |
1285 | struct zyd_softc *sc = rf->rf_sc; | |
1286 | ||
1287 | zyd_write16_m(sc, ZYD_CR11, on ? 0x00 : 0x04); | |
1288 | zyd_write16_m(sc, ZYD_CR251, on ? 0x3f : 0x2f); | |
1289 | fail: | |
1290 | return (error); | |
1291 | } | |
1292 | ||
1293 | static int | |
1294 | zyd_al7230B_set_channel(struct zyd_rf *rf, uint8_t chan) | |
1295 | { | |
1296 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1297 | struct zyd_softc *sc = rf->rf_sc; | |
1298 | static const struct { | |
1299 | uint32_t r1, r2; | |
1300 | } rfprog[] = ZYD_AL7230B_CHANTABLE; | |
1301 | static const uint32_t rfsc[] = ZYD_AL7230B_RF_SETCHANNEL; | |
1302 | int i, error; | |
1303 | ||
1304 | zyd_write16_m(sc, ZYD_CR240, 0x57); | |
1305 | zyd_write16_m(sc, ZYD_CR251, 0x2f); | |
1306 | ||
1307 | for (i = 0; i < N(rfsc); i++) { | |
1308 | if ((error = zyd_rfwrite(sc, rfsc[i])) != 0) | |
1309 | return (error); | |
1310 | } | |
1311 | ||
1312 | zyd_write16_m(sc, ZYD_CR128, 0x14); | |
1313 | zyd_write16_m(sc, ZYD_CR129, 0x12); | |
1314 | zyd_write16_m(sc, ZYD_CR130, 0x10); | |
1315 | zyd_write16_m(sc, ZYD_CR38, 0x38); | |
1316 | zyd_write16_m(sc, ZYD_CR136, 0xdf); | |
1317 | ||
1318 | error = zyd_rfwrite(sc, rfprog[chan - 1].r1); | |
1319 | if (error != 0) | |
1320 | goto fail; | |
1321 | error = zyd_rfwrite(sc, rfprog[chan - 1].r2); | |
1322 | if (error != 0) | |
1323 | goto fail; | |
1324 | error = zyd_rfwrite(sc, 0x3c9000); | |
1325 | if (error != 0) | |
1326 | goto fail; | |
1327 | ||
1328 | zyd_write16_m(sc, ZYD_CR251, 0x3f); | |
1329 | zyd_write16_m(sc, ZYD_CR203, 0x06); | |
1330 | zyd_write16_m(sc, ZYD_CR240, 0x08); | |
1331 | fail: | |
1332 | return (error); | |
1333 | #undef N | |
1334 | } | |
1335 | ||
1336 | /* | |
1337 | * AL2210 RF methods. | |
1338 | */ | |
1339 | static int | |
1340 | zyd_al2210_init(struct zyd_rf *rf) | |
1341 | { | |
1342 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1343 | struct zyd_softc *sc = rf->rf_sc; | |
1344 | static const struct zyd_phy_pair phyini[] = ZYD_AL2210_PHY; | |
1345 | static const uint32_t rfini[] = ZYD_AL2210_RF; | |
1346 | uint32_t tmp; | |
1347 | int i, error; | |
1348 | ||
1349 | zyd_write32_m(sc, ZYD_CR18, 2); | |
1350 | ||
1351 | /* init RF-dependent PHY registers */ | |
1352 | for (i = 0; i < N(phyini); i++) | |
1353 | zyd_write16_m(sc, phyini[i].reg, phyini[i].val); | |
1354 | ||
1355 | /* init AL2210 radio */ | |
1356 | for (i = 0; i < N(rfini); i++) { | |
1357 | if ((error = zyd_rfwrite(sc, rfini[i])) != 0) | |
1358 | return (error); | |
1359 | } | |
1360 | zyd_write16_m(sc, ZYD_CR47, 0x1e); | |
1361 | zyd_read32_m(sc, ZYD_CR_RADIO_PD, &tmp); | |
1362 | zyd_write32_m(sc, ZYD_CR_RADIO_PD, tmp & ~1); | |
1363 | zyd_write32_m(sc, ZYD_CR_RADIO_PD, tmp | 1); | |
1364 | zyd_write32_m(sc, ZYD_CR_RFCFG, 0x05); | |
1365 | zyd_write32_m(sc, ZYD_CR_RFCFG, 0x00); | |
1366 | zyd_write16_m(sc, ZYD_CR47, 0x1e); | |
1367 | zyd_write32_m(sc, ZYD_CR18, 3); | |
1368 | fail: | |
1369 | return (error); | |
1370 | #undef N | |
1371 | } | |
1372 | ||
1373 | static int | |
1374 | zyd_al2210_switch_radio(struct zyd_rf *rf, int on) | |
1375 | { | |
1376 | /* vendor driver does nothing for this RF chip */ | |
1377 | ||
1378 | return (0); | |
1379 | } | |
1380 | ||
1381 | static int | |
1382 | zyd_al2210_set_channel(struct zyd_rf *rf, uint8_t chan) | |
1383 | { | |
1384 | int error; | |
1385 | struct zyd_softc *sc = rf->rf_sc; | |
1386 | static const uint32_t rfprog[] = ZYD_AL2210_CHANTABLE; | |
1387 | uint32_t tmp; | |
1388 | ||
1389 | zyd_write32_m(sc, ZYD_CR18, 2); | |
1390 | zyd_write16_m(sc, ZYD_CR47, 0x1e); | |
1391 | zyd_read32_m(sc, ZYD_CR_RADIO_PD, &tmp); | |
1392 | zyd_write32_m(sc, ZYD_CR_RADIO_PD, tmp & ~1); | |
1393 | zyd_write32_m(sc, ZYD_CR_RADIO_PD, tmp | 1); | |
1394 | zyd_write32_m(sc, ZYD_CR_RFCFG, 0x05); | |
1395 | zyd_write32_m(sc, ZYD_CR_RFCFG, 0x00); | |
1396 | zyd_write16_m(sc, ZYD_CR47, 0x1e); | |
1397 | ||
1398 | /* actually set the channel */ | |
1399 | error = zyd_rfwrite(sc, rfprog[chan - 1]); | |
1400 | if (error != 0) | |
1401 | goto fail; | |
1402 | ||
1403 | zyd_write32_m(sc, ZYD_CR18, 3); | |
1404 | fail: | |
1405 | return (error); | |
1406 | } | |
1407 | ||
1408 | /* | |
1409 | * GCT RF methods. | |
1410 | */ | |
1411 | static int | |
1412 | zyd_gct_init(struct zyd_rf *rf) | |
1413 | { | |
1414 | #define ZYD_GCT_INTR_REG 0x85c1 | |
1415 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1416 | struct zyd_softc *sc = rf->rf_sc; | |
1417 | static const struct zyd_phy_pair phyini[] = ZYD_GCT_PHY; | |
1418 | static const uint32_t rfini[] = ZYD_GCT_RF; | |
1419 | static const uint16_t vco[11][7] = ZYD_GCT_VCO; | |
1420 | int i, idx = -1, error; | |
1421 | uint16_t data; | |
1422 | ||
1423 | /* init RF-dependent PHY registers */ | |
1424 | for (i = 0; i < N(phyini); i++) | |
1425 | zyd_write16_m(sc, phyini[i].reg, phyini[i].val); | |
1426 | ||
1427 | /* init cgt radio */ | |
1428 | for (i = 0; i < N(rfini); i++) { | |
1429 | if ((error = zyd_rfwrite(sc, rfini[i])) != 0) | |
1430 | return (error); | |
1431 | } | |
1432 | ||
1433 | error = zyd_gct_mode(rf); | |
1434 | if (error != 0) | |
1435 | return (error); | |
1436 | ||
1437 | for (i = 0; i < N(vco) - 1; i++) { | |
1438 | error = zyd_gct_set_channel_synth(rf, 1, 0); | |
1439 | if (error != 0) | |
1440 | goto fail; | |
1441 | error = zyd_gct_write(rf, vco[i][0]); | |
1442 | if (error != 0) | |
1443 | goto fail; | |
1444 | zyd_write16_m(sc, ZYD_GCT_INTR_REG, 0xf); | |
1445 | zyd_read16_m(sc, ZYD_GCT_INTR_REG, &data); | |
1446 | if ((data & 0xf) == 0) { | |
1447 | idx = i; | |
1448 | break; | |
1449 | } | |
1450 | } | |
1451 | if (idx == -1) { | |
1452 | error = zyd_gct_set_channel_synth(rf, 1, 1); | |
1453 | if (error != 0) | |
1454 | goto fail; | |
1455 | error = zyd_gct_write(rf, 0x6662); | |
1456 | if (error != 0) | |
1457 | goto fail; | |
1458 | } | |
1459 | ||
1460 | rf->idx = idx; | |
1461 | zyd_write16_m(sc, ZYD_CR203, 0x6); | |
1462 | fail: | |
1463 | return (error); | |
1464 | #undef N | |
1465 | #undef ZYD_GCT_INTR_REG | |
1466 | } | |
1467 | ||
1468 | static int | |
1469 | zyd_gct_mode(struct zyd_rf *rf) | |
1470 | { | |
1471 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1472 | struct zyd_softc *sc = rf->rf_sc; | |
1473 | static const uint32_t mode[] = { | |
1474 | 0x25f98, 0x25f9a, 0x25f94, 0x27fd4 | |
1475 | }; | |
1476 | int i, error; | |
1477 | ||
1478 | for (i = 0; i < N(mode); i++) { | |
1479 | if ((error = zyd_rfwrite(sc, mode[i])) != 0) | |
1480 | break; | |
1481 | } | |
1482 | return (error); | |
1483 | #undef N | |
1484 | } | |
1485 | ||
1486 | static int | |
1487 | zyd_gct_set_channel_synth(struct zyd_rf *rf, int chan, int acal) | |
1488 | { | |
1489 | int error, idx = chan - 1; | |
1490 | struct zyd_softc *sc = rf->rf_sc; | |
1491 | static uint32_t acal_synth[] = ZYD_GCT_CHANNEL_ACAL; | |
1492 | static uint32_t std_synth[] = ZYD_GCT_CHANNEL_STD; | |
1493 | static uint32_t div_synth[] = ZYD_GCT_CHANNEL_DIV; | |
1494 | ||
1495 | error = zyd_rfwrite(sc, | |
1496 | (acal == 1) ? acal_synth[idx] : std_synth[idx]); | |
1497 | if (error != 0) | |
1498 | return (error); | |
1499 | return zyd_rfwrite(sc, div_synth[idx]); | |
1500 | } | |
1501 | ||
1502 | static int | |
1503 | zyd_gct_write(struct zyd_rf *rf, uint16_t value) | |
1504 | { | |
1505 | struct zyd_softc *sc = rf->rf_sc; | |
1506 | ||
1507 | return zyd_rfwrite(sc, 0x300000 | 0x40000 | value); | |
1508 | } | |
1509 | ||
1510 | static int | |
1511 | zyd_gct_switch_radio(struct zyd_rf *rf, int on) | |
1512 | { | |
1513 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1514 | int error; | |
1515 | struct zyd_softc *sc = rf->rf_sc; | |
1516 | ||
1517 | error = zyd_rfwrite(sc, on ? 0x25f94 : 0x25f90); | |
1518 | if (error != 0) | |
1519 | return (error); | |
1520 | ||
1521 | zyd_write16_m(sc, ZYD_CR11, on ? 0x00 : 0x04); | |
1522 | zyd_write16_m(sc, ZYD_CR251, | |
1523 | on ? ((sc->sc_macrev == ZYD_ZD1211B) ? 0x7f : 0x3f) : 0x2f); | |
1524 | fail: | |
1525 | return (error); | |
1526 | } | |
1527 | ||
1528 | static int | |
1529 | zyd_gct_set_channel(struct zyd_rf *rf, uint8_t chan) | |
1530 | { | |
1531 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1532 | int error, i; | |
1533 | struct zyd_softc *sc = rf->rf_sc; | |
1534 | static const struct zyd_phy_pair cmd[] = { | |
1535 | { ZYD_CR80, 0x30 }, { ZYD_CR81, 0x30 }, { ZYD_CR79, 0x58 }, | |
1536 | { ZYD_CR12, 0xf0 }, { ZYD_CR77, 0x1b }, { ZYD_CR78, 0x58 }, | |
1537 | }; | |
1538 | static const uint16_t vco[11][7] = ZYD_GCT_VCO; | |
1539 | ||
1540 | error = zyd_gct_set_channel_synth(rf, chan, 0); | |
1541 | if (error != 0) | |
1542 | goto fail; | |
1543 | error = zyd_gct_write(rf, (rf->idx == -1) ? 0x6662 : | |
1544 | vco[rf->idx][((chan - 1) / 2)]); | |
1545 | if (error != 0) | |
1546 | goto fail; | |
1547 | error = zyd_gct_mode(rf); | |
1548 | if (error != 0) | |
1549 | return (error); | |
1550 | for (i = 0; i < N(cmd); i++) | |
1551 | zyd_write16_m(sc, cmd[i].reg, cmd[i].val); | |
1552 | error = zyd_gct_txgain(rf, chan); | |
1553 | if (error != 0) | |
1554 | return (error); | |
1555 | zyd_write16_m(sc, ZYD_CR203, 0x6); | |
1556 | fail: | |
1557 | return (error); | |
1558 | #undef N | |
1559 | } | |
1560 | ||
1561 | static int | |
1562 | zyd_gct_txgain(struct zyd_rf *rf, uint8_t chan) | |
1563 | { | |
1564 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1565 | struct zyd_softc *sc = rf->rf_sc; | |
1566 | static uint32_t txgain[] = ZYD_GCT_TXGAIN; | |
1567 | uint8_t idx = sc->sc_pwrint[chan - 1]; | |
1568 | ||
1569 | if (idx >= N(txgain)) { | |
1570 | device_printf(sc->sc_dev, "could not set TX gain (%d %#x)\n", | |
1571 | chan, idx); | |
1572 | return 0; | |
1573 | } | |
1574 | ||
1575 | return zyd_rfwrite(sc, 0x700000 | txgain[idx]); | |
1576 | #undef N | |
1577 | } | |
1578 | ||
1579 | /* | |
1580 | * Maxim2 RF methods. | |
1581 | */ | |
1582 | static int | |
1583 | zyd_maxim2_init(struct zyd_rf *rf) | |
1584 | { | |
1585 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1586 | struct zyd_softc *sc = rf->rf_sc; | |
1587 | static const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY; | |
1588 | static const uint32_t rfini[] = ZYD_MAXIM2_RF; | |
1589 | uint16_t tmp; | |
1590 | int i, error; | |
1591 | ||
1592 | /* init RF-dependent PHY registers */ | |
1593 | for (i = 0; i < N(phyini); i++) | |
1594 | zyd_write16_m(sc, phyini[i].reg, phyini[i].val); | |
1595 | ||
1596 | zyd_read16_m(sc, ZYD_CR203, &tmp); | |
1597 | zyd_write16_m(sc, ZYD_CR203, tmp & ~(1 << 4)); | |
1598 | ||
1599 | /* init maxim2 radio */ | |
1600 | for (i = 0; i < N(rfini); i++) { | |
1601 | if ((error = zyd_rfwrite(sc, rfini[i])) != 0) | |
1602 | return (error); | |
1603 | } | |
1604 | zyd_read16_m(sc, ZYD_CR203, &tmp); | |
1605 | zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); | |
1606 | fail: | |
1607 | return (error); | |
1608 | #undef N | |
1609 | } | |
1610 | ||
1611 | static int | |
1612 | zyd_maxim2_switch_radio(struct zyd_rf *rf, int on) | |
1613 | { | |
1614 | ||
1615 | /* vendor driver does nothing for this RF chip */ | |
1616 | return (0); | |
1617 | } | |
1618 | ||
1619 | static int | |
1620 | zyd_maxim2_set_channel(struct zyd_rf *rf, uint8_t chan) | |
1621 | { | |
1622 | #define N(a) (sizeof(a) / sizeof((a)[0])) | |
1623 | struct zyd_softc *sc = rf->rf_sc; | |
1624 | static const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY; | |
1625 | static const uint32_t rfini[] = ZYD_MAXIM2_RF; | |
1626 | static const struct { | |
1627 | uint32_t r1, r2; | |
1628 | } rfprog[] = ZYD_MAXIM2_CHANTABLE; | |
1629 | uint16_t tmp; | |
1630 | int i, error; | |
1631 | ||
1632 | /* | |
1633 | * Do the same as we do when initializing it, except for the channel | |
1634 | * values coming from the two channel tables. | |
1635 | */ | |
1636 | ||
1637 | /* init RF-dependent PHY registers */ | |
1638 | for (i = 0; i < N(phyini); i++) | |
1639 | zyd_write16_m(sc, phyini[i].reg, phyini[i].val); | |
1640 | ||
1641 | zyd_read16_m(sc, ZYD_CR203, &tmp); | |
1642 | zyd_write16_m(sc, ZYD_CR203, tmp & ~(1 << 4)); | |
1643 | ||
1644 | /* first two values taken from the chantables */ | |
1645 | error = zyd_rfwrite(sc, rfprog[chan - 1].r1); | |
1646 | if (error != 0) | |
1647 | goto fail; | |
1648 | error = zyd_rfwrite(sc, rfprog[chan - 1].r2); | |
1649 | if (error != 0) | |
1650 | goto fail; | |
1651 | ||
1652 | /* init maxim2 radio - skipping the two first values */ | |
1653 | for (i = 2; i < N(rfini); i++) { | |
1654 | if ((error = zyd_rfwrite(sc, rfini[i])) != 0) | |
1655 | return (error); | |
1656 | } | |
1657 | zyd_read16_m(sc, ZYD_CR203, &tmp); | |
1658 | zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); | |
1659 | fail: | |
1660 | return (error); | |
1661 | #undef N | |
1662 | } | |
1663 | ||
1664 | static int | |
1665 | zyd_rf_attach(struct zyd_softc *sc, uint8_t type) | |
1666 | { | |
1667 | struct zyd_rf *rf = &sc->sc_rf; | |
1668 | ||
1669 | rf->rf_sc = sc; | |
1670 | rf->update_pwr = 1; | |
1671 | ||
1672 | switch (type) { | |
1673 | case ZYD_RF_RFMD: | |
1674 | rf->init = zyd_rfmd_init; | |
1675 | rf->switch_radio = zyd_rfmd_switch_radio; | |
1676 | rf->set_channel = zyd_rfmd_set_channel; | |
1677 | rf->width = 24; /* 24-bit RF values */ | |
1678 | break; | |
1679 | case ZYD_RF_AL2230: | |
1680 | case ZYD_RF_AL2230S: | |
1681 | if (sc->sc_macrev == ZYD_ZD1211B) { | |
1682 | rf->init = zyd_al2230_init_b; | |
1683 | rf->set_channel = zyd_al2230_set_channel_b; | |
1684 | } else { | |
1685 | rf->init = zyd_al2230_init; | |
1686 | rf->set_channel = zyd_al2230_set_channel; | |
1687 | } | |
1688 | rf->switch_radio = zyd_al2230_switch_radio; | |
1689 | rf->bandedge6 = zyd_al2230_bandedge6; | |
1690 | rf->width = 24; /* 24-bit RF values */ | |
1691 | break; | |
1692 | case ZYD_RF_AL7230B: | |
1693 | rf->init = zyd_al7230B_init; | |
1694 | rf->switch_radio = zyd_al7230B_switch_radio; | |
1695 | rf->set_channel = zyd_al7230B_set_channel; | |
1696 | rf->width = 24; /* 24-bit RF values */ | |
1697 | break; | |
1698 | case ZYD_RF_AL2210: | |
1699 | rf->init = zyd_al2210_init; | |
1700 | rf->switch_radio = zyd_al2210_switch_radio; | |
1701 | rf->set_channel = zyd_al2210_set_channel; | |
1702 | rf->width = 24; /* 24-bit RF values */ | |
1703 | break; | |
1704 | case ZYD_RF_MAXIM_NEW: | |
1705 | case ZYD_RF_GCT: | |
1706 | rf->init = zyd_gct_init; | |
1707 | rf->switch_radio = zyd_gct_switch_radio; | |
1708 | rf->set_channel = zyd_gct_set_channel; | |
1709 | rf->width = 24; /* 24-bit RF values */ | |
1710 | rf->update_pwr = 0; | |
1711 | break; | |
1712 | case ZYD_RF_MAXIM_NEW2: | |
1713 | rf->init = zyd_maxim2_init; | |
1714 | rf->switch_radio = zyd_maxim2_switch_radio; | |
1715 | rf->set_channel = zyd_maxim2_set_channel; | |
1716 | rf->width = 18; /* 18-bit RF values */ | |
1717 | break; | |
1718 | default: | |
1719 | device_printf(sc->sc_dev, | |
1720 | "sorry, radio \"%s\" is not supported yet\n", | |
1721 | zyd_rf_name(type)); | |
1722 | return (EINVAL); | |
1723 | } | |
1724 | return (0); | |
1725 | } | |
1726 | ||
1727 | static const char * | |
1728 | zyd_rf_name(uint8_t type) | |
1729 | { | |
1730 | static const char * const zyd_rfs[] = { | |
1731 | "unknown", "unknown", "UW2451", "UCHIP", "AL2230", | |
1732 | "AL7230B", "THETA", "AL2210", "MAXIM_NEW", "GCT", | |
1733 | "AL2230S", "RALINK", "INTERSIL", "RFMD", "MAXIM_NEW2", | |
1734 | "PHILIPS" | |
1735 | }; | |
1736 | ||
1737 | return zyd_rfs[(type > 15) ? 0 : type]; | |
1738 | } | |
1739 | ||
1740 | static int | |
1741 | zyd_hw_init(struct zyd_softc *sc) | |
1742 | { | |
1743 | int error; | |
1744 | const struct zyd_phy_pair *phyp; | |
1745 | struct zyd_rf *rf = &sc->sc_rf; | |
1746 | uint16_t val; | |
1747 | ||
1748 | /* specify that the plug and play is finished */ | |
1749 | zyd_write32_m(sc, ZYD_MAC_AFTER_PNP, 1); | |
1750 | zyd_read16_m(sc, ZYD_FIRMWARE_BASE_ADDR, &sc->sc_fwbase); | |
1751 | DPRINTF(sc, ZYD_DEBUG_FW, "firmware base address=0x%04x\n", | |
1752 | sc->sc_fwbase); | |
1753 | ||
1754 | /* retrieve firmware revision number */ | |
1755 | zyd_read16_m(sc, sc->sc_fwbase + ZYD_FW_FIRMWARE_REV, &sc->sc_fwrev); | |
1756 | zyd_write32_m(sc, ZYD_CR_GPI_EN, 0); | |
1757 | zyd_write32_m(sc, ZYD_MAC_CONT_WIN_LIMIT, 0x7f043f); | |
1758 | /* set mandatory rates - XXX assumes 802.11b/g */ | |
1759 | zyd_write32_m(sc, ZYD_MAC_MAN_RATE, 0x150f); | |
1760 | ||
1761 | /* disable interrupts */ | |
1762 | zyd_write32_m(sc, ZYD_CR_INTERRUPT, 0); | |
1763 | ||
1764 | if ((error = zyd_read_pod(sc)) != 0) { | |
1765 | device_printf(sc->sc_dev, "could not read EEPROM\n"); | |
1766 | goto fail; | |
1767 | } | |
1768 | ||
1769 | /* PHY init (resetting) */ | |
1770 | error = zyd_lock_phy(sc); | |
1771 | if (error != 0) | |
1772 | goto fail; | |
1773 | phyp = (sc->sc_macrev == ZYD_ZD1211B) ? zyd_def_phyB : zyd_def_phy; | |
1774 | for (; phyp->reg != 0; phyp++) | |
1775 | zyd_write16_m(sc, phyp->reg, phyp->val); | |
1776 | if (sc->sc_macrev == ZYD_ZD1211 && sc->sc_fix_cr157 != 0) { | |
1777 | zyd_read16_m(sc, ZYD_EEPROM_PHY_REG, &val); | |
1778 | zyd_write32_m(sc, ZYD_CR157, val >> 8); | |
1779 | } | |
1780 | error = zyd_unlock_phy(sc); | |
1781 | if (error != 0) | |
1782 | goto fail; | |
1783 | ||
1784 | /* HMAC init */ | |
1785 | zyd_write32_m(sc, ZYD_MAC_ACK_EXT, 0x00000020); | |
1786 | zyd_write32_m(sc, ZYD_CR_ADDA_MBIAS_WT, 0x30000808); | |
1787 | zyd_write32_m(sc, ZYD_MAC_SNIFFER, 0x00000000); | |
1788 | zyd_write32_m(sc, ZYD_MAC_RXFILTER, 0x00000000); | |
1789 | zyd_write32_m(sc, ZYD_MAC_GHTBL, 0x00000000); | |
1790 | zyd_write32_m(sc, ZYD_MAC_GHTBH, 0x80000000); | |
1791 | zyd_write32_m(sc, ZYD_MAC_MISC, 0x000000a4); | |
1792 | zyd_write32_m(sc, ZYD_CR_ADDA_PWR_DWN, 0x0000007f); | |
1793 | zyd_write32_m(sc, ZYD_MAC_BCNCFG, 0x00f00401); | |
1794 | zyd_write32_m(sc, ZYD_MAC_PHY_DELAY2, 0x00000000); | |
1795 | zyd_write32_m(sc, ZYD_MAC_ACK_EXT, 0x00000080); | |
1796 | zyd_write32_m(sc, ZYD_CR_ADDA_PWR_DWN, 0x00000000); | |
1797 | zyd_write32_m(sc, ZYD_MAC_SIFS_ACK_TIME, 0x00000100); | |
1798 | zyd_write32_m(sc, ZYD_CR_RX_PE_DELAY, 0x00000070); | |
1799 | zyd_write32_m(sc, ZYD_CR_PS_CTRL, 0x10000000); | |
1800 | zyd_write32_m(sc, ZYD_MAC_RTSCTSRATE, 0x02030203); | |
1801 | zyd_write32_m(sc, ZYD_MAC_AFTER_PNP, 1); | |
1802 | zyd_write32_m(sc, ZYD_MAC_BACKOFF_PROTECT, 0x00000114); | |
1803 | zyd_write32_m(sc, ZYD_MAC_DIFS_EIFS_SIFS, 0x0a47c032); | |
1804 | zyd_write32_m(sc, ZYD_MAC_CAM_MODE, 0x3); | |
1805 | ||
1806 | if (sc->sc_macrev == ZYD_ZD1211) { | |
1807 | zyd_write32_m(sc, ZYD_MAC_RETRY, 0x00000002); | |
1808 | zyd_write32_m(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0640); | |
1809 | } else { | |
1810 | zyd_write32_m(sc, ZYD_MACB_MAX_RETRY, 0x02020202); | |
1811 | zyd_write32_m(sc, ZYD_MACB_TXPWR_CTL4, 0x007f003f); | |
1812 | zyd_write32_m(sc, ZYD_MACB_TXPWR_CTL3, 0x007f003f); | |
1813 | zyd_write32_m(sc, ZYD_MACB_TXPWR_CTL2, 0x003f001f); | |
1814 | zyd_write32_m(sc, ZYD_MACB_TXPWR_CTL1, 0x001f000f); | |
1815 | zyd_write32_m(sc, ZYD_MACB_AIFS_CTL1, 0x00280028); | |
1816 | zyd_write32_m(sc, ZYD_MACB_AIFS_CTL2, 0x008C003C); | |
1817 | zyd_write32_m(sc, ZYD_MACB_TXOP, 0x01800824); | |
1818 | zyd_write32_m(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0eff); | |
1819 | } | |
1820 | ||
1821 | /* init beacon interval to 100ms */ | |
1822 | if ((error = zyd_set_beacon_interval(sc, 100)) != 0) | |
1823 | goto fail; | |
1824 | ||
1825 | if ((error = zyd_rf_attach(sc, sc->sc_rfrev)) != 0) { | |
1826 | device_printf(sc->sc_dev, "could not attach RF, rev 0x%x\n", | |
1827 | sc->sc_rfrev); | |
1828 | goto fail; | |
1829 | } | |
1830 | ||
1831 | /* RF chip init */ | |
1832 | error = zyd_lock_phy(sc); | |
1833 | if (error != 0) | |
1834 | goto fail; | |
1835 | error = (*rf->init)(rf); | |
1836 | if (error != 0) { | |
1837 | device_printf(sc->sc_dev, | |
1838 | "radio initialization failed, error %d\n", error); | |
1839 | goto fail; | |
1840 | } | |
1841 | error = zyd_unlock_phy(sc); | |
1842 | if (error != 0) | |
1843 | goto fail; | |
1844 | ||
1845 | if ((error = zyd_read_eeprom(sc)) != 0) { | |
1846 | device_printf(sc->sc_dev, "could not read EEPROM\n"); | |
1847 | goto fail; | |
1848 | } | |
1849 | ||
1850 | fail: return (error); | |
1851 | } | |
1852 | ||
1853 | static int | |
1854 | zyd_read_pod(struct zyd_softc *sc) | |
1855 | { | |
1856 | int error; | |
1857 | uint32_t tmp; | |
1858 | ||
1859 | zyd_read32_m(sc, ZYD_EEPROM_POD, &tmp); | |
1860 | sc->sc_rfrev = tmp & 0x0f; | |
1861 | sc->sc_ledtype = (tmp >> 4) & 0x01; | |
1862 | sc->sc_al2230s = (tmp >> 7) & 0x01; | |
1863 | sc->sc_cckgain = (tmp >> 8) & 0x01; | |
1864 | sc->sc_fix_cr157 = (tmp >> 13) & 0x01; | |
1865 | sc->sc_parev = (tmp >> 16) & 0x0f; | |
1866 | sc->sc_bandedge6 = (tmp >> 21) & 0x01; | |
1867 | sc->sc_newphy = (tmp >> 31) & 0x01; | |
1868 | sc->sc_txled = ((tmp & (1 << 24)) && (tmp & (1 << 29))) ? 0 : 1; | |
1869 | fail: | |
1870 | return (error); | |
1871 | } | |
1872 | ||
1873 | static int | |
1874 | zyd_read_eeprom(struct zyd_softc *sc) | |
1875 | { | |
1876 | uint16_t val; | |
1877 | int error, i; | |
1878 | ||
1879 | /* read Tx power calibration tables */ | |
1880 | for (i = 0; i < 7; i++) { | |
1881 | zyd_read16_m(sc, ZYD_EEPROM_PWR_CAL + i, &val); | |
1882 | sc->sc_pwrcal[i * 2] = val >> 8; | |
1883 | sc->sc_pwrcal[i * 2 + 1] = val & 0xff; | |
1884 | zyd_read16_m(sc, ZYD_EEPROM_PWR_INT + i, &val); | |
1885 | sc->sc_pwrint[i * 2] = val >> 8; | |
1886 | sc->sc_pwrint[i * 2 + 1] = val & 0xff; | |
1887 | zyd_read16_m(sc, ZYD_EEPROM_36M_CAL + i, &val); | |
1888 | sc->sc_ofdm36_cal[i * 2] = val >> 8; | |
1889 | sc->sc_ofdm36_cal[i * 2 + 1] = val & 0xff; | |
1890 | zyd_read16_m(sc, ZYD_EEPROM_48M_CAL + i, &val); | |
1891 | sc->sc_ofdm48_cal[i * 2] = val >> 8; | |
1892 | sc->sc_ofdm48_cal[i * 2 + 1] = val & 0xff; | |
1893 | zyd_read16_m(sc, ZYD_EEPROM_54M_CAL + i, &val); | |
1894 | sc->sc_ofdm54_cal[i * 2] = val >> 8; | |
1895 | sc->sc_ofdm54_cal[i * 2 + 1] = val & 0xff; | |
1896 | } | |
1897 | fail: | |
1898 | return (error); | |
1899 | } | |
1900 | ||
1901 | static int | |
1902 | zyd_get_macaddr(struct zyd_softc *sc) | |
1903 | { | |
1904 | struct usb_device_request req; | |
1905 | usb_error_t error; | |
1906 | ||
1907 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
1908 | req.bRequest = ZYD_READFWDATAREQ; | |
1909 | USETW(req.wValue, ZYD_EEPROM_MAC_ADDR_P1); | |
1910 | USETW(req.wIndex, 0); | |
1911 | USETW(req.wLength, IEEE80211_ADDR_LEN); | |
1912 | ||
1913 | error = zyd_do_request(sc, &req, sc->sc_bssid); | |
1914 | if (error != 0) { | |
1915 | device_printf(sc->sc_dev, "could not read EEPROM: %s\n", | |
1916 | usbd_errstr(error)); | |
1917 | } | |
1918 | ||
1919 | return (error); | |
1920 | } | |
1921 | ||
1922 | static int | |
1923 | zyd_set_macaddr(struct zyd_softc *sc, const uint8_t *addr) | |
1924 | { | |
1925 | int error; | |
1926 | uint32_t tmp; | |
1927 | ||
1928 | tmp = addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]; | |
1929 | zyd_write32_m(sc, ZYD_MAC_MACADRL, tmp); | |
1930 | tmp = addr[5] << 8 | addr[4]; | |
1931 | zyd_write32_m(sc, ZYD_MAC_MACADRH, tmp); | |
1932 | fail: | |
1933 | return (error); | |
1934 | } | |
1935 | ||
1936 | static int | |
1937 | zyd_set_bssid(struct zyd_softc *sc, const uint8_t *addr) | |
1938 | { | |
1939 | int error; | |
1940 | uint32_t tmp; | |
1941 | ||
1942 | tmp = addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]; | |
1943 | zyd_write32_m(sc, ZYD_MAC_BSSADRL, tmp); | |
1944 | tmp = addr[5] << 8 | addr[4]; | |
1945 | zyd_write32_m(sc, ZYD_MAC_BSSADRH, tmp); | |
1946 | fail: | |
1947 | return (error); | |
1948 | } | |
1949 | ||
1950 | static int | |
1951 | zyd_switch_radio(struct zyd_softc *sc, int on) | |
1952 | { | |
1953 | struct zyd_rf *rf = &sc->sc_rf; | |
1954 | int error; | |
1955 | ||
1956 | error = zyd_lock_phy(sc); | |
1957 | if (error != 0) | |
1958 | goto fail; | |
1959 | error = (*rf->switch_radio)(rf, on); | |
1960 | if (error != 0) | |
1961 | goto fail; | |
1962 | error = zyd_unlock_phy(sc); | |
1963 | fail: | |
1964 | return (error); | |
1965 | } | |
1966 | ||
1967 | static int | |
1968 | zyd_set_led(struct zyd_softc *sc, int which, int on) | |
1969 | { | |
1970 | int error; | |
1971 | uint32_t tmp; | |
1972 | ||
1973 | zyd_read32_m(sc, ZYD_MAC_TX_PE_CONTROL, &tmp); | |
1974 | tmp &= ~which; | |
1975 | if (on) | |
1976 | tmp |= which; | |
1977 | zyd_write32_m(sc, ZYD_MAC_TX_PE_CONTROL, tmp); | |
1978 | fail: | |
1979 | return (error); | |
1980 | } | |
1981 | ||
1982 | static void | |
1983 | zyd_set_multi(struct zyd_softc *sc) | |
1984 | { | |
1985 | int error; | |
1986 | struct ifnet *ifp = sc->sc_ifp; | |
1987 | struct ieee80211com *ic = ifp->if_l2com; | |
1988 | struct ifmultiaddr *ifma; | |
1989 | uint32_t low, high; | |
1990 | uint8_t v; | |
1991 | ||
1992 | if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | |
1993 | return; | |
1994 | ||
1995 | low = 0x00000000; | |
1996 | high = 0x80000000; | |
1997 | ||
1998 | if (ic->ic_opmode == IEEE80211_M_MONITOR || | |
1999 | (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { | |
2000 | low = 0xffffffff; | |
2001 | high = 0xffffffff; | |
2002 | } else { | |
2003 | if_maddr_rlock(ifp); | |
2004 | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | |
2005 | if (ifma->ifma_addr->sa_family != AF_LINK) | |
2006 | continue; | |
2007 | v = ((uint8_t *)LLADDR((struct sockaddr_dl *) | |
2008 | ifma->ifma_addr))[5] >> 2; | |
2009 | if (v < 32) | |
2010 | low |= 1 << v; | |
2011 | else | |
2012 | high |= 1 << (v - 32); | |
2013 | } | |
2014 | if_maddr_runlock(ifp); | |
2015 | } | |
2016 | ||
2017 | /* reprogram multicast global hash table */ | |
2018 | zyd_write32_m(sc, ZYD_MAC_GHTBL, low); | |
2019 | zyd_write32_m(sc, ZYD_MAC_GHTBH, high); | |
2020 | fail: | |
2021 | if (error != 0) | |
2022 | device_printf(sc->sc_dev, | |
2023 | "could not set multicast hash table\n"); | |
2024 | } | |
2025 | ||
2026 | static void | |
2027 | zyd_update_mcast(struct ifnet *ifp) | |
2028 | { | |
2029 | struct zyd_softc *sc = ifp->if_softc; | |
2030 | ||
2031 | if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | |
2032 | return; | |
2033 | ||
2034 | ZYD_LOCK(sc); | |
2035 | zyd_set_multi(sc); | |
2036 | ZYD_UNLOCK(sc); | |
2037 | } | |
2038 | ||
2039 | static int | |
2040 | zyd_set_rxfilter(struct zyd_softc *sc) | |
2041 | { | |
2042 | struct ifnet *ifp = sc->sc_ifp; | |
2043 | struct ieee80211com *ic = ifp->if_l2com; | |
2044 | uint32_t rxfilter; | |
2045 | ||
2046 | switch (ic->ic_opmode) { | |
2047 | case IEEE80211_M_STA: | |
2048 | rxfilter = ZYD_FILTER_BSS; | |
2049 | break; | |
2050 | case IEEE80211_M_IBSS: | |
2051 | case IEEE80211_M_HOSTAP: | |
2052 | rxfilter = ZYD_FILTER_HOSTAP; | |
2053 | break; | |
2054 | case IEEE80211_M_MONITOR: | |
2055 | rxfilter = ZYD_FILTER_MONITOR; | |
2056 | break; | |
2057 | default: | |
2058 | /* should not get there */ | |
2059 | return (EINVAL); | |
2060 | } | |
2061 | return zyd_write32(sc, ZYD_MAC_RXFILTER, rxfilter); | |
2062 | } | |
2063 | ||
2064 | static void | |
2065 | zyd_set_chan(struct zyd_softc *sc, struct ieee80211_channel *c) | |
2066 | { | |
2067 | int error; | |
2068 | struct ifnet *ifp = sc->sc_ifp; | |
2069 | struct ieee80211com *ic = ifp->if_l2com; | |
2070 | struct zyd_rf *rf = &sc->sc_rf; | |
2071 | uint32_t tmp; | |
2072 | int chan; | |
2073 | ||
2074 | chan = ieee80211_chan2ieee(ic, c); | |
2075 | if (chan == 0 || chan == IEEE80211_CHAN_ANY) { | |
2076 | /* XXX should NEVER happen */ | |
2077 | device_printf(sc->sc_dev, | |
2078 | "%s: invalid channel %x\n", __func__, chan); | |
2079 | return; | |
2080 | } | |
2081 | ||
2082 | error = zyd_lock_phy(sc); | |
2083 | if (error != 0) | |
2084 | goto fail; | |
2085 | ||
2086 | error = (*rf->set_channel)(rf, chan); | |
2087 | if (error != 0) | |
2088 | goto fail; | |
2089 | ||
2090 | if (rf->update_pwr) { | |
2091 | /* update Tx power */ | |
2092 | zyd_write16_m(sc, ZYD_CR31, sc->sc_pwrint[chan - 1]); | |
2093 | ||
2094 | if (sc->sc_macrev == ZYD_ZD1211B) { | |
2095 | zyd_write16_m(sc, ZYD_CR67, | |
2096 | sc->sc_ofdm36_cal[chan - 1]); | |
2097 | zyd_write16_m(sc, ZYD_CR66, | |
2098 | sc->sc_ofdm48_cal[chan - 1]); | |
2099 | zyd_write16_m(sc, ZYD_CR65, | |
2100 | sc->sc_ofdm54_cal[chan - 1]); | |
2101 | zyd_write16_m(sc, ZYD_CR68, sc->sc_pwrcal[chan - 1]); | |
2102 | zyd_write16_m(sc, ZYD_CR69, 0x28); | |
2103 | zyd_write16_m(sc, ZYD_CR69, 0x2a); | |
2104 | } | |
2105 | } | |
2106 | if (sc->sc_cckgain) { | |
2107 | /* set CCK baseband gain from EEPROM */ | |
2108 | if (zyd_read32(sc, ZYD_EEPROM_PHY_REG, &tmp) == 0) | |
2109 | zyd_write16_m(sc, ZYD_CR47, tmp & 0xff); | |
2110 | } | |
2111 | if (sc->sc_bandedge6 && rf->bandedge6 != NULL) { | |
2112 | error = (*rf->bandedge6)(rf, c); | |
2113 | if (error != 0) | |
2114 | goto fail; | |
2115 | } | |
2116 | zyd_write32_m(sc, ZYD_CR_CONFIG_PHILIPS, 0); | |
2117 | ||
2118 | error = zyd_unlock_phy(sc); | |
2119 | if (error != 0) | |
2120 | goto fail; | |
2121 | ||
2122 | sc->sc_rxtap.wr_chan_freq = sc->sc_txtap.wt_chan_freq = | |
2123 | htole16(c->ic_freq); | |
2124 | sc->sc_rxtap.wr_chan_flags = sc->sc_txtap.wt_chan_flags = | |
2125 | htole16(c->ic_flags); | |
2126 | fail: | |
2127 | return; | |
2128 | } | |
2129 | ||
2130 | static int | |
2131 | zyd_set_beacon_interval(struct zyd_softc *sc, int bintval) | |
2132 | { | |
2133 | int error; | |
2134 | uint32_t val; | |
2135 | ||
2136 | zyd_read32_m(sc, ZYD_CR_ATIM_WND_PERIOD, &val); | |
2137 | sc->sc_atim_wnd = val; | |
2138 | zyd_read32_m(sc, ZYD_CR_PRE_TBTT, &val); | |
2139 | sc->sc_pre_tbtt = val; | |
2140 | sc->sc_bcn_int = bintval; | |
2141 | ||
2142 | if (sc->sc_bcn_int <= 5) | |
2143 | sc->sc_bcn_int = 5; | |
2144 | if (sc->sc_pre_tbtt < 4 || sc->sc_pre_tbtt >= sc->sc_bcn_int) | |
2145 | sc->sc_pre_tbtt = sc->sc_bcn_int - 1; | |
2146 | if (sc->sc_atim_wnd >= sc->sc_pre_tbtt) | |
2147 | sc->sc_atim_wnd = sc->sc_pre_tbtt - 1; | |
2148 | ||
2149 | zyd_write32_m(sc, ZYD_CR_ATIM_WND_PERIOD, sc->sc_atim_wnd); | |
2150 | zyd_write32_m(sc, ZYD_CR_PRE_TBTT, sc->sc_pre_tbtt); | |
2151 | zyd_write32_m(sc, ZYD_CR_BCN_INTERVAL, sc->sc_bcn_int); | |
2152 | fail: | |
2153 | return (error); | |
2154 | } | |
2155 | ||
2156 | static void | |
2157 | zyd_rx_data(struct usb_xfer *xfer, int offset, uint16_t len) | |
2158 | { | |
2159 | struct zyd_softc *sc = usbd_xfer_softc(xfer); | |
2160 | struct ifnet *ifp = sc->sc_ifp; | |
2161 | struct ieee80211com *ic = ifp->if_l2com; | |
2162 | struct zyd_plcphdr plcp; | |
2163 | struct zyd_rx_stat stat; | |
2164 | struct usb_page_cache *pc; | |
2165 | struct mbuf *m; | |
2166 | int rlen, rssi; | |
2167 | ||
2168 | if (len < ZYD_MIN_FRAGSZ) { | |
2169 | DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too short (length=%d)\n", | |
2170 | device_get_nameunit(sc->sc_dev), len); | |
2171 | ifp->if_ierrors++; | |
2172 | return; | |
2173 | } | |
2174 | pc = usbd_xfer_get_frame(xfer, 0); | |
2175 | usbd_copy_out(pc, offset, &plcp, sizeof(plcp)); | |
2176 | usbd_copy_out(pc, offset + len - sizeof(stat), &stat, sizeof(stat)); | |
2177 | ||
2178 | if (stat.flags & ZYD_RX_ERROR) { | |
2179 | DPRINTF(sc, ZYD_DEBUG_RECV, | |
2180 | "%s: RX status indicated error (%x)\n", | |
2181 | device_get_nameunit(sc->sc_dev), stat.flags); | |
2182 | ifp->if_ierrors++; | |
2183 | return; | |
2184 | } | |
2185 | ||
2186 | /* compute actual frame length */ | |
2187 | rlen = len - sizeof(struct zyd_plcphdr) - | |
2188 | sizeof(struct zyd_rx_stat) - IEEE80211_CRC_LEN; | |
2189 | ||
2190 | /* allocate a mbuf to store the frame */ | |
2191 | if (rlen > MCLBYTES) { | |
2192 | DPRINTF(sc, ZYD_DEBUG_RECV, "%s: frame too long (length=%d)\n", | |
2193 | device_get_nameunit(sc->sc_dev), rlen); | |
2194 | ifp->if_ierrors++; | |
2195 | return; | |
2196 | } else if (rlen > MHLEN) | |
2197 | m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); | |
2198 | else | |
2199 | m = m_gethdr(M_DONTWAIT, MT_DATA); | |
2200 | if (m == NULL) { | |
2201 | DPRINTF(sc, ZYD_DEBUG_RECV, "%s: could not allocate rx mbuf\n", | |
2202 | device_get_nameunit(sc->sc_dev)); | |
2203 | ifp->if_ierrors++; | |
2204 | return; | |
2205 | } | |
2206 | m->m_pkthdr.rcvif = ifp; | |
2207 | m->m_pkthdr.len = m->m_len = rlen; | |
2208 | usbd_copy_out(pc, offset + sizeof(plcp), mtod(m, uint8_t *), rlen); | |
2209 | ||
2210 | if (ieee80211_radiotap_active(ic)) { | |
2211 | struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap; | |
2212 | ||
2213 | tap->wr_flags = 0; | |
2214 | if (stat.flags & (ZYD_RX_BADCRC16 | ZYD_RX_BADCRC32)) | |
2215 | tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; | |
2216 | /* XXX toss, no way to express errors */ | |
2217 | if (stat.flags & ZYD_RX_DECRYPTERR) | |
2218 | tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; | |
2219 | tap->wr_rate = ieee80211_plcp2rate(plcp.signal, | |
2220 | (stat.flags & ZYD_RX_OFDM) ? | |
2221 | IEEE80211_T_OFDM : IEEE80211_T_CCK); | |
2222 | tap->wr_antsignal = stat.rssi + -95; | |
2223 | tap->wr_antnoise = -95; /* XXX */ | |
2224 | } | |
2225 | rssi = (stat.rssi > 63) ? 127 : 2 * stat.rssi; | |
2226 | ||
2227 | sc->sc_rx_data[sc->sc_rx_count].rssi = rssi; | |
2228 | sc->sc_rx_data[sc->sc_rx_count].m = m; | |
2229 | sc->sc_rx_count++; | |
2230 | } | |
2231 | ||
2232 | static void | |
2233 | zyd_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) | |
2234 | { | |
2235 | struct zyd_softc *sc = usbd_xfer_softc(xfer); | |
2236 | struct ifnet *ifp = sc->sc_ifp; | |
2237 | struct ieee80211com *ic = ifp->if_l2com; | |
2238 | struct ieee80211_node *ni; | |
2239 | struct zyd_rx_desc desc; | |
2240 | struct mbuf *m; | |
2241 | struct usb_page_cache *pc; | |
2242 | uint32_t offset; | |
2243 | uint8_t rssi; | |
2244 | int8_t nf; | |
2245 | int i; | |
2246 | int actlen; | |
2247 | ||
2248 | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | |
2249 | ||
2250 | sc->sc_rx_count = 0; | |
2251 | switch (USB_GET_STATE(xfer)) { | |
2252 | case USB_ST_TRANSFERRED: | |
2253 | pc = usbd_xfer_get_frame(xfer, 0); | |
2254 | usbd_copy_out(pc, actlen - sizeof(desc), &desc, sizeof(desc)); | |
2255 | ||
2256 | offset = 0; | |
2257 | if (UGETW(desc.tag) == ZYD_TAG_MULTIFRAME) { | |
2258 | DPRINTF(sc, ZYD_DEBUG_RECV, | |
2259 | "%s: received multi-frame transfer\n", __func__); | |
2260 | ||
2261 | for (i = 0; i < ZYD_MAX_RXFRAMECNT; i++) { | |
2262 | uint16_t len16 = UGETW(desc.len[i]); | |
2263 | ||
2264 | if (len16 == 0 || len16 > actlen) | |
2265 | break; | |
2266 | ||
2267 | zyd_rx_data(xfer, offset, len16); | |
2268 | ||
2269 | /* next frame is aligned on a 32-bit boundary */ | |
2270 | len16 = (len16 + 3) & ~3; | |
2271 | offset += len16; | |
2272 | if (len16 > actlen) | |
2273 | break; | |
2274 | actlen -= len16; | |
2275 | } | |
2276 | } else { | |
2277 | DPRINTF(sc, ZYD_DEBUG_RECV, | |
2278 | "%s: received single-frame transfer\n", __func__); | |
2279 | ||
2280 | zyd_rx_data(xfer, 0, actlen); | |
2281 | } | |
2282 | /* FALLTHROUGH */ | |
2283 | case USB_ST_SETUP: | |
2284 | tr_setup: | |
2285 | usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); | |
2286 | usbd_transfer_submit(xfer); | |
2287 | ||
2288 | /* | |
2289 | * At the end of a USB callback it is always safe to unlock | |
2290 | * the private mutex of a device! That is why we do the | |
2291 | * "ieee80211_input" here, and not some lines up! | |
2292 | */ | |
2293 | ZYD_UNLOCK(sc); | |
2294 | for (i = 0; i < sc->sc_rx_count; i++) { | |
2295 | rssi = sc->sc_rx_data[i].rssi; | |
2296 | m = sc->sc_rx_data[i].m; | |
2297 | sc->sc_rx_data[i].m = NULL; | |
2298 | ||
2299 | nf = -95; /* XXX */ | |
2300 | ||
2301 | ni = ieee80211_find_rxnode(ic, | |
2302 | mtod(m, struct ieee80211_frame_min *)); | |
2303 | if (ni != NULL) { | |
2304 | (void)ieee80211_input(ni, m, rssi, nf); | |
2305 | ieee80211_free_node(ni); | |
2306 | } else | |
2307 | (void)ieee80211_input_all(ic, m, rssi, nf); | |
2308 | } | |
2309 | if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && | |
2310 | !IFQ_IS_EMPTY(&ifp->if_snd)) | |
2311 | zyd_start(ifp); | |
2312 | ZYD_LOCK(sc); | |
2313 | break; | |
2314 | ||
2315 | default: /* Error */ | |
2316 | DPRINTF(sc, ZYD_DEBUG_ANY, "frame error: %s\n", usbd_errstr(error)); | |
2317 | ||
2318 | if (error != USB_ERR_CANCELLED) { | |
2319 | /* try to clear stall first */ | |
2320 | usbd_xfer_set_stall(xfer); | |
2321 | goto tr_setup; | |
2322 | } | |
2323 | break; | |
2324 | } | |
2325 | } | |
2326 | ||
2327 | static uint8_t | |
2328 | zyd_plcp_signal(struct zyd_softc *sc, int rate) | |
2329 | { | |
2330 | switch (rate) { | |
2331 | /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ | |
2332 | case 12: | |
2333 | return (0xb); | |
2334 | case 18: | |
2335 | return (0xf); | |
2336 | case 24: | |
2337 | return (0xa); | |
2338 | case 36: | |
2339 | return (0xe); | |
2340 | case 48: | |
2341 | return (0x9); | |
2342 | case 72: | |
2343 | return (0xd); | |
2344 | case 96: | |
2345 | return (0x8); | |
2346 | case 108: | |
2347 | return (0xc); | |
2348 | /* CCK rates (NB: not IEEE std, device-specific) */ | |
2349 | case 2: | |
2350 | return (0x0); | |
2351 | case 4: | |
2352 | return (0x1); | |
2353 | case 11: | |
2354 | return (0x2); | |
2355 | case 22: | |
2356 | return (0x3); | |
2357 | } | |
2358 | ||
2359 | device_printf(sc->sc_dev, "unsupported rate %d\n", rate); | |
2360 | return (0x0); | |
2361 | } | |
2362 | ||
2363 | static void | |
2364 | zyd_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) | |
2365 | { | |
2366 | struct zyd_softc *sc = usbd_xfer_softc(xfer); | |
2367 | struct ifnet *ifp = sc->sc_ifp; | |
2368 | struct ieee80211vap *vap; | |
2369 | struct zyd_tx_data *data; | |
2370 | struct mbuf *m; | |
2371 | struct usb_page_cache *pc; | |
2372 | int actlen; | |
2373 | ||
2374 | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | |
2375 | ||
2376 | switch (USB_GET_STATE(xfer)) { | |
2377 | case USB_ST_TRANSFERRED: | |
2378 | DPRINTF(sc, ZYD_DEBUG_ANY, "transfer complete, %u bytes\n", | |
2379 | actlen); | |
2380 | ||
2381 | /* free resources */ | |
2382 | data = usbd_xfer_get_priv(xfer); | |
2383 | zyd_tx_free(data, 0); | |
2384 | usbd_xfer_set_priv(xfer, NULL); | |
2385 | ||
2386 | ifp->if_opackets++; | |
2387 | ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |
2388 | ||
2389 | /* FALLTHROUGH */ | |
2390 | case USB_ST_SETUP: | |
2391 | tr_setup: | |
2392 | data = STAILQ_FIRST(&sc->tx_q); | |
2393 | if (data) { | |
2394 | STAILQ_REMOVE_HEAD(&sc->tx_q, next); | |
2395 | m = data->m; | |
2396 | ||
2397 | if (m->m_pkthdr.len > ZYD_MAX_TXBUFSZ) { | |
2398 | DPRINTF(sc, ZYD_DEBUG_ANY, "data overflow, %u bytes\n", | |
2399 | m->m_pkthdr.len); | |
2400 | m->m_pkthdr.len = ZYD_MAX_TXBUFSZ; | |
2401 | } | |
2402 | pc = usbd_xfer_get_frame(xfer, 0); | |
2403 | usbd_copy_in(pc, 0, &data->desc, ZYD_TX_DESC_SIZE); | |
2404 | usbd_m_copy_in(pc, ZYD_TX_DESC_SIZE, m, 0, | |
2405 | m->m_pkthdr.len); | |
2406 | ||
2407 | vap = data->ni->ni_vap; | |
2408 | if (ieee80211_radiotap_active_vap(vap)) { | |
2409 | struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; | |
2410 | ||
2411 | tap->wt_flags = 0; | |
2412 | tap->wt_rate = data->rate; | |
2413 | ||
2414 | ieee80211_radiotap_tx(vap, m); | |
2415 | } | |
2416 | ||
2417 | usbd_xfer_set_frame_len(xfer, 0, ZYD_TX_DESC_SIZE + m->m_pkthdr.len); | |
2418 | usbd_xfer_set_priv(xfer, data); | |
2419 | usbd_transfer_submit(xfer); | |
2420 | } | |
2421 | ZYD_UNLOCK(sc); | |
2422 | zyd_start(ifp); | |
2423 | ZYD_LOCK(sc); | |
2424 | break; | |
2425 | ||
2426 | default: /* Error */ | |
2427 | DPRINTF(sc, ZYD_DEBUG_ANY, "transfer error, %s\n", | |
2428 | usbd_errstr(error)); | |
2429 | ||
2430 | ifp->if_oerrors++; | |
2431 | data = usbd_xfer_get_priv(xfer); | |
2432 | usbd_xfer_set_priv(xfer, NULL); | |
2433 | if (data != NULL) | |
2434 | zyd_tx_free(data, error); | |
2435 | ||
2436 | if (error != USB_ERR_CANCELLED) { | |
2437 | if (error == USB_ERR_TIMEOUT) | |
2438 | device_printf(sc->sc_dev, "device timeout\n"); | |
2439 | ||
2440 | /* | |
2441 | * Try to clear stall first, also if other | |
2442 | * errors occur, hence clearing stall | |
2443 | * introduces a 50 ms delay: | |
2444 | */ | |
2445 | usbd_xfer_set_stall(xfer); | |
2446 | goto tr_setup; | |
2447 | } | |
2448 | break; | |
2449 | } | |
2450 | } | |
2451 | ||
2452 | static int | |
2453 | zyd_tx_start(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) | |
2454 | { | |
2455 | struct ieee80211vap *vap = ni->ni_vap; | |
2456 | struct ieee80211com *ic = ni->ni_ic; | |
2457 | struct zyd_tx_desc *desc; | |
2458 | struct zyd_tx_data *data; | |
2459 | struct ieee80211_frame *wh; | |
2460 | const struct ieee80211_txparam *tp; | |
2461 | struct ieee80211_key *k; | |
2462 | int rate, totlen; | |
2463 | static uint8_t ratediv[] = ZYD_TX_RATEDIV; | |
2464 | uint8_t phy; | |
2465 | uint16_t pktlen; | |
2466 | uint32_t bits; | |
2467 | ||
2468 | wh = mtod(m0, struct ieee80211_frame *); | |
2469 | data = STAILQ_FIRST(&sc->tx_free); | |
2470 | STAILQ_REMOVE_HEAD(&sc->tx_free, next); | |
2471 | sc->tx_nfree--; | |
2472 | ||
2473 | if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT || | |
2474 | (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) { | |
2475 | tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; | |
2476 | rate = tp->mgmtrate; | |
2477 | } else { | |
2478 | tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; | |
2479 | /* for data frames */ | |
2480 | if (IEEE80211_IS_MULTICAST(wh->i_addr1)) | |
2481 | rate = tp->mcastrate; | |
2482 | else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) | |
2483 | rate = tp->ucastrate; | |
2484 | else { | |
2485 | (void) ieee80211_ratectl_rate(ni, NULL, 0); | |
2486 | rate = ni->ni_txrate; | |
2487 | } | |
2488 | } | |
2489 | ||
2490 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | |
2491 | k = ieee80211_crypto_encap(ni, m0); | |
2492 | if (k == NULL) { | |
2493 | m_freem(m0); | |
2494 | return (ENOBUFS); | |
2495 | } | |
2496 | /* packet header may have moved, reset our local pointer */ | |
2497 | wh = mtod(m0, struct ieee80211_frame *); | |
2498 | } | |
2499 | ||
2500 | data->ni = ni; | |
2501 | data->m = m0; | |
2502 | data->rate = rate; | |
2503 | ||
2504 | /* fill Tx descriptor */ | |
2505 | desc = &data->desc; | |
2506 | phy = zyd_plcp_signal(sc, rate); | |
2507 | desc->phy = phy; | |
2508 | if (ZYD_RATE_IS_OFDM(rate)) { | |
2509 | desc->phy |= ZYD_TX_PHY_OFDM; | |
2510 | if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) | |
2511 | desc->phy |= ZYD_TX_PHY_5GHZ; | |
2512 | } else if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) | |
2513 | desc->phy |= ZYD_TX_PHY_SHPREAMBLE; | |
2514 | ||
2515 | totlen = m0->m_pkthdr.len + IEEE80211_CRC_LEN; | |
2516 | desc->len = htole16(totlen); | |
2517 | ||
2518 | desc->flags = ZYD_TX_FLAG_BACKOFF; | |
2519 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { | |
2520 | /* multicast frames are not sent at OFDM rates in 802.11b/g */ | |
2521 | if (totlen > vap->iv_rtsthreshold) { | |
2522 | desc->flags |= ZYD_TX_FLAG_RTS; | |
2523 | } else if (ZYD_RATE_IS_OFDM(rate) && | |
2524 | (ic->ic_flags & IEEE80211_F_USEPROT)) { | |
2525 | if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) | |
2526 | desc->flags |= ZYD_TX_FLAG_CTS_TO_SELF; | |
2527 | else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) | |
2528 | desc->flags |= ZYD_TX_FLAG_RTS; | |
2529 | } | |
2530 | } else | |
2531 | desc->flags |= ZYD_TX_FLAG_MULTICAST; | |
2532 | if ((wh->i_fc[0] & | |
2533 | (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == | |
2534 | (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_PS_POLL)) | |
2535 | desc->flags |= ZYD_TX_FLAG_TYPE(ZYD_TX_TYPE_PS_POLL); | |
2536 | ||
2537 | /* actual transmit length (XXX why +10?) */ | |
2538 | pktlen = ZYD_TX_DESC_SIZE + 10; | |
2539 | if (sc->sc_macrev == ZYD_ZD1211) | |
2540 | pktlen += totlen; | |
2541 | desc->pktlen = htole16(pktlen); | |
2542 | ||
2543 | bits = (rate == 11) ? (totlen * 16) + 10 : | |
2544 | ((rate == 22) ? (totlen * 8) + 10 : (totlen * 8)); | |
2545 | desc->plcp_length = htole16(bits / ratediv[phy]); | |
2546 | desc->plcp_service = 0; | |
2547 | if (rate == 22 && (bits % 11) > 0 && (bits % 11) <= 3) | |
2548 | desc->plcp_service |= ZYD_PLCP_LENGEXT; | |
2549 | desc->nextlen = 0; | |
2550 | ||
2551 | if (ieee80211_radiotap_active_vap(vap)) { | |
2552 | struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; | |
2553 | ||
2554 | tap->wt_flags = 0; | |
2555 | tap->wt_rate = rate; | |
2556 | ||
2557 | ieee80211_radiotap_tx(vap, m0); | |
2558 | } | |
2559 | ||
2560 | DPRINTF(sc, ZYD_DEBUG_XMIT, | |
2561 | "%s: sending data frame len=%zu rate=%u\n", | |
2562 | device_get_nameunit(sc->sc_dev), (size_t)m0->m_pkthdr.len, | |
2563 | rate); | |
2564 | ||
2565 | STAILQ_INSERT_TAIL(&sc->tx_q, data, next); | |
2566 | usbd_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); | |
2567 | ||
2568 | return (0); | |
2569 | } | |
2570 | ||
2571 | static void | |
2572 | zyd_start(struct ifnet *ifp) | |
2573 | { | |
2574 | struct zyd_softc *sc = ifp->if_softc; | |
2575 | struct ieee80211_node *ni; | |
2576 | struct mbuf *m; | |
2577 | ||
2578 | ZYD_LOCK(sc); | |
2579 | for (;;) { | |
2580 | IFQ_DRV_DEQUEUE(&ifp->if_snd, m); | |
2581 | if (m == NULL) | |
2582 | break; | |
2583 | if (sc->tx_nfree == 0) { | |
2584 | IFQ_DRV_PREPEND(&ifp->if_snd, m); | |
2585 | ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |
2586 | break; | |
2587 | } | |
2588 | ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; | |
2589 | if (zyd_tx_start(sc, m, ni) != 0) { | |
2590 | ieee80211_free_node(ni); | |
2591 | ifp->if_oerrors++; | |
2592 | break; | |
2593 | } | |
2594 | } | |
2595 | ZYD_UNLOCK(sc); | |
2596 | } | |
2597 | ||
2598 | static int | |
2599 | zyd_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, | |
2600 | const struct ieee80211_bpf_params *params) | |
2601 | { | |
2602 | struct ieee80211com *ic = ni->ni_ic; | |
2603 | struct ifnet *ifp = ic->ic_ifp; | |
2604 | struct zyd_softc *sc = ifp->if_softc; | |
2605 | ||
2606 | ZYD_LOCK(sc); | |
2607 | /* prevent management frames from being sent if we're not ready */ | |
2608 | if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { | |
2609 | ZYD_UNLOCK(sc); | |
2610 | m_freem(m); | |
2611 | ieee80211_free_node(ni); | |
2612 | return (ENETDOWN); | |
2613 | } | |
2614 | if (sc->tx_nfree == 0) { | |
2615 | ifp->if_drv_flags |= IFF_DRV_OACTIVE; | |
2616 | ZYD_UNLOCK(sc); | |
2617 | m_freem(m); | |
2618 | ieee80211_free_node(ni); | |
2619 | return (ENOBUFS); /* XXX */ | |
2620 | } | |
2621 | ||
2622 | /* | |
2623 | * Legacy path; interpret frame contents to decide | |
2624 | * precisely how to send the frame. | |
2625 | * XXX raw path | |
2626 | */ | |
2627 | if (zyd_tx_start(sc, m, ni) != 0) { | |
2628 | ZYD_UNLOCK(sc); | |
2629 | ifp->if_oerrors++; | |
2630 | ieee80211_free_node(ni); | |
2631 | return (EIO); | |
2632 | } | |
2633 | ZYD_UNLOCK(sc); | |
2634 | return (0); | |
2635 | } | |
2636 | ||
2637 | static int | |
2638 | zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | |
2639 | { | |
2640 | struct zyd_softc *sc = ifp->if_softc; | |
2641 | struct ieee80211com *ic = ifp->if_l2com; | |
2642 | struct ifreq *ifr = (struct ifreq *) data; | |
2643 | int error = 0, startall = 0; | |
2644 | ||
2645 | switch (cmd) { | |
2646 | case SIOCSIFFLAGS: | |
2647 | ZYD_LOCK(sc); | |
2648 | if (ifp->if_flags & IFF_UP) { | |
2649 | if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | |
2650 | zyd_init_locked(sc); | |
2651 | startall = 1; | |
2652 | } else | |
2653 | zyd_set_multi(sc); | |
2654 | } else { | |
2655 | if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |
2656 | zyd_stop(sc); | |
2657 | } | |
2658 | ZYD_UNLOCK(sc); | |
2659 | if (startall) | |
2660 | ieee80211_start_all(ic); | |
2661 | break; | |
2662 | case SIOCGIFMEDIA: | |
2663 | error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); | |
2664 | break; | |
2665 | case SIOCGIFADDR: | |
2666 | error = ether_ioctl(ifp, cmd, data); | |
2667 | break; | |
2668 | default: | |
2669 | error = EINVAL; | |
2670 | break; | |
2671 | } | |
2672 | return (error); | |
2673 | } | |
2674 | ||
2675 | static void | |
2676 | zyd_init_locked(struct zyd_softc *sc) | |
2677 | { | |
2678 | struct ifnet *ifp = sc->sc_ifp; | |
2679 | struct ieee80211com *ic = ifp->if_l2com; | |
2680 | struct usb_config_descriptor *cd; | |
2681 | int error; | |
2682 | uint32_t val; | |
e707c6f3 SW |
2683 | #ifdef USB_DEBUG |
2684 | char ethstr[ETHER_ADDRSTRLEN + 1]; | |
2685 | #endif | |
12bd3c8b SW |
2686 | |
2687 | ZYD_LOCK_ASSERT(sc, MA_OWNED); | |
2688 | ||
2689 | if (!(sc->sc_flags & ZYD_FLAG_INITONCE)) { | |
2690 | error = zyd_loadfirmware(sc); | |
2691 | if (error != 0) { | |
2692 | device_printf(sc->sc_dev, | |
2693 | "could not load firmware (error=%d)\n", error); | |
2694 | goto fail; | |
2695 | } | |
2696 | ||
2697 | /* reset device */ | |
2698 | cd = usbd_get_config_descriptor(sc->sc_udev); | |
2699 | error = usbd_req_set_config(sc->sc_udev, &sc->sc_mtx, | |
2700 | cd->bConfigurationValue); | |
2701 | if (error) | |
2702 | device_printf(sc->sc_dev, "reset failed, continuing\n"); | |
2703 | ||
2704 | error = zyd_hw_init(sc); | |
2705 | if (error) { | |
2706 | device_printf(sc->sc_dev, | |
2707 | "hardware initialization failed\n"); | |
2708 | goto fail; | |
2709 | } | |
2710 | ||
2711 | device_printf(sc->sc_dev, | |
2712 | "HMAC ZD1211%s, FW %02x.%02x, RF %s S%x, PA%x LED %x " | |
2713 | "BE%x NP%x Gain%x F%x\n", | |
2714 | (sc->sc_macrev == ZYD_ZD1211) ? "": "B", | |
2715 | sc->sc_fwrev >> 8, sc->sc_fwrev & 0xff, | |
2716 | zyd_rf_name(sc->sc_rfrev), sc->sc_al2230s, sc->sc_parev, | |
2717 | sc->sc_ledtype, sc->sc_bandedge6, sc->sc_newphy, | |
2718 | sc->sc_cckgain, sc->sc_fix_cr157); | |
2719 | ||
2720 | /* read regulatory domain (currently unused) */ | |
2721 | zyd_read32_m(sc, ZYD_EEPROM_SUBID, &val); | |
2722 | sc->sc_regdomain = val >> 16; | |
2723 | DPRINTF(sc, ZYD_DEBUG_INIT, "regulatory domain %x\n", | |
2724 | sc->sc_regdomain); | |
2725 | ||
2726 | /* we'll do software WEP decryption for now */ | |
2727 | DPRINTF(sc, ZYD_DEBUG_INIT, "%s: setting encryption type\n", | |
2728 | __func__); | |
2729 | zyd_write32_m(sc, ZYD_MAC_ENCRYPTION_TYPE, ZYD_ENC_SNIFFER); | |
2730 | ||
2731 | sc->sc_flags |= ZYD_FLAG_INITONCE; | |
2732 | } | |
2733 | ||
2734 | if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |
2735 | zyd_stop(sc); | |
2736 | ||
e707c6f3 SW |
2737 | DPRINTF(sc, ZYD_DEBUG_INIT, "setting MAC address to %s\n", |
2738 | kether_ntoa(IF_LLADDR(ifp), ethstr)); | |
12bd3c8b SW |
2739 | error = zyd_set_macaddr(sc, IF_LLADDR(ifp)); |
2740 | if (error != 0) | |
2741 | return; | |
2742 | ||
2743 | /* set basic rates */ | |
2744 | if (ic->ic_curmode == IEEE80211_MODE_11B) | |
2745 | zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0x0003); | |
2746 | else if (ic->ic_curmode == IEEE80211_MODE_11A) | |
2747 | zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0x1500); | |
2748 | else /* assumes 802.11b/g */ | |
2749 | zyd_write32_m(sc, ZYD_MAC_BAS_RATE, 0xff0f); | |
2750 | ||
2751 | /* promiscuous mode */ | |
2752 | zyd_write32_m(sc, ZYD_MAC_SNIFFER, 0); | |
2753 | /* multicast setup */ | |
2754 | zyd_set_multi(sc); | |
2755 | /* set RX filter */ | |
2756 | error = zyd_set_rxfilter(sc); | |
2757 | if (error != 0) | |
2758 | goto fail; | |
2759 | ||
2760 | /* switch radio transmitter ON */ | |
2761 | error = zyd_switch_radio(sc, 1); | |
2762 | if (error != 0) | |
2763 | goto fail; | |
2764 | /* set default BSS channel */ | |
2765 | zyd_set_chan(sc, ic->ic_curchan); | |
2766 | ||
2767 | /* | |
2768 | * Allocate Tx and Rx xfer queues. | |
2769 | */ | |
2770 | zyd_setup_tx_list(sc); | |
2771 | ||
2772 | /* enable interrupts */ | |
2773 | zyd_write32_m(sc, ZYD_CR_INTERRUPT, ZYD_HWINT_MASK); | |
2774 | ||
2775 | ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |
2776 | ifp->if_drv_flags |= IFF_DRV_RUNNING; | |
2777 | usbd_xfer_set_stall(sc->sc_xfer[ZYD_BULK_WR]); | |
2778 | usbd_transfer_start(sc->sc_xfer[ZYD_BULK_RD]); | |
2779 | usbd_transfer_start(sc->sc_xfer[ZYD_INTR_RD]); | |
2780 | ||
2781 | return; | |
2782 | ||
2783 | fail: zyd_stop(sc); | |
2784 | return; | |
2785 | } | |
2786 | ||
2787 | static void | |
2788 | zyd_init(void *priv) | |
2789 | { | |
2790 | struct zyd_softc *sc = priv; | |
2791 | struct ifnet *ifp = sc->sc_ifp; | |
2792 | struct ieee80211com *ic = ifp->if_l2com; | |
2793 | ||
2794 | ZYD_LOCK(sc); | |
2795 | zyd_init_locked(sc); | |
2796 | ZYD_UNLOCK(sc); | |
2797 | ||
2798 | if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |
2799 | ieee80211_start_all(ic); /* start all vap's */ | |
2800 | } | |
2801 | ||
2802 | static void | |
2803 | zyd_stop(struct zyd_softc *sc) | |
2804 | { | |
2805 | struct ifnet *ifp = sc->sc_ifp; | |
2806 | int error; | |
2807 | ||
2808 | ZYD_LOCK_ASSERT(sc, MA_OWNED); | |
2809 | ||
2810 | ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | |
2811 | ||
2812 | /* | |
2813 | * Drain all the transfers, if not already drained: | |
2814 | */ | |
2815 | ZYD_UNLOCK(sc); | |
2816 | usbd_transfer_drain(sc->sc_xfer[ZYD_BULK_WR]); | |
2817 | usbd_transfer_drain(sc->sc_xfer[ZYD_BULK_RD]); | |
2818 | ZYD_LOCK(sc); | |
2819 | ||
2820 | zyd_unsetup_tx_list(sc); | |
2821 | ||
2822 | /* Stop now if the device was never set up */ | |
2823 | if (!(sc->sc_flags & ZYD_FLAG_INITONCE)) | |
2824 | return; | |
2825 | ||
2826 | /* switch radio transmitter OFF */ | |
2827 | error = zyd_switch_radio(sc, 0); | |
2828 | if (error != 0) | |
2829 | goto fail; | |
2830 | /* disable Rx */ | |
2831 | zyd_write32_m(sc, ZYD_MAC_RXFILTER, 0); | |
2832 | /* disable interrupts */ | |
2833 | zyd_write32_m(sc, ZYD_CR_INTERRUPT, 0); | |
2834 | ||
2835 | fail: | |
2836 | return; | |
2837 | } | |
2838 | ||
2839 | static int | |
2840 | zyd_loadfirmware(struct zyd_softc *sc) | |
2841 | { | |
2842 | struct usb_device_request req; | |
2843 | size_t size; | |
2844 | u_char *fw; | |
2845 | uint8_t stat; | |
2846 | uint16_t addr; | |
2847 | ||
2848 | if (sc->sc_flags & ZYD_FLAG_FWLOADED) | |
2849 | return (0); | |
2850 | ||
2851 | if (sc->sc_macrev == ZYD_ZD1211) { | |
2852 | fw = (u_char *)zd1211_firmware; | |
2853 | size = sizeof(zd1211_firmware); | |
2854 | } else { | |
2855 | fw = (u_char *)zd1211b_firmware; | |
2856 | size = sizeof(zd1211b_firmware); | |
2857 | } | |
2858 | ||
2859 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
2860 | req.bRequest = ZYD_DOWNLOADREQ; | |
2861 | USETW(req.wIndex, 0); | |
2862 | ||
2863 | addr = ZYD_FIRMWARE_START_ADDR; | |
2864 | while (size > 0) { | |
2865 | /* | |
2866 | * When the transfer size is 4096 bytes, it is not | |
2867 | * likely to be able to transfer it. | |
2868 | * The cause is port or machine or chip? | |
2869 | */ | |
2870 | const int mlen = min(size, 64); | |
2871 | ||
2872 | DPRINTF(sc, ZYD_DEBUG_FW, | |
2873 | "loading firmware block: len=%d, addr=0x%x\n", mlen, addr); | |
2874 | ||
2875 | USETW(req.wValue, addr); | |
2876 | USETW(req.wLength, mlen); | |
2877 | if (zyd_do_request(sc, &req, fw) != 0) | |
2878 | return (EIO); | |
2879 | ||
2880 | addr += mlen / 2; | |
2881 | fw += mlen; | |
2882 | size -= mlen; | |
2883 | } | |
2884 | ||
2885 | /* check whether the upload succeeded */ | |
2886 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
2887 | req.bRequest = ZYD_DOWNLOADSTS; | |
2888 | USETW(req.wValue, 0); | |
2889 | USETW(req.wIndex, 0); | |
2890 | USETW(req.wLength, sizeof(stat)); | |
2891 | if (zyd_do_request(sc, &req, &stat) != 0) | |
2892 | return (EIO); | |
2893 | ||
2894 | sc->sc_flags |= ZYD_FLAG_FWLOADED; | |
2895 | ||
2896 | return (stat & 0x80) ? (EIO) : (0); | |
2897 | } | |
2898 | ||
2899 | static void | |
2900 | zyd_scan_start(struct ieee80211com *ic) | |
2901 | { | |
2902 | struct ifnet *ifp = ic->ic_ifp; | |
2903 | struct zyd_softc *sc = ifp->if_softc; | |
2904 | ||
2905 | ZYD_LOCK(sc); | |
2906 | /* want broadcast address while scanning */ | |
2907 | zyd_set_bssid(sc, ifp->if_broadcastaddr); | |
2908 | ZYD_UNLOCK(sc); | |
2909 | } | |
2910 | ||
2911 | static void | |
2912 | zyd_scan_end(struct ieee80211com *ic) | |
2913 | { | |
2914 | struct zyd_softc *sc = ic->ic_ifp->if_softc; | |
2915 | ||
2916 | ZYD_LOCK(sc); | |
2917 | /* restore previous bssid */ | |
2918 | zyd_set_bssid(sc, sc->sc_bssid); | |
2919 | ZYD_UNLOCK(sc); | |
2920 | } | |
2921 | ||
2922 | static void | |
2923 | zyd_set_channel(struct ieee80211com *ic) | |
2924 | { | |
2925 | struct zyd_softc *sc = ic->ic_ifp->if_softc; | |
2926 | ||
2927 | ZYD_LOCK(sc); | |
2928 | zyd_set_chan(sc, ic->ic_curchan); | |
2929 | ZYD_UNLOCK(sc); | |
2930 | } | |
2931 | ||
2932 | static device_method_t zyd_methods[] = { | |
2933 | /* Device interface */ | |
2934 | DEVMETHOD(device_probe, zyd_match), | |
2935 | DEVMETHOD(device_attach, zyd_attach), | |
2936 | DEVMETHOD(device_detach, zyd_detach), | |
2937 | ||
2938 | { 0, 0 } | |
2939 | }; | |
2940 | ||
2941 | static driver_t zyd_driver = { | |
2942 | "zyd", | |
2943 | zyd_methods, | |
2944 | sizeof(struct zyd_softc) | |
2945 | }; | |
2946 | ||
2947 | static devclass_t zyd_devclass; | |
2948 | ||
2949 | DRIVER_MODULE(zyd, uhub, zyd_driver, zyd_devclass, NULL, 0); | |
2950 | MODULE_DEPEND(zyd, usb, 1, 1, 1); | |
2951 | MODULE_DEPEND(zyd, wlan, 1, 1, 1); | |
2952 | MODULE_VERSION(zyd, 1); |