xref: /freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c (revision d3d381b2b194b4d24853e92eecef55f262688d1a)
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 
92 static int
93 rtwn_usb_match(device_t self)
94 {
95 	struct usb_attach_arg *uaa = device_get_ivars(self);
96 
97 	if (uaa->usb_mode != USB_MODE_HOST)
98 		return (ENXIO);
99 	if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX)
100 		return (ENXIO);
101 	if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX)
102 		return (ENXIO);
103 
104 	return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa));
105 }
106 
107 static int
108 rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[],
109     int ndata, int maxsz)
110 {
111 	int i, error;
112 
113 	for (i = 0; i < ndata; i++) {
114 		struct rtwn_data *dp = &data[i];
115 		dp->m = NULL;
116 		dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT);
117 		if (dp->buf == NULL) {
118 			device_printf(sc->sc_dev,
119 			    "could not allocate buffer\n");
120 			error = ENOMEM;
121 			goto fail;
122 		}
123 		dp->ni = NULL;
124 	}
125 
126 	return (0);
127 fail:
128 	rtwn_usb_free_list(sc, data, ndata);
129 	return (error);
130 }
131 
132 static int
133 rtwn_usb_alloc_rx_list(struct rtwn_softc *sc)
134 {
135 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
136 	int error, i;
137 
138 	error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT,
139 	    uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT);
140 	if (error != 0)
141 		return (error);
142 
143 	STAILQ_INIT(&uc->uc_rx_active);
144 	STAILQ_INIT(&uc->uc_rx_inactive);
145 
146 	for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++)
147 		STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next);
148 
149 	return (0);
150 }
151 
152 static int
153 rtwn_usb_alloc_tx_list(struct rtwn_softc *sc)
154 {
155 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
156 	int error, i;
157 
158 	error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT,
159 	    RTWN_USB_TXBUFSZ);
160 	if (error != 0)
161 		return (error);
162 
163 	STAILQ_INIT(&uc->uc_tx_active);
164 	STAILQ_INIT(&uc->uc_tx_inactive);
165 	STAILQ_INIT(&uc->uc_tx_pending);
166 
167 	for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++)
168 		STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next);
169 
170 	return (0);
171 }
172 
173 static void
174 rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata)
175 {
176 	int i;
177 
178 	for (i = 0; i < ndata; i++) {
179 		struct rtwn_data *dp = &data[i];
180 
181 		if (dp->buf != NULL) {
182 			free(dp->buf, M_USBDEV);
183 			dp->buf = NULL;
184 		}
185 		if (dp->ni != NULL) {
186 			ieee80211_free_node(dp->ni);
187 			dp->ni = NULL;
188 		}
189 		if (dp->m != NULL) {
190 			m_freem(dp->m);
191 			dp->m = NULL;
192 		}
193 	}
194 }
195 
196 static void
197 rtwn_usb_free_rx_list(struct rtwn_softc *sc)
198 {
199 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
200 
201 	rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT);
202 
203 	uc->uc_rx_stat_len = 0;
204 	uc->uc_rx_off = 0;
205 
206 	STAILQ_INIT(&uc->uc_rx_active);
207 	STAILQ_INIT(&uc->uc_rx_inactive);
208 }
209 
210 static void
211 rtwn_usb_free_tx_list(struct rtwn_softc *sc)
212 {
213 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
214 
215 	rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT);
216 
217 	STAILQ_INIT(&uc->uc_tx_active);
218 	STAILQ_INIT(&uc->uc_tx_inactive);
219 	STAILQ_INIT(&uc->uc_tx_pending);
220 }
221 
222 static void
223 rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap)
224 {
225 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
226 
227 	RTWN_ASSERT_LOCKED(sc);
228 
229 	rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap);
230 	rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap);
231 	if (vap == NULL) {
232 		rtwn_usb_reset_rx_list(uc);
233 		sc->qfullmsk = 0;
234 	}
235 }
236 
237 static void
238 rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc,
239     rtwn_datahead *head, struct ieee80211vap *vap)
240 {
241 	struct rtwn_vap *uvp = RTWN_VAP(vap);
242 	struct rtwn_data *dp, *tmp;
243 	int id;
244 
245 	id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID);
246 
247 	STAILQ_FOREACH_SAFE(dp, head, next, tmp) {
248 		if (vap == NULL || (dp->ni == NULL &&
249 		    (dp->id == id || id == RTWN_VAP_ID_INVALID)) ||
250 		    (dp->ni != NULL && dp->ni->ni_vap == vap)) {
251 			if (dp->ni != NULL) {
252 				ieee80211_free_node(dp->ni);
253 				dp->ni = NULL;
254 			}
255 
256 			if (dp->m != NULL) {
257 				m_freem(dp->m);
258 				dp->m = NULL;
259 			}
260 
261 			STAILQ_REMOVE(head, dp, rtwn_data, next);
262 			STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next);
263 		}
264 	}
265 }
266 
267 static void
268 rtwn_usb_reset_rx_list(struct rtwn_usb_softc *uc)
269 {
270 	int i;
271 
272 	for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) {
273 		struct rtwn_data *dp = &uc->uc_rx[i];
274 
275 		if (dp->m != NULL) {
276 			m_freem(dp->m);
277 			dp->m = NULL;
278 		}
279 	}
280 	uc->uc_rx_stat_len = 0;
281 	uc->uc_rx_off = 0;
282 }
283 
284 static void
285 rtwn_usb_start_xfers(struct rtwn_softc *sc)
286 {
287 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
288 
289 	usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]);
290 }
291 
292 static void
293 rtwn_usb_abort_xfers(struct rtwn_softc *sc)
294 {
295 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
296 	int i;
297 
298 	RTWN_ASSERT_LOCKED(sc);
299 
300 	/* abort any pending transfers */
301 	RTWN_UNLOCK(sc);
302 	for (i = 0; i < RTWN_N_TRANSFER; i++)
303 		usbd_transfer_drain(uc->uc_xfer[i]);
304 	RTWN_LOCK(sc);
305 }
306 
307 static int
308 rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf,
309     uint16_t reg, int mlen)
310 {
311 	int error;
312 
313 	/* XXX fix this deconst */
314 	error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf),
315 	    mlen);
316 
317 	return (error);
318 }
319 
320 static void
321 rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc)
322 {
323 
324 	rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0,
325 	    R92C_TXDMA_OFFSET_DROP_DATA_EN, 1);
326 }
327 
328 static void
329 rtwn_usb_attach_methods(struct rtwn_softc *sc)
330 {
331 	sc->sc_write_1		= rtwn_usb_write_1;
332 	sc->sc_write_2		= rtwn_usb_write_2;
333 	sc->sc_write_4		= rtwn_usb_write_4;
334 	sc->sc_read_1		= rtwn_usb_read_1;
335 	sc->sc_read_2		= rtwn_usb_read_2;
336 	sc->sc_read_4		= rtwn_usb_read_4;
337 	sc->sc_delay		= rtwn_usb_delay;
338 	sc->sc_tx_start		= rtwn_usb_tx_start;
339 	sc->sc_start_xfers	= rtwn_usb_start_xfers;
340 	sc->sc_reset_lists	= rtwn_usb_reset_lists;
341 	sc->sc_abort_xfers	= rtwn_usb_abort_xfers;
342 	sc->sc_fw_write_block	= rtwn_usb_fw_write_block;
343 	sc->sc_get_qmap		= rtwn_usb_get_qmap;
344 	sc->sc_set_desc_addr	= rtwn_nop_softc;
345 	sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx;
346 	sc->sc_beacon_update_begin = rtwn_nop_softc_vap;
347 	sc->sc_beacon_update_end = rtwn_nop_softc_vap;
348 	sc->sc_beacon_unload	= rtwn_nop_softc_int;
349 
350 	sc->bcn_check_interval	= 100;
351 }
352 
353 static void
354 rtwn_usb_sysctlattach(struct rtwn_softc *sc)
355 {
356 	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
357 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
358 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
359 	char str[64];
360 	int ret;
361 
362 	ret = snprintf(str, sizeof(str),
363 	    "Rx buffer size, 512-byte units [%d...%d]",
364 	    RTWN_USB_RXBUFSZ_MIN, RTWN_USB_RXBUFSZ_MAX);
365 	KASSERT(ret > 0, ("ret (%d) <= 0!\n", ret));
366 	(void) ret;
367 
368 	uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_DEF;
369 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
370 	    "rx_buf_size", CTLFLAG_RDTUN, &uc->uc_rx_buf_size,
371 	    uc->uc_rx_buf_size, str);
372 	if (uc->uc_rx_buf_size < RTWN_USB_RXBUFSZ_MIN)
373 		uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MIN;
374 	if (uc->uc_rx_buf_size > RTWN_USB_RXBUFSZ_MAX)
375 		uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MAX;
376 }
377 
378 static int
379 rtwn_usb_attach(device_t self)
380 {
381 	struct usb_attach_arg *uaa = device_get_ivars(self);
382 	struct rtwn_usb_softc *uc = device_get_softc(self);
383 	struct rtwn_softc *sc = &uc->uc_sc;
384 	struct ieee80211com *ic = &sc->sc_ic;
385 	int error;
386 
387 	device_set_usb_desc(self);
388 	uc->uc_udev = uaa->device;
389 	sc->sc_dev = self;
390 	ic->ic_name = device_get_nameunit(self);
391 
392 	/* Need to be initialized early. */
393 	rtwn_sysctlattach(sc);
394 	rtwn_usb_sysctlattach(sc);
395 	mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF);
396 
397 	rtwn_usb_attach_methods(sc);
398 	rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa));
399 
400 	error = rtwn_usb_setup_endpoints(uc);
401 	if (error != 0)
402 		goto detach;
403 
404 	/* Allocate Tx/Rx buffers. */
405 	error = rtwn_usb_alloc_rx_list(sc);
406 	if (error != 0)
407 		goto detach;
408 
409 	error = rtwn_usb_alloc_tx_list(sc);
410 	if (error != 0)
411 		goto detach;
412 
413 	/* Generic attach. */
414 	error = rtwn_attach(sc);
415 	if (error != 0)
416 		goto detach;
417 
418 	return (0);
419 
420 detach:
421 	rtwn_usb_detach(self);		/* failure */
422 	return (ENXIO);
423 }
424 
425 static int
426 rtwn_usb_detach(device_t self)
427 {
428 	struct rtwn_usb_softc *uc = device_get_softc(self);
429 	struct rtwn_softc *sc = &uc->uc_sc;
430 
431 	/* Generic detach. */
432 	rtwn_detach(sc);
433 
434 	/* Free Tx/Rx buffers. */
435 	rtwn_usb_free_tx_list(sc);
436 	rtwn_usb_free_rx_list(sc);
437 
438 	/* Detach all USB transfers. */
439 	usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER);
440 
441 	rtwn_detach_private(sc);
442 	mtx_destroy(&sc->sc_mtx);
443 
444 	return (0);
445 }
446 
447 static int
448 rtwn_usb_suspend(device_t self)
449 {
450 	struct rtwn_usb_softc *uc = device_get_softc(self);
451 
452 	rtwn_suspend(&uc->uc_sc);
453 
454 	return (0);
455 }
456 
457 static int
458 rtwn_usb_resume(device_t self)
459 {
460 	struct rtwn_usb_softc *uc = device_get_softc(self);
461 
462 	rtwn_resume(&uc->uc_sc);
463 
464 	return (0);
465 }
466 
467 static device_method_t rtwn_usb_methods[] = {
468 	/* Device interface */
469 	DEVMETHOD(device_probe,		rtwn_usb_match),
470 	DEVMETHOD(device_attach,	rtwn_usb_attach),
471 	DEVMETHOD(device_detach,	rtwn_usb_detach),
472 	DEVMETHOD(device_suspend,	rtwn_usb_suspend),
473 	DEVMETHOD(device_resume,	rtwn_usb_resume),
474 
475 	DEVMETHOD_END
476 };
477 
478 static driver_t rtwn_usb_driver = {
479 	"rtwn",
480 	rtwn_usb_methods,
481 	sizeof(struct rtwn_usb_softc)
482 };
483 
484 static devclass_t rtwn_usb_devclass;
485 
486 DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, rtwn_usb_devclass, NULL, NULL);
487 MODULE_VERSION(rtwn_usb, 1);
488 MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1);
489 MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1);
490 MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2);
491 USB_PNP_HOST_INFO(rtwn_devs);
492