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