Annotation of sys/dev/usb/if_upl.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_upl.c,v 1.38 2007/06/14 10:11:15 mbalmer Exp $ */
! 2: /* $NetBSD: if_upl.c,v 1.19 2002/07/11 21:14:26 augustss Exp $ */
! 3: /*
! 4: * Copyright (c) 2000 The NetBSD Foundation, Inc.
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to The NetBSD Foundation
! 8: * by Lennart Augustsson (lennart@augustsson.net) at
! 9: * Carlstedt Research & Technology.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Prolific PL2301/PL2302 driver
! 42: */
! 43:
! 44: #include "bpfilter.h"
! 45:
! 46: #include <sys/param.h>
! 47: #include <sys/systm.h>
! 48: #include <sys/timeout.h>
! 49: #include <sys/sockio.h>
! 50: #include <sys/mbuf.h>
! 51: #include <sys/malloc.h>
! 52: #include <sys/kernel.h>
! 53: #include <sys/socket.h>
! 54:
! 55: #include <sys/device.h>
! 56:
! 57: #include <net/if.h>
! 58: #include <net/if_types.h>
! 59: #include <net/if_dl.h>
! 60: #include <net/netisr.h>
! 61:
! 62: #if NBPFILTER > 0
! 63: #include <net/bpf.h>
! 64: #endif
! 65:
! 66: #ifdef INET
! 67: #include <netinet/in.h>
! 68: #include <netinet/in_var.h>
! 69: #include <netinet/in_systm.h>
! 70: #include <netinet/ip.h>
! 71: #include <netinet/if_ether.h>
! 72: #else
! 73: #error upl without INET?
! 74: #endif
! 75:
! 76: #include <dev/usb/usb.h>
! 77: #include <dev/usb/usbdi.h>
! 78: #include <dev/usb/usbdi_util.h>
! 79: #include <dev/usb/usbdevs.h>
! 80:
! 81: /*
! 82: * 7 6 5 4 3 2 1 0
! 83: * tx rx 1 0
! 84: * 1110 0000 rxdata
! 85: * 1010 0000 idle
! 86: * 0010 0000 tx over
! 87: * 0110 tx over + rxd
! 88: */
! 89:
! 90: #define UPL_RXDATA 0x40
! 91: #define UPL_TXOK 0x80
! 92:
! 93: #define UPL_INTR_PKTLEN 1
! 94:
! 95: #define UPL_CONFIG_NO 1
! 96: #define UPL_IFACE_IDX 0
! 97:
! 98: /***/
! 99:
! 100: #define UPL_INTR_INTERVAL 20
! 101:
! 102: #define UPL_BUFSZ 1024
! 103:
! 104: #define UPL_RX_FRAMES 1
! 105: #define UPL_TX_FRAMES 1
! 106:
! 107: #define UPL_RX_LIST_CNT 1
! 108: #define UPL_TX_LIST_CNT 1
! 109:
! 110: #define UPL_ENDPT_RX 0x0
! 111: #define UPL_ENDPT_TX 0x1
! 112: #define UPL_ENDPT_INTR 0x2
! 113: #define UPL_ENDPT_MAX 0x3
! 114:
! 115: struct upl_type {
! 116: u_int16_t upl_vid;
! 117: u_int16_t upl_did;
! 118: };
! 119:
! 120: struct upl_softc;
! 121:
! 122: struct upl_chain {
! 123: struct upl_softc *upl_sc;
! 124: usbd_xfer_handle upl_xfer;
! 125: char *upl_buf;
! 126: struct mbuf *upl_mbuf;
! 127: int upl_idx;
! 128: };
! 129:
! 130: struct upl_cdata {
! 131: struct upl_chain upl_tx_chain[UPL_TX_LIST_CNT];
! 132: struct upl_chain upl_rx_chain[UPL_RX_LIST_CNT];
! 133: int upl_tx_prod;
! 134: int upl_tx_cons;
! 135: int upl_tx_cnt;
! 136: int upl_rx_prod;
! 137: };
! 138:
! 139: struct upl_softc {
! 140: struct device sc_dev;
! 141:
! 142: struct ifnet sc_if;
! 143: struct timeout sc_stat_ch;
! 144:
! 145: usbd_device_handle sc_udev;
! 146: usbd_interface_handle sc_iface;
! 147: u_int16_t sc_vendor;
! 148: u_int16_t sc_product;
! 149: int sc_ed[UPL_ENDPT_MAX];
! 150: usbd_pipe_handle sc_ep[UPL_ENDPT_MAX];
! 151: struct upl_cdata sc_cdata;
! 152:
! 153: uByte sc_ibuf;
! 154:
! 155: char sc_dying;
! 156: char sc_attached;
! 157: u_int sc_rx_errs;
! 158: struct timeval sc_rx_notice;
! 159: u_int sc_intr_errs;
! 160: };
! 161:
! 162: #ifdef UPL_DEBUG
! 163: #define DPRINTF(x) do { if (upldebug) printf x; } while (0)
! 164: #define DPRINTFN(n,x) do { if (upldebug >= (n)) printf x; } while (0)
! 165: int upldebug = 0;
! 166: #else
! 167: #define DPRINTF(x)
! 168: #define DPRINTFN(n,x)
! 169: #endif
! 170:
! 171: /*
! 172: * Various supported device vendors/products.
! 173: */
! 174: struct upl_type sc_devs[] = {
! 175: { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2301 },
! 176: { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302 },
! 177: { 0, 0 }
! 178: };
! 179:
! 180: int upl_match(struct device *, void *, void *);
! 181: void upl_attach(struct device *, struct device *, void *);
! 182: int upl_detach(struct device *, int);
! 183: int upl_activate(struct device *, enum devact);
! 184:
! 185: struct cfdriver upl_cd = {
! 186: NULL, "upl", DV_IFNET
! 187: };
! 188:
! 189: const struct cfattach upl_ca = {
! 190: sizeof(struct upl_softc),
! 191: upl_match,
! 192: upl_attach,
! 193: upl_detach,
! 194: upl_activate,
! 195: };
! 196:
! 197: int upl_openpipes(struct upl_softc *);
! 198: int upl_tx_list_init(struct upl_softc *);
! 199: int upl_rx_list_init(struct upl_softc *);
! 200: int upl_newbuf(struct upl_softc *, struct upl_chain *, struct mbuf *);
! 201: int upl_send(struct upl_softc *, struct mbuf *, int);
! 202: void upl_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 203: void upl_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 204: void upl_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 205: void upl_start(struct ifnet *);
! 206: int upl_ioctl(struct ifnet *, u_long, caddr_t);
! 207: void upl_init(void *);
! 208: void upl_stop(struct upl_softc *);
! 209: void upl_watchdog(struct ifnet *);
! 210:
! 211: int upl_output(struct ifnet *, struct mbuf *, struct sockaddr *,
! 212: struct rtentry *);
! 213: void upl_input(struct ifnet *, struct mbuf *);
! 214:
! 215: /*
! 216: * Probe for a Prolific chip.
! 217: */
! 218: int
! 219: upl_match(struct device *parent, void *match, void *aux)
! 220: {
! 221: struct usb_attach_arg *uaa = aux;
! 222: struct upl_type *t;
! 223:
! 224: if (uaa->iface != NULL)
! 225: return (UMATCH_NONE);
! 226:
! 227: for (t = sc_devs; t->upl_vid != 0; t++)
! 228: if (uaa->vendor == t->upl_vid && uaa->product == t->upl_did)
! 229: return (UMATCH_VENDOR_PRODUCT);
! 230:
! 231: return (UMATCH_NONE);
! 232: }
! 233:
! 234: void
! 235: upl_attach(struct device *parent, struct device *self, void *aux)
! 236: {
! 237: struct upl_softc *sc = (struct upl_softc *)self;
! 238: struct usb_attach_arg *uaa = aux;
! 239: char *devinfop;
! 240: int s;
! 241: usbd_device_handle dev = uaa->device;
! 242: usbd_interface_handle iface;
! 243: usbd_status err;
! 244: struct ifnet *ifp;
! 245: usb_interface_descriptor_t *id;
! 246: usb_endpoint_descriptor_t *ed;
! 247: int i;
! 248:
! 249: DPRINTFN(5,(" : upl_attach: sc=%p, dev=%p", sc, dev));
! 250:
! 251: devinfop = usbd_devinfo_alloc(dev, 0);
! 252: printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 253: usbd_devinfo_free(devinfop);
! 254:
! 255: err = usbd_set_config_no(dev, UPL_CONFIG_NO, 1);
! 256: if (err) {
! 257: printf("%s: setting config no failed\n",
! 258: sc->sc_dev.dv_xname);
! 259: return;
! 260: }
! 261:
! 262: sc->sc_udev = dev;
! 263: sc->sc_product = uaa->product;
! 264: sc->sc_vendor = uaa->vendor;
! 265:
! 266: err = usbd_device2interface_handle(dev, UPL_IFACE_IDX, &iface);
! 267: if (err) {
! 268: printf("%s: getting interface handle failed\n",
! 269: sc->sc_dev.dv_xname);
! 270: return;
! 271: }
! 272:
! 273: sc->sc_iface = iface;
! 274: id = usbd_get_interface_descriptor(iface);
! 275:
! 276: /* Find endpoints. */
! 277: for (i = 0; i < id->bNumEndpoints; i++) {
! 278: ed = usbd_interface2endpoint_descriptor(iface, i);
! 279: if (ed == NULL) {
! 280: printf("%s: couldn't get ep %d\n",
! 281: sc->sc_dev.dv_xname, i);
! 282: return;
! 283: }
! 284: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 285: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 286: sc->sc_ed[UPL_ENDPT_RX] = ed->bEndpointAddress;
! 287: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 288: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 289: sc->sc_ed[UPL_ENDPT_TX] = ed->bEndpointAddress;
! 290: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 291: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
! 292: sc->sc_ed[UPL_ENDPT_INTR] = ed->bEndpointAddress;
! 293: }
! 294: }
! 295:
! 296: if (sc->sc_ed[UPL_ENDPT_RX] == 0 || sc->sc_ed[UPL_ENDPT_TX] == 0 ||
! 297: sc->sc_ed[UPL_ENDPT_INTR] == 0) {
! 298: printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
! 299: return;
! 300: }
! 301:
! 302: s = splnet();
! 303:
! 304: /* Initialize interface info.*/
! 305: ifp = &sc->sc_if;
! 306: ifp->if_softc = sc;
! 307: ifp->if_mtu = UPL_BUFSZ;
! 308: ifp->if_flags = IFF_POINTOPOINT | IFF_NOARP | IFF_SIMPLEX;
! 309: ifp->if_ioctl = upl_ioctl;
! 310: ifp->if_start = upl_start;
! 311: ifp->if_watchdog = upl_watchdog;
! 312: strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
! 313:
! 314: ifp->if_type = IFT_OTHER;
! 315: ifp->if_addrlen = 0;
! 316: ifp->if_hdrlen = 0;
! 317: ifp->if_output = upl_output;
! 318: ifp->if_baudrate = 12000000;
! 319: IFQ_SET_READY(&ifp->if_snd);
! 320:
! 321: /* Attach the interface. */
! 322: if_attach(ifp);
! 323: if_alloc_sadl(ifp);
! 324:
! 325: sc->sc_attached = 1;
! 326: splx(s);
! 327:
! 328: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 329: &sc->sc_dev);
! 330: }
! 331:
! 332: int
! 333: upl_detach(struct device *self, int flags)
! 334: {
! 335: struct upl_softc *sc = (struct upl_softc *)self;
! 336: struct ifnet *ifp = &sc->sc_if;
! 337: int s;
! 338:
! 339: DPRINTFN(2,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 340:
! 341: s = splusb();
! 342:
! 343: if (!sc->sc_attached) {
! 344: /* Detached before attached finished, so just bail out. */
! 345: splx(s);
! 346: return (0);
! 347: }
! 348:
! 349: if (ifp->if_flags & IFF_RUNNING)
! 350: upl_stop(sc);
! 351:
! 352: if_detach(ifp);
! 353:
! 354: #ifdef DIAGNOSTIC
! 355: if (sc->sc_ep[UPL_ENDPT_TX] != NULL ||
! 356: sc->sc_ep[UPL_ENDPT_RX] != NULL ||
! 357: sc->sc_ep[UPL_ENDPT_INTR] != NULL)
! 358: printf("%s: detach has active endpoints\n",
! 359: sc->sc_dev.dv_xname);
! 360: #endif
! 361:
! 362: sc->sc_attached = 0;
! 363: splx(s);
! 364:
! 365: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 366: &sc->sc_dev);
! 367:
! 368: return (0);
! 369: }
! 370:
! 371: int
! 372: upl_activate(struct device *self, enum devact act)
! 373: {
! 374: struct upl_softc *sc = (struct upl_softc *)self;
! 375:
! 376: DPRINTFN(2,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 377:
! 378: switch (act) {
! 379: case DVACT_ACTIVATE:
! 380: break;
! 381:
! 382: case DVACT_DEACTIVATE:
! 383: sc->sc_dying = 1;
! 384: break;
! 385: }
! 386: return (0);
! 387: }
! 388:
! 389: /*
! 390: * Initialize an RX descriptor and attach an MBUF cluster.
! 391: */
! 392: int
! 393: upl_newbuf(struct upl_softc *sc, struct upl_chain *c, struct mbuf *m)
! 394: {
! 395: struct mbuf *m_new = NULL;
! 396:
! 397: DPRINTFN(8,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 398:
! 399: if (m == NULL) {
! 400: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 401: if (m_new == NULL) {
! 402: printf("%s: no memory for rx list "
! 403: "-- packet dropped!\n", sc->sc_dev.dv_xname);
! 404: return (ENOBUFS);
! 405: }
! 406:
! 407: MCLGET(m_new, M_DONTWAIT);
! 408: if (!(m_new->m_flags & M_EXT)) {
! 409: printf("%s: no memory for rx list "
! 410: "-- packet dropped!\n", sc->sc_dev.dv_xname);
! 411: m_freem(m_new);
! 412: return (ENOBUFS);
! 413: }
! 414: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 415: } else {
! 416: m_new = m;
! 417: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 418: m_new->m_data = m_new->m_ext.ext_buf;
! 419: }
! 420:
! 421: c->upl_mbuf = m_new;
! 422:
! 423: return (0);
! 424: }
! 425:
! 426: int
! 427: upl_rx_list_init(struct upl_softc *sc)
! 428: {
! 429: struct upl_cdata *cd;
! 430: struct upl_chain *c;
! 431: int i;
! 432:
! 433: DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 434:
! 435: cd = &sc->sc_cdata;
! 436: for (i = 0; i < UPL_RX_LIST_CNT; i++) {
! 437: c = &cd->upl_rx_chain[i];
! 438: c->upl_sc = sc;
! 439: c->upl_idx = i;
! 440: if (upl_newbuf(sc, c, NULL) == ENOBUFS)
! 441: return (ENOBUFS);
! 442: if (c->upl_xfer == NULL) {
! 443: c->upl_xfer = usbd_alloc_xfer(sc->sc_udev);
! 444: if (c->upl_xfer == NULL)
! 445: return (ENOBUFS);
! 446: c->upl_buf = usbd_alloc_buffer(c->upl_xfer, UPL_BUFSZ);
! 447: if (c->upl_buf == NULL) {
! 448: usbd_free_xfer(c->upl_xfer);
! 449: return (ENOBUFS);
! 450: }
! 451: }
! 452: }
! 453:
! 454: return (0);
! 455: }
! 456:
! 457: int
! 458: upl_tx_list_init(struct upl_softc *sc)
! 459: {
! 460: struct upl_cdata *cd;
! 461: struct upl_chain *c;
! 462: int i;
! 463:
! 464: DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 465:
! 466: cd = &sc->sc_cdata;
! 467: for (i = 0; i < UPL_TX_LIST_CNT; i++) {
! 468: c = &cd->upl_tx_chain[i];
! 469: c->upl_sc = sc;
! 470: c->upl_idx = i;
! 471: c->upl_mbuf = NULL;
! 472: if (c->upl_xfer == NULL) {
! 473: c->upl_xfer = usbd_alloc_xfer(sc->sc_udev);
! 474: if (c->upl_xfer == NULL)
! 475: return (ENOBUFS);
! 476: c->upl_buf = usbd_alloc_buffer(c->upl_xfer, UPL_BUFSZ);
! 477: if (c->upl_buf == NULL) {
! 478: usbd_free_xfer(c->upl_xfer);
! 479: return (ENOBUFS);
! 480: }
! 481: }
! 482: }
! 483:
! 484: return (0);
! 485: }
! 486:
! 487: /*
! 488: * A frame has been uploaded: pass the resulting mbuf chain up to
! 489: * the higher level protocols.
! 490: */
! 491: void
! 492: upl_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 493: {
! 494: struct upl_chain *c = priv;
! 495: struct upl_softc *sc = c->upl_sc;
! 496: struct ifnet *ifp = &sc->sc_if;
! 497: struct mbuf *m;
! 498: int total_len = 0;
! 499: int s;
! 500:
! 501: if (sc->sc_dying)
! 502: return;
! 503:
! 504: if (!(ifp->if_flags & IFF_RUNNING))
! 505: return;
! 506:
! 507: if (status != USBD_NORMAL_COMPLETION) {
! 508: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 509: return;
! 510: sc->sc_rx_errs++;
! 511: if (usbd_ratecheck(&sc->sc_rx_notice)) {
! 512: printf("%s: %u usb errors on rx: %s\n",
! 513: sc->sc_dev.dv_xname, sc->sc_rx_errs,
! 514: usbd_errstr(status));
! 515: sc->sc_rx_errs = 0;
! 516: }
! 517: if (status == USBD_STALLED)
! 518: usbd_clear_endpoint_stall_async(sc->sc_ep[UPL_ENDPT_RX]);
! 519: goto done;
! 520: }
! 521:
! 522: usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
! 523:
! 524: DPRINTFN(9,("%s: %s: enter status=%d length=%d\n",
! 525: sc->sc_dev.dv_xname, __func__, status, total_len));
! 526:
! 527: m = c->upl_mbuf;
! 528: memcpy(mtod(c->upl_mbuf, char *), c->upl_buf, total_len);
! 529:
! 530: ifp->if_ipackets++;
! 531: m->m_pkthdr.len = m->m_len = total_len;
! 532:
! 533: m->m_pkthdr.rcvif = ifp;
! 534:
! 535: s = splnet();
! 536:
! 537: /* XXX ugly */
! 538: if (upl_newbuf(sc, c, NULL) == ENOBUFS) {
! 539: ifp->if_ierrors++;
! 540: goto done1;
! 541: }
! 542:
! 543: #if NBPFILTER > 0
! 544: /*
! 545: * Handle BPF listeners. Let the BPF user see the packet, but
! 546: * don't pass it up to the ether_input() layer unless it's
! 547: * a broadcast packet, multicast packet, matches our ethernet
! 548: * address or the interface is in promiscuous mode.
! 549: */
! 550: if (ifp->if_bpf) {
! 551: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 552: }
! 553: #endif
! 554:
! 555: DPRINTFN(10,("%s: %s: deliver %d\n", sc->sc_dev.dv_xname,
! 556: __func__, m->m_len));
! 557:
! 558: ether_input_mbuf(ifp, m);
! 559:
! 560: done1:
! 561: splx(s);
! 562:
! 563: done:
! 564: #if 1
! 565: /* Setup new transfer. */
! 566: usbd_setup_xfer(c->upl_xfer, sc->sc_ep[UPL_ENDPT_RX],
! 567: c, c->upl_buf, UPL_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 568: USBD_NO_TIMEOUT, upl_rxeof);
! 569: usbd_transfer(c->upl_xfer);
! 570:
! 571: DPRINTFN(10,("%s: %s: start rx\n", sc->sc_dev.dv_xname,
! 572: __func__));
! 573: #endif
! 574: }
! 575:
! 576: /*
! 577: * A frame was downloaded to the chip. It's safe for us to clean up
! 578: * the list buffers.
! 579: */
! 580: void
! 581: upl_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 582: {
! 583: struct upl_chain *c = priv;
! 584: struct upl_softc *sc = c->upl_sc;
! 585: struct ifnet *ifp = &sc->sc_if;
! 586: int s;
! 587:
! 588: if (sc->sc_dying)
! 589: return;
! 590:
! 591: s = splnet();
! 592:
! 593: DPRINTFN(10,("%s: %s: enter status=%d\n", sc->sc_dev.dv_xname,
! 594: __func__, status));
! 595:
! 596: ifp->if_timer = 0;
! 597: ifp->if_flags &= ~IFF_OACTIVE;
! 598:
! 599: if (status != USBD_NORMAL_COMPLETION) {
! 600: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
! 601: splx(s);
! 602: return;
! 603: }
! 604: ifp->if_oerrors++;
! 605: printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname,
! 606: usbd_errstr(status));
! 607: if (status == USBD_STALLED)
! 608: usbd_clear_endpoint_stall_async(sc->sc_ep[UPL_ENDPT_TX]);
! 609: splx(s);
! 610: return;
! 611: }
! 612:
! 613: ifp->if_opackets++;
! 614:
! 615: m_freem(c->upl_mbuf);
! 616: c->upl_mbuf = NULL;
! 617:
! 618: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 619: upl_start(ifp);
! 620:
! 621: splx(s);
! 622: }
! 623:
! 624: int
! 625: upl_send(struct upl_softc *sc, struct mbuf *m, int idx)
! 626: {
! 627: int total_len;
! 628: struct upl_chain *c;
! 629: usbd_status err;
! 630:
! 631: c = &sc->sc_cdata.upl_tx_chain[idx];
! 632:
! 633: /*
! 634: * Copy the mbuf data into a contiguous buffer, leaving two
! 635: * bytes at the beginning to hold the frame length.
! 636: */
! 637: m_copydata(m, 0, m->m_pkthdr.len, c->upl_buf);
! 638: c->upl_mbuf = m;
! 639:
! 640: total_len = m->m_pkthdr.len;
! 641:
! 642: DPRINTFN(10,("%s: %s: total_len=%d\n",
! 643: sc->sc_dev.dv_xname, __func__, total_len));
! 644:
! 645: usbd_setup_xfer(c->upl_xfer, sc->sc_ep[UPL_ENDPT_TX],
! 646: c, c->upl_buf, total_len, USBD_NO_COPY, USBD_DEFAULT_TIMEOUT,
! 647: upl_txeof);
! 648:
! 649: /* Transmit */
! 650: err = usbd_transfer(c->upl_xfer);
! 651: if (err != USBD_IN_PROGRESS) {
! 652: printf("%s: upl_send error=%s\n", sc->sc_dev.dv_xname,
! 653: usbd_errstr(err));
! 654: upl_stop(sc);
! 655: return (EIO);
! 656: }
! 657:
! 658: sc->sc_cdata.upl_tx_cnt++;
! 659:
! 660: return (0);
! 661: }
! 662:
! 663: void
! 664: upl_start(struct ifnet *ifp)
! 665: {
! 666: struct upl_softc *sc = ifp->if_softc;
! 667: struct mbuf *m_head = NULL;
! 668:
! 669: if (sc->sc_dying)
! 670: return;
! 671:
! 672: DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
! 673:
! 674: if (ifp->if_flags & IFF_OACTIVE)
! 675: return;
! 676:
! 677: IFQ_POLL(&ifp->if_snd, m_head);
! 678: if (m_head == NULL)
! 679: return;
! 680:
! 681: if (upl_send(sc, m_head, 0)) {
! 682: ifp->if_flags |= IFF_OACTIVE;
! 683: return;
! 684: }
! 685:
! 686: IFQ_DEQUEUE(&ifp->if_snd, m_head);
! 687:
! 688: #if NBPFILTER > 0
! 689: /*
! 690: * If there's a BPF listener, bounce a copy of this frame
! 691: * to him.
! 692: */
! 693: if (ifp->if_bpf)
! 694: bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
! 695: #endif
! 696:
! 697: ifp->if_flags |= IFF_OACTIVE;
! 698:
! 699: /*
! 700: * Set a timeout in case the chip goes out to lunch.
! 701: */
! 702: ifp->if_timer = 5;
! 703: }
! 704:
! 705: void
! 706: upl_init(void *xsc)
! 707: {
! 708: struct upl_softc *sc = xsc;
! 709: struct ifnet *ifp = &sc->sc_if;
! 710: int s;
! 711:
! 712: if (sc->sc_dying)
! 713: return;
! 714:
! 715: DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
! 716:
! 717: if (ifp->if_flags & IFF_RUNNING)
! 718: return;
! 719:
! 720: s = splnet();
! 721:
! 722: /* Init TX ring. */
! 723: if (upl_tx_list_init(sc) == ENOBUFS) {
! 724: printf("%s: tx list init failed\n", sc->sc_dev.dv_xname);
! 725: splx(s);
! 726: return;
! 727: }
! 728:
! 729: /* Init RX ring. */
! 730: if (upl_rx_list_init(sc) == ENOBUFS) {
! 731: printf("%s: rx list init failed\n", sc->sc_dev.dv_xname);
! 732: splx(s);
! 733: return;
! 734: }
! 735:
! 736: if (sc->sc_ep[UPL_ENDPT_RX] == NULL) {
! 737: if (upl_openpipes(sc)) {
! 738: splx(s);
! 739: return;
! 740: }
! 741: }
! 742:
! 743: ifp->if_flags |= IFF_RUNNING;
! 744: ifp->if_flags &= ~IFF_OACTIVE;
! 745:
! 746: splx(s);
! 747: }
! 748:
! 749: int
! 750: upl_openpipes(struct upl_softc *sc)
! 751: {
! 752: struct upl_chain *c;
! 753: usbd_status err;
! 754: int i;
! 755:
! 756: /* Open RX and TX pipes. */
! 757: err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UPL_ENDPT_RX],
! 758: USBD_EXCLUSIVE_USE, &sc->sc_ep[UPL_ENDPT_RX]);
! 759: if (err) {
! 760: printf("%s: open rx pipe failed: %s\n",
! 761: sc->sc_dev.dv_xname, usbd_errstr(err));
! 762: return (EIO);
! 763: }
! 764: err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UPL_ENDPT_TX],
! 765: USBD_EXCLUSIVE_USE, &sc->sc_ep[UPL_ENDPT_TX]);
! 766: if (err) {
! 767: printf("%s: open tx pipe failed: %s\n",
! 768: sc->sc_dev.dv_xname, usbd_errstr(err));
! 769: return (EIO);
! 770: }
! 771: err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ed[UPL_ENDPT_INTR],
! 772: USBD_EXCLUSIVE_USE, &sc->sc_ep[UPL_ENDPT_INTR], sc,
! 773: &sc->sc_ibuf, UPL_INTR_PKTLEN, upl_intr,
! 774: UPL_INTR_INTERVAL);
! 775: if (err) {
! 776: printf("%s: open intr pipe failed: %s\n",
! 777: sc->sc_dev.dv_xname, usbd_errstr(err));
! 778: return (EIO);
! 779: }
! 780:
! 781:
! 782: #if 1
! 783: /* Start up the receive pipe. */
! 784: for (i = 0; i < UPL_RX_LIST_CNT; i++) {
! 785: c = &sc->sc_cdata.upl_rx_chain[i];
! 786: usbd_setup_xfer(c->upl_xfer, sc->sc_ep[UPL_ENDPT_RX],
! 787: c, c->upl_buf, UPL_BUFSZ,
! 788: USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
! 789: upl_rxeof);
! 790: usbd_transfer(c->upl_xfer);
! 791: }
! 792: #endif
! 793:
! 794: return (0);
! 795: }
! 796:
! 797: void
! 798: upl_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 799: {
! 800: struct upl_softc *sc = priv;
! 801: struct ifnet *ifp = &sc->sc_if;
! 802: uByte stat;
! 803:
! 804: DPRINTFN(15,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
! 805:
! 806: if (sc->sc_dying)
! 807: return;
! 808:
! 809: if (!(ifp->if_flags & IFF_RUNNING))
! 810: return;
! 811:
! 812: if (status != USBD_NORMAL_COMPLETION) {
! 813: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
! 814: return;
! 815: }
! 816: sc->sc_intr_errs++;
! 817: if (usbd_ratecheck(&sc->sc_rx_notice)) {
! 818: printf("%s: %u usb errors on intr: %s\n",
! 819: sc->sc_dev.dv_xname, sc->sc_rx_errs,
! 820: usbd_errstr(status));
! 821: sc->sc_intr_errs = 0;
! 822: }
! 823: if (status == USBD_STALLED)
! 824: usbd_clear_endpoint_stall_async(sc->sc_ep[UPL_ENDPT_RX]);
! 825: return;
! 826: }
! 827:
! 828: stat = sc->sc_ibuf;
! 829:
! 830: if (stat == 0)
! 831: return;
! 832:
! 833: DPRINTFN(10,("%s: %s: stat=0x%02x\n", sc->sc_dev.dv_xname,
! 834: __func__, stat));
! 835:
! 836: }
! 837:
! 838: int
! 839: upl_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
! 840: {
! 841: struct upl_softc *sc = ifp->if_softc;
! 842: struct ifaddr *ifa = (struct ifaddr *)data;
! 843: struct ifreq *ifr = (struct ifreq *)data;
! 844: int s, error = 0;
! 845:
! 846: if (sc->sc_dying)
! 847: return (EIO);
! 848:
! 849: DPRINTFN(5,("%s: %s: cmd=0x%08lx\n",
! 850: sc->sc_dev.dv_xname, __func__, command));
! 851:
! 852: s = splnet();
! 853:
! 854: switch(command) {
! 855: case SIOCSIFADDR:
! 856: ifp->if_flags |= IFF_UP;
! 857: upl_init(sc);
! 858:
! 859: switch (ifa->ifa_addr->sa_family) {
! 860: #ifdef INET
! 861: case AF_INET:
! 862: break;
! 863: #endif /* INET */
! 864: }
! 865: break;
! 866:
! 867: case SIOCSIFMTU:
! 868: if (ifr->ifr_mtu > UPL_BUFSZ)
! 869: error = EINVAL;
! 870: else
! 871: ifp->if_mtu = ifr->ifr_mtu;
! 872: break;
! 873:
! 874: case SIOCSIFFLAGS:
! 875: if (ifp->if_flags & IFF_UP) {
! 876: if (!(ifp->if_flags & IFF_RUNNING))
! 877: upl_init(sc);
! 878: } else {
! 879: if (ifp->if_flags & IFF_RUNNING)
! 880: upl_stop(sc);
! 881: }
! 882: error = 0;
! 883: break;
! 884: default:
! 885: error = EINVAL;
! 886: break;
! 887: }
! 888:
! 889: splx(s);
! 890:
! 891: return (error);
! 892: }
! 893:
! 894: void
! 895: upl_watchdog(struct ifnet *ifp)
! 896: {
! 897: struct upl_softc *sc = ifp->if_softc;
! 898:
! 899: DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
! 900:
! 901: if (sc->sc_dying)
! 902: return;
! 903:
! 904: ifp->if_oerrors++;
! 905: printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
! 906:
! 907: upl_stop(sc);
! 908: upl_init(sc);
! 909:
! 910: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 911: upl_start(ifp);
! 912: }
! 913:
! 914: /*
! 915: * Stop the adapter and free any mbufs allocated to the
! 916: * RX and TX lists.
! 917: */
! 918: void
! 919: upl_stop(struct upl_softc *sc)
! 920: {
! 921: usbd_status err;
! 922: struct ifnet *ifp;
! 923: int i;
! 924:
! 925: DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
! 926:
! 927: ifp = &sc->sc_if;
! 928: ifp->if_timer = 0;
! 929: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 930:
! 931: /* Stop transfers. */
! 932: if (sc->sc_ep[UPL_ENDPT_RX] != NULL) {
! 933: err = usbd_abort_pipe(sc->sc_ep[UPL_ENDPT_RX]);
! 934: if (err) {
! 935: printf("%s: abort rx pipe failed: %s\n",
! 936: sc->sc_dev.dv_xname, usbd_errstr(err));
! 937: }
! 938: err = usbd_close_pipe(sc->sc_ep[UPL_ENDPT_RX]);
! 939: if (err) {
! 940: printf("%s: close rx pipe failed: %s\n",
! 941: sc->sc_dev.dv_xname, usbd_errstr(err));
! 942: }
! 943: sc->sc_ep[UPL_ENDPT_RX] = NULL;
! 944: }
! 945:
! 946: if (sc->sc_ep[UPL_ENDPT_TX] != NULL) {
! 947: err = usbd_abort_pipe(sc->sc_ep[UPL_ENDPT_TX]);
! 948: if (err) {
! 949: printf("%s: abort tx pipe failed: %s\n",
! 950: sc->sc_dev.dv_xname, usbd_errstr(err));
! 951: }
! 952: err = usbd_close_pipe(sc->sc_ep[UPL_ENDPT_TX]);
! 953: if (err) {
! 954: printf("%s: close tx pipe failed: %s\n",
! 955: sc->sc_dev.dv_xname, usbd_errstr(err));
! 956: }
! 957: sc->sc_ep[UPL_ENDPT_TX] = NULL;
! 958: }
! 959:
! 960: if (sc->sc_ep[UPL_ENDPT_INTR] != NULL) {
! 961: err = usbd_abort_pipe(sc->sc_ep[UPL_ENDPT_INTR]);
! 962: if (err) {
! 963: printf("%s: abort intr pipe failed: %s\n",
! 964: sc->sc_dev.dv_xname, usbd_errstr(err));
! 965: }
! 966: err = usbd_close_pipe(sc->sc_ep[UPL_ENDPT_INTR]);
! 967: if (err) {
! 968: printf("%s: close intr pipe failed: %s\n",
! 969: sc->sc_dev.dv_xname, usbd_errstr(err));
! 970: }
! 971: sc->sc_ep[UPL_ENDPT_INTR] = NULL;
! 972: }
! 973:
! 974: /* Free RX resources. */
! 975: for (i = 0; i < UPL_RX_LIST_CNT; i++) {
! 976: if (sc->sc_cdata.upl_rx_chain[i].upl_mbuf != NULL) {
! 977: m_freem(sc->sc_cdata.upl_rx_chain[i].upl_mbuf);
! 978: sc->sc_cdata.upl_rx_chain[i].upl_mbuf = NULL;
! 979: }
! 980: if (sc->sc_cdata.upl_rx_chain[i].upl_xfer != NULL) {
! 981: usbd_free_xfer(sc->sc_cdata.upl_rx_chain[i].upl_xfer);
! 982: sc->sc_cdata.upl_rx_chain[i].upl_xfer = NULL;
! 983: }
! 984: }
! 985:
! 986: /* Free TX resources. */
! 987: for (i = 0; i < UPL_TX_LIST_CNT; i++) {
! 988: if (sc->sc_cdata.upl_tx_chain[i].upl_mbuf != NULL) {
! 989: m_freem(sc->sc_cdata.upl_tx_chain[i].upl_mbuf);
! 990: sc->sc_cdata.upl_tx_chain[i].upl_mbuf = NULL;
! 991: }
! 992: if (sc->sc_cdata.upl_tx_chain[i].upl_xfer != NULL) {
! 993: usbd_free_xfer(sc->sc_cdata.upl_tx_chain[i].upl_xfer);
! 994: sc->sc_cdata.upl_tx_chain[i].upl_xfer = NULL;
! 995: }
! 996: }
! 997: }
! 998:
! 999: int
! 1000: upl_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
! 1001: struct rtentry *rt0)
! 1002: {
! 1003: int s, len, error;
! 1004:
! 1005: DPRINTFN(10,("%s: %s: enter\n",
! 1006: ((struct upl_softc *)ifp->if_softc)->sc_dev.dv_xname,
! 1007: __func__));
! 1008:
! 1009: len = m->m_pkthdr.len;
! 1010: s = splnet();
! 1011: /*
! 1012: * Queue message on interface, and start output if interface
! 1013: * not yet active.
! 1014: */
! 1015: IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
! 1016: if (error) {
! 1017: /* mbuf is already freed */
! 1018: splx(s);
! 1019: return (error);
! 1020: }
! 1021: ifp->if_obytes += len;
! 1022: if ((ifp->if_flags & IFF_OACTIVE) == 0)
! 1023: (*ifp->if_start)(ifp);
! 1024: splx(s);
! 1025:
! 1026: return (0);
! 1027: }
! 1028:
! 1029: void
! 1030: upl_input(struct ifnet *ifp, struct mbuf *m)
! 1031: {
! 1032: struct ifqueue *inq;
! 1033: int s;
! 1034:
! 1035: /* XXX Assume all traffic is IP */
! 1036:
! 1037: schednetisr(NETISR_IP);
! 1038: inq = &ipintrq;
! 1039:
! 1040: s = splnet();
! 1041: if (IF_QFULL(inq)) {
! 1042: IF_DROP(inq);
! 1043: splx(s);
! 1044: #if 0
! 1045: if (sc->sc_flags & SC_DEBUG)
! 1046: printf("%s: input queue full\n", ifp->if_xname);
! 1047: #endif
! 1048: ifp->if_iqdrops++;
! 1049: return;
! 1050: }
! 1051: IF_ENQUEUE(inq, m);
! 1052: splx(s);
! 1053: ifp->if_ipackets++;
! 1054: ifp->if_ibytes += m->m_len;
! 1055: }
CVSweb