[BACK]Return to if_upl.c CVS log [TXT][DIR] Up to [local] / sys / dev / usb

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