Annotation of sys/dev/usb/if_wi_usb.c, Revision 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