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(<v->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], <v->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