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