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