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