xref: /openbsd/sys/dev/usb/if_wi_usb.c (revision 3a81c204)
1 /*	$OpenBSD: if_wi_usb.c,v 1.78 2024/10/06 01:28:39 jsg Exp $ */
2 
3 /*
4  * Copyright (c) 2003 Dale Rahn. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * Effort sponsored in part by the Defense Advanced Research Projects
27  * Agency (DARPA) and Air Force Research Laboratory, Air Force
28  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/device.h>
35 #include <sys/timeout.h>
36 #include <sys/kthread.h>
37 
38 #include <net/if.h>
39 #include <net/if_media.h>
40 
41 #include <netinet/in.h>
42 #include <netinet/if_ether.h>
43 
44 #include <dev/usb/usb.h>
45 #include <dev/usb/usbdi.h>
46 #include <dev/usb/usbdi_util.h>
47 #include <dev/usb/usbdevs.h>
48 
49 #define ROUNDUP64(x) (((x)+63) & ~63)
50 
51 #include <net80211/ieee80211_var.h>
52 #include <net80211/ieee80211_ioctl.h>
53 
54 #include <machine/bus.h>
55 
56 #include <dev/ic/if_wireg.h>
57 #include <dev/ic/if_wi_ieee.h>
58 #include <dev/ic/if_wivar.h>
59 
60 #include <dev/usb/if_wi_usb.h>
61 
62 int wi_usb_do_transmit_sync(struct wi_usb_softc *wsc, struct wi_usb_chain *c,
63     void *ident);
64 void wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
65     usbd_status status);
66 void wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
67     usbd_status status);
68 void wi_usb_rxeof(struct usbd_xfer *xfer, void *priv,
69     usbd_status status);
70 void wi_usb_intr(struct usbd_xfer *xfer, void *priv,
71     usbd_status status);
72 void wi_usb_stop(struct wi_usb_softc *usc);
73 int wi_usb_tx_list_init(struct wi_usb_softc *usc);
74 int wi_usb_rx_list_init(struct wi_usb_softc *usc);
75 int wi_usb_open_pipes(struct wi_usb_softc *usc);
76 void wi_usb_cmdresp(struct wi_usb_chain *c);
77 void wi_usb_rridresp(struct wi_usb_chain *c);
78 void wi_usb_wridresp(struct wi_usb_chain *c);
79 void wi_usb_infofrm(struct wi_usb_chain *c, int len);
80 int wi_send_packet(struct wi_usb_softc *sc, int id);
81 void wi_usb_rxfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
82 void wi_usb_txfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
83 void wi_usb_start_thread(void *);
84 
85 int wi_usb_tx_lock_try(struct wi_usb_softc *sc);
86 void wi_usb_tx_lock(struct wi_usb_softc *usc);
87 void wi_usb_tx_unlock(struct wi_usb_softc *usc);
88 void wi_usb_ctl_lock(struct wi_usb_softc *usc);
89 void wi_usb_ctl_unlock(struct wi_usb_softc *usc);
90 
91 void wi_dump_data(void *buffer, int len);
92 
93 void wi_usb_thread(void *arg);
94 
95 #ifdef WI_USB_DEBUG
96 #define DPRINTF(x)      do { if (wi_usbdebug) printf x; } while (0)
97 #define DPRINTFN(n,x)   do { if (wi_usbdebug >= (n)) printf x; } while (0)
98 int     wi_usbdebug = 1;
99 #else
100 #define DPRINTF(x)
101 #define DPRINTFN(n,x)
102 #endif
103 
104 struct wi_usb_thread_info {
105 	int status;
106 	int dying;
107 	int idle;
108 };
109 
110 /* thread status flags */
111 #define WI_START	0x01
112 #define WI_DYING	0x02
113 #define WI_INQUIRE	0x04
114 #define WI_WATCHDOG	0x08
115 
116 
117 struct wi_usb_softc {
118 	struct wi_softc		sc_wi;
119 #define wi_usb_dev sc_wi.sc_dev
120 
121 	struct timeout		wi_usb_stat_ch;
122 
123 	struct usbd_device	*wi_usb_udev;
124 	struct usbd_interface	*wi_usb_iface;
125 	u_int16_t		wi_usb_vendor;
126 	u_int16_t		wi_usb_product;
127 	int			wi_usb_ed[WI_USB_ENDPT_MAX];
128 	struct usbd_pipe	*wi_usb_ep[WI_USB_ENDPT_MAX];
129 
130 	struct wi_usb_chain	wi_usb_tx_chain[WI_USB_TX_LIST_CNT];
131 	struct wi_usb_chain	wi_usb_rx_chain[WI_USB_RX_LIST_CNT];
132 
133 	int			wi_usb_refcnt;
134 	char			wi_usb_attached;
135 	int			wi_usb_intr_errs;
136 	struct timeval		wi_usb_rx_notice;
137 
138 	int			wi_usb_pollpending;
139 
140 	wi_usb_usbin		wi_usb_ibuf;
141 	int			wi_usb_tx_prod;
142 	int			wi_usb_tx_cons;
143 	int			wi_usb_tx_cnt;
144 	int			wi_usb_rx_prod;
145 
146 	struct wi_ltv_gen	*ridltv;
147 	int			ridresperr;
148 
149 	int			cmdresp;
150 	int			cmdresperr;
151 	int			txresp;
152 	int			txresperr;
153 
154 	/* nummem (tx/mgmt) */
155 	int			wi_usb_nummem;
156 #define MAX_WI_NMEM 3
157 	void			*wi_usb_txmem[MAX_WI_NMEM];
158 	int			wi_usb_txmemsize[MAX_WI_NMEM];
159 	void			*wi_usb_rxmem;
160 	int			wi_usb_rxmemsize;
161 
162 	void			*wi_info;
163 	void			*wi_rxframe;
164 
165 	/* prevent multiple outstanding USB requests */
166 	int			wi_lock;
167 	int			wi_lockwait;
168 
169 	/* prevent multiple command requests */
170 	int			wi_ctllock;
171 	int			wi_ctllockwait;
172 	struct proc		*wi_curproc;
173 
174 	/* kthread */
175 	struct wi_usb_thread_info	*wi_thread_info;
176 	int			wi_resetonce;
177 };
178 
179 struct wi_funcs wi_func_usb = {
180         wi_cmd_usb,
181         wi_read_record_usb,
182         wi_write_record_usb,
183         wi_alloc_nicmem_usb,
184         wi_read_data_usb,
185         wi_write_data_usb,
186         wi_get_fid_usb,
187         wi_init_usb,
188 
189         wi_start_usb,
190         wi_ioctl_usb,
191         wi_watchdog_usb,
192         wi_inquire_usb,
193 };
194 
195 /*
196  * Various supported device vendors/products.
197  */
198 const struct wi_usb_type {
199 	struct usb_devno	wi_usb_device;
200 	u_int16_t	wi_usb_flags;
201 	/* XXX */
202 } wi_usb_devs[] = {
203 	{{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_111 }, 0 },
204 	{{ USB_VENDOR_ACERW, USB_PRODUCT_ACERW_WARPLINK }, 0 },
205 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_FREELAN }, 0 },
206 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_PRISM_25 }, 0 },
207 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_PRISM_25A }, 0 },
208 	{{ USB_VENDOR_ADAPTEC, USB_PRODUCT_ADAPTEC_AWN8020 }, 0 },
209 	{{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_WLAN }, 0 },
210 	{{ USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUSTEK_WL140 }, 0 },
211 	{{ USB_VENDOR_AVERATEC, USB_PRODUCT_AVERATEC_USBWLAN }, 0 },
212 	{{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_W100 }, 0 },
213 	{{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_W200 }, 0 },
214 	{{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLANUSB }, 0 },
215 	{{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_KEY }, 0 },
216 	{{ USB_VENDOR_DELL, USB_PRODUCT_DELL_TM1180 }, 0 },
217 	{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120F }, 0 },
218 	{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL122 }, 0 },
219 	{{ USB_VENDOR_INTEL, USB_PRODUCT_INTEL_I2011B }, 0 },
220 	{{ USB_VENDOR_INTERSIL, USB_PRODUCT_INTERSIL_PRISM_2X }, 0 },
221 	{{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11 }, 0 },
222 	{{ USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_XP7250_WL }, 0 },
223 	{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11_25 }, 0 },
224 	{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB12_11 }, 0 },
225 	{{ USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V30 }, 0 },
226 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KB11 }, 0 },
227 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KS11G }, 0 },
228 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_S11 }, 0 },
229 	{{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN510 }, 0 },
230 	{{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_MA111NA }, 0 },
231 	{{ USB_VENDOR_PHEENET, USB_PRODUCT_PHEENET_WL503IA }, 0 },
232 	{{ USB_VENDOR_PHEENET, USB_PRODUCT_PHEENET_WM168B }, 0 },
233 	{{ USB_VENDOR_PLANEX, USB_PRODUCT_PLANEX_GW_US11H }, 0 },
234 	{{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM22 }, 0 },
235 	{{ USB_VENDOR_SITECOM2, USB_PRODUCT_SITECOM2_WL022 }, 0 },
236 	{{ USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_0193 }, 0 },
237 	{{ USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZYAIR_B200 }, 0 },
238 	{{ USB_VENDOR_USR, USB_PRODUCT_USR_USR1120 }, 0 },
239 	{{ USB_VENDOR_VIEWSONIC, USB_PRODUCT_VIEWSONIC_AIRSYNC }, 0 },
240 	{{ USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_XI725 }, 0 },
241 	{{ USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_XI735 }, 0 }
242 };
243 #define wi_usb_lookup(v, p) ((struct wi_usb_type *)usb_lookup(wi_usb_devs, v, p))
244 
245 int wi_usb_match(struct device *, void *, void *);
246 void wi_usb_attach(struct device *, struct device *, void *);
247 int wi_usb_detach(struct device *, int);
248 
249 const struct cfattach wi_usb_ca = {
250 	sizeof(struct wi_usb_softc), wi_usb_match, wi_usb_attach, wi_usb_detach
251 };
252 
253 int
wi_usb_match(struct device * parent,void * match,void * aux)254 wi_usb_match(struct device *parent, void *match, void *aux)
255 {
256 	struct usb_attach_arg	*uaa = aux;
257 
258 	if (uaa->iface == NULL || uaa->configno != 1)
259 		return (UMATCH_NONE);
260 
261 	return (wi_usb_lookup(uaa->vendor, uaa->product) != NULL ?
262 		UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
263 }
264 
265 
266 /*
267  * Attach the interface. Allocate softc structures, do ifmedia
268  * setup and ethernet/BPF attach.
269  */
270 void
wi_usb_attach(struct device * parent,struct device * self,void * aux)271 wi_usb_attach(struct device *parent, struct device *self, void *aux)
272 {
273 	struct wi_usb_softc	*sc = (struct wi_usb_softc *)self;
274 	struct usb_attach_arg	*uaa = aux;
275 /*	int			s; */
276 	struct usbd_device	*dev = uaa->device;
277 	struct usbd_interface	*iface = uaa->iface;
278 	usb_interface_descriptor_t	*id;
279 	usb_endpoint_descriptor_t	*ed;
280 	int			 i;
281 
282 	DPRINTFN(5,(" : wi_usb_attach: sc=%p", sc));
283 
284 	/* XXX - any tasks? */
285 
286 	/* XXX - flags? */
287 
288 	sc->wi_usb_udev = dev;
289 	sc->wi_usb_iface = iface;
290 	sc->wi_usb_product = uaa->product;
291 	sc->wi_usb_vendor = uaa->vendor;
292 
293 	sc->sc_wi.wi_usb_cdata = sc;
294 	sc->sc_wi.wi_flags |= WI_FLAGS_BUS_USB;
295 
296 	sc->wi_lock = 0;
297 	sc->wi_lockwait = 0;
298 	sc->wi_resetonce = 0;
299 
300 	id = usbd_get_interface_descriptor(iface);
301 
302 	/* Find endpoints. */
303 	for (i = 0; i < id->bNumEndpoints; i++) {
304 		ed = usbd_interface2endpoint_descriptor(iface, i);
305 		if (ed == NULL) {
306 			printf("%s: couldn't get endpoint descriptor %d\n",
307 			    sc->wi_usb_dev.dv_xname, i);
308 			return;
309 		}
310 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
311 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
312 			sc->wi_usb_ed[WI_USB_ENDPT_RX] = ed->bEndpointAddress;
313 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
314 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
315 			sc->wi_usb_ed[WI_USB_ENDPT_TX] = ed->bEndpointAddress;
316 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
317 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
318 			sc->wi_usb_ed[WI_USB_ENDPT_INTR] = ed->bEndpointAddress;
319 		}
320 	}
321 
322 	sc->wi_usb_nummem = 0;
323 
324 	/* attach wi device */
325 
326 	if (wi_usb_rx_list_init(sc)) {
327 		printf("%s: rx list init failed\n",
328 		    sc->wi_usb_dev.dv_xname);
329 		return;
330 	}
331 	if (wi_usb_tx_list_init(sc)) {
332 		printf("%s: tx list init failed\n",
333 		    sc->wi_usb_dev.dv_xname);
334 		return;
335 	}
336 
337 	if (wi_usb_open_pipes(sc)){
338 		printf("%s: open pipes failed\n",
339 		    sc->wi_usb_dev.dv_xname);
340 		return;
341 	}
342 
343 	sc->wi_usb_attached = 1;
344 
345 	kthread_create_deferred(wi_usb_start_thread, sc);
346 }
347 
348 int
wi_usb_detach(struct device * self,int flags)349 wi_usb_detach(struct device *self, int flags)
350 {
351 	struct wi_usb_softc	*sc = (struct wi_usb_softc *)self;
352 	struct ifnet		*ifp = WI_GET_IFP(sc);
353 	struct wi_softc		*wsc = &sc->sc_wi;
354 	int s;
355 	int err;
356 
357 	/* Detached before attach finished, so just bail out. */
358 	if (!sc->wi_usb_attached)
359 		return (0);
360 
361 	if (sc->wi_thread_info != NULL) {
362 		sc->wi_thread_info->dying = 1;
363 
364 		sc->wi_thread_info->status |= WI_DYING;
365 		if (sc->wi_thread_info->idle)
366 			wakeup(sc->wi_thread_info);
367 	}
368 
369 	/* tasks? */
370 
371 	s = splusb();
372 	/* detach wi */
373 
374 	if (!(wsc->wi_flags & WI_FLAGS_ATTACHED)) {
375 		printf("%s: already detached\n", sc->wi_usb_dev.dv_xname);
376 		splx(s);
377 		return (0);
378 	}
379 
380 	wi_detach(&sc->sc_wi);
381 
382 	wsc->wi_flags = 0;
383 
384 	if (ifp->if_softc != NULL) {
385 		ether_ifdetach(ifp);
386 		if_detach(ifp);
387 	}
388 
389 	sc->wi_usb_attached = 0;
390 
391 	if (--sc->wi_usb_refcnt >= 0) {
392 		/* Wait for processes to go away. */
393 		usb_detach_wait(&sc->wi_usb_dev);
394 	}
395 
396 	while (sc->wi_usb_nummem) {
397 		sc->wi_usb_nummem--;
398 		free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_USBDEV,
399 		  sc->wi_usb_txmemsize[sc->wi_usb_nummem]);
400 		sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
401 		sc->wi_usb_txmemsize[sc->wi_usb_nummem] = 0;
402 	}
403 
404 	if (sc->wi_usb_ep[WI_USB_ENDPT_INTR] != NULL) {
405 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]);
406 		if (err) {
407 			printf("%s: close intr pipe failed: %s\n",
408 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
409 		}
410 		sc->wi_usb_ep[WI_USB_ENDPT_INTR] = NULL;
411 	}
412 	if (sc->wi_usb_ep[WI_USB_ENDPT_TX] != NULL) {
413 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]);
414 		if (err) {
415 			printf("%s: close tx pipe failed: %s\n",
416 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
417 		}
418 		sc->wi_usb_ep[WI_USB_ENDPT_TX] = NULL;
419 	}
420 	if (sc->wi_usb_ep[WI_USB_ENDPT_RX] != NULL) {
421 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]);
422 		if (err) {
423 			printf("%s: close rx pipe failed: %s\n",
424 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
425 		}
426 		sc->wi_usb_ep[WI_USB_ENDPT_RX] = NULL;
427 	}
428 
429 	splx(s);
430 
431 	return (0);
432 }
433 
434 int
wi_send_packet(struct wi_usb_softc * sc,int id)435 wi_send_packet(struct wi_usb_softc *sc, int id)
436 {
437 	struct wi_usb_chain	*c;
438 	struct wi_frame		*wibuf;
439 	int			total_len, rnd_len;
440 	int			err;
441 
442 	c = &sc->wi_usb_tx_chain[0];
443 
444 	DPRINTFN(10,("%s: %s: id=%x\n",
445 	    sc->wi_usb_dev.dv_xname, __func__, id));
446 
447 	/* assemble packet from write_data buffer */
448 	if (id == 0 || id == 1) {
449 		/* tx_lock acquired before wi_start() */
450 		wibuf = sc->wi_usb_txmem[id];
451 
452 		total_len = sizeof (struct wi_frame) +
453 		    letoh16(wibuf->wi_dat_len);
454 		rnd_len = ROUNDUP64(total_len);
455 		if ((total_len > sc->wi_usb_txmemsize[id]) ||
456 		   (rnd_len > WI_USB_BUFSZ )){
457 			printf("invalid packet len: %x memsz %x max %x\n",
458 			    total_len, sc->wi_usb_txmemsize[id], WI_USB_BUFSZ);
459 
460 			err = EIO;
461 			goto err_ret;
462 		}
463 
464 		sc->txresp = WI_CMD_TX;
465 		sc->txresperr = 0;
466 
467 		bcopy(wibuf, c->wi_usb_buf, total_len);
468 
469 		bzero(((char *)c->wi_usb_buf)+total_len,
470 		    rnd_len - total_len);
471 
472 		/* zero old packet for next TX */
473 		bzero(wibuf, total_len);
474 
475 		total_len = rnd_len;
476 
477 		DPRINTFN(5,("%s: %s: id=%x len=%x\n",
478 		    sc->wi_usb_dev.dv_xname, __func__, id, total_len));
479 
480 		usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
481 		    c, c->wi_usb_buf, rnd_len,
482 		    USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
483 		    WI_USB_TX_TIMEOUT, wi_usb_txeof_frm);
484 
485 		err = usbd_transfer(c->wi_usb_xfer);
486 		if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
487 			printf("%s: %s: error=%s\n",
488 			    sc->wi_usb_dev.dv_xname, __func__,
489 			    usbd_errstr(err));
490 			/* Stop the interface from process context. */
491 			wi_usb_stop(sc);
492 			err = EIO;
493 		} else {
494 			err = 0;
495 		}
496 
497 		DPRINTFN(5,("%s: %s: exit err=%x\n",
498 		    sc->wi_usb_dev.dv_xname, __func__, err));
499 err_ret:
500 		return err;
501 	}
502 	printf("%s:%s: invalid packet id sent %x\n",
503 	    sc->wi_usb_dev.dv_xname, __func__, id);
504 	return 0;
505 }
506 
507 int
wi_cmd_usb(struct wi_softc * wsc,int cmd,int val0,int val1,int val2)508 wi_cmd_usb(struct wi_softc *wsc, int cmd, int val0, int val1, int val2)
509 {
510 	struct wi_usb_chain	*c;
511 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
512 	struct wi_cmdreq	*pcmd;
513 	int			total_len, rnd_len;
514 	int			err;
515 
516 	DPRINTFN(5,("%s: %s: enter cmd=%x %x %x %x\n",
517 	    sc->wi_usb_dev.dv_xname, __func__, cmd, val0, val1, val2));
518 
519 	if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_TX) {
520 		return wi_send_packet(sc, val0);
521 	}
522 
523 
524 	if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_INI) {
525 		/* free alloc_nicmem regions */
526 		while (sc->wi_usb_nummem) {
527 			sc->wi_usb_nummem--;
528 			free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_USBDEV,
529 			  sc->wi_usb_txmemsize[sc->wi_usb_nummem]);
530 			sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
531 			sc->wi_usb_txmemsize[sc->wi_usb_nummem] = 0;
532 		}
533 
534 #if 0
535 		/* if this is the first time, init, otherwise do not?? */
536 		if (sc->wi_resetonce) {
537 			return 0;
538 		} else
539 			sc->wi_resetonce = 1;
540 #endif
541 	}
542 
543 	wi_usb_ctl_lock(sc);
544 
545 	wi_usb_tx_lock(sc);
546 
547 	c = &sc->wi_usb_tx_chain[0];
548 	pcmd = c->wi_usb_buf;
549 
550 
551 	total_len = sizeof (struct wi_cmdreq);
552 	rnd_len = ROUNDUP64(total_len);
553 	if (rnd_len > WI_USB_BUFSZ) {
554 		printf("read_record buf size err %x %x\n",
555 		    rnd_len, WI_USB_BUFSZ);
556 		err = EIO;
557 		goto err_ret;
558 	}
559 
560 	sc->cmdresp = cmd;
561 	sc->cmdresperr = 0;
562 
563 	pcmd->type = htole16(WI_USB_CMDREQ);
564 	pcmd->cmd  = htole16(cmd);
565 	pcmd->param0  = htole16(val0);
566 	pcmd->param1  = htole16(val1);
567 	pcmd->param2  = htole16(val2);
568 
569 	bzero(((char*)pcmd)+total_len, rnd_len - total_len);
570 
571 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
572 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
573 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
574 
575 	err = wi_usb_do_transmit_sync(sc, c, &sc->cmdresperr);
576 
577 	if (err == 0)
578 		err = sc->cmdresperr;
579 
580 	sc->cmdresperr = 0;
581 
582 err_ret:
583 	wi_usb_tx_unlock(sc);
584 
585 	wi_usb_ctl_unlock(sc);
586 
587 	DPRINTFN(5,("%s: %s: exit err=%x\n",
588 	    sc->wi_usb_dev.dv_xname, __func__, err));
589 	return err;
590 }
591 
592 
593 int
wi_read_record_usb(struct wi_softc * wsc,struct wi_ltv_gen * ltv)594 wi_read_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
595 {
596 	struct wi_usb_chain	*c;
597 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
598 	struct wi_rridreq	*prid;
599 	int			total_len, rnd_len;
600 	int			err;
601 	struct wi_ltv_gen	*oltv = NULL, p2ltv;
602 
603 	DPRINTFN(5,("%s: %s: enter rid=%x\n",
604 	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type));
605 
606 	/* Do we need to deal with these here, as in _io version?
607 	 * WI_RID_ENCRYPTION -> WI_RID_P2_ENCRYPTION
608 	 * WI_RID_TX_CRYPT_KEY -> WI_RID_P2_TX_CRYPT_KEY
609 	 */
610 	if (wsc->sc_firmware_type != WI_LUCENT) {
611 		oltv = ltv;
612 		switch (ltv->wi_type) {
613 		case WI_RID_ENCRYPTION:
614 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
615 			p2ltv.wi_len = 2;
616 			ltv = &p2ltv;
617 			break;
618 		case WI_RID_TX_CRYPT_KEY:
619 			if (ltv->wi_val > WI_NLTV_KEYS)
620 				return (EINVAL);
621 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
622 			p2ltv.wi_len = 2;
623 			ltv = &p2ltv;
624 			break;
625 		}
626 	}
627 
628 	wi_usb_tx_lock(sc);
629 
630 	c = &sc->wi_usb_tx_chain[0];
631 	prid = c->wi_usb_buf;
632 
633 	total_len = sizeof(struct wi_rridreq);
634 	rnd_len = ROUNDUP64(total_len);
635 
636 	if (rnd_len > WI_USB_BUFSZ) {
637 		printf("read_record buf size err %x %x\n",
638 		    rnd_len, WI_USB_BUFSZ);
639 		wi_usb_tx_unlock(sc);
640 		return EIO;
641 	}
642 
643 	sc->ridltv = ltv;
644 	sc->ridresperr = 0;
645 
646 	prid->type = htole16(WI_USB_RRIDREQ);
647 	prid->frmlen = htole16(2);	/* variable size? */
648 	prid->rid  = htole16(ltv->wi_type);
649 
650 	bzero(((char*)prid)+total_len, rnd_len - total_len);
651 
652 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
653 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
654 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
655 
656 	DPRINTFN(10,("%s: %s: total_len=%x, wilen %d\n",
657 	    sc->wi_usb_dev.dv_xname, __func__, total_len, ltv->wi_len));
658 
659 	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
660 
661 	/* Do we need to deal with these here, as in _io version?
662 	 *
663 	 * WI_RID_TX_RATE
664 	 * WI_RID_CUR_TX_RATE
665 	 * WI_RID_ENCRYPTION
666 	 * WI_RID_TX_CRYPT_KEY
667 	 * WI_RID_CNFAUTHMODE
668 	 */
669 	if (ltv->wi_type == WI_RID_PORTTYPE && wsc->wi_ptype == WI_PORTTYPE_IBSS
670 	    && ltv->wi_val == wsc->wi_ibss_port) {
671 		/*
672 		 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
673 		 * Since Lucent uses port type 1 for BSS *and* IBSS we
674 		 * have to rely on wi_ptype to distinguish this for us.
675 		 */
676 		ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
677 	} else if (wsc->sc_firmware_type != WI_LUCENT) {
678 		int v;
679 
680 		switch (oltv->wi_type) {
681 		case WI_RID_TX_RATE:
682 		case WI_RID_CUR_TX_RATE:
683 			switch (letoh16(ltv->wi_val)) {
684 			case 1: v = 1; break;
685 			case 2: v = 2; break;
686 			case 3:	v = 6; break;
687 			case 4: v = 5; break;
688 			case 7: v = 7; break;
689 			case 8: v = 11; break;
690 			case 15: v = 3; break;
691 			default: v = 0x100 + letoh16(ltv->wi_val); break;
692 			}
693 			oltv->wi_val = htole16(v);
694 			break;
695 		case WI_RID_ENCRYPTION:
696 			oltv->wi_len = 2;
697 			if (ltv->wi_val & htole16(0x01))
698 				oltv->wi_val = htole16(1);
699 			else
700 				oltv->wi_val = htole16(0);
701 			break;
702 		case WI_RID_TX_CRYPT_KEY:
703 		case WI_RID_CNFAUTHMODE:
704 			oltv->wi_len = 2;
705 			oltv->wi_val = ltv->wi_val;
706 			break;
707 		}
708 	}
709 
710 	if (err == 0)
711 		err = sc->ridresperr;
712 
713 	sc->ridresperr = 0;
714 
715 	wi_usb_tx_unlock(sc);
716 
717 	DPRINTFN(5,("%s: %s: exit err=%x\n",
718 	    sc->wi_usb_dev.dv_xname, __func__, err));
719 	return err;
720 }
721 
722 int
wi_write_record_usb(struct wi_softc * wsc,struct wi_ltv_gen * ltv)723 wi_write_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
724 {
725 	struct wi_usb_chain	*c;
726 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
727 	struct wi_wridreq	*prid;
728 	int			total_len, rnd_len;
729 	int			err;
730 	struct wi_ltv_gen	p2ltv;
731 	u_int16_t		val = 0;
732 	int			i;
733 
734 	DPRINTFN(5,("%s: %s: enter rid=%x wi_len %d copying %x\n",
735 	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type, ltv->wi_len,
736 	    (ltv->wi_len-1)*2 ));
737 
738 	/* Do we need to deal with these here, as in _io version?
739 	 * WI_PORTTYPE_IBSS -> WI_RID_PORTTYPE
740 	 * RID_TX_RATE munging
741 	 * RID_ENCRYPTION
742 	 * WI_RID_TX_CRYPT_KEY
743 	 * WI_RID_DEFLT_CRYPT_KEYS
744 	 */
745 	if (ltv->wi_type == WI_RID_PORTTYPE &&
746 	    letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
747 		/* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
748 		p2ltv.wi_type = WI_RID_PORTTYPE;
749 		p2ltv.wi_len = 2;
750 		p2ltv.wi_val = wsc->wi_ibss_port;
751 		ltv = &p2ltv;
752 	} else if (wsc->sc_firmware_type != WI_LUCENT) {
753 		int v;
754 
755 		switch (ltv->wi_type) {
756 		case WI_RID_TX_RATE:
757 			p2ltv.wi_type = WI_RID_TX_RATE;
758 			p2ltv.wi_len = 2;
759 			switch (letoh16(ltv->wi_val)) {
760 			case 1: v = 1; break;
761 			case 2: v = 2; break;
762 			case 3:	v = 15; break;
763 			case 5: v = 4; break;
764 			case 6: v = 3; break;
765 			case 7: v = 7; break;
766 			case 11: v = 8; break;
767 			default: return EINVAL;
768 			}
769 			p2ltv.wi_val = htole16(v);
770 			ltv = &p2ltv;
771 			break;
772 		case WI_RID_ENCRYPTION:
773 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
774 			p2ltv.wi_len = 2;
775 			if (ltv->wi_val & htole16(0x01)) {
776 				val = PRIVACY_INVOKED;
777 				/*
778 				 * If using shared key WEP we must set the
779 				 * EXCLUDE_UNENCRYPTED bit.  Symbol cards
780 				 * need this bit set even when not using
781 				 * shared key. We can't just test for
782 				 * IEEE80211_AUTH_SHARED since Symbol cards
783 				 * have 2 shared key modes.
784 				 */
785 				if (wsc->wi_authtype != IEEE80211_AUTH_OPEN ||
786 				    wsc->sc_firmware_type == WI_SYMBOL)
787 					val |= EXCLUDE_UNENCRYPTED;
788 
789 				switch (wsc->wi_crypto_algorithm) {
790 				case WI_CRYPTO_FIRMWARE_WEP:
791 					/*
792 					 * TX encryption is broken in
793 					 * Host AP mode.
794 					 */
795 					if (wsc->wi_ptype == WI_PORTTYPE_HOSTAP)
796 						val |= HOST_ENCRYPT;
797 					break;
798 				case WI_CRYPTO_SOFTWARE_WEP:
799 					val |= HOST_ENCRYPT|HOST_DECRYPT;
800 					break;
801 				}
802 				p2ltv.wi_val = htole16(val);
803 			} else
804 				p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
805 			ltv = &p2ltv;
806 			break;
807 		case WI_RID_TX_CRYPT_KEY:
808 			if (ltv->wi_val > WI_NLTV_KEYS)
809 				return (EINVAL);
810 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
811 			p2ltv.wi_len = 2;
812 			p2ltv.wi_val = ltv->wi_val;
813 			ltv = &p2ltv;
814 			break;
815 		case WI_RID_DEFLT_CRYPT_KEYS: {
816 				int error;
817 				int keylen;
818 				struct wi_ltv_str ws;
819 				struct wi_ltv_keys *wk;
820 
821 				wk = (struct wi_ltv_keys *)ltv;
822 				keylen = wk->wi_keys[wsc->wi_tx_key].wi_keylen;
823 				keylen = letoh16(keylen);
824 
825 				for (i = 0; i < 4; i++) {
826 					bzero(&ws, sizeof(ws));
827 					ws.wi_len = (keylen > 5) ? 8 : 4;
828 					ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
829 					bcopy(&wk->wi_keys[i].wi_keydat,
830 					    ws.wi_str, keylen);
831 					error = wi_write_record_usb(wsc,
832 					    (struct wi_ltv_gen *)&ws);
833 					if (error)
834 						return (error);
835 				}
836 			}
837 			return (0);
838 		}
839 	}
840 
841 	wi_usb_tx_lock(sc);
842 
843 	c = &sc->wi_usb_tx_chain[0];
844 
845 	prid = c->wi_usb_buf;
846 
847 	total_len = sizeof(prid->type) + sizeof(prid->frmlen) +
848 	    sizeof(prid->rid) + (ltv->wi_len-1)*2;
849 	rnd_len = ROUNDUP64(total_len);
850 	if (rnd_len > WI_USB_BUFSZ) {
851 		printf("write_record buf size err %x %x\n",
852 		    rnd_len, WI_USB_BUFSZ);
853 		wi_usb_tx_unlock(sc);
854 		return EIO;
855 	}
856 
857 	prid->type = htole16(WI_USB_WRIDREQ);
858 	prid->frmlen = htole16(ltv->wi_len);
859 	prid->rid  = htole16(ltv->wi_type);
860 	if (ltv->wi_len > 1)
861 		bcopy(&ltv->wi_val, &prid->data[0], (ltv->wi_len-1)*2);
862 
863 	bzero(((char*)prid)+total_len, rnd_len - total_len);
864 
865 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
866 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
867 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
868 
869 	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
870 
871 	if (err == 0)
872 		err = sc->ridresperr;
873 
874 	sc->ridresperr = 0;
875 
876 	wi_usb_tx_unlock(sc);
877 
878 	DPRINTFN(5,("%s: %s: exit err=%x\n",
879 	    sc->wi_usb_dev.dv_xname, __func__, err));
880 	return err;
881 }
882 
883 /*
884  * This is an ugly compat portion to emulate the I/O which writes
885  * a packet or management information
886  * The data is copied into local memory for the requested
887  * 'id' then on the wi_cmd WI_CMD_TX, the id argument
888  * will identify which buffer to use
889  */
890 int
wi_alloc_nicmem_usb(struct wi_softc * wsc,int len,int * id)891 wi_alloc_nicmem_usb(struct wi_softc *wsc, int len, int *id)
892 {
893 	int nmem;
894 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
895 
896 	DPRINTFN(10,("%s: %s: enter len=%x\n",
897 	    sc->wi_usb_dev.dv_xname, __func__, len));
898 
899 	/*
900 	 * NOTE THIS IS A USB DEVICE WHICH WILL LIKELY HAVE MANY
901 	 * CONNECTS/DISCONNECTS, FREE THIS MEMORY XXX XXX XXX !!! !!!
902 	 */
903 	nmem = sc->wi_usb_nummem++;
904 
905 	if (nmem >= MAX_WI_NMEM) {
906 		sc->wi_usb_nummem--;
907 		return ENOMEM;
908 	}
909 
910 	sc->wi_usb_txmem[nmem] = malloc(len, M_USBDEV, M_WAITOK | M_CANFAIL);
911 	if (sc->wi_usb_txmem[nmem] == NULL) {
912 		sc->wi_usb_nummem--;
913 		return ENOMEM;
914 	}
915 	sc->wi_usb_txmemsize[nmem] = len;
916 
917 	*id = nmem;
918 	return 0;
919 }
920 
921 /*
922  * this is crazy, we skip the first 16 bits of the buf so that it
923  * can be used as the 'type' of the usb transfer.
924  */
925 
926 
927 int
wi_write_data_usb(struct wi_softc * wsc,int id,int off,caddr_t buf,int len)928 wi_write_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
929 {
930 	u_int8_t	*ptr;
931 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
932 
933 	DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
934 	    sc->wi_usb_dev.dv_xname, __func__, id, off, len));
935 
936 	if (id < 0 && id >= sc->wi_usb_nummem)
937 		return EIO;
938 
939 	ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
940 
941 	if (len + off > sc->wi_usb_txmemsize[id])
942 		return EIO;
943 	DPRINTFN(10,("%s: %s: completed \n",
944 	    sc->wi_usb_dev.dv_xname, __func__));
945 
946 	bcopy(buf, ptr, len);
947 	return 0;
948 }
949 
950 /*
951  * On the prism I/O, this read_data points to the hardware buffer
952  * which contains the
953  */
954 int
wi_read_data_usb(struct wi_softc * wsc,int id,int off,caddr_t buf,int len)955 wi_read_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
956 {
957 	u_int8_t	*ptr;
958 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
959 
960 	DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
961 	    sc->wi_usb_dev.dv_xname, __func__, id, off, len));
962 
963 	if (id == 0x1001 && sc->wi_info != NULL)
964 		ptr = (u_int8_t *)sc->wi_info + off;
965 	else if (id == 0x1000 && sc->wi_rxframe != NULL)
966 		ptr = (u_int8_t *)sc->wi_rxframe + off;
967 	else if (id >= 0 && id < sc->wi_usb_nummem) {
968 
969 		if (sc->wi_usb_txmem[id] == NULL)
970 			return EIO;
971 		if (len + off > sc->wi_usb_txmemsize[id])
972 			return EIO;
973 
974 		ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
975 	} else
976 		return EIO;
977 
978 	if (id < sc->wi_usb_nummem) {
979 		ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
980 
981 		if (len + off > sc->wi_usb_txmemsize[id])
982 			return EIO;
983 	}
984 
985 	bcopy(ptr, buf, len);
986 	return 0;
987 }
988 
989 void
wi_usb_stop(struct wi_usb_softc * sc)990 wi_usb_stop(struct wi_usb_softc *sc)
991 {
992 	DPRINTFN(1,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
993 	/* XXX */
994 
995 	/* Stop transfers */
996 }
997 
998 int
wi_usb_do_transmit_sync(struct wi_usb_softc * sc,struct wi_usb_chain * c,void * ident)999 wi_usb_do_transmit_sync(struct wi_usb_softc *sc, struct wi_usb_chain *c,
1000     void *ident)
1001 {
1002 	usbd_status		err;
1003 
1004 	DPRINTFN(10,("%s: %s:\n",
1005 	    sc->wi_usb_dev.dv_xname, __func__));
1006 
1007 	sc->wi_usb_refcnt++;
1008 	err = usbd_transfer(c->wi_usb_xfer);
1009 	if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
1010 		printf("%s: %s error=%s\n",
1011 		    sc->wi_usb_dev.dv_xname, __func__,
1012 		    usbd_errstr(err));
1013 		/* Stop the interface from process context. */
1014 		wi_usb_stop(sc);
1015 		err = EIO;
1016 		goto done;
1017 	}
1018 	err = tsleep_nsec(ident, PRIBIO, "wiTXsync", SEC_TO_NSEC(1));
1019 	if (err) {
1020 		DPRINTFN(1,("%s: %s: err %x\n",
1021 		    sc->wi_usb_dev.dv_xname, __func__, err));
1022 		err = ETIMEDOUT;
1023 	}
1024 done:
1025 	if (--sc->wi_usb_refcnt < 0)
1026 		usb_detach_wakeup(&sc->wi_usb_dev);
1027 	return err;
1028 }
1029 
1030 
1031 /*
1032  * A command/rrid/wrid  was sent to the chip. It's safe for us to clean up
1033  * the list buffers.
1034  */
1035 
1036 void
wi_usb_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)1037 wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
1038     usbd_status status)
1039 {
1040 	struct wi_usb_chain	*c = priv;
1041 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1042 
1043 	int			s;
1044 
1045 	if (usbd_is_dying(sc->wi_usb_udev))
1046 		return;
1047 
1048 	s = splnet();
1049 
1050 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1051 		    __func__, status));
1052 
1053 	if (status != USBD_NORMAL_COMPLETION) {
1054 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1055 			splx(s);
1056 			return;
1057 		}
1058 		printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
1059 		    usbd_errstr(status));
1060 		if (status == USBD_STALLED) {
1061 			sc->wi_usb_refcnt++;
1062 			usbd_clear_endpoint_stall_async(
1063 			    sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1064 			if (--sc->wi_usb_refcnt < 0)
1065 				usb_detach_wakeup(&sc->wi_usb_dev);
1066 		}
1067 		splx(s);
1068 		return;
1069 	}
1070 
1071 	splx(s);
1072 }
1073 
1074 /*
1075  * A packet was sent to the chip. It's safe for us to clean up
1076  * the list buffers.
1077  */
1078 
1079 void
wi_usb_txeof_frm(struct usbd_xfer * xfer,void * priv,usbd_status status)1080 wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
1081     usbd_status status)
1082 {
1083 	struct wi_usb_chain	*c = priv;
1084 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1085 	struct wi_softc		*wsc = &sc->sc_wi;
1086 	struct ifnet		*ifp = &wsc->sc_ic.ic_if;
1087 
1088 	int			s;
1089 	int			err = 0;
1090 
1091 	if (usbd_is_dying(sc->wi_usb_udev))
1092 		return;
1093 
1094 	s = splnet();
1095 
1096 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1097 		    __func__, status));
1098 
1099 	if (status != USBD_NORMAL_COMPLETION) {
1100 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1101 			splx(s);
1102 			return;
1103 		}
1104 		printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
1105 		    usbd_errstr(status));
1106 		if (status == USBD_STALLED) {
1107 			sc->wi_usb_refcnt++;
1108 			usbd_clear_endpoint_stall_async(
1109 			    sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1110 			if (--sc->wi_usb_refcnt < 0)
1111 				usb_detach_wakeup(&sc->wi_usb_dev);
1112 		}
1113 		splx(s);
1114 		return;
1115 	}
1116 
1117 	if (status)
1118 		err = WI_EV_TX_EXC;
1119 
1120 	wi_txeof(wsc, err);
1121 
1122 	wi_usb_tx_unlock(sc);
1123 
1124 	if (!ifq_empty(&ifp->if_snd))
1125 		wi_start_usb(ifp);
1126 
1127 	splx(s);
1128 }
1129 
1130 int
wi_usb_rx_list_init(struct wi_usb_softc * sc)1131 wi_usb_rx_list_init(struct wi_usb_softc *sc)
1132 {
1133 	struct wi_usb_chain	*c;
1134 	int			i;
1135 
1136 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1137 
1138 	for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
1139 		c = &sc->wi_usb_rx_chain[i];
1140 		c->wi_usb_sc = sc;
1141 		c->wi_usb_idx = i;
1142 		if (c->wi_usb_xfer != NULL) {
1143 			printf("UGH RX\n");
1144 		}
1145 		if (c->wi_usb_xfer == NULL) {
1146 			c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
1147 			if (c->wi_usb_xfer == NULL)
1148 				return (ENOBUFS);
1149 			c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
1150 			    WI_USB_BUFSZ);
1151 			if (c->wi_usb_buf == NULL)
1152 				return (ENOBUFS); /* XXX free xfer */
1153 		}
1154 	}
1155 
1156 	return (0);
1157 }
1158 
1159 int
wi_usb_tx_list_init(struct wi_usb_softc * sc)1160 wi_usb_tx_list_init(struct wi_usb_softc *sc)
1161 {
1162 	struct wi_usb_chain	*c;
1163 	int			i;
1164 
1165 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1166 
1167 	for (i = 0; i < WI_USB_TX_LIST_CNT; i++) {
1168 		c = &sc->wi_usb_tx_chain[i];
1169 		c->wi_usb_sc = sc;
1170 		c->wi_usb_idx = i;
1171 		c->wi_usb_mbuf = NULL;
1172 		if (c->wi_usb_xfer != NULL) {
1173 			printf("UGH TX\n");
1174 		}
1175 		if (c->wi_usb_xfer == NULL) {
1176 			c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
1177 			if (c->wi_usb_xfer == NULL)
1178 				return (ENOBUFS);
1179 			c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
1180 			    WI_USB_BUFSZ);
1181 			if (c->wi_usb_buf == NULL)
1182 				return (ENOBUFS);
1183 		}
1184 	}
1185 
1186 	return (0);
1187 }
1188 
1189 int
wi_usb_open_pipes(struct wi_usb_softc * sc)1190 wi_usb_open_pipes(struct wi_usb_softc *sc)
1191 {
1192 	usbd_status		err;
1193 	int			error = 0;
1194 	struct wi_usb_chain	*c;
1195 	int			i;
1196 
1197 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
1198 
1199 	sc->wi_usb_refcnt++;
1200 
1201 	/* Open RX and TX pipes. */
1202 	err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_RX],
1203 	    USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1204 	if (err) {
1205 		printf("%s: open rx pipe failed: %s\n",
1206 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1207 		error = EIO;
1208 		goto done;
1209 	}
1210 
1211 	err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_TX],
1212 	    USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1213 	if (err) {
1214 		printf("%s: open tx pipe failed: %s\n",
1215 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1216 		error = EIO;
1217 		goto done;
1218 	}
1219 
1220 	/* is this used? */
1221 	err = usbd_open_pipe_intr(sc->wi_usb_iface,
1222 	    sc->wi_usb_ed[WI_USB_ENDPT_INTR], 0,
1223 	    &sc->wi_usb_ep[WI_USB_ENDPT_INTR], sc, &sc->wi_usb_ibuf,
1224 	    WI_USB_INTR_PKTLEN, wi_usb_intr, WI_USB_INTR_INTERVAL);
1225 	if (err) {
1226 		printf("%s: open intr pipe failed: %s\n",
1227 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1228 		error = EIO;
1229 		goto done;
1230 	}
1231 
1232 	/* Start up the receive pipe. */
1233 	for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
1234 		c = &sc->wi_usb_rx_chain[i];
1235 		usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
1236 		    c, c->wi_usb_buf, WI_USB_BUFSZ,
1237 		    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1238 		    wi_usb_rxeof);
1239 		DPRINTFN(10,("%s: %s: start read\n", sc->wi_usb_dev.dv_xname,
1240 			    __func__));
1241 		usbd_transfer(c->wi_usb_xfer);
1242 	}
1243 
1244 done:
1245 	if (--sc->wi_usb_refcnt < 0)
1246 		usb_detach_wakeup(&sc->wi_usb_dev);
1247 
1248 	return (error);
1249 }
1250 
1251 /*
1252  * This is a bit of a kludge, however wi_rxeof and wi_update_stats
1253  * call wi_get_fid to determine where the data associated with
1254  * the transaction is located, the returned id is then used to
1255  * wi_read_data the information out.
1256  *
1257  * This code returns which 'fid' should be used. The results are only valid
1258  * during a wi_usb_rxeof because the data is received packet is 'held'
1259  * an a variable for reading by wi_read_data_usb for that period.
1260  *
1261  * for magic numbers this uses  0x1000, 0x1001 for rx/info
1262  */
1263 
1264 int
wi_get_fid_usb(struct wi_softc * sc,int fid)1265 wi_get_fid_usb(struct wi_softc *sc, int fid)
1266 {
1267 	switch (fid) {
1268 	case WI_RX_FID:
1269 		return 0x1000;
1270 	case WI_INFO_FID:
1271 		return 0x1001;
1272 	default:
1273 		return 0x1111;
1274 	}
1275 
1276 }
1277 
1278 #if 0
1279 void
1280 wi_dump_data(void *buffer, int len)
1281 {
1282 	int i;
1283 	for (i = 0; i < len; i++) {
1284 		if (((i) % 16) == 0)
1285 			printf("\n %02x:", i);
1286 		printf(" %02x",
1287 		    ((uint8_t *)(buffer))[i]);
1288 
1289 	}
1290 	printf("\n");
1291 
1292 }
1293 #endif
1294 
1295 /*
1296  * A frame has been received.
1297  */
1298 void
wi_usb_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)1299 wi_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
1300 {
1301 	struct wi_usb_chain	*c = priv;
1302 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1303 	wi_usb_usbin		*uin;
1304 	int			total_len = 0;
1305 	u_int16_t		rtype;
1306 
1307 	if (usbd_is_dying(sc->wi_usb_udev))
1308 		return;
1309 
1310 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1311 		    __func__, status));
1312 
1313 
1314 	if (status != USBD_NORMAL_COMPLETION) {
1315 		if (status == USBD_NOT_STARTED || status == USBD_IOERROR
1316 		    || status == USBD_CANCELLED) {
1317 			printf("%s: %u usb errors on rx: %s\n",
1318 			    sc->wi_usb_dev.dv_xname, 1,
1319 			    /* sc->wi_usb_rx_errs, */
1320 			    usbd_errstr(status));
1321 			return;
1322 		}
1323 #if 0
1324 		sc->wi_usb_rx_errs++;
1325 		if (usbd_ratecheck(&sc->wi_usb_rx_notice)) {
1326 			printf("%s: %u usb errors on rx: %s\n",
1327 			    sc->wi_usb_dev.dv_xname, sc->wi_usb_rx_errs,
1328 			    usbd_errstr(status));
1329 			sc->wi_usb_rx_errs = 0;
1330 		}
1331 #endif
1332 		if (status == USBD_STALLED) {
1333 			sc->wi_usb_refcnt++;
1334 			usbd_clear_endpoint_stall_async(
1335 			    sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1336 			if (--sc->wi_usb_refcnt < 0)
1337 				usb_detach_wakeup(&sc->wi_usb_dev);
1338 		}
1339 		goto done;
1340 	}
1341 
1342 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
1343 
1344 	if (total_len < 6) /* short XXX */
1345 		goto done;
1346 
1347 	uin = (wi_usb_usbin *)(c->wi_usb_buf);
1348 
1349 	rtype = letoh16(uin->type);
1350 
1351 
1352 #if 0
1353 	wi_dump_data(c->wi_usb_buf, total_len);
1354 #endif
1355 
1356 	if (WI_USB_ISRXFRM(rtype)) {
1357 		wi_usb_rxfrm(sc, uin, total_len);
1358 		goto done;
1359 	}
1360 	if (WI_USB_ISTXFRM(rtype)) {
1361 		DPRINTFN(2,("%s: %s: txfrm type %x\n",
1362 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1363 		wi_usb_txfrm(sc, uin, total_len);
1364 		goto done;
1365 	}
1366 
1367 	switch (rtype) {
1368 	case WI_USB_INFOFRM:
1369 		/* info packet, INFO_FID hmm */
1370 		DPRINTFN(10,("%s: %s: infofrm type %x\n",
1371 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1372 		wi_usb_infofrm(c, total_len);
1373 		break;
1374 	case WI_USB_CMDRESP:
1375 		wi_usb_cmdresp(c);
1376 		break;
1377 	case WI_USB_WRIDRESP:
1378 		wi_usb_wridresp(c);
1379 		break;
1380 	case WI_USB_RRIDRESP:
1381 		wi_usb_rridresp(c);
1382 		break;
1383 	case WI_USB_WMEMRESP:
1384 		/* Not currently used */
1385 		DPRINTFN(2,("%s: %s: wmemresp type %x\n",
1386 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1387 		break;
1388 	case WI_USB_RMEMRESP:
1389 		/* Not currently used */
1390 		DPRINTFN(2,("%s: %s: rmemresp type %x\n",
1391 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1392 		break;
1393 	case WI_USB_BUFAVAIL:
1394 		printf("wi_usb: received USB_BUFAVAIL packet\n"); /* XXX */
1395 		break;
1396 	case WI_USB_ERROR:
1397 		printf("wi_usb: received USB_ERROR packet\n"); /* XXX */
1398 		break;
1399 #if 0
1400 	default:
1401 		printf("wi_usb: received Unknown packet 0x%x len %x\n",
1402 		    rtype, total_len);
1403 		wi_dump_data(c->wi_usb_buf, total_len);
1404 #endif
1405 	}
1406 
1407  done:
1408 	/* Setup new transfer. */
1409 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
1410 	    c, c->wi_usb_buf, WI_USB_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
1411 	    USBD_NO_TIMEOUT, wi_usb_rxeof);
1412 	sc->wi_usb_refcnt++;
1413 	usbd_transfer(c->wi_usb_xfer);
1414 	if (--sc->wi_usb_refcnt < 0)
1415 		usb_detach_wakeup(&sc->wi_usb_dev);
1416 
1417 	DPRINTFN(10,("%s: %s: start rx\n", sc->wi_usb_dev.dv_xname,
1418 		    __func__));
1419 }
1420 
1421 void
wi_usb_intr(struct usbd_xfer * xfer,void * priv,usbd_status status)1422 wi_usb_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
1423 {
1424 	struct wi_usb_softc	*sc = priv;
1425 
1426 	DPRINTFN(2,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1427 
1428 	if (usbd_is_dying(sc->wi_usb_udev))
1429 		return;
1430 
1431 	if (status != USBD_NORMAL_COMPLETION) {
1432 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1433 			return;
1434 
1435 		if (status == USBD_STALLED) {
1436 			sc->wi_usb_refcnt++;
1437 			usbd_clear_endpoint_stall_async(
1438 			    sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1439 			if (--sc->wi_usb_refcnt < 0)
1440 				usb_detach_wakeup(&sc->wi_usb_dev);
1441 		}
1442 		return;
1443 	}
1444 	/* XXX oerrors or collisions? */
1445 }
1446 void
wi_usb_cmdresp(struct wi_usb_chain * c)1447 wi_usb_cmdresp(struct wi_usb_chain *c)
1448 {
1449 	struct wi_cmdresp *presp = (struct wi_cmdresp *)(c->wi_usb_buf);
1450 	u_int16_t status = letoh16(presp->status);
1451 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1452 	uint16_t type;
1453 	uint16_t cmdresperr;
1454 
1455 	type = htole16(presp->type);
1456 	cmdresperr = letoh16(presp->resp0);
1457 	DPRINTFN(10,("%s: %s: enter type=%x, status=%x, cmdresp=%x, "
1458 	    "resp=%x,%x,%x\n",
1459 	    sc->wi_usb_dev.dv_xname, __func__, type, status, sc->cmdresp,
1460 	    cmdresperr, letoh16(presp->resp1),
1461 	    letoh16(presp->resp2)));
1462 
1463 	/* XXX */
1464 	if (sc->cmdresp != (status & WI_STAT_CMD_CODE)) {
1465 		DPRINTFN(1,("%s: cmd ty %x st %x cmd %x failed %x\n",
1466 		    sc->wi_usb_dev.dv_xname,
1467 			type, status, sc->cmdresp, cmdresperr));
1468 		return;
1469 	}
1470 
1471 	sc->cmdresperr = (status & WI_STAT_CMD_RESULT) >> 8;
1472 
1473 	sc->cmdresp = 0; /* good value for idle == INI ?? XXX  */
1474 
1475 	wakeup(&sc->cmdresperr);
1476 }
1477 void
wi_usb_rridresp(struct wi_usb_chain * c)1478 wi_usb_rridresp(struct wi_usb_chain *c)
1479 {
1480 	struct wi_rridresp *presp = (struct wi_rridresp *)(c->wi_usb_buf);
1481 	u_int16_t frmlen = letoh16(presp->frmlen);
1482 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1483 	struct wi_ltv_gen *ltv;
1484 	uint16_t rid;
1485 
1486 	rid = letoh16(presp->rid);
1487 	ltv =  sc->ridltv;
1488 
1489 	if (ltv == 0) {
1490 		DPRINTFN(5,("%s: %s: enter ltv = 0 rid=%x len %d\n",
1491 		    sc->wi_usb_dev.dv_xname, __func__, rid,
1492 		    frmlen));
1493 		return;
1494 	}
1495 
1496 	DPRINTFN(5,("%s: %s: enter rid=%x expecting %x len %d exptlen %d\n",
1497 	    sc->wi_usb_dev.dv_xname, __func__, rid, ltv->wi_type,
1498 	    frmlen, ltv->wi_len));
1499 
1500 	rid = letoh16(presp->rid);
1501 
1502 	if (rid != ltv->wi_type) {
1503 		sc->ridresperr = EIO;
1504 		return;
1505 	}
1506 
1507 	if (frmlen > ltv->wi_len) {
1508 		sc->ridresperr = ENOSPC;
1509 		sc->ridltv = 0;
1510 		wakeup(&sc->ridresperr);
1511 		return;
1512 	}
1513 
1514 	ltv->wi_len = frmlen;
1515 
1516 	DPRINTFN(10,("%s: %s: copying %d frmlen %d\n",
1517 	    sc->wi_usb_dev.dv_xname, __func__, (ltv->wi_len-1)*2,
1518 	    frmlen));
1519 
1520 	if (ltv->wi_len > 1)
1521 		bcopy(&presp->data[0], &ltv->wi_val,
1522 		    (ltv->wi_len-1)*2);
1523 
1524 	sc->ridresperr = 0;
1525 	sc->ridltv = 0;
1526 	wakeup(&sc->ridresperr);
1527 
1528 }
1529 
1530 void
wi_usb_wridresp(struct wi_usb_chain * c)1531 wi_usb_wridresp(struct wi_usb_chain *c)
1532 {
1533 	struct wi_wridresp *presp = (struct wi_wridresp *)(c->wi_usb_buf);
1534 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1535 	uint16_t status;
1536 
1537 	status = letoh16(presp->status);
1538 
1539 	DPRINTFN(10,("%s: %s: enter status=%x\n",
1540 	    sc->wi_usb_dev.dv_xname, __func__, status));
1541 
1542 	sc->ridresperr = (status & WI_STAT_CMD_RESULT) >> 8;
1543 	sc->ridltv = 0;
1544 	wakeup(&sc->ridresperr);
1545 }
1546 
1547 void
wi_usb_infofrm(struct wi_usb_chain * c,int len)1548 wi_usb_infofrm(struct wi_usb_chain *c, int len)
1549 {
1550 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1551 
1552 	DPRINTFN(10,("%s: %s: enter\n",
1553 	    sc->wi_usb_dev.dv_xname, __func__));
1554 
1555 	sc->wi_info = ((char *)c->wi_usb_buf) + 2;
1556 	wi_update_stats(&sc->sc_wi);
1557 	sc->wi_info = NULL;
1558 }
1559 
1560 void
wi_usb_txfrm(struct wi_usb_softc * sc,wi_usb_usbin * uin,int total_len)1561 wi_usb_txfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
1562 {
1563 	u_int16_t		status;
1564 	int 			s;
1565 	struct wi_softc		*wsc = &sc->sc_wi;
1566 	struct ifnet		*ifp = &wsc->sc_ic.ic_if;
1567 
1568 	s = splnet();
1569 	status = letoh16(uin->type); /* XXX -- type == status */
1570 
1571 
1572 	DPRINTFN(2,("%s: %s: enter status=%d\n",
1573 	    sc->wi_usb_dev.dv_xname, __func__, status));
1574 
1575 	if (sc->txresp == WI_CMD_TX) {
1576 		sc->txresperr=status;
1577 		sc->txresp = 0;
1578 		wakeup(&sc->txresperr);
1579 	} else {
1580 		if (status != 0) /* XXX */
1581 			wi_watchdog_usb(ifp);
1582 	DPRINTFN(1,("%s: %s: txresp not expected status=%d \n",
1583 	    sc->wi_usb_dev.dv_xname, __func__, status));
1584 	}
1585 
1586 	splx(s);
1587 }
1588 void
wi_usb_rxfrm(struct wi_usb_softc * sc,wi_usb_usbin * uin,int total_len)1589 wi_usb_rxfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
1590 {
1591 	int s;
1592 
1593 	DPRINTFN(5,("%s: %s: enter len=%d\n",
1594 	    sc->wi_usb_dev.dv_xname, __func__, total_len));
1595 
1596 	s = splnet();
1597 
1598 	sc->wi_rxframe = (void *)uin;
1599 
1600 	wi_rxeof(&sc->sc_wi);
1601 
1602 	sc->wi_rxframe = NULL;
1603 
1604 	splx(s);
1605 
1606 }
1607 
1608 
1609 void
wi_usb_start_thread(void * arg)1610 wi_usb_start_thread(void *arg)
1611 {
1612 	struct wi_usb_softc	*sc = arg;
1613 	kthread_create (wi_usb_thread, arg, NULL, sc->wi_usb_dev.dv_xname);
1614 }
1615 
1616 void
wi_start_usb(struct ifnet * ifp)1617 wi_start_usb(struct ifnet *ifp)
1618 {
1619 	struct wi_softc		*wsc;
1620 	struct wi_usb_softc	*sc;
1621 	int s;
1622 
1623 	wsc = ifp->if_softc;
1624 	sc  = wsc->wi_usb_cdata;
1625 
1626 	s = splnet();
1627 
1628 	DPRINTFN(5,("%s: %s:\n",
1629 	    sc->wi_usb_dev.dv_xname, __func__));
1630 
1631 	if (wi_usb_tx_lock_try(sc)) {
1632 		/* lock acquired do start now */
1633 		wi_func_io.f_start(ifp);
1634 	} else {
1635 		sc->wi_thread_info->status |= WI_START;
1636 		if (sc->wi_thread_info->idle)
1637 			wakeup(sc->wi_thread_info);
1638 	}
1639 
1640 	splx(s);
1641 }
1642 
1643 /*
1644  * inquire is called from interrupt context (timeout)
1645  * It is not possible to sleep in interrupt context so it is necessary
1646  * to signal the kernel thread to perform the action.
1647  */
1648 void
wi_init_usb(struct wi_softc * wsc)1649 wi_init_usb(struct wi_softc *wsc)
1650 {
1651 	DPRINTFN(5,("%s: %s:\n", WI_PRT_ARG(wsc), __func__));
1652 
1653 	wi_usb_ctl_lock(wsc->wi_usb_cdata);
1654 	wi_func_io.f_init(wsc);
1655 	wi_usb_ctl_unlock(wsc->wi_usb_cdata);
1656 }
1657 
1658 
1659 /*
1660  * inquire is called from interrupt context (timeout)
1661  * It is not possible to sleep in interrupt context so it is necessary
1662  * to signal the kernel thread to perform the action.
1663  */
1664 void
wi_inquire_usb(void * xsc)1665 wi_inquire_usb(void *xsc)
1666 {
1667 	struct wi_softc		*wsc = xsc;
1668 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
1669 	int s;
1670 
1671 
1672 	s = splnet();
1673 
1674 	DPRINTFN(2,("%s: %s:\n",
1675 	    sc->wi_usb_dev.dv_xname, __func__));
1676 
1677 	sc->wi_thread_info->status |= WI_INQUIRE;
1678 
1679 	if (sc->wi_thread_info->idle)
1680 		wakeup(sc->wi_thread_info);
1681 	splx(s);
1682 }
1683 
1684 /*
1685  * Watchdog is normally called from interrupt context (timeout)
1686  * It is not possible to sleep in interrupt context so it is necessary
1687  * to signal the kernel thread to perform the action.
1688  */
1689 void
wi_watchdog_usb(struct ifnet * ifp)1690 wi_watchdog_usb(struct ifnet *ifp)
1691 {
1692 	struct wi_softc		*wsc;
1693 	struct wi_usb_softc	*sc;
1694 	int s;
1695 
1696 	wsc = ifp->if_softc;
1697 	sc = wsc->wi_usb_cdata;
1698 
1699 	s = splnet();
1700 
1701 	DPRINTFN(5,("%s: %s: ifp %x\n",
1702 	    sc->wi_usb_dev.dv_xname, __func__, ifp));
1703 
1704 	sc->wi_thread_info->status |= WI_WATCHDOG;
1705 
1706 	if (sc->wi_thread_info->idle)
1707 		wakeup(sc->wi_thread_info);
1708 	splx(s);
1709 }
1710 
1711 /*
1712  * ioctl will always be called from a user context,
1713  * therefore it is possible to sleep in the calling context
1714  * acquire the lock and call the real ioctl function directly
1715  */
1716 int
wi_ioctl_usb(struct ifnet * ifp,u_long command,caddr_t data)1717 wi_ioctl_usb(struct ifnet *ifp, u_long command, caddr_t data)
1718 {
1719 	struct wi_softc		*wsc;
1720 	int err;
1721 
1722 	wsc = ifp->if_softc;
1723 
1724 	wi_usb_ctl_lock(wsc->wi_usb_cdata);
1725 	err = wi_func_io.f_ioctl(ifp, command, data);
1726 	wi_usb_ctl_unlock(wsc->wi_usb_cdata);
1727 	return err;
1728 }
1729 
1730 void
wi_usb_thread(void * arg)1731 wi_usb_thread(void *arg)
1732 {
1733 	struct wi_usb_softc *sc = arg;
1734 	struct wi_usb_thread_info *wi_thread_info;
1735 	int s;
1736 
1737 	wi_thread_info = malloc(sizeof(*wi_thread_info), M_USBDEV, M_WAITOK);
1738 
1739 	/*
1740 	 * is there a remote possibility that the device could
1741 	 * be removed before the kernel thread starts up?
1742 	 */
1743 
1744 	sc->wi_usb_refcnt++;
1745 
1746 	sc->wi_thread_info = wi_thread_info;
1747 	wi_thread_info->dying = 0;
1748 	wi_thread_info->status = 0;
1749 
1750 	wi_usb_ctl_lock(sc);
1751 
1752 	wi_attach(&sc->sc_wi, &wi_func_usb);
1753 
1754 	wi_usb_ctl_unlock(sc);
1755 
1756 	for(;;) {
1757 		if (wi_thread_info->dying) {
1758 			if (--sc->wi_usb_refcnt < 0)
1759 				usb_detach_wakeup(&sc->wi_usb_dev);
1760 			kthread_exit(0);
1761 		}
1762 
1763 		DPRINTFN(5,("%s: %s: dying %x status %x\n",
1764 		    sc->wi_usb_dev.dv_xname, __func__,
1765 			wi_thread_info->dying, wi_thread_info->status));
1766 
1767 		wi_usb_ctl_lock(sc);
1768 
1769 		DPRINTFN(5,("%s: %s: starting %x\n",
1770 		    sc->wi_usb_dev.dv_xname, __func__,
1771 		    wi_thread_info->status));
1772 
1773 		s = splusb();
1774 		if (wi_thread_info->status & WI_START) {
1775 			wi_thread_info->status &= ~WI_START;
1776 			wi_usb_tx_lock(sc);
1777 			wi_func_io.f_start(&sc->sc_wi.sc_ic.ic_if);
1778 			/*
1779 			 * tx_unlock is explicitly missing here
1780 			 * it is done in txeof_frm
1781 			 */
1782 		} else if (wi_thread_info->status & WI_INQUIRE) {
1783 			wi_thread_info->status &= ~WI_INQUIRE;
1784 			wi_func_io.f_inquire(&sc->sc_wi);
1785 		} else if (wi_thread_info->status & WI_WATCHDOG) {
1786 			wi_thread_info->status &= ~WI_WATCHDOG;
1787 			wi_func_io.f_watchdog( &sc->sc_wi.sc_ic.ic_if);
1788 		}
1789 		splx(s);
1790 
1791 		DPRINTFN(5,("%s: %s: ending %x\n",
1792 		    sc->wi_usb_dev.dv_xname, __func__,
1793 		    wi_thread_info->status));
1794 		wi_usb_ctl_unlock(sc);
1795 
1796 		if (wi_thread_info->status == 0) {
1797 			s = splnet();
1798 			wi_thread_info->idle = 1;
1799 			tsleep_nsec(wi_thread_info, PRIBIO, "wiIDL", INFSLP);
1800 			wi_thread_info->idle = 0;
1801 			splx(s);
1802 		}
1803 	}
1804 }
1805 
1806 int
wi_usb_tx_lock_try(struct wi_usb_softc * sc)1807 wi_usb_tx_lock_try(struct wi_usb_softc *sc)
1808 {
1809 	int s;
1810 
1811 	s = splnet();
1812 
1813 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1814 
1815 	if (sc->wi_lock != 0) {
1816 		splx(s);
1817 		return 0; /* failed to acquire lock */
1818 	}
1819 
1820 	sc->wi_lock = 1;
1821 
1822 	splx(s);
1823 
1824 	return 1;
1825 }
1826 void
wi_usb_tx_lock(struct wi_usb_softc * sc)1827 wi_usb_tx_lock(struct wi_usb_softc *sc)
1828 {
1829 	int s;
1830 
1831 	s = splnet();
1832 
1833 	again:
1834 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1835 
1836 	if (sc->wi_lock != 0) {
1837 		sc->wi_lockwait++;
1838 		DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
1839 		__func__, sc->wi_lockwait ));
1840 		tsleep_nsec(&sc->wi_lock, PRIBIO, "witxl", INFSLP);
1841 	}
1842 
1843 	if (sc->wi_lock != 0)
1844 		goto again;
1845 	sc->wi_lock = 1;
1846 
1847 	splx(s);
1848 
1849 	return;
1850 
1851 }
1852 
1853 void
wi_usb_tx_unlock(struct wi_usb_softc * sc)1854 wi_usb_tx_unlock(struct wi_usb_softc *sc)
1855 {
1856 	int s;
1857 	s = splnet();
1858 
1859 	sc->wi_lock = 0;
1860 
1861 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1862 
1863 	if (sc->wi_lockwait) {
1864 		DPRINTFN(10,("%s: %s: waking\n",
1865 		    sc->wi_usb_dev.dv_xname, __func__));
1866 		sc->wi_lockwait = 0;
1867 		wakeup(&sc->wi_lock);
1868 	}
1869 
1870 	splx(s);
1871 }
1872 
1873 void
wi_usb_ctl_lock(struct wi_usb_softc * sc)1874 wi_usb_ctl_lock(struct wi_usb_softc *sc)
1875 {
1876 	int s;
1877 
1878 	s = splnet();
1879 
1880 	again:
1881 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,
1882 	    __func__));
1883 
1884 	if (sc->wi_ctllock != 0) {
1885 		if (curproc == sc->wi_curproc) {
1886 			/* allow recursion */
1887 			sc->wi_ctllock++;
1888 			splx(s);
1889 			return;
1890 		}
1891 		sc->wi_ctllockwait++;
1892 		DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
1893 		__func__, sc->wi_ctllockwait ));
1894 		tsleep_nsec(&sc->wi_ctllock, PRIBIO, "wiusbthr", INFSLP);
1895 	}
1896 
1897 	if (sc->wi_ctllock != 0)
1898 		goto again;
1899 	sc->wi_ctllock++;
1900 	sc->wi_curproc = curproc;
1901 
1902 	splx(s);
1903 
1904 	return;
1905 
1906 }
1907 
1908 void
wi_usb_ctl_unlock(struct wi_usb_softc * sc)1909 wi_usb_ctl_unlock(struct wi_usb_softc *sc)
1910 {
1911 	int s;
1912 
1913 	s = splnet();
1914 
1915 	sc->wi_ctllock--;
1916 
1917 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1918 
1919 	if (sc->wi_ctllock == 0 && sc->wi_ctllockwait) {
1920 		DPRINTFN(10,("%s: %s: waking\n",
1921 		    sc->wi_usb_dev.dv_xname, __func__));
1922 		sc->wi_ctllockwait = 0;
1923 		sc->wi_curproc = 0;
1924 		wakeup(&sc->wi_ctllock);
1925 	}
1926 
1927 	splx(s);
1928 }
1929