xref: /freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c (revision 716fd348)
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);
489