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