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