1 /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include <sys/param.h>
25 #include <sys/sysctl.h>
26 #include <sys/lock.h>
27 #include <sys/mutex.h>
28 #include <sys/mbuf.h>
29 #include <sys/kernel.h>
30 #include <sys/socket.h>
31 #include <sys/systm.h>
32 #include <sys/malloc.h>
33 #include <sys/module.h>
34 #include <sys/bus.h>
35 #include <sys/endian.h>
36 #include <sys/linker.h>
37 #include <sys/kdb.h>
38
39 #include <net/if.h>
40 #include <net/if_var.h>
41 #include <net/ethernet.h>
42 #include <net/if_media.h>
43
44 #include <net80211/ieee80211_var.h>
45
46 #include <dev/usb/usb.h>
47 #include <dev/usb/usbdi.h>
48 #include "usbdevs.h"
49
50 #include <dev/rtwn/if_rtwnvar.h>
51 #include <dev/rtwn/if_rtwn_nop.h>
52
53 #include <dev/rtwn/usb/rtwn_usb_var.h>
54
55 #include <dev/rtwn/usb/rtwn_usb_attach.h>
56 #include <dev/rtwn/usb/rtwn_usb_ep.h>
57 #include <dev/rtwn/usb/rtwn_usb_reg.h>
58 #include <dev/rtwn/usb/rtwn_usb_tx.h>
59
60 #include <dev/rtwn/rtl8192c/r92c_reg.h>
61
62 static device_probe_t rtwn_usb_match;
63 static device_attach_t rtwn_usb_attach;
64 static device_detach_t rtwn_usb_detach;
65 static device_suspend_t rtwn_usb_suspend;
66 static device_resume_t rtwn_usb_resume;
67
68 static int rtwn_usb_alloc_list(struct rtwn_softc *,
69 struct rtwn_data[], int, int);
70 static int rtwn_usb_alloc_rx_list(struct rtwn_softc *);
71 static int rtwn_usb_alloc_tx_list(struct rtwn_softc *);
72 static void rtwn_usb_free_list(struct rtwn_softc *,
73 struct rtwn_data data[], int);
74 static void rtwn_usb_free_rx_list(struct rtwn_softc *);
75 static void rtwn_usb_free_tx_list(struct rtwn_softc *);
76 static void rtwn_usb_reset_lists(struct rtwn_softc *,
77 struct ieee80211vap *);
78 static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *,
79 rtwn_datahead *, struct ieee80211vap *);
80 static void rtwn_usb_reset_rx_list(struct rtwn_usb_softc *);
81 static void rtwn_usb_start_xfers(struct rtwn_softc *);
82 static void rtwn_usb_abort_xfers(struct rtwn_softc *);
83 static int rtwn_usb_fw_write_block(struct rtwn_softc *,
84 const uint8_t *, uint16_t, int);
85 static void rtwn_usb_drop_incorrect_tx(struct rtwn_softc *);
86 static void rtwn_usb_attach_methods(struct rtwn_softc *);
87 static void rtwn_usb_sysctlattach(struct rtwn_softc *);
88
89 #define RTWN_CONFIG_INDEX 0
90
91 static int
92 rtwn_usb_match(device_t self)
93 {
94 struct usb_attach_arg *uaa = device_get_ivars(self);
95
96 if (uaa->usb_mode != USB_MODE_HOST)
97 return (ENXIO);
98 if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX)
99 return (ENXIO);
100 if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX)
101 return (ENXIO);
102
103 return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa));
104 }
105
106 static int
107 rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[],
108 int ndata, int maxsz)
109 {
110 int i, error;
111
112 for (i = 0; i < ndata; i++) {
113 struct rtwn_data *dp = &data[i];
114 dp->m = NULL;
115 dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT);
116 if (dp->buf == NULL) {
117 device_printf(sc->sc_dev,
118 "could not allocate buffer\n");
119 error = ENOMEM;
120 goto fail;
121 }
122 dp->ni = NULL;
123 }
124
125 return (0);
126 fail:
127 rtwn_usb_free_list(sc, data, ndata);
128 return (error);
129 }
130
131 static int
132 rtwn_usb_alloc_rx_list(struct rtwn_softc *sc)
133 {
134 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
135 int error, i;
136
137 error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT,
138 uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT);
139 if (error != 0)
140 return (error);
141
142 STAILQ_INIT(&uc->uc_rx_active);
143 STAILQ_INIT(&uc->uc_rx_inactive);
144
145 for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++)
146 STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next);
147
148 return (0);
149 }
150
151 static int
152 rtwn_usb_alloc_tx_list(struct rtwn_softc *sc)
153 {
154 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
155 int error, i;
156
157 error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT,
158 RTWN_USB_TXBUFSZ);
159 if (error != 0)
160 return (error);
161
162 STAILQ_INIT(&uc->uc_tx_active);
163 STAILQ_INIT(&uc->uc_tx_inactive);
164 STAILQ_INIT(&uc->uc_tx_pending);
165
166 for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++)
167 STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next);
168
169 return (0);
170 }
171
172 static void
173 rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata)
174 {
175 int i;
176
177 for (i = 0; i < ndata; i++) {
178 struct rtwn_data *dp = &data[i];
179
180 if (dp->buf != NULL) {
181 free(dp->buf, M_USBDEV);
182 dp->buf = NULL;
183 }
184 if (dp->ni != NULL) {
185 ieee80211_free_node(dp->ni);
186 dp->ni = NULL;
187 }
188 if (dp->m != NULL) {
189 m_freem(dp->m);
190 dp->m = NULL;
191 }
192 }
193 }
194
195 static void
196 rtwn_usb_free_rx_list(struct rtwn_softc *sc)
197 {
198 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
199
200 rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT);
201
202 uc->uc_rx_stat_len = 0;
203 uc->uc_rx_off = 0;
204
205 STAILQ_INIT(&uc->uc_rx_active);
206 STAILQ_INIT(&uc->uc_rx_inactive);
207 }
208
209 static void
210 rtwn_usb_free_tx_list(struct rtwn_softc *sc)
211 {
212 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
213
214 rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT);
215
216 STAILQ_INIT(&uc->uc_tx_active);
217 STAILQ_INIT(&uc->uc_tx_inactive);
218 STAILQ_INIT(&uc->uc_tx_pending);
219 }
220
221 static void
222 rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap)
223 {
224 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
225
226 RTWN_ASSERT_LOCKED(sc);
227
228 rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap);
229 rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap);
230 if (vap == NULL) {
231 rtwn_usb_reset_rx_list(uc);
232 sc->qfullmsk = 0;
233 }
234 }
235
236 static void
237 rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc,
238 rtwn_datahead *head, struct ieee80211vap *vap)
239 {
240 struct rtwn_vap *uvp = RTWN_VAP(vap);
241 struct rtwn_data *dp, *tmp;
242 int id;
243
244 id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID);
245
246 STAILQ_FOREACH_SAFE(dp, head, next, tmp) {
247 if (vap == NULL || (dp->ni == NULL &&
248 (dp->id == id || id == RTWN_VAP_ID_INVALID)) ||
249 (dp->ni != NULL && dp->ni->ni_vap == vap)) {
250 if (dp->ni != NULL) {
251 ieee80211_free_node(dp->ni);
252 dp->ni = NULL;
253 }
254
255 if (dp->m != NULL) {
256 m_freem(dp->m);
257 dp->m = NULL;
258 }
259
260 STAILQ_REMOVE(head, dp, rtwn_data, next);
261 STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next);
262 }
263 }
264 }
265
266 static void
267 rtwn_usb_reset_rx_list(struct rtwn_usb_softc *uc)
268 {
269 int i;
270
271 for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) {
272 struct rtwn_data *dp = &uc->uc_rx[i];
273
274 if (dp->m != NULL) {
275 m_freem(dp->m);
276 dp->m = NULL;
277 }
278 }
279 uc->uc_rx_stat_len = 0;
280 uc->uc_rx_off = 0;
281 }
282
283 static void
284 rtwn_usb_start_xfers(struct rtwn_softc *sc)
285 {
286 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
287
288 usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]);
289 }
290
291 static void
292 rtwn_usb_abort_xfers(struct rtwn_softc *sc)
293 {
294 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
295 int i;
296
297 RTWN_ASSERT_LOCKED(sc);
298
299 /* abort any pending transfers */
300 RTWN_UNLOCK(sc);
301 for (i = 0; i < RTWN_N_TRANSFER; i++)
302 usbd_transfer_drain(uc->uc_xfer[i]);
303 RTWN_LOCK(sc);
304 }
305
306 static int
307 rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf,
308 uint16_t reg, int mlen)
309 {
310 int error;
311
312 /* XXX fix this deconst */
313 error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf),
314 mlen);
315
316 return (error);
317 }
318
319 static void
320 rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc)
321 {
322
323 rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0,
324 R92C_TXDMA_OFFSET_DROP_DATA_EN, 1);
325 }
326
327 static void
328 rtwn_usb_attach_methods(struct rtwn_softc *sc)
329 {
330 sc->sc_write_1 = rtwn_usb_write_1;
331 sc->sc_write_2 = rtwn_usb_write_2;
332 sc->sc_write_4 = rtwn_usb_write_4;
333 sc->sc_read_1 = rtwn_usb_read_1;
334 sc->sc_read_2 = rtwn_usb_read_2;
335 sc->sc_read_4 = rtwn_usb_read_4;
336 sc->sc_delay = rtwn_usb_delay;
337 sc->sc_tx_start = rtwn_usb_tx_start;
338 sc->sc_start_xfers = rtwn_usb_start_xfers;
339 sc->sc_reset_lists = rtwn_usb_reset_lists;
340 sc->sc_abort_xfers = rtwn_usb_abort_xfers;
341 sc->sc_fw_write_block = rtwn_usb_fw_write_block;
342 sc->sc_get_qmap = rtwn_usb_get_qmap;
343 sc->sc_set_desc_addr = rtwn_nop_softc;
344 sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx;
345 sc->sc_beacon_update_begin = rtwn_nop_softc_vap;
346 sc->sc_beacon_update_end = rtwn_nop_softc_vap;
347 sc->sc_beacon_unload = rtwn_nop_softc_int;
348
349 sc->bcn_check_interval = 100;
350 }
351
352 static void
353 rtwn_usb_sysctlattach(struct rtwn_softc *sc)
354 {
355 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
356 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
357 struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
358 char str[64];
359 int ret;
360
361 ret = snprintf(str, sizeof(str),
362 "Rx buffer size, 512-byte units [%d...%d]",
363 RTWN_USB_RXBUFSZ_MIN, RTWN_USB_RXBUFSZ_MAX);
364 KASSERT(ret > 0, ("ret (%d) <= 0!\n", ret));
365 (void) ret;
366
367 uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_DEF;
368 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
369 "rx_buf_size", CTLFLAG_RDTUN, &uc->uc_rx_buf_size,
370 uc->uc_rx_buf_size, str);
371 if (uc->uc_rx_buf_size < RTWN_USB_RXBUFSZ_MIN)
372 uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MIN;
373 if (uc->uc_rx_buf_size > RTWN_USB_RXBUFSZ_MAX)
374 uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MAX;
375 }
376
377 static int
378 rtwn_usb_attach(device_t self)
379 {
380 struct usb_attach_arg *uaa = device_get_ivars(self);
381 struct rtwn_usb_softc *uc = device_get_softc(self);
382 struct rtwn_softc *sc = &uc->uc_sc;
383 struct ieee80211com *ic = &sc->sc_ic;
384 int error;
385
386 device_set_usb_desc(self);
387 uc->uc_udev = uaa->device;
388 sc->sc_dev = self;
389 ic->ic_name = device_get_nameunit(self);
390
391 /* Need to be initialized early. */
392 rtwn_sysctlattach(sc);
393 rtwn_usb_sysctlattach(sc);
394 mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF);
395
396 rtwn_usb_attach_methods(sc);
397 rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa));
398
399 error = rtwn_usb_setup_endpoints(uc);
400 if (error != 0)
401 goto detach;
402
403 /* Allocate Tx/Rx buffers. */
404 error = rtwn_usb_alloc_rx_list(sc);
405 if (error != 0)
406 goto detach;
407
408 error = rtwn_usb_alloc_tx_list(sc);
409 if (error != 0)
410 goto detach;
411
412 /* Generic attach. */
413 error = rtwn_attach(sc);
414 if (error != 0)
415 goto detach;
416
417 return (0);
418
419 detach:
420 rtwn_usb_detach(self); /* failure */
421 return (ENXIO);
422 }
423
424 static int
425 rtwn_usb_detach(device_t self)
426 {
427 struct rtwn_usb_softc *uc = device_get_softc(self);
428 struct rtwn_softc *sc = &uc->uc_sc;
429
430 /* Generic detach. */
431 rtwn_detach(sc);
432
433 /* Free Tx/Rx buffers. */
434 rtwn_usb_free_tx_list(sc);
435 rtwn_usb_free_rx_list(sc);
436
437 /* Detach all USB transfers. */
438 usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER);
439
440 rtwn_detach_private(sc);
441 mtx_destroy(&sc->sc_mtx);
442
443 return (0);
444 }
445
446 static int
447 rtwn_usb_suspend(device_t self)
448 {
449 struct rtwn_usb_softc *uc = device_get_softc(self);
450
451 rtwn_suspend(&uc->uc_sc);
452
453 return (0);
454 }
455
456 static int
457 rtwn_usb_resume(device_t self)
458 {
459 struct rtwn_usb_softc *uc = device_get_softc(self);
460
461 rtwn_resume(&uc->uc_sc);
462
463 return (0);
464 }
465
466 static device_method_t rtwn_usb_methods[] = {
467 /* Device interface */
468 DEVMETHOD(device_probe, rtwn_usb_match),
469 DEVMETHOD(device_attach, rtwn_usb_attach),
470 DEVMETHOD(device_detach, rtwn_usb_detach),
471 DEVMETHOD(device_suspend, rtwn_usb_suspend),
472 DEVMETHOD(device_resume, rtwn_usb_resume),
473
474 DEVMETHOD_END
475 };
476
477 static driver_t rtwn_usb_driver = {
478 "rtwn",
479 rtwn_usb_methods,
480 sizeof(struct rtwn_usb_softc)
481 };
482
483 DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, NULL, NULL);
484 MODULE_VERSION(rtwn_usb, 1);
485 MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1);
486 MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1);
487 MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2);
488 USB_PNP_HOST_INFO(rtwn_devs);
Cache object: 8d8fe2bf283ffc9d616b6703f130f91d
|