[BACK]Return to if_upl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / usb

Annotation of src/sys/dev/usb/if_upl.c, Revision 1.53

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

CVSweb <webmaster@jp.NetBSD.org>