if_rsu.c revision 1.1 1 /* $NetBSD: if_rsu.c,v 1.1 2026/10/18 20:17:42 nia Exp $ */
2 /* $OpenBSD: if_rsu.c,v 1.53 2024/05/23 03:21:08 jsg Exp $ */
3
4 /*-
5 * Copyright (c) 2010 Damien Bergamini <damien.bergamini (at) free.fr>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*
21 * Driver for Realtek RTL8188SU/RTL8191SU/RTL8192SU.
22 */
23
24 /*
25 * XXX: This driver is unfinished. It attaches but is not yet usable.
26 */
27
28 #include <sys/param.h>
29 #include <sys/sockio.h>
30 #include <sys/mbuf.h>
31 #include <sys/systm.h>
32 #include <sys/callout.h>
33 #include <sys/module.h>
34 #include <sys/device.h>
35 #include <sys/endian.h>
36
37 #include <machine/intr.h>
38
39 #include <net/if.h>
40 #include <net/if_dl.h>
41 #include <net/if_ether.h>
42 #include <net/if_media.h>
43
44 #include <netinet/in.h>
45
46 #include <net80211/ieee80211_var.h>
47 #include <net80211/ieee80211_radiotap.h>
48
49 #include <dev/firmload.h>
50
51 #include <dev/usb/usb.h>
52 #include <dev/usb/usbdi.h>
53 #include <dev/usb/usbdivar.h>
54 #include <dev/usb/usbdi_util.h>
55 #include <dev/usb/usbdevs.h>
56
57 #include <dev/usb/if_rsureg.h>
58
59 #ifdef RSU_DEBUG
60 #define DPRINTF(x) do { if (rsu_debug) printf x; } while (0)
61 #define DPRINTFN(n, x) do { if (rsu_debug >= (n)) printf x; } while (0)
62 int rsu_debug = 4;
63 #else
64 #define DPRINTF(x)
65 #define DPRINTFN(n, x)
66 #endif
67
68 /*
69 * NB: When updating this list of devices, beware to also update the list
70 * of devices that have HT support disabled below, if applicable.
71 */
72 static const struct usb_devno rsu_devs[] = {
73 { USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RTL8192SU },
74 { USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUSTEK_USBN10 },
75 { USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUSTEK_RTL8192SU_1 },
76 { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8192SU_1 },
77 { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8192SU_2 },
78 { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8192SU_3 },
79 { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8192SU_4 },
80 { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8192SU_5 },
81 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RTL8192SU_1 },
82 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RTL8192SU_2 },
83 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RTL8192SU_3 },
84 { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_RTL8192SU_1 },
85 { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_RTL8192SU_2 },
86 { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_RTL8192SU_3 },
87 { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB300GNM },
88 { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA131A1 },
89 { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RTL8192SU_1 },
90 { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RTL8192SU_2 },
91 { USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_RTL8192SU_1 },
92 { USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_RTL8192SU_2 },
93 { USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_RTL8192SU_3 },
94 { USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUN54 },
95 { USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWNUM300 },
96 { USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RTL8192SU_1 },
97 { USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RTL8192SU_2 },
98 { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUSNANO },
99 { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8171 },
100 { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8172 },
101 { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8173 },
102 { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8174 },
103 { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8192SU },
104 { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8712 },
105 { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8713 },
106 { USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RTL8192SU_1 },
107 { USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RTL8192SU_2 },
108 { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL349V1 },
109 { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL353 },
110 { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RTL8188S },
111 { USB_VENDOR_SWEEX2, USB_PRODUCT_SWEEX2_LW154 }
112 };
113
114 #ifdef notyet
115 /* List of devices that have HT support disabled. */
116 static const struct usb_devno rsu_devs_noht[] = {
117 { USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUS_RTL8192SU_1 },
118 { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8192SU_4 }
119 };
120 #endif
121
122 static int rsu_match(device_t, cfdata_t, void *);
123 static void rsu_attach(device_t, device_t, void *);
124 static int rsu_detach(device_t, int);
125 static int rsu_activate(device_t, enum devact);
126
127 int rsu_open_pipes(struct rsu_softc *);
128 void rsu_close_pipes(struct rsu_softc *);
129 int rsu_alloc_rx_list(struct rsu_softc *);
130 void rsu_free_rx_list(struct rsu_softc *);
131 int rsu_alloc_tx_list(struct rsu_softc *);
132 void rsu_free_tx_list(struct rsu_softc *);
133 void rsu_task(void *);
134 void rsu_do_async(struct rsu_softc *,
135 void (*)(struct rsu_softc *, void *), void *, int);
136 void rsu_wait_async(struct rsu_softc *);
137 int rsu_write_region_1(struct rsu_softc *, uint16_t, uint8_t *,
138 int);
139 void rsu_write_1(struct rsu_softc *, uint16_t, uint8_t);
140 void rsu_write_2(struct rsu_softc *, uint16_t, uint16_t);
141 void rsu_write_4(struct rsu_softc *, uint16_t, uint32_t);
142 int rsu_read_region_1(struct rsu_softc *, uint16_t, uint8_t *,
143 int);
144 uint8_t rsu_read_1(struct rsu_softc *, uint16_t);
145 uint16_t rsu_read_2(struct rsu_softc *, uint16_t);
146 uint32_t rsu_read_4(struct rsu_softc *, uint16_t);
147 int rsu_fw_iocmd(struct rsu_softc *, uint32_t);
148 uint8_t rsu_efuse_read_1(struct rsu_softc *, uint16_t);
149 int rsu_read_rom(struct rsu_softc *);
150 int rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int);
151 int rsu_media_change(struct ifnet *);
152 void rsu_calib_to(void *);
153 void rsu_calib_cb(struct rsu_softc *, void *);
154 int rsu_newstate(struct ieee80211com *, enum ieee80211_state, int);
155 void rsu_newstate_cb(struct rsu_softc *, void *);
156 int rsu_site_survey(struct rsu_softc *);
157 int rsu_join_bss(struct rsu_softc *, struct ieee80211_node *);
158 int rsu_disconnect(struct rsu_softc *);
159 void rsu_event_survey(struct rsu_softc *, uint8_t *, int);
160 void rsu_event_join_bss(struct rsu_softc *, uint8_t *, int);
161 void rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int);
162 void rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int);
163 int8_t rsu_get_rssi(struct rsu_softc *, int, void *);
164 void rsu_rx_frame(struct rsu_softc *, uint8_t *, int);
165 void rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int);
166 void rsu_rxeof(struct usbd_xfer *, void *, usbd_status);
167 void rsu_txeof(struct usbd_xfer *, void *, usbd_status);
168 int rsu_tx(struct rsu_softc *, struct mbuf *,
169 struct ieee80211_node *);
170 int rsu_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
171 int, int);
172 void rsu_start(struct ifnet *);
173 void rsu_watchdog(struct ifnet *);
174 int rsu_ioctl(struct ifnet *, u_long, void *);
175 void rsu_power_on_acut(struct rsu_softc *);
176 void rsu_power_on_bcut(struct rsu_softc *);
177 void rsu_power_off(struct rsu_softc *);
178 int rsu_fw_loadsection(struct rsu_softc *, uint8_t *, int);
179 int rsu_load_firmware(struct rsu_softc *);
180 int rsu_init(struct ifnet *);
181 void rsu_stop(struct ifnet *);
182
183 CFATTACH_DECL_NEW(rsu, sizeof(struct rsu_softc), rsu_match,
184 rsu_attach, rsu_detach, rsu_activate);
185
186 static int
187 rsu_activate(device_t self, enum devact act)
188 {
189 struct rsu_softc *sc = device_private(self);
190 switch (act) {
191 case DVACT_DEACTIVATE:
192 if_deactivate(sc->sc_ic.ic_ifp);
193 return 0;
194 default:
195 return EOPNOTSUPP;
196 }
197 }
198
199 static int
200 rsu_match(device_t parent, cfdata_t match, void *aux)
201 {
202 struct usb_attach_arg *uaa = aux;
203
204 return ((usb_lookup(rsu_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ?
205 UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
206 }
207
208 static void
209 rsu_attach(device_t parent, device_t self, void *aux)
210 {
211 struct rsu_softc *sc = device_private(self);
212 struct usb_attach_arg *uaa = aux;
213 struct ieee80211com *ic = &sc->sc_ic;
214 struct ifnet *ifp = &sc->sc_ec.ec_if;
215 int i, error;
216
217 sc->sc_dev = self;
218 sc->sc_udev = uaa->uaa_device;
219
220 cv_init(&sc->sc_task_cv, "rsutsk");
221 mutex_init(&sc->sc_task_mtx, MUTEX_DEFAULT, IPL_NET);
222 mutex_init(&sc->sc_tx_mtx, MUTEX_DEFAULT, IPL_NONE);
223
224 usb_init_task(&sc->sc_task, rsu_task, sc, 0);
225
226 callout_init(&sc->calib_to, 0);
227 callout_setfunc(&sc->calib_to, rsu_calib_to, sc);
228
229 /* Read chip revision. */
230 sc->cut = MS(rsu_read_4(sc, R92S_PMC_FSM), R92S_PMC_FSM_CUT);
231 if (sc->cut != 3)
232 sc->cut = (sc->cut >> 1) + 1;
233
234 KASSERT(sc->sc_dev != NULL);
235
236 error = usbd_set_config_no(sc->sc_udev, 1, 0);
237 if (error != 0) {
238 aprint_error_dev(self, "failed to set configuration"
239 ", err=%s\n", usbd_errstr(error));
240 return;
241 }
242
243 /* Get the first interface handle. */
244 error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface);
245 if (error != 0) {
246 aprint_error_dev(self, "could not get interface handle\n");
247 return;
248 }
249
250 error = rsu_read_rom(sc);
251 if (error != 0) {
252 printf("%s: could not read ROM\n", device_xname(sc->sc_dev));
253 return;
254 }
255 IEEE80211_ADDR_COPY(ic->ic_myaddr, &sc->rom[0x12]);
256
257 printf("%s: MAC/BB RTL8712 cut %d, address %s\n",
258 device_xname(sc->sc_dev), sc->cut, ether_sprintf(ic->ic_myaddr));
259
260 if (rsu_open_pipes(sc) != 0)
261 return;
262
263 KASSERT(ifp != NULL);
264
265 ic->ic_ifp = ifp;
266 ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */
267 ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */
268 ic->ic_state = IEEE80211_S_INIT;
269
270 /* Set device capabilities. */
271 ic->ic_caps =
272 IEEE80211_C_MONITOR | /* Monitor mode. */
273 IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */
274 IEEE80211_C_SHSLOT | /* Short slot time supported. */
275 IEEE80211_C_WPA; /* WPA/RSN. */
276
277 #ifdef notyet
278 ic->ic_caps +=
279 IEEE80211_C_WEP; /* WEP. */
280 #endif
281
282 #ifdef notyet
283 /* Check if HT support is present. */
284 if (usb_lookup(rsu_devs_noht, uaa->uaa_vendor, uaa->uaa_product) == NULL) {
285 /* Set HT capabilities. */
286 ic->ic_htcaps =
287 IEEE80211_HTCAP_CBW20_40 |
288 IEEE80211_HTCAP_DSSSCCK40;
289 /* Set supported HT rates. */
290 for (i = 0; i < 2; i++)
291 ic->ic_sup_mcs[i] = 0xff;
292 }
293 #endif
294
295 /* Set supported .11b and .11g rates. */
296 ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
297 ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
298
299 /* Set supported .11b and .11g channels (1 through 14). */
300 for (i = 1; i <= 14; i++) {
301 ic->ic_channels[i].ic_freq =
302 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
303 ic->ic_channels[i].ic_flags =
304 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
305 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
306 }
307
308 ifp->if_softc = sc;
309 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
310 ifp->if_init = rsu_init;
311 ifp->if_ioctl = rsu_ioctl;
312 ifp->if_start = rsu_start;
313 ifp->if_watchdog = rsu_watchdog;
314 memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
315
316 if_initialize(ifp);
317 ieee80211_ifattach(ic);
318
319 /* Override state transition machine. */
320 sc->sc_newstate = ic->ic_newstate;
321 ic->ic_newstate = rsu_newstate;
322
323 /* XXX media locking needs revisiting */
324 mutex_init(&sc->sc_media_mtx, MUTEX_DEFAULT, IPL_SOFTUSB);
325 ieee80211_media_init_with_lock(ic,
326 rsu_media_change, ieee80211_media_status, &sc->sc_media_mtx);
327
328 if_register(ifp);
329
330 ieee80211_announce(ic);
331
332 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
333 }
334
335 static int
336 rsu_detach(device_t self, int flags)
337 {
338 struct rsu_softc *sc = device_private(self);
339 struct ieee80211com *ic = &sc->sc_ic;
340 struct ifnet *ifp = sc->sc_ic.ic_ifp;
341 int s;
342
343 s = splusb();
344
345 if (ifp->if_flags & IFF_RUNNING) {
346 rsu_stop(ifp);
347 callout_halt(&sc->calib_to, NULL);
348 usb_rem_task_wait(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER,
349 NULL);
350 }
351
352 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
353 ieee80211_ifdetach(ic);
354 if_detach(ifp);
355
356 mutex_destroy(&sc->sc_media_mtx);
357
358 /* Abort and close Tx/Rx pipes. */
359 rsu_close_pipes(sc);
360
361 /* Free Tx/Rx buffers. */
362 rsu_free_tx_list(sc);
363 rsu_free_rx_list(sc);
364 splx(s);
365
366 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
367
368 callout_destroy(&sc->calib_to);
369
370 mutex_destroy(&sc->sc_task_mtx);
371 mutex_destroy(&sc->sc_tx_mtx);
372
373 return (0);
374 }
375
376 int
377 rsu_open_pipes(struct rsu_softc *sc)
378 {
379 usb_interface_descriptor_t *id;
380 int i, error;
381
382 /*
383 * Determine the number of Tx/Rx endpoints (there are chips with
384 * 4, 6 or 11 endpoints).
385 */
386 id = usbd_get_interface_descriptor(sc->sc_iface);
387 sc->npipes = id->bNumEndpoints;
388 if (sc->npipes == 4)
389 sc->qid2idx = rsu_qid2idx_4ep;
390 else if (sc->npipes == 6)
391 sc->qid2idx = rsu_qid2idx_6ep;
392 else /* Assume npipes==11; will fail below otherwise. */
393 sc->qid2idx = rsu_qid2idx_11ep;
394 DPRINTF(("%d endpoints configuration\n", sc->npipes));
395
396 /* Open all pipes. */
397 for (i = 0; i < MIN(sc->npipes, (int)__arraycount(r92s_epaddr)); i++) {
398 error = usbd_open_pipe(sc->sc_iface, r92s_epaddr[i], 0,
399 &sc->pipe[i]);
400 if (error != 0) {
401 printf("%s: could not open bulk pipe 0x%02x\n",
402 device_xname(sc->sc_dev), r92s_epaddr[i]);
403 break;
404 }
405 }
406 if (error != 0)
407 rsu_close_pipes(sc);
408 return (error);
409 }
410
411 void
412 rsu_close_pipes(struct rsu_softc *sc)
413 {
414 struct usbd_pipe *pipe;
415 int i;
416
417 /* Close all pipes. */
418 for (i = 0; i < sc->npipes; i++) {
419 pipe = atomic_swap_ptr(&sc->pipe[i], NULL);
420 if (pipe != NULL) {
421 usbd_close_pipe(pipe);
422 }
423 }
424 }
425
426 int
427 rsu_alloc_rx_list(struct rsu_softc *sc)
428 {
429 struct rsu_rx_data *data;
430 int i, error = 0;
431
432 for (i = 0; i < RSU_RX_LIST_COUNT; i++) {
433 data = &sc->rx_data[i];
434
435 data->sc = sc; /* Backpointer for callbacks. */
436
437 error = usbd_create_xfer(data->pipe, RSU_RXBUFSZ,
438 0, 0, &data->xfer);
439 if (error) {
440 printf("%s: could not allocate xfer\n",
441 device_xname(sc->sc_dev));
442 error = ENOMEM;
443 break;
444 }
445 data->buf = usbd_get_buffer(data->xfer);
446 }
447 if (error != 0)
448 rsu_free_rx_list(sc);
449 return (error);
450 }
451
452 void
453 rsu_free_rx_list(struct rsu_softc *sc)
454 {
455 int i;
456
457 /* NB: Caller must abort pipe first. */
458 for (i = 0; i < RSU_RX_LIST_COUNT; i++) {
459 if (sc->rx_data[i].xfer != NULL)
460 usbd_destroy_xfer(sc->rx_data[i].xfer);
461 sc->rx_data[i].xfer = NULL;
462 }
463 }
464
465 int
466 rsu_alloc_tx_list(struct rsu_softc *sc)
467 {
468 struct rsu_tx_data *data;
469 int i, error = 0;
470
471 mutex_enter(&sc->sc_tx_mtx);
472 TAILQ_INIT(&sc->tx_free_list);
473 for (i = 0; i < RSU_TX_LIST_COUNT; i++) {
474 data = &sc->tx_data[i];
475
476 data->sc = sc; /* Backpointer for callbacks. */
477
478 error = usbd_create_xfer(data->pipe,
479 RSU_TXBUFSZ, USBD_FORCE_SHORT_XFER, 0,
480 &data->xfer);
481 if (error) {
482 printf("%s: could not allocate xfer\n",
483 device_xname(sc->sc_dev));
484 error = ENOMEM;
485 break;
486 }
487 data->buf = usbd_get_buffer(data->xfer);
488
489 /* Append this Tx buffer to our free list. */
490 TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
491 }
492 if (error != 0)
493 rsu_free_tx_list(sc);
494
495 mutex_exit(&sc->sc_tx_mtx);
496 return (error);
497 }
498
499 void
500 rsu_free_tx_list(struct rsu_softc *sc)
501 {
502 struct usbd_xfer *xfer;
503 int i;
504
505 /* NB: Caller must abort pipe first. */
506 for (i = 0; i < RSU_TX_LIST_COUNT; i++) {
507 xfer = atomic_swap_ptr(&sc->tx_data[i].xfer, NULL);
508 if (xfer != NULL)
509 usbd_destroy_xfer(xfer);
510 }
511 }
512
513 void
514 rsu_task(void *arg)
515 {
516 struct rsu_softc *sc = arg;
517 struct rsu_host_cmd_ring *ring = &sc->cmdq;
518 struct rsu_host_cmd *cmd;
519 int s;
520
521 /* Process host commands. */
522 s = splusb();
523 mutex_spin_enter(&sc->sc_task_mtx);
524
525 while (ring->next != ring->cur) {
526 cmd = &ring->cmd[ring->next];
527 splx(s);
528 membar_consumer();
529 /* Invoke callback. */
530 cmd->cb(sc, cmd->data);
531 s = splusb();
532 atomic_dec_uint(&ring->queued);
533 ring->next = (ring->next + 1) % RSU_HOST_CMD_RING_COUNT;
534 }
535
536 mutex_spin_exit(&sc->sc_task_mtx);
537 splx(s);
538 }
539
540 void
541 rsu_do_async(struct rsu_softc *sc,
542 void (*cb)(struct rsu_softc *, void *), void *arg, int len)
543 {
544 struct rsu_host_cmd_ring *ring = &sc->cmdq;
545 struct rsu_host_cmd *cmd;
546 bool schedtask = false;
547 int s;
548
549 s = splusb();
550 mutex_spin_enter(&sc->sc_task_mtx);
551
552 cmd = &ring->cmd[ring->cur];
553 cmd->cb = cb;
554 KASSERT(len <= sizeof(cmd->data));
555 memcpy(cmd->data, arg, len);
556 ring->cur = (ring->cur + 1) % RSU_HOST_CMD_RING_COUNT;
557
558 /* If there is no pending command already, schedule a task. */
559 if (atomic_inc_uint_nv(&ring->queued) == 1)
560 schedtask = true;
561
562 mutex_spin_exit(&sc->sc_task_mtx);
563 splx(s);
564
565 if (schedtask)
566 usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER);
567 }
568
569 void
570 rsu_wait_async(struct rsu_softc *sc)
571 {
572 /* Wait for all queued asynchronous commands to complete. */
573 mutex_spin_enter(&sc->sc_task_mtx);
574 while (sc->cmdq.queued > 0)
575 cv_wait(&sc->sc_task_cv, &sc->sc_task_mtx);
576 mutex_spin_exit(&sc->sc_task_mtx);
577 }
578
579 int
580 rsu_write_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf,
581 int len)
582 {
583 usb_device_request_t req;
584
585 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
586 req.bRequest = R92S_REQ_REGS;
587 USETW(req.wValue, addr);
588 USETW(req.wIndex, 0);
589 USETW(req.wLength, len);
590 return (usbd_do_request(sc->sc_udev, &req, buf));
591 }
592
593 void
594 rsu_write_1(struct rsu_softc *sc, uint16_t addr, uint8_t val)
595 {
596 rsu_write_region_1(sc, addr, &val, 1);
597 }
598
599 void
600 rsu_write_2(struct rsu_softc *sc, uint16_t addr, uint16_t val)
601 {
602 val = htole16(val);
603 rsu_write_region_1(sc, addr, (uint8_t *)&val, 2);
604 }
605
606 void
607 rsu_write_4(struct rsu_softc *sc, uint16_t addr, uint32_t val)
608 {
609 val = htole32(val);
610 rsu_write_region_1(sc, addr, (uint8_t *)&val, 4);
611 }
612
613 int
614 rsu_read_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf,
615 int len)
616 {
617 usb_device_request_t req;
618
619 req.bmRequestType = UT_READ_VENDOR_DEVICE;
620 req.bRequest = R92S_REQ_REGS;
621 USETW(req.wValue, addr);
622 USETW(req.wIndex, 0);
623 USETW(req.wLength, len);
624 return (usbd_do_request(sc->sc_udev, &req, buf));
625 }
626
627 uint8_t
628 rsu_read_1(struct rsu_softc *sc, uint16_t addr)
629 {
630 uint8_t val;
631
632 if (rsu_read_region_1(sc, addr, &val, 1) != 0)
633 return (0xff);
634 return (val);
635 }
636
637 uint16_t
638 rsu_read_2(struct rsu_softc *sc, uint16_t addr)
639 {
640 uint16_t val;
641
642 if (rsu_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0)
643 return (0xffff);
644 return (le16toh(val));
645 }
646
647 uint32_t
648 rsu_read_4(struct rsu_softc *sc, uint16_t addr)
649 {
650 uint32_t val;
651
652 if (rsu_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0)
653 return (0xffffffff);
654 return (le32toh(val));
655 }
656
657 int
658 rsu_fw_iocmd(struct rsu_softc *sc, uint32_t iocmd)
659 {
660 int ntries;
661
662 rsu_write_4(sc, R92S_IOCMD_CTRL, iocmd);
663 DELAY(100);
664 for (ntries = 0; ntries < 50; ntries++) {
665 if (rsu_read_4(sc, R92S_IOCMD_CTRL) == 0)
666 return (0);
667 DELAY(10);
668 }
669 return (ETIMEDOUT);
670 }
671
672 uint8_t
673 rsu_efuse_read_1(struct rsu_softc *sc, uint16_t addr)
674 {
675 uint32_t reg;
676 int ntries;
677
678 reg = rsu_read_4(sc, R92S_EFUSE_CTRL);
679 reg = RW(reg, R92S_EFUSE_CTRL_ADDR, addr);
680 reg &= ~R92S_EFUSE_CTRL_VALID;
681 rsu_write_4(sc, R92S_EFUSE_CTRL, reg);
682 /* Wait for read operation to complete. */
683 for (ntries = 0; ntries < 100; ntries++) {
684 reg = rsu_read_4(sc, R92S_EFUSE_CTRL);
685 if (reg & R92S_EFUSE_CTRL_VALID)
686 return (MS(reg, R92S_EFUSE_CTRL_DATA));
687 DELAY(5);
688 }
689 printf("%s: could not read efuse byte at address 0x%x\n",
690 device_xname(sc->sc_dev), addr);
691 return (0xff);
692 }
693
694 int
695 rsu_read_rom(struct rsu_softc *sc)
696 {
697 uint8_t *rom = sc->rom;
698 uint16_t addr = 0;
699 uint32_t reg;
700 uint8_t off, msk;
701 int i;
702
703 /* Make sure that ROM type is eFuse and that autoload succeeded. */
704 reg = rsu_read_1(sc, R92S_EE_9346CR);
705 if ((reg & (R92S_9356SEL | R92S_EEPROM_EN)) != R92S_EEPROM_EN)
706 return (EIO);
707
708 /* Turn on 2.5V to prevent eFuse leakage. */
709 reg = rsu_read_1(sc, R92S_EFUSE_TEST + 3);
710 rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg | 0x80);
711 usbd_delay_ms(sc->sc_udev, 10);
712 rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg & ~0x80);
713
714 /* Read full ROM image. */
715 memset(&sc->rom, 0xff, sizeof(sc->rom));
716 while (addr < 512) {
717 reg = rsu_efuse_read_1(sc, addr);
718 if (reg == 0xff)
719 break;
720 addr++;
721 off = reg >> 4;
722 msk = reg & 0xf;
723 for (i = 0; i < 4; i++) {
724 if (msk & (1 << i))
725 continue;
726 rom[off * 8 + i * 2 + 0] =
727 rsu_efuse_read_1(sc, addr);
728 addr++;
729 rom[off * 8 + i * 2 + 1] =
730 rsu_efuse_read_1(sc, addr);
731 addr++;
732 }
733 }
734
735 #ifdef RSU_DEBUG
736 if (rsu_debug >= 5) {
737 /* Dump ROM content. */
738 printf("\n");
739 for (i = 0; i < sizeof(sc->rom); i++)
740 printf("%02x:", rom[i]);
741 printf("\n");
742 }
743 #endif
744 return (0);
745 }
746
747 int
748 rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len)
749 {
750 struct rsu_tx_data *data;
751 struct r92s_tx_desc *txd;
752 struct r92s_fw_cmd_hdr *cmd;
753 int cmdsz, xferlen;
754
755 data = sc->fwcmd_data;
756
757 /* Round-up command length to a multiple of 8 bytes. */
758 cmdsz = (len + 7) & ~7;
759
760 xferlen = sizeof(*txd) + sizeof(*cmd) + cmdsz;
761 KASSERT(xferlen <= RSU_TXBUFSZ);
762 memset(data->buf, 0, xferlen);
763
764 /* Setup Tx descriptor. */
765 txd = (struct r92s_tx_desc *)data->buf;
766 txd->txdw0 = htole32(
767 SM(R92S_TXDW0_OFFSET, sizeof(*txd)) |
768 SM(R92S_TXDW0_PKTLEN, sizeof(*cmd) + cmdsz) |
769 R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG);
770 txd->txdw1 = htole32(SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_H2C));
771
772 /* Setup command header. */
773 cmd = (struct r92s_fw_cmd_hdr *)&txd[1];
774 cmd->len = htole16(cmdsz);
775 cmd->code = code;
776 cmd->seq = sc->cmd_seq;
777 sc->cmd_seq = (sc->cmd_seq + 1) & 0x7f;
778
779 /* Copy command payload. */
780 memcpy(&cmd[1], buf, len);
781
782 DPRINTFN(2, ("Tx cmd code=%d len=%d\n", code, cmdsz));
783 /*pipe = sc->pipe[sc->qid2idx[RSU_QID_H2C]];*/
784 usbd_setup_xfer(data->xfer, data, data->buf, xferlen,
785 USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS,
786 RSU_CMD_TIMEOUT, NULL);
787 return (usbd_transfer(data->xfer));
788 }
789
790 int
791 rsu_media_change(struct ifnet *ifp)
792 {
793 int error;
794
795 error = ieee80211_media_change(ifp);
796 if (error != ENETRESET)
797 return (error);
798
799 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
800 (IFF_UP | IFF_RUNNING)) {
801 rsu_stop(ifp);
802 error = rsu_init(ifp);
803 }
804 return (error);
805 }
806
807 void
808 rsu_calib_to(void *arg)
809 {
810 struct rsu_softc *sc = arg;
811
812 /* Do it in a process context. */
813 rsu_do_async(sc, rsu_calib_cb, NULL, 0);
814 }
815
816 void
817 rsu_calib_cb(struct rsu_softc *sc, void *arg)
818 {
819 uint32_t reg;
820
821 #ifdef notyet
822 /* Read WPS PBC status. */
823 rsu_write_1(sc, R92S_MAC_PINMUX_CTRL,
824 R92S_GPIOMUX_EN | SM(R92S_GPIOSEL_GPIO, R92S_GPIOSEL_GPIO_JTAG));
825 rsu_write_1(sc, R92S_GPIO_IO_SEL,
826 rsu_read_1(sc, R92S_GPIO_IO_SEL) & ~R92S_GPIO_WPS);
827 reg = rsu_read_1(sc, R92S_GPIO_CTRL);
828 if (reg != 0xff && (reg & R92S_GPIO_WPS))
829 DPRINTF(("WPS PBC is pushed\n"));
830 #endif
831
832 /* Read current signal level. */
833 if (rsu_fw_iocmd(sc, 0xf4000001) == 0) {
834 reg = rsu_read_4(sc, R92S_IOCMD_DATA);
835 DPRINTFN(8, ("RSSI=%d%%\n", reg >> 4));
836 }
837 (void)reg;
838
839 callout_schedule(&sc->calib_to, hz);
840 }
841
842 int
843 rsu_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
844 {
845 struct rsu_softc *sc = ic->ic_ifp->if_softc;
846 struct rsu_cmd_newstate cmd;
847
848 callout_stop(&sc->calib_to);
849
850 /* Do it in a process context. */
851 cmd.state = nstate;
852 cmd.arg = arg;
853 rsu_do_async(sc, rsu_newstate_cb, &cmd, sizeof(cmd));
854 return (0);
855 }
856
857 void
858 rsu_newstate_cb(struct rsu_softc *sc, void *arg)
859 {
860 struct rsu_cmd_newstate *cmd = arg;
861 struct ieee80211com *ic = &sc->sc_ic;
862 struct ifnet *ifp = sc->sc_ic.ic_ifp;
863 enum ieee80211_state ostate;
864 int error, s;
865
866 s = splnet();
867 ostate = ic->ic_state;
868
869 if (ostate == IEEE80211_S_RUN) {
870 /* Stop calibration. */
871 callout_halt(&sc->calib_to, NULL);
872 /* Disassociate from our current BSS. */
873 (void)rsu_disconnect(sc);
874 }
875 switch (cmd->state) {
876 case IEEE80211_S_INIT:
877 break;
878 case IEEE80211_S_SCAN:
879 error = rsu_site_survey(sc);
880 if (error != 0) {
881 printf("%s: could not send site survey command\n",
882 device_xname(sc->sc_dev));
883 }
884 if (ifp->if_flags & IFF_DEBUG)
885 printf("%s: %s -> %s\n", ifp->if_xname,
886 ieee80211_state_name[ic->ic_state],
887 ieee80211_state_name[cmd->state]);
888 ic->ic_state = cmd->state;
889 splx(s);
890 return;
891 case IEEE80211_S_AUTH:
892 ic->ic_state = cmd->state;
893 splx(s);
894 return;
895 case IEEE80211_S_ASSOC:
896 /* No-op for this driver. See rsu_event_join_bss(). */
897 if (ifp->if_flags & IFF_DEBUG)
898 printf("%s: %s -> %s\n", ifp->if_xname,
899 ieee80211_state_name[ic->ic_state],
900 ieee80211_state_name[cmd->state]);
901 ic->ic_state = cmd->state;
902 splx(s);
903 return;
904 case IEEE80211_S_RUN:
905 /* Indicate highest supported rate. */
906 ic->ic_bss->ni_txrate = ic->ic_bss->ni_rates.rs_nrates - 1;
907
908 /* Start periodic calibration. */
909 callout_schedule(&sc->calib_to, hz);
910 break;
911 }
912 (void)sc->sc_newstate(ic, cmd->state, cmd->arg);
913 splx(s);
914 }
915
916 int
917 rsu_site_survey(struct rsu_softc *sc)
918 {
919 struct ieee80211com *ic = &sc->sc_ic;
920 struct r92s_fw_cmd_sitesurvey cmd;
921
922 memset(&cmd, 0, sizeof(cmd));
923 if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->scan_pass == 1)
924 cmd.active = htole32(1);
925 cmd.limit = htole32(48);
926 if (sc->scan_pass == 1) {
927 /* Do a directed scan for second pass. */
928 cmd.ssidlen = htole32(ic->ic_des_esslen);
929 memcpy(cmd.ssid, ic->ic_des_essid, ic->ic_des_esslen);
930 }
931 DPRINTF(("sending site survey command, pass=%d\n", sc->scan_pass));
932 return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd)));
933 }
934
935 int
936 rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni)
937 {
938 struct ieee80211com *ic = &sc->sc_ic;
939 struct ndis_wlan_bssid_ex *bss;
940 struct ndis_802_11_fixed_ies *fixed;
941 struct r92s_fw_cmd_auth auth;
942 uint8_t buf[sizeof(*bss) + 128], *frm;
943 uint8_t opmode;
944 int error;
945
946 /* Let the FW decide the opmode based on the capinfo field. */
947 opmode = NDIS802_11AUTOUNKNOWN;
948 DPRINTF(("setting operating mode to %d\n", opmode));
949 error = rsu_fw_cmd(sc, R92S_CMD_SET_OPMODE, &opmode, sizeof(opmode));
950 if (error != 0)
951 return (error);
952
953 memset(&auth, 0, sizeof(auth));
954 auth.mode = R92S_AUTHMODE_OPEN;
955 DPRINTF(("setting auth mode to %d\n", auth.mode));
956 error = rsu_fw_cmd(sc, R92S_CMD_SET_AUTH, &auth, sizeof(auth));
957 if (error != 0)
958 return (error);
959
960 memset(buf, 0, sizeof(buf));
961 bss = (struct ndis_wlan_bssid_ex *)buf;
962 IEEE80211_ADDR_COPY(bss->macaddr, ni->ni_bssid);
963 bss->ssid.ssidlen = htole32(ni->ni_esslen);
964 memcpy(bss->ssid.ssid, ni->ni_essid, ni->ni_esslen);
965 bss->rssi = htole32(ni->ni_rssi);
966 if (ic->ic_curmode == IEEE80211_MODE_11B)
967 bss->networktype = htole32(NDIS802_11DS);
968 else
969 bss->networktype = htole32(NDIS802_11OFDM24);
970 bss->config.len = htole32(sizeof(bss->config));
971 bss->config.bintval = htole32(ni->ni_intval);
972 bss->config.dsconfig = htole32(ieee80211_chan2ieee(ic, ni->ni_chan));
973 bss->inframode = htole32(NDIS802_11INFRASTRUCTURE);
974 memcpy(bss->supprates, ni->ni_rates.rs_rates,
975 ni->ni_rates.rs_nrates);
976 /* Write the fixed fields of the beacon frame. */
977 fixed = (struct ndis_802_11_fixed_ies *)&bss[1];
978 memcpy(&fixed->tstamp, ni->ni_tstamp.data, 8);
979 fixed->bintval = htole16(ni->ni_intval);
980 fixed->capabilities = htole16(ni->ni_capinfo);
981 /* Write IEs to be included in the association request. */
982 frm = (uint8_t *)&fixed[1];
983 bss->ieslen = htole32(frm - (uint8_t *)fixed);
984 bss->len = htole32(((frm - buf) + 3) & ~3);
985 DPRINTF(("sending join bss command to %s chan %d\n",
986 ether_sprintf(bss->macaddr), le32toh(bss->config.dsconfig)));
987 return (rsu_fw_cmd(sc, R92S_CMD_JOIN_BSS, buf, sizeof(buf)));
988 }
989
990 int
991 rsu_disconnect(struct rsu_softc *sc)
992 {
993 uint32_t zero = 0; /* :-) */
994
995 /* Disassociate from our current BSS. */
996 DPRINTF(("sending disconnect command\n"));
997 return (rsu_fw_cmd(sc, R92S_CMD_DISCONNECT, &zero, sizeof(zero)));
998 }
999
1000 void
1001 rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
1002 {
1003 struct ieee80211com *ic = &sc->sc_ic;
1004 struct ieee80211_node *ni;
1005 struct ieee80211_frame *wh;
1006 struct ndis_wlan_bssid_ex *bss;
1007 struct mbuf *m;
1008 uint32_t pktlen, ieslen;
1009
1010 if (__predict_false(len < sizeof(*bss)))
1011 return;
1012 bss = (struct ndis_wlan_bssid_ex *)buf;
1013 ieslen = le32toh(bss->ieslen);
1014 if (ieslen > len - sizeof(*bss))
1015 return;
1016
1017 DPRINTFN(2, ("found BSS %s: len=%d chan=%d inframode=%d "
1018 "networktype=%d privacy=%d\n",
1019 ether_sprintf(bss->macaddr), le32toh(bss->len),
1020 le32toh(bss->config.dsconfig), le32toh(bss->inframode),
1021 le32toh(bss->networktype), le32toh(bss->privacy)));
1022
1023 /* Build a fake beacon frame to let net80211 do all the parsing. */
1024 pktlen = sizeof(*wh) + ieslen;
1025 if (__predict_false(pktlen > MCLBYTES))
1026 return;
1027 MGETHDR(m, M_DONTWAIT, MT_DATA);
1028 if (__predict_false(m == NULL))
1029 return;
1030 if (pktlen > MHLEN) {
1031 MCLGET(m, M_DONTWAIT);
1032 if (!(m->m_flags & M_EXT)) {
1033 m_free(m);
1034 return;
1035 }
1036 }
1037 wh = mtod(m, struct ieee80211_frame *);
1038 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
1039 IEEE80211_FC0_SUBTYPE_BEACON;
1040 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1041 *(uint16_t *)wh->i_dur = 0;
1042 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
1043 IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr);
1044 IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr);
1045 *(uint16_t *)wh->i_seq = 0;
1046 memcpy(&wh[1], (uint8_t *)&bss[1], ieslen);
1047
1048 /* Finalize mbuf. */
1049 m->m_pkthdr.len = m->m_len = pktlen;
1050
1051 ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
1052 ieee80211_input(ic, m, ni, le32toh(bss->rssi), 0);
1053 /* Node is no longer needed. */
1054 ieee80211_free_node(ni);
1055 }
1056
1057 void
1058 rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len)
1059 {
1060 struct ieee80211com *ic = &sc->sc_ic;
1061 struct ieee80211_node *ni = ic->ic_bss;
1062 struct r92s_event_join_bss *rsp;
1063 int res;
1064
1065 if (__predict_false(len < sizeof(*rsp)))
1066 return;
1067 rsp = (struct r92s_event_join_bss *)buf;
1068 res = (int)le32toh(rsp->join_res);
1069
1070 DPRINTF(("Rx join BSS event len=%d res=%d\n", len, res));
1071 if (res <= 0) {
1072 ic->ic_stats.is_rx_auth_fail++;
1073 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1074 return;
1075 }
1076 DPRINTF(("associated with %s associd=%d\n",
1077 ether_sprintf(rsp->bss.macaddr), le32toh(rsp->associd)));
1078
1079 ni->ni_associd = le32toh(rsp->associd) | 0xc000;
1080
1081 /* Force an ASSOC->RUN transition. AUTH->RUN is invalid. */
1082 ic->ic_state = IEEE80211_S_ASSOC;
1083 ieee80211_new_state(ic, IEEE80211_S_RUN,
1084 IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
1085 }
1086
1087 void
1088 rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len)
1089 {
1090 struct ieee80211com *ic = &sc->sc_ic;
1091 struct ifnet *ifp = sc->sc_ic.ic_ifp;
1092
1093 DPRINTFN(4, ("Rx event code=%d len=%d\n", code, len));
1094 switch (code) {
1095 case R92S_EVT_SURVEY:
1096 if (ic->ic_state == IEEE80211_S_SCAN)
1097 rsu_event_survey(sc, buf, len);
1098 break;
1099 case R92S_EVT_SURVEY_DONE:
1100 DPRINTF(("site survey pass %d done, found %d BSS\n",
1101 sc->scan_pass, le32toh(*(uint32_t *)buf)));
1102 if (ic->ic_state != IEEE80211_S_SCAN)
1103 break; /* Ignore if not scanning. */
1104 if (sc->scan_pass == 0 && ic->ic_des_esslen != 0) {
1105 /* Schedule a directed scan for hidden APs. */
1106 sc->scan_pass = 1;
1107 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1108 break;
1109 }
1110 sc->scan_pass = 0;
1111 break;
1112 case R92S_EVT_JOIN_BSS:
1113 if (ic->ic_state == IEEE80211_S_AUTH)
1114 rsu_event_join_bss(sc, buf, len);
1115 break;
1116 case R92S_EVT_DEL_STA:
1117 DPRINTF(("disassociated from %s\n", ether_sprintf(buf)));
1118 if (ic->ic_state == IEEE80211_S_RUN &&
1119 IEEE80211_ADDR_EQ(ic->ic_bss->ni_bssid, buf))
1120 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1121 break;
1122 case R92S_EVT_WPS_PBC:
1123 DPRINTF(("WPS PBC pushed.\n"));
1124 break;
1125 case R92S_EVT_FWDBG:
1126 if (ifp->if_flags & IFF_DEBUG) {
1127 buf[60] = '\0';
1128 printf("FWDBG: %s\n", (char *)buf);
1129 }
1130 break;
1131 }
1132 }
1133
1134 void
1135 rsu_rx_multi_event(struct rsu_softc *sc, uint8_t *buf, int len)
1136 {
1137 struct r92s_fw_cmd_hdr *cmd;
1138 int cmdsz;
1139
1140 DPRINTFN(6, ("Rx events len=%d\n", len));
1141
1142 /* Skip Rx status. */
1143 buf += sizeof(struct r92s_rx_stat);
1144 len -= sizeof(struct r92s_rx_stat);
1145
1146 /* Process all events. */
1147 for (;;) {
1148 /* Check that command header fits. */
1149 if (__predict_false(len < sizeof(*cmd)))
1150 break;
1151 cmd = (struct r92s_fw_cmd_hdr *)buf;
1152 /* Check that command payload fits. */
1153 cmdsz = le16toh(cmd->len);
1154 if (__predict_false(len < sizeof(*cmd) + cmdsz))
1155 break;
1156 if (cmdsz > len)
1157 break;
1158
1159 /* Process firmware event. */
1160 rsu_rx_event(sc, cmd->code, (uint8_t *)&cmd[1], cmdsz);
1161
1162 if (!(cmd->seq & R92S_FW_CMD_MORE))
1163 break;
1164 buf += sizeof(*cmd) + cmdsz;
1165 len -= sizeof(*cmd) + cmdsz;
1166 }
1167 }
1168
1169 int8_t
1170 rsu_get_rssi(struct rsu_softc *sc, int rate, void *physt)
1171 {
1172 static const int8_t cckoff[] = { 14, -2, -20, -40 };
1173 struct r92s_rx_phystat *phy;
1174 struct r92s_rx_cck *cck;
1175 uint8_t rpt;
1176 int8_t rssi;
1177
1178 if (rate <= 3) {
1179 cck = (struct r92s_rx_cck *)physt;
1180 rpt = (cck->agc_rpt >> 6) & 0x3;
1181 rssi = cck->agc_rpt & 0x3e;
1182 rssi = cckoff[rpt] - rssi;
1183 } else { /* OFDM/HT. */
1184 phy = (struct r92s_rx_phystat *)physt;
1185 rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 106;
1186 }
1187 return (rssi);
1188 }
1189
1190 void
1191 rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen)
1192 {
1193 struct ieee80211com *ic = &sc->sc_ic;
1194 struct ifnet *ifp = sc->sc_ic.ic_ifp;
1195 struct ieee80211_frame *wh;
1196 struct ieee80211_node *ni;
1197 struct r92s_rx_stat *stat;
1198 uint32_t rxdw0, rxdw3;
1199 struct mbuf *m;
1200 uint8_t rate;
1201 int8_t rssi = 0;
1202 int s, infosz;
1203
1204 stat = (struct r92s_rx_stat *)buf;
1205 rxdw0 = le32toh(stat->rxdw0);
1206 rxdw3 = le32toh(stat->rxdw3);
1207
1208 if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) {
1209 if_statinc(ifp, if_ierrors);
1210 return;
1211 }
1212 if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) {
1213 if_statinc(ifp, if_ierrors);
1214 return;
1215 }
1216
1217 rate = MS(rxdw3, R92S_RXDW3_RATE);
1218 infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8;
1219
1220 /* Get RSSI from PHY status descriptor if present. */
1221 if (infosz != 0)
1222 rssi = rsu_get_rssi(sc, rate, &stat[1]);
1223
1224 DPRINTFN(5, ("Rx frame len=%d rate=%d infosz=%d rssi=%d\n",
1225 pktlen, rate, infosz, rssi));
1226
1227 MGETHDR(m, M_DONTWAIT, MT_DATA);
1228 if (__predict_false(m == NULL)) {
1229 if_statinc(ifp, if_ierrors);
1230 return;
1231 }
1232 if (pktlen > MHLEN) {
1233 MCLGET(m, M_DONTWAIT);
1234 if (__predict_false(!(m->m_flags & M_EXT))) {
1235 if_statinc(ifp, if_ierrors);
1236 m_freem(m);
1237 return;
1238 }
1239 }
1240 /* Finalize mbuf. */
1241 m_set_rcvif(m, ifp);
1242
1243 /* Hardware does Rx TCP checksum offload. */
1244 if (rxdw3 & R92S_RXDW3_TCPCHKVALID) {
1245 if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT))
1246 m->m_pkthdr.csum_flags |= M_CSUM_TCPv4;
1247 else
1248 m->m_pkthdr.csum_flags |= M_CSUM_TCP_UDP_BAD;
1249 }
1250 wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz);
1251 memcpy(mtod(m, uint8_t *), wh, pktlen);
1252 m->m_pkthdr.len = m->m_len = pktlen;
1253
1254 s = splnet();
1255
1256 ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
1257 ieee80211_input(ic, m, ni, rssi, 0);
1258 /* Node is no longer needed. */
1259 ieee80211_free_node(ni);
1260 splx(s);
1261 }
1262
1263 void
1264 rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len)
1265 {
1266 struct r92s_rx_stat *stat;
1267 uint32_t rxdw0;
1268 int totlen, pktlen, infosz, npkts;
1269
1270 /* Get the number of encapsulated frames. */
1271 stat = (struct r92s_rx_stat *)buf;
1272 npkts = MS(le32toh(stat->rxdw2), R92S_RXDW2_PKTCNT);
1273 DPRINTFN(6, ("Rx %d frames in one chunk\n", npkts));
1274
1275 /* Process all of them. */
1276 while (npkts-- > 0) {
1277 if (__predict_false(len < sizeof(*stat)))
1278 break;
1279 stat = (struct r92s_rx_stat *)buf;
1280 rxdw0 = le32toh(stat->rxdw0);
1281
1282 pktlen = MS(rxdw0, R92S_RXDW0_PKTLEN);
1283 if (__predict_false(pktlen == 0))
1284 break;
1285
1286 infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8;
1287
1288 /* Make sure everything fits in xfer. */
1289 totlen = sizeof(*stat) + infosz + pktlen;
1290 if (__predict_false(totlen > len))
1291 break;
1292
1293 /* Process 802.11 frame. */
1294 rsu_rx_frame(sc, buf, pktlen);
1295
1296 /* Next chunk is 128-byte aligned. */
1297 totlen = (totlen + 127) & ~127;
1298 buf += totlen;
1299 len -= totlen;
1300 }
1301 }
1302
1303 void
1304 rsu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
1305 {
1306 struct rsu_rx_data *data = priv;
1307 struct rsu_softc *sc = data->sc;
1308 struct r92s_rx_stat *stat;
1309 struct ifnet *ifp = sc->sc_ic.ic_ifp;
1310 int len;
1311
1312 if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
1313 DPRINTF(("RX status=%d\n", status));
1314 if (status == USBD_STALLED)
1315 usbd_clear_endpoint_stall_async(data->pipe);
1316 if (status != USBD_CANCELLED)
1317 goto resubmit;
1318 return;
1319 }
1320 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
1321
1322 if (__predict_false(len < sizeof(*stat))) {
1323 DPRINTF(("xfer too short %d\n", len));
1324 if_statinc(ifp, if_ierrors);
1325 goto resubmit;
1326 }
1327 if (len > RSU_RXBUFSZ) {
1328 DPRINTF(("xfer too large %d\n", len));
1329 if_statinc(ifp, if_ierrors);
1330 goto resubmit;
1331 }
1332
1333 /* Determine if it is a firmware C2H event or an 802.11 frame. */
1334 stat = (struct r92s_rx_stat *)data->buf;
1335 if ((le32toh(stat->rxdw1) & 0x1ff) == 0x1ff)
1336 rsu_rx_multi_event(sc, data->buf, len);
1337 else
1338 rsu_rx_multi_frame(sc, data->buf, len);
1339
1340 resubmit:
1341 /* Setup a new transfer. */
1342 usbd_setup_xfer(xfer, data, data->buf, RSU_RXBUFSZ,
1343 USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, rsu_rxeof);
1344 (void)usbd_transfer(xfer);
1345 }
1346
1347 void
1348 rsu_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
1349 {
1350 struct rsu_tx_data *data = priv;
1351 struct rsu_softc *sc = data->sc;
1352 struct ifnet *ifp = sc->sc_ic.ic_ifp;
1353 int s;
1354
1355 s = splnet();
1356
1357 /* Put this Tx buffer back to our free list. */
1358 mutex_enter(&sc->sc_tx_mtx);
1359 TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
1360 mutex_exit(&sc->sc_tx_mtx);
1361
1362 if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
1363 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1364 return;
1365
1366 DPRINTF(("TX status=%d\n", status));
1367 if (status == USBD_STALLED)
1368 usbd_clear_endpoint_stall_async(data->pipe);
1369 if_statinc(ifp, if_oerrors);
1370 splx(s);
1371 return;
1372 }
1373 sc->sc_tx_timer = 0;
1374
1375 /* We just released a Tx buffer, notify Tx. */
1376 if (ifp->if_flags & IFF_OACTIVE) {
1377 ifp->if_flags &= ~IFF_OACTIVE;
1378 rsu_start(ifp);
1379 }
1380 splx(s);
1381 }
1382
1383 int
1384 rsu_tx(struct rsu_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
1385 {
1386 struct ieee80211_frame *wh;
1387 struct rsu_tx_data *data;
1388 struct r92s_tx_desc *txd;
1389 struct usbd_pipe *pipe;
1390 uint16_t qos;
1391 uint8_t qid, tid = 0;
1392 int hasqos, xferlen, error;
1393
1394 wh = mtod(m, struct ieee80211_frame *);
1395
1396 #ifdef notyet
1397 if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
1398 k = ieee80211_get_txkey(ic, wh, ni);
1399 if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
1400 return (ENOBUFS);
1401 wh = mtod(m, struct ieee80211_frame *);
1402 }
1403 #endif
1404
1405 if ((hasqos = ieee80211_has_qos(wh))) {
1406 qos = ieee80211_get_qos(wh);
1407 tid = qos & IEEE80211_QOS_TID;
1408 qid = rsu_ac2qid[TID_TO_WME_AC(tid)];
1409 } else
1410 qid = RSU_QID_BE;
1411
1412 /* Get the USB pipe to use for this queue id. */
1413 pipe = sc->pipe[sc->qid2idx[qid]];
1414
1415 /* Grab a Tx buffer from our free list. */
1416 mutex_enter(&sc->sc_tx_mtx);
1417 data = TAILQ_FIRST(&sc->tx_free_list);
1418 TAILQ_REMOVE(&sc->tx_free_list, data, next);
1419 mutex_exit(&sc->sc_tx_mtx);
1420
1421 /* Fill Tx descriptor. */
1422 txd = (struct r92s_tx_desc *)data->buf;
1423 memset(txd, 0, sizeof(*txd));
1424
1425 txd->txdw0 |= htole32(
1426 SM(R92S_TXDW0_PKTLEN, m->m_pkthdr.len) |
1427 SM(R92S_TXDW0_OFFSET, sizeof(*txd)) |
1428 R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG);
1429
1430 txd->txdw1 |= htole32(
1431 SM(R92S_TXDW1_MACID, R92S_MACID_BSS) |
1432 SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_BE));
1433 if (!hasqos)
1434 txd->txdw1 |= htole32(R92S_TXDW1_NONQOS);
1435 #ifdef notyet
1436 if (k != NULL) {
1437 switch (k->k_cipher) {
1438 case IEEE80211_CIPHER_WEP:
1439 k->wk_flags |= IEEE80211_KEY_GROUP; /* XXX */
1440 if (k->wk_keylen == 5)
1441 mode = RT2860_MODE_WEP40;
1442 else
1443 mode = RT2860_MODE_WEP104;
1444 break;
1445 case IEEE80211_CIPHER_TKIP:
1446 cipher = R92S_TXDW1_CIPHER_TKIP;
1447 break;
1448 case IEEE80211_CIPHER_AES_CCM:
1449 cipher = R92S_TXDW1_CIPHER_AES;
1450 break;
1451 default:
1452 cipher = R92S_TXDW1_CIPHER_NONE;
1453 }
1454 txd->txdw1 |= htole32(
1455 SM(R92S_TXDW1_CIPHER, cipher) |
1456 SM(R92S_TXDW1_KEYIDX, k->k_id));
1457 }
1458 #endif
1459 txd->txdw2 |= htole32(R92S_TXDW2_BK);
1460 if (IEEE80211_IS_MULTICAST(wh->i_addr1))
1461 txd->txdw2 |= htole32(R92S_TXDW2_BMCAST);
1462 /*
1463 * Firmware will use and increment the sequence number for the
1464 * specified TID.
1465 */
1466 txd->txdw3 |= htole32(SM(R92S_TXDW3_SEQ, tid));
1467
1468 xferlen = sizeof(*txd) + m->m_pkthdr.len;
1469 m_copydata(m, 0, m->m_pkthdr.len, &txd[1]);
1470 m_freem(m);
1471
1472 data->pipe = pipe;
1473 usbd_setup_xfer(data->xfer, data, data->buf, xferlen,
1474 USBD_FORCE_SHORT_XFER, RSU_TX_TIMEOUT,
1475 rsu_txeof);
1476 error = usbd_transfer(data->xfer);
1477 if (__predict_false(error != USBD_IN_PROGRESS && error != 0)) {
1478 /* Put this Tx buffer back to our free list. */
1479 mutex_enter(&sc->sc_tx_mtx);
1480 TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
1481 mutex_exit(&sc->sc_tx_mtx);
1482 return (error);
1483 }
1484 ieee80211_free_node(ni);
1485 return (0);
1486 }
1487
1488 void
1489 rsu_start(struct ifnet *ifp)
1490 {
1491 struct rsu_softc *sc = ifp->if_softc;
1492 struct ieee80211com *ic = &sc->sc_ic;
1493 struct ether_header *eh;
1494 struct ieee80211_node *ni;
1495 struct mbuf *m;
1496
1497 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
1498 return;
1499
1500 for (;;) {
1501 if (TAILQ_EMPTY(&sc->tx_free_list)) {
1502 ifp->if_flags |= IFF_OACTIVE;
1503 break;
1504 }
1505 if (ic->ic_state != IEEE80211_S_RUN)
1506 break;
1507
1508 /* Encapsulate and send data frames. */
1509 IFQ_DEQUEUE(&ifp->if_snd, m);
1510 if (m == NULL)
1511 break;
1512
1513 eh = mtod(m, struct ether_header *);
1514 ni = ieee80211_find_txnode(ic, eh->ether_dhost);
1515 if (ni == NULL) {
1516 m_freem(m);
1517 if_statinc(ifp, if_oerrors);
1518 continue;
1519 }
1520
1521 if ((m = ieee80211_encap(ic, m, ni)) == NULL) {
1522 ieee80211_free_node(ni);
1523 if_statinc(ifp, if_oerrors);
1524 continue;
1525 }
1526
1527 if (rsu_tx(sc, m, ni) != 0) {
1528 ieee80211_free_node(ni);
1529 if_statinc(ifp, if_oerrors);
1530 continue;
1531 }
1532
1533 sc->sc_tx_timer = 5;
1534 ifp->if_timer = 1;
1535 }
1536 }
1537
1538 void
1539 rsu_watchdog(struct ifnet *ifp)
1540 {
1541 struct rsu_softc *sc = ifp->if_softc;
1542
1543 ifp->if_timer = 0;
1544
1545 if (sc->sc_tx_timer > 0) {
1546 if (--sc->sc_tx_timer == 0) {
1547 printf("%s: device timeout\n",
1548 device_xname(sc->sc_dev));
1549 /* rsu_init(ifp); XXX needs a process context! */
1550 if_statinc(ifp, if_oerrors);
1551 return;
1552 }
1553 ifp->if_timer = 1;
1554 }
1555 ieee80211_watchdog(&sc->sc_ic);
1556 }
1557
1558 int
1559 rsu_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1560 {
1561 struct rsu_softc *sc = ifp->if_softc;
1562 struct ieee80211com *ic = &sc->sc_ic;
1563 int s, error = 0;
1564
1565 s = splnet();
1566
1567 switch (cmd) {
1568 case SIOCSIFADDR:
1569 ifp->if_flags |= IFF_UP;
1570 /* FALLTHROUGH */
1571 case SIOCSIFFLAGS:
1572 switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
1573 case IFF_UP|IFF_RUNNING:
1574 break;
1575 case IFF_UP:
1576 rsu_init(ifp);
1577 break;
1578 case IFF_RUNNING:
1579 rsu_stop(ifp);
1580 break;
1581 case 0:
1582 break;
1583 }
1584 break;
1585 default:
1586 error = ieee80211_ioctl(ic, cmd, data);
1587 }
1588
1589 if (error == ENETRESET) {
1590 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
1591 (IFF_UP | IFF_RUNNING)) {
1592 rsu_stop(ifp);
1593 rsu_init(ifp);
1594 }
1595 error = 0;
1596 }
1597 splx(s);
1598
1599 return (error);
1600 }
1601
1602 /*
1603 * Power on sequence for A-cut adapters.
1604 */
1605 void
1606 rsu_power_on_acut(struct rsu_softc *sc)
1607 {
1608 uint32_t reg;
1609
1610 rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53);
1611 rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57);
1612
1613 /* Enable AFE macro block's bandgap and Mbias. */
1614 rsu_write_1(sc, R92S_AFE_MISC,
1615 rsu_read_1(sc, R92S_AFE_MISC) |
1616 R92S_AFE_MISC_BGEN | R92S_AFE_MISC_MBEN);
1617 /* Enable LDOA15 block. */
1618 rsu_write_1(sc, R92S_LDOA15_CTRL,
1619 rsu_read_1(sc, R92S_LDOA15_CTRL) | R92S_LDA15_EN);
1620
1621 rsu_write_1(sc, R92S_SPS1_CTRL,
1622 rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_LDEN);
1623 usbd_delay_ms(sc->sc_udev, 2);
1624 /* Enable switch regulator block. */
1625 rsu_write_1(sc, R92S_SPS1_CTRL,
1626 rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_SWEN);
1627
1628 rsu_write_4(sc, R92S_SPS1_CTRL, 0x00a7b267);
1629
1630 rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
1631 rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) | 0x08);
1632
1633 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1634 rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x20);
1635
1636 rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
1637 rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) & ~0x90);
1638
1639 /* Enable AFE clock. */
1640 rsu_write_1(sc, R92S_AFE_XTAL_CTRL + 1,
1641 rsu_read_1(sc, R92S_AFE_XTAL_CTRL + 1) & ~0x04);
1642 /* Enable AFE PLL macro block. */
1643 rsu_write_1(sc, R92S_AFE_PLL_CTRL,
1644 rsu_read_1(sc, R92S_AFE_PLL_CTRL) | 0x11);
1645 /* Attach AFE PLL to MACTOP/BB. */
1646 rsu_write_1(sc, R92S_SYS_ISO_CTRL,
1647 rsu_read_1(sc, R92S_SYS_ISO_CTRL) & ~0x11);
1648
1649 /* Switch to 40MHz clock instead of 80MHz. */
1650 rsu_write_2(sc, R92S_SYS_CLKR,
1651 rsu_read_2(sc, R92S_SYS_CLKR) & ~R92S_SYS_CLKSEL);
1652
1653 /* Enable MAC clock. */
1654 rsu_write_2(sc, R92S_SYS_CLKR,
1655 rsu_read_2(sc, R92S_SYS_CLKR) |
1656 R92S_MAC_CLK_EN | R92S_SYS_CLK_EN);
1657
1658 rsu_write_1(sc, R92S_PMC_FSM, 0x02);
1659
1660 /* Enable digital core and IOREG R/W. */
1661 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1662 rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x08);
1663
1664 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1665 rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x80);
1666
1667 /* Switch the control path to firmware. */
1668 reg = rsu_read_2(sc, R92S_SYS_CLKR);
1669 reg = (reg & ~R92S_SWHW_SEL) | R92S_FWHW_SEL;
1670 rsu_write_2(sc, R92S_SYS_CLKR, reg);
1671
1672 rsu_write_2(sc, R92S_CR, 0x37fc);
1673
1674 /* Fix USB RX FIFO issue. */
1675 rsu_write_1(sc, 0xfe5c,
1676 rsu_read_1(sc, 0xfe5c) | 0x80);
1677 rsu_write_1(sc, 0x00ab,
1678 rsu_read_1(sc, 0x00ab) | 0xc0);
1679
1680 rsu_write_1(sc, R92S_SYS_CLKR,
1681 rsu_read_1(sc, R92S_SYS_CLKR) & ~R92S_SYS_CPU_CLKSEL);
1682 }
1683
1684 /*
1685 * Power on sequence for B-cut and C-cut adapters.
1686 */
1687 void
1688 rsu_power_on_bcut(struct rsu_softc *sc)
1689 {
1690 uint32_t reg;
1691 int ntries;
1692
1693 /* Prevent eFuse leakage. */
1694 rsu_write_1(sc, 0x37, 0xb0);
1695 usbd_delay_ms(sc->sc_udev, 10);
1696 rsu_write_1(sc, 0x37, 0x30);
1697
1698 /* Switch the control path to hardware. */
1699 reg = rsu_read_2(sc, R92S_SYS_CLKR);
1700 if (reg & R92S_FWHW_SEL) {
1701 rsu_write_2(sc, R92S_SYS_CLKR,
1702 reg & ~(R92S_SWHW_SEL | R92S_FWHW_SEL));
1703 }
1704 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1705 rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) & ~0x8c);
1706 usbd_delay_ms(sc->sc_udev, 10);
1707
1708 rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53);
1709 rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57);
1710
1711 reg = rsu_read_1(sc, R92S_AFE_MISC);
1712 rsu_write_1(sc, R92S_AFE_MISC, reg | R92S_AFE_MISC_BGEN);
1713 rsu_write_1(sc, R92S_AFE_MISC, reg | R92S_AFE_MISC_BGEN |
1714 R92S_AFE_MISC_MBEN | R92S_AFE_MISC_I32_EN);
1715
1716 /* Enable PLL. */
1717 rsu_write_1(sc, R92S_LDOA15_CTRL,
1718 rsu_read_1(sc, R92S_LDOA15_CTRL) | R92S_LDA15_EN);
1719
1720 rsu_write_1(sc, R92S_LDOV12D_CTRL,
1721 rsu_read_1(sc, R92S_LDOV12D_CTRL) | R92S_LDV12_EN);
1722
1723 rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
1724 rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) | 0x08);
1725
1726 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1727 rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x20);
1728
1729 /* Support 64KB IMEM. */
1730 rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
1731 rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) & ~0x97);
1732
1733 /* Enable AFE clock. */
1734 rsu_write_1(sc, R92S_AFE_XTAL_CTRL + 1,
1735 rsu_read_1(sc, R92S_AFE_XTAL_CTRL + 1) & ~0x04);
1736 /* Enable AFE PLL macro block. */
1737 reg = rsu_read_1(sc, R92S_AFE_PLL_CTRL);
1738 rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11);
1739 usbd_delay_ms(sc->sc_udev, 5);
1740 rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x51);
1741 usbd_delay_ms(sc->sc_udev, 5);
1742 rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11);
1743 usbd_delay_ms(sc->sc_udev, 5);
1744
1745 /* Attach AFE PLL to MACTOP/BB. */
1746 rsu_write_1(sc, R92S_SYS_ISO_CTRL,
1747 rsu_read_1(sc, R92S_SYS_ISO_CTRL) & ~0x11);
1748
1749 /* Switch to 40MHz clock. */
1750 rsu_write_1(sc, R92S_SYS_CLKR, 0x00);
1751 /* Disable CPU clock and 80MHz SSC. */
1752 rsu_write_1(sc, R92S_SYS_CLKR,
1753 rsu_read_1(sc, R92S_SYS_CLKR) | 0xa0);
1754 /* Enable MAC clock. */
1755 rsu_write_2(sc, R92S_SYS_CLKR,
1756 rsu_read_2(sc, R92S_SYS_CLKR) |
1757 R92S_MAC_CLK_EN | R92S_SYS_CLK_EN);
1758
1759 rsu_write_1(sc, R92S_PMC_FSM, 0x02);
1760
1761 /* Enable digital core and IOREG R/W. */
1762 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1763 rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x08);
1764
1765 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1766 rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x80);
1767
1768 /* Switch the control path to firmware. */
1769 reg = rsu_read_2(sc, R92S_SYS_CLKR);
1770 reg = (reg & ~R92S_SWHW_SEL) | R92S_FWHW_SEL;
1771 rsu_write_2(sc, R92S_SYS_CLKR, reg);
1772
1773 rsu_write_2(sc, R92S_CR, 0x37fc);
1774
1775 /* Fix USB RX FIFO issue. */
1776 rsu_write_1(sc, 0xfe5c,
1777 rsu_read_1(sc, 0xfe5c) | 0x80);
1778
1779 rsu_write_1(sc, R92S_SYS_CLKR,
1780 rsu_read_1(sc, R92S_SYS_CLKR) & ~R92S_SYS_CPU_CLKSEL);
1781
1782 rsu_write_1(sc, 0xfe1c, 0x80);
1783
1784 /* Make sure TxDMA is ready to download firmware. */
1785 for (ntries = 0; ntries < 20; ntries++) {
1786 reg = rsu_read_1(sc, R92S_TCR);
1787 if ((reg & (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT)) ==
1788 (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT))
1789 break;
1790 DELAY(5);
1791 }
1792 if (ntries == 20) {
1793 /* Reset TxDMA. */
1794 reg = rsu_read_1(sc, R92S_CR);
1795 rsu_write_1(sc, R92S_CR, reg & ~R92S_CR_TXDMA_EN);
1796 DELAY(2);
1797 rsu_write_1(sc, R92S_CR, reg | R92S_CR_TXDMA_EN);
1798 }
1799 }
1800
1801 void
1802 rsu_power_off(struct rsu_softc *sc)
1803 {
1804 /* Turn RF off. */
1805 rsu_write_1(sc, R92S_RF_CTRL, 0x00);
1806 usbd_delay_ms(sc->sc_udev, 5);
1807
1808 /* Turn MAC off. */
1809 /* Switch control path. */
1810 rsu_write_1(sc, R92S_SYS_CLKR + 1, 0x38);
1811 /* Reset MACTOP. */
1812 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 0x70);
1813 rsu_write_1(sc, R92S_PMC_FSM, 0x06);
1814 rsu_write_1(sc, R92S_SYS_ISO_CTRL + 0, 0xf9);
1815 rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1, 0xe8);
1816
1817 /* Disable AFE PLL. */
1818 rsu_write_1(sc, R92S_AFE_PLL_CTRL, 0x00);
1819 /* Disable A15V. */
1820 rsu_write_1(sc, R92S_LDOA15_CTRL, 0x54);
1821 /* Disable eFuse 1.2V. */
1822 rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 0x50);
1823 rsu_write_1(sc, R92S_LDOV12D_CTRL, 0x24);
1824 /* Enable AFE macro block's bandgap and Mbias. */
1825 rsu_write_1(sc, R92S_AFE_MISC, 0x30);
1826 /* Disable 1.6V LDO. */
1827 rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x56);
1828 rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x43);
1829 }
1830
1831 int
1832 rsu_fw_loadsection(struct rsu_softc *sc, uint8_t *buf, int len)
1833 {
1834 struct rsu_tx_data *data;
1835 struct r92s_tx_desc *txd;
1836 /*struct usbd_pipe *pipe;*/
1837 int mlen, error;
1838
1839 data = sc->fwcmd_data;
1840 /*pipe = sc->pipe[sc->qid2idx[RSU_QID_VO]];*/
1841 txd = (struct r92s_tx_desc *)data->buf;
1842 while (len > 0) {
1843 memset(txd, 0, sizeof(*txd));
1844 if (len <= RSU_TXBUFSZ - sizeof(*txd)) {
1845 /* Last chunk. */
1846 txd->txdw0 |= htole32(R92S_TXDW0_LINIP);
1847 mlen = len;
1848 } else
1849 mlen = RSU_TXBUFSZ - sizeof(*txd);
1850 txd->txdw0 |= htole32(SM(R92S_TXDW0_PKTLEN, mlen));
1851 memcpy(&txd[1], buf, mlen);
1852
1853 usbd_setup_xfer(data->xfer, data, data->buf,
1854 sizeof(*txd) + mlen,
1855 USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS,
1856 RSU_TX_TIMEOUT, NULL);
1857 error = usbd_transfer(data->xfer);
1858 if (error != 0)
1859 return (error);
1860 buf += mlen;
1861 len -= mlen;
1862 }
1863 return (0);
1864 }
1865
1866 int
1867 rsu_load_firmware(struct rsu_softc *sc)
1868 {
1869 struct r92s_fw_hdr *hdr;
1870 struct r92s_fw_priv *dmem;
1871 uint8_t *imem, *emem;
1872 int imemsz, ememsz;
1873 u_char *fw;
1874 size_t size;
1875 uint32_t reg;
1876 int ntries, error;
1877 firmware_handle_t fh;
1878
1879 if ((error = firmware_open("rsu", "rsu-rtl8712", &fh)) != 0) {
1880 printf("%s: failed firmware_open of file %s (error %d)\n",
1881 device_xname(sc->sc_dev), "rsu-rtl8712", error);
1882 return error;
1883 }
1884
1885 size = firmware_get_size(fh);
1886 if ((fw = firmware_malloc(size)) == NULL) {
1887 firmware_close(fh);
1888 return ENOMEM;
1889 }
1890
1891 if ((error = firmware_read(fh, 0, fw, size)) != 0) {
1892 firmware_close(fh);
1893 goto fail;
1894 }
1895
1896 firmware_close(fh);
1897
1898 if (size < sizeof(*hdr)) {
1899 printf("%s: firmware too short\n", device_xname(sc->sc_dev));
1900 error = EINVAL;
1901 goto fail;
1902 }
1903
1904 hdr = (struct r92s_fw_hdr *)fw;
1905 if (hdr->signature != htole16(0x8712) &&
1906 hdr->signature != htole16(0x8192)) {
1907 printf("%s: invalid firmware signature 0x%x\n",
1908 device_xname(sc->sc_dev), le16toh(hdr->signature));
1909 error = EINVAL;
1910 goto fail;
1911 }
1912 DPRINTF(("FW V%d %02x-%02x %02x:%02x\n", le16toh(hdr->version),
1913 hdr->month, hdr->day, hdr->hour, hdr->minute));
1914
1915 /* Make sure that driver and firmware are in sync. */
1916 if (hdr->privsz != htole32(sizeof(*dmem))) {
1917 printf("%s: unsupported firmware image\n",
1918 device_xname(sc->sc_dev));
1919 error = EINVAL;
1920 goto fail;
1921 }
1922 /* Get FW sections sizes. */
1923 imemsz = le32toh(hdr->imemsz);
1924 ememsz = le32toh(hdr->sramsz);
1925 /* Check that all FW sections fit in image. */
1926 if (size < sizeof(*hdr) + imemsz + ememsz) {
1927 printf("%s: firmware too short\n", device_xname(sc->sc_dev));
1928 error = EINVAL;
1929 goto fail;
1930 }
1931 imem = (uint8_t *)&hdr[1];
1932 emem = imem + imemsz;
1933
1934 /* Load IMEM section. */
1935 error = rsu_fw_loadsection(sc, imem, imemsz);
1936 if (error != 0) {
1937 printf("%s: could not load firmware section %s\n",
1938 device_xname(sc->sc_dev), "IMEM");
1939 goto fail;
1940 }
1941 /* Wait for load to complete. */
1942 for (ntries = 0; ntries < 10; ntries++) {
1943 reg = rsu_read_2(sc, R92S_TCR);
1944 if (reg & R92S_TCR_IMEM_CODE_DONE)
1945 break;
1946 DELAY(10);
1947 }
1948 if (ntries == 10 || !(reg & R92S_TCR_IMEM_CHK_RPT)) {
1949 printf("%s: timeout waiting for %s transfer\n",
1950 device_xname(sc->sc_dev), "IMEM");
1951 error = ETIMEDOUT;
1952 goto fail;
1953 }
1954
1955 /* Load EMEM section. */
1956 error = rsu_fw_loadsection(sc, emem, ememsz);
1957 if (error != 0) {
1958 printf("%s: could not load firmware section %s\n",
1959 device_xname(sc->sc_dev), "EMEM");
1960 goto fail;
1961 }
1962 /* Wait for load to complete. */
1963 for (ntries = 0; ntries < 10; ntries++) {
1964 reg = rsu_read_2(sc, R92S_TCR);
1965 if (reg & R92S_TCR_EMEM_CODE_DONE)
1966 break;
1967 DELAY(10);
1968 }
1969 if (ntries == 10 || !(reg & R92S_TCR_EMEM_CHK_RPT)) {
1970 printf("%s: timeout waiting for %s transfer\n",
1971 device_xname(sc->sc_dev), "EMEM");
1972 error = ETIMEDOUT;
1973 goto fail;
1974 }
1975
1976 /* Enable CPU. */
1977 rsu_write_1(sc, R92S_SYS_CLKR,
1978 rsu_read_1(sc, R92S_SYS_CLKR) | R92S_SYS_CPU_CLKSEL);
1979 if (!(rsu_read_1(sc, R92S_SYS_CLKR) & R92S_SYS_CPU_CLKSEL)) {
1980 printf("%s: could not enable system clock\n",
1981 device_xname(sc->sc_dev));
1982 error = EIO;
1983 goto fail;
1984 }
1985 rsu_write_2(sc, R92S_SYS_FUNC_EN,
1986 rsu_read_2(sc, R92S_SYS_FUNC_EN) | R92S_FEN_CPUEN);
1987 if (!(rsu_read_2(sc, R92S_SYS_FUNC_EN) & R92S_FEN_CPUEN)) {
1988 printf("%s: could not enable microcontroller\n",
1989 device_xname(sc->sc_dev));
1990 error = EIO;
1991 goto fail;
1992 }
1993
1994 /* Wait for CPU to initialize. */
1995 for (ntries = 0; ntries < 100; ntries++) {
1996 if (rsu_read_2(sc, R92S_TCR) & R92S_TCR_IMEM_RDY)
1997 break;
1998 usbd_delay_ms(sc->sc_udev, 10);
1999 }
2000 if (ntries == 100) {
2001 printf("%s: timeout waiting for microcontroller\n",
2002 device_xname(sc->sc_dev));
2003 error = ETIMEDOUT;
2004 goto fail;
2005 }
2006
2007 /* Update DMEM section before loading. */
2008 dmem = &hdr->priv;
2009 memset(dmem, 0, sizeof(*dmem));
2010 dmem->hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172;
2011 dmem->nendpoints = sc->npipes;
2012 dmem->rf_config = 0x12; /* 1T2R */
2013 dmem->vcs_type = R92S_VCS_TYPE_AUTO;
2014 dmem->vcs_mode = R92S_VCS_MODE_RTS_CTS;
2015 #ifdef notyet
2016 dmem->bw40_en = (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) != 0;
2017 #else
2018 dmem->bw40_en = 0;
2019 #endif
2020 dmem->turbo_mode = 1;
2021 /* Load DMEM section. */
2022 error = rsu_fw_loadsection(sc, (uint8_t *)dmem, sizeof(*dmem));
2023 if (error != 0) {
2024 printf("%s: could not load firmware section %s\n",
2025 device_xname(sc->sc_dev), "DMEM");
2026 goto fail;
2027 }
2028 /* Wait for load to complete. */
2029 for (ntries = 0; ntries < 100; ntries++) {
2030 if (rsu_read_2(sc, R92S_TCR) & R92S_TCR_DMEM_CODE_DONE)
2031 break;
2032 DELAY(1000);
2033 }
2034 if (ntries == 100) {
2035 printf("%s: timeout waiting for %s transfer\n",
2036 device_xname(sc->sc_dev), "DMEM");
2037 error = ETIMEDOUT;
2038 goto fail;
2039 }
2040 /* Wait for firmware readiness. */
2041 for (ntries = 0; ntries < 60; ntries++) {
2042 if (!(rsu_read_2(sc, R92S_TCR) & R92S_TCR_FWRDY))
2043 break;
2044 usbd_delay_ms(sc->sc_udev, 10);
2045 }
2046 if (ntries == 60) {
2047 printf("%s: timeout waiting for firmware readiness\n",
2048 device_xname(sc->sc_dev));
2049 error = ETIMEDOUT;
2050 goto fail;
2051 }
2052 fail:
2053 firmware_free(fw, size);
2054 return (error);
2055 }
2056
2057 int
2058 rsu_init(struct ifnet *ifp)
2059 {
2060 struct rsu_softc *sc = ifp->if_softc;
2061 struct ieee80211com *ic = &sc->sc_ic;
2062 struct r92s_set_pwr_mode cmd;
2063 struct rsu_rx_data *data;
2064 int i, error;
2065
2066 /* Init host async commands ring. */
2067
2068 mutex_enter(&sc->sc_task_mtx);
2069 sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0;
2070 mutex_exit(&sc->sc_task_mtx);
2071
2072 /* Allocate Tx/Rx buffers. */
2073 error = rsu_alloc_rx_list(sc);
2074 if (error != 0) {
2075 printf("%s: could not allocate Rx buffers\n",
2076 device_xname(sc->sc_dev));
2077 goto fail;
2078 }
2079 error = rsu_alloc_tx_list(sc);
2080 if (error != 0) {
2081 printf("%s: could not allocate Tx buffers\n",
2082 device_xname(sc->sc_dev));
2083 goto fail;
2084 }
2085
2086 /* Reserve one Tx buffer for firmware commands. */
2087 mutex_enter(&sc->sc_tx_mtx);
2088 sc->fwcmd_data = TAILQ_FIRST(&sc->tx_free_list);
2089 TAILQ_REMOVE(&sc->tx_free_list, sc->fwcmd_data, next);
2090 mutex_exit(&sc->sc_tx_mtx);
2091
2092 /* Power on adapter. */
2093 if (sc->cut == 1)
2094 rsu_power_on_acut(sc);
2095 else
2096 rsu_power_on_bcut(sc);
2097 /* Load firmware. */
2098 error = rsu_load_firmware(sc);
2099 if (error != 0)
2100 goto fail;
2101
2102 /* Enable Rx TCP checksum offload. */
2103 rsu_write_4(sc, R92S_RCR,
2104 rsu_read_4(sc, R92S_RCR) | 0x04000000);
2105 /* Append PHY status. */
2106 rsu_write_4(sc, R92S_RCR,
2107 rsu_read_4(sc, R92S_RCR) | 0x02000000);
2108
2109 rsu_write_4(sc, R92S_CR,
2110 rsu_read_4(sc, R92S_CR) & ~0xff000000);
2111
2112 /* Use 128 bytes pages. */
2113 rsu_write_1(sc, 0x00b5,
2114 rsu_read_1(sc, 0x00b5) | 0x01);
2115 /* Enable USB Rx aggregation. */
2116 rsu_write_1(sc, 0x00bd,
2117 rsu_read_1(sc, 0x00bd) | 0x80);
2118 /* Set USB Rx aggregation threshold. */
2119 rsu_write_1(sc, 0x00d9, 0x01);
2120 /* Set USB Rx aggregation timeout (1.7ms/4). */
2121 rsu_write_1(sc, 0xfe5b, 0x04);
2122 /* Fix USB Rx FIFO issue. */
2123 rsu_write_1(sc, 0xfe5c,
2124 rsu_read_1(sc, 0xfe5c) | 0x80);
2125
2126 /* Set MAC address. */
2127 IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl));
2128 rsu_write_region_1(sc, R92S_MACID, ic->ic_myaddr, IEEE80211_ADDR_LEN);
2129
2130 /* Queue Rx xfers (XXX C2H pipe for 11-pipe configurations?) */
2131 for (i = 0; i < RSU_RX_LIST_COUNT; i++) {
2132 data = &sc->rx_data[i];
2133
2134 data->pipe = sc->pipe[sc->qid2idx[RSU_QID_RXOFF]];
2135 usbd_setup_xfer(data->xfer, data, data->buf,
2136 RSU_RXBUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT,
2137 rsu_rxeof);
2138 error = usbd_transfer(data->xfer);
2139 if (error != 0 && error != USBD_IN_PROGRESS)
2140 goto fail;
2141 }
2142
2143 /* NB: it really takes that long for firmware to boot. */
2144 usbd_delay_ms(sc->sc_udev, 1500);
2145
2146 DPRINTF(("setting MAC address to %s\n", ether_sprintf(ic->ic_myaddr)));
2147 error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, ic->ic_myaddr,
2148 IEEE80211_ADDR_LEN);
2149 if (error != 0) {
2150 printf("%s: could not set MAC address\n",
2151 device_xname(sc->sc_dev));
2152 goto fail;
2153 }
2154
2155 rsu_write_1(sc, R92S_USB_HRPWM,
2156 R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON);
2157
2158 memset(&cmd, 0, sizeof(cmd));
2159 cmd.mode = R92S_PS_MODE_ACTIVE;
2160 DPRINTF(("setting ps mode to %d\n", cmd.mode));
2161 error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd));
2162 if (error != 0) {
2163 printf("%s: could not set PS mode\n",
2164 device_xname(sc->sc_dev));
2165 goto fail;
2166 }
2167
2168 #ifdef notyet
2169 if (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) {
2170 /* Enable 40MHz mode. */
2171 error = rsu_fw_iocmd(sc,
2172 SM(R92S_IOCMD_CLASS, 0xf4) |
2173 SM(R92S_IOCMD_INDEX, 0x00) |
2174 SM(R92S_IOCMD_VALUE, 0x0007));
2175 if (error != 0) {
2176 printf("%s: could not enable 40MHz mode\n",
2177 device_xname(sc->sc_dev));
2178 goto fail;
2179 }
2180 }
2181 #endif
2182
2183 /* Set default channel. */
2184 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
2185
2186 /* We're ready to go. */
2187 ifp->if_flags &= ~IFF_OACTIVE;
2188 ifp->if_flags |= IFF_RUNNING;
2189
2190 sc->scan_pass = 0;
2191 if (ic->ic_opmode == IEEE80211_M_MONITOR)
2192 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2193 else
2194 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2195 return (0);
2196 fail:
2197 rsu_stop(ifp);
2198 return (error);
2199 }
2200
2201 void
2202 rsu_stop(struct ifnet *ifp)
2203 {
2204 struct rsu_softc *sc = ifp->if_softc;
2205 struct ieee80211com *ic = &sc->sc_ic;
2206 int i, s;
2207
2208 sc->sc_tx_timer = 0;
2209 ifp->if_timer = 0;
2210 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
2211
2212 s = splusb();
2213 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2214 /* Wait for all async commands to complete. */
2215 rsu_wait_async(sc);
2216 splx(s);
2217
2218 callout_destroy(&sc->calib_to);
2219
2220 /* Power off adapter. */
2221 rsu_power_off(sc);
2222
2223 /* Abort Tx/Rx. */
2224 for (i = 0; i < sc->npipes; i++)
2225 usbd_abort_pipe(sc->pipe[i]);
2226
2227 /* Free Tx/Rx buffers. */
2228 rsu_free_tx_list(sc);
2229 rsu_free_rx_list(sc);
2230 }
2231
2232 MODULE(MODULE_CLASS_DRIVER, if_rsu, NULL);
2233
2234 #ifdef _MODULE
2235 #include "ioconf.c"
2236 #endif
2237
2238 static int
2239 if_rsu_modcmd(modcmd_t cmd, void *arg)
2240 {
2241 int error = 0;
2242
2243 switch (cmd) {
2244 case MODULE_CMD_INIT:
2245 #ifdef _MODULE
2246 error = config_init_component(cfdriver_ioconf_rsu,
2247 cfattach_ioconf_rsu, cfdata_ioconf_rsu);
2248 #endif
2249 return error;
2250 case MODULE_CMD_FINI:
2251 #ifdef _MODULE
2252 error = config_fini_component(cfdriver_ioconf_rsu,
2253 cfattach_ioconf_rsu, cfdata_ioconf_rsu);
2254 #endif
2255 return error;
2256 default:
2257 return ENOTTY;
2258 }
2259 }
2260