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

Annotation of sys/dev/usb/ucom.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ucom.c,v 1.41 2007/06/14 10:11:15 mbalmer Exp $ */
        !             2: /*     $NetBSD: ucom.c,v 1.49 2003/01/01 00:10:25 thorpej Exp $        */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Lennart Augustsson (lennart@augustsson.net) at
        !            10:  * Carlstedt Research & Technology.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *        This product includes software developed by the NetBSD
        !            23:  *        Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40: /*
        !            41:  * This code is very heavily based on the 16550 driver, com.c.
        !            42:  */
        !            43:
        !            44: #include <sys/param.h>
        !            45: #include <sys/systm.h>
        !            46: #include <sys/kernel.h>
        !            47: #include <sys/rwlock.h>
        !            48: #include <sys/ioctl.h>
        !            49: #include <sys/conf.h>
        !            50: #include <sys/tty.h>
        !            51: #include <sys/file.h>
        !            52: #include <sys/selinfo.h>
        !            53: #include <sys/proc.h>
        !            54: #include <sys/vnode.h>
        !            55: #include <sys/device.h>
        !            56: #include <sys/poll.h>
        !            57:
        !            58: #include <dev/usb/usb.h>
        !            59:
        !            60: #include <dev/usb/usbdi.h>
        !            61: #include <dev/usb/usbdi_util.h>
        !            62: #include <dev/usb/uhidev.h>
        !            63: #include <dev/usb/usbdevs.h>
        !            64: #include <dev/usb/usb_quirks.h>
        !            65:
        !            66: #include <dev/usb/ucomvar.h>
        !            67:
        !            68: #include "ucom.h"
        !            69:
        !            70: #if NUCOM > 0
        !            71:
        !            72: #ifdef UCOM_DEBUG
        !            73: #define DPRINTFN(n, x) do { if (ucomdebug > (n)) printf x; } while (0)
        !            74: int ucomdebug = 0;
        !            75: #else
        !            76: #define DPRINTFN(n, x)
        !            77: #endif
        !            78: #define DPRINTF(x) DPRINTFN(0, x)
        !            79:
        !            80: #define        UCOMUNIT_MASK           0x7f
        !            81: #define        UCOMCUA_MASK            0x80
        !            82:
        !            83: #define LINESW(tp, func)       (linesw[(tp)->t_line].func)
        !            84:
        !            85: #define        UCOMUNIT(x)             (minor(x) & UCOMUNIT_MASK)
        !            86: #define        UCOMCUA(x)              (minor(x) & UCOMCUA_MASK)
        !            87:
        !            88: struct ucom_softc {
        !            89:        struct device           sc_dev;         /* base device */
        !            90:
        !            91:        usbd_device_handle      sc_udev;        /* USB device */
        !            92:        struct uhidev_softc     *sc_uhidev;     /* hid device (if deeper) */
        !            93:
        !            94:        usbd_interface_handle   sc_iface;       /* data interface */
        !            95:
        !            96:        int                     sc_bulkin_no;   /* bulk in endpoint address */
        !            97:        usbd_pipe_handle        sc_bulkin_pipe; /* bulk in pipe */
        !            98:        usbd_xfer_handle        sc_ixfer;       /* read request */
        !            99:        u_char                  *sc_ibuf;       /* read buffer */
        !           100:        u_int                   sc_ibufsize;    /* read buffer size */
        !           101:        u_int                   sc_ibufsizepad; /* read buffer size padded */
        !           102:
        !           103:        int                     sc_bulkout_no;  /* bulk out endpoint address */
        !           104:        usbd_pipe_handle        sc_bulkout_pipe;/* bulk out pipe */
        !           105:        usbd_xfer_handle        sc_oxfer;       /* write request */
        !           106:        u_char                  *sc_obuf;       /* write buffer */
        !           107:        u_int                   sc_obufsize;    /* write buffer size */
        !           108:        u_int                   sc_opkthdrlen;  /* header length of
        !           109:                                                 * output packet */
        !           110:
        !           111:        usbd_pipe_handle        sc_ipipe;       /* hid interrupt input pipe */
        !           112:        usbd_pipe_handle        sc_opipe;       /* hid interrupt pipe */
        !           113:
        !           114:        struct ucom_methods     *sc_methods;
        !           115:        void                    *sc_parent;
        !           116:        int                     sc_portno;
        !           117:
        !           118:        struct tty              *sc_tty;        /* our tty */
        !           119:        u_char                  sc_lsr;
        !           120:        u_char                  sc_msr;
        !           121:        u_char                  sc_mcr;
        !           122:        u_char                  sc_tx_stopped;
        !           123:        int                     sc_swflags;
        !           124:
        !           125:        u_char                  sc_cua;
        !           126:
        !           127:        struct rwlock           sc_lock;        /* lock during open */
        !           128:        int                     sc_open;
        !           129:        int                     sc_refcnt;
        !           130:        u_char                  sc_dying;       /* disconnecting */
        !           131: };
        !           132:
        !           133: void   ucom_cleanup(struct ucom_softc *);
        !           134: void   ucom_hwiflow(struct ucom_softc *);
        !           135: int    ucomparam(struct tty *, struct termios *);
        !           136: void   ucomstart(struct tty *);
        !           137: void   ucom_shutdown(struct ucom_softc *);
        !           138: int    ucom_do_ioctl(struct ucom_softc *, u_long, caddr_t,
        !           139:                              int, struct proc *);
        !           140: void   ucom_dtr(struct ucom_softc *, int);
        !           141: void   ucom_rts(struct ucom_softc *, int);
        !           142: void   ucom_break(struct ucom_softc *, int);
        !           143: usbd_status ucomstartread(struct ucom_softc *);
        !           144: void   ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
        !           145: void   ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
        !           146: void   tiocm_to_ucom(struct ucom_softc *, u_long, int);
        !           147: int    ucom_to_tiocm(struct ucom_softc *);
        !           148: void   ucom_lock(struct ucom_softc *);
        !           149: void   ucom_unlock(struct ucom_softc *);
        !           150:
        !           151: int ucom_match(struct device *, void *, void *);
        !           152: void ucom_attach(struct device *, struct device *, void *);
        !           153: int ucom_detach(struct device *, int);
        !           154: int ucom_activate(struct device *, enum devact);
        !           155:
        !           156: struct cfdriver ucom_cd = {
        !           157:        NULL, "ucom", DV_DULL
        !           158: };
        !           159:
        !           160: const struct cfattach ucom_ca = {
        !           161:        sizeof(struct ucom_softc),
        !           162:        ucom_match,
        !           163:        ucom_attach,
        !           164:        ucom_detach,
        !           165:        ucom_activate,
        !           166: };
        !           167:
        !           168: void
        !           169: ucom_lock(struct ucom_softc *sc)
        !           170: {
        !           171:        sc->sc_refcnt++;
        !           172:        rw_enter_write(&sc->sc_lock);
        !           173: }
        !           174:
        !           175: void
        !           176: ucom_unlock(struct ucom_softc *sc)
        !           177: {
        !           178:        rw_exit_write(&sc->sc_lock);
        !           179:        if (--sc->sc_refcnt < 0)
        !           180:                usb_detach_wakeup(&sc->sc_dev);
        !           181: }
        !           182:
        !           183: int
        !           184: ucom_match(struct device *parent, void *match, void *aux)
        !           185: {
        !           186:        return (1);
        !           187: }
        !           188:
        !           189: void
        !           190: ucom_attach(struct device *parent, struct device *self, void *aux)
        !           191: {
        !           192:        struct ucom_softc *sc = (struct ucom_softc *)self;
        !           193:        struct ucom_attach_args *uca = aux;
        !           194:        struct tty *tp;
        !           195:
        !           196:        if (uca->info != NULL)
        !           197:                printf(", %s", uca->info);
        !           198:        printf("\n");
        !           199:
        !           200:        sc->sc_udev = uca->device;
        !           201:        sc->sc_iface = uca->iface;
        !           202:        sc->sc_bulkout_no = uca->bulkout;
        !           203:        sc->sc_bulkin_no = uca->bulkin;
        !           204:        sc->sc_uhidev = uca->uhidev;
        !           205:        sc->sc_ibufsize = uca->ibufsize;
        !           206:        sc->sc_ibufsizepad = uca->ibufsizepad;
        !           207:        sc->sc_obufsize = uca->obufsize;
        !           208:        sc->sc_opkthdrlen = uca->opkthdrlen;
        !           209:        sc->sc_methods = uca->methods;
        !           210:        sc->sc_parent = uca->arg;
        !           211:        sc->sc_portno = uca->portno;
        !           212:
        !           213:        tp = ttymalloc();
        !           214:        tp->t_oproc = ucomstart;
        !           215:        tp->t_param = ucomparam;
        !           216:        sc->sc_tty = tp;
        !           217:        sc->sc_cua = 0;
        !           218:
        !           219:        rw_init(&sc->sc_lock, "ucomlk");
        !           220:
        !           221:        sc->sc_open = 0;
        !           222: }
        !           223:
        !           224: int
        !           225: ucom_detach(struct device *self, int flags)
        !           226: {
        !           227:        struct ucom_softc *sc = (struct ucom_softc *)self;
        !           228:        struct tty *tp = sc->sc_tty;
        !           229:        int maj, mn;
        !           230:        int s;
        !           231:
        !           232:        DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
        !           233:                 sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
        !           234:
        !           235:        sc->sc_dying = 1;
        !           236:
        !           237:        if (sc->sc_bulkin_pipe != NULL)
        !           238:                usbd_abort_pipe(sc->sc_bulkin_pipe);
        !           239:        if (sc->sc_bulkout_pipe != NULL)
        !           240:                usbd_abort_pipe(sc->sc_bulkout_pipe);
        !           241:
        !           242:        s = splusb();
        !           243:        if (--sc->sc_refcnt >= 0) {
        !           244:                /* Wake up anyone waiting */
        !           245:                if (tp != NULL) {
        !           246:                        CLR(tp->t_state, TS_CARR_ON);
        !           247:                        CLR(tp->t_cflag, CLOCAL | MDMBUF);
        !           248:                        ttyflush(tp, FREAD|FWRITE);
        !           249:                }
        !           250:                /* Wait for processes to go away. */
        !           251:                usb_detach_wait(&sc->sc_dev);
        !           252:        }
        !           253:        splx(s);
        !           254:
        !           255:        /* locate the major number */
        !           256:        for (maj = 0; maj < nchrdev; maj++)
        !           257:                if (cdevsw[maj].d_open == ucomopen)
        !           258:                        break;
        !           259:
        !           260:        /* Nuke the vnodes for any open instances. */
        !           261:        mn = self->dv_unit;
        !           262:        DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn));
        !           263:        vdevgone(maj, mn, mn, VCHR);
        !           264:        vdevgone(maj, mn | UCOMCUA_MASK, mn | UCOMCUA_MASK, VCHR);
        !           265:
        !           266:        /* Detach and free the tty. */
        !           267:        if (tp != NULL) {
        !           268:                ttyfree(tp);
        !           269:                sc->sc_tty = NULL;
        !           270:        }
        !           271:
        !           272:        return (0);
        !           273: }
        !           274:
        !           275: int
        !           276: ucom_activate(struct device *self, enum devact act)
        !           277: {
        !           278:        struct ucom_softc *sc = (struct ucom_softc *)self;
        !           279:
        !           280:        DPRINTFN(5,("ucom_activate: %d\n", act));
        !           281:
        !           282:        switch (act) {
        !           283:        case DVACT_ACTIVATE:
        !           284:                break;
        !           285:
        !           286:        case DVACT_DEACTIVATE:
        !           287:                sc->sc_dying = 1;
        !           288:                break;
        !           289:        }
        !           290:        return (0);
        !           291: }
        !           292:
        !           293: void
        !           294: ucom_shutdown(struct ucom_softc *sc)
        !           295: {
        !           296:        struct tty *tp = sc->sc_tty;
        !           297:
        !           298:        DPRINTF(("ucom_shutdown\n"));
        !           299:        /*
        !           300:         * Hang up if necessary.  Wait a bit, so the other side has time to
        !           301:         * notice even if we immediately open the port again.
        !           302:         */
        !           303:        if (ISSET(tp->t_cflag, HUPCL)) {
        !           304:                ucom_dtr(sc, 0);
        !           305:                (void)tsleep(sc, TTIPRI, ttclos, hz);
        !           306:        }
        !           307: }
        !           308:
        !           309: int
        !           310: ucomopen(dev_t dev, int flag, int mode, struct proc *p)
        !           311: {
        !           312:        int unit = UCOMUNIT(dev);
        !           313:        usbd_status err;
        !           314:        struct ucom_softc *sc;
        !           315:        struct tty *tp;
        !           316:        struct termios t;
        !           317:        int s;
        !           318:        int error;
        !           319:
        !           320:        if (unit >= ucom_cd.cd_ndevs)
        !           321:                return (ENXIO);
        !           322:        sc = ucom_cd.cd_devs[unit];
        !           323:        if (sc == NULL)
        !           324:                return (ENXIO);
        !           325:
        !           326:        if (sc->sc_dying)
        !           327:                return (EIO);
        !           328:
        !           329:        if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
        !           330:                return (ENXIO);
        !           331:
        !           332:        /* open the pipes if this is the first open */
        !           333:        ucom_lock(sc);
        !           334:        if (sc->sc_open++ == 0) {
        !           335:                s = splusb();
        !           336:
        !           337:                DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
        !           338:                    sc->sc_bulkin_no, sc->sc_bulkout_no));
        !           339:                DPRINTF(("ucomopen: hid %p pipes in=%p out=%p\n",
        !           340:                    sc->sc_uhidev, sc->sc_ipipe, sc->sc_opipe));
        !           341:
        !           342:                if (sc->sc_bulkin_no != -1) {
        !           343:
        !           344:                        /* Open the bulk pipes */
        !           345:                        err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
        !           346:                            &sc->sc_bulkin_pipe);
        !           347:                        if (err) {
        !           348:                                DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
        !           349:                                    sc->sc_dev.dv_xname, sc->sc_bulkin_no,
        !           350:                                    usbd_errstr(err)));
        !           351:                                error = EIO;
        !           352:                                goto fail_0;
        !           353:                        }
        !           354:                        err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
        !           355:                            USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
        !           356:                        if (err) {
        !           357:                                DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
        !           358:                                    sc->sc_dev.dv_xname, sc->sc_bulkout_no,
        !           359:                                    usbd_errstr(err)));
        !           360:                                error = EIO;
        !           361:                                goto fail_1;
        !           362:                        }
        !           363:
        !           364:                        /* Allocate a request and an input buffer and start reading. */
        !           365:                        sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
        !           366:                        if (sc->sc_ixfer == NULL) {
        !           367:                                error = ENOMEM;
        !           368:                                goto fail_2;
        !           369:                        }
        !           370:
        !           371:                        sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
        !           372:                            sc->sc_ibufsizepad);
        !           373:                        if (sc->sc_ibuf == NULL) {
        !           374:                                error = ENOMEM;
        !           375:                                goto fail_2;
        !           376:                        }
        !           377:
        !           378:                        sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
        !           379:                        if (sc->sc_oxfer == NULL) {
        !           380:                                error = ENOMEM;
        !           381:                                goto fail_3;
        !           382:                        }
        !           383:                } else {
        !           384:                        /*
        !           385:                         * input/output pipes and xfers already allocated
        !           386:                         * as is the input buffer.
        !           387:                         */
        !           388:                        sc->sc_ipipe = sc->sc_uhidev->sc_ipipe;
        !           389:                        sc->sc_ixfer = sc->sc_uhidev->sc_ixfer;
        !           390:                        sc->sc_opipe = sc->sc_uhidev->sc_opipe;
        !           391:                        sc->sc_oxfer = sc->sc_uhidev->sc_oxfer;
        !           392:                }
        !           393:
        !           394:                sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
        !           395:                    sc->sc_obufsize + sc->sc_opkthdrlen);
        !           396:                if (sc->sc_obuf == NULL) {
        !           397:                        error = ENOMEM;
        !           398:                        goto fail_4;
        !           399:                }
        !           400:
        !           401:                if (sc->sc_methods->ucom_open != NULL) {
        !           402:                        error = sc->sc_methods->ucom_open(sc->sc_parent,
        !           403:                            sc->sc_portno);
        !           404:                        if (error) {
        !           405:                                ucom_cleanup(sc);
        !           406:                                splx(s);
        !           407:                                ucom_unlock(sc);
        !           408:                                return (error);
        !           409:                        }
        !           410:                }
        !           411:
        !           412:                ucom_status_change(sc);
        !           413:
        !           414:                ucomstartread(sc);
        !           415:
        !           416:                splx(s);
        !           417:        }
        !           418:        ucom_unlock(sc);
        !           419:
        !           420:        s = spltty();
        !           421:        tp = sc->sc_tty;
        !           422:        splx(s);
        !           423:
        !           424:        DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
        !           425:
        !           426:        tp->t_dev = dev;
        !           427:        if (!ISSET(tp->t_state, TS_ISOPEN)) {
        !           428:                SET(tp->t_state, TS_WOPEN);
        !           429:                ttychars(tp);
        !           430:
        !           431:                /*
        !           432:                 * Initialize the termios status to the defaults.  Add in the
        !           433:                 * sticky bits from TIOCSFLAGS.
        !           434:                 */
        !           435:                t.c_ispeed = 0;
        !           436:                t.c_ospeed = TTYDEF_SPEED;
        !           437:                t.c_cflag = TTYDEF_CFLAG;
        !           438:                if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
        !           439:                        SET(t.c_cflag, CLOCAL);
        !           440:                if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
        !           441:                        SET(t.c_cflag, CRTSCTS);
        !           442:                if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
        !           443:                        SET(t.c_cflag, MDMBUF);
        !           444:
        !           445:                /* Make sure ucomparam() will do something. */
        !           446:                tp->t_ospeed = 0;
        !           447:                (void) ucomparam(tp, &t);
        !           448:                tp->t_iflag = TTYDEF_IFLAG;
        !           449:                tp->t_oflag = TTYDEF_OFLAG;
        !           450:                tp->t_lflag = TTYDEF_LFLAG;
        !           451:
        !           452:                s = spltty();
        !           453:                ttsetwater(tp);
        !           454:
        !           455:                /*
        !           456:                 * Turn on DTR.  We must always do this, even if carrier is not
        !           457:                 * present, because otherwise we'd have to use TIOCSDTR
        !           458:                 * immediately after setting CLOCAL, which applications do not
        !           459:                 * expect.  We always assert DTR while the device is open
        !           460:                 * unless explicitly requested to deassert it.
        !           461:                 */
        !           462:                ucom_dtr(sc, 1);
        !           463:
        !           464:                /* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/
        !           465:                ucom_hwiflow(sc);
        !           466:
        !           467:                if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || UCOMCUA(dev) ||
        !           468:                    ISSET(sc->sc_msr, UMSR_DCD) || ISSET(tp->t_cflag, MDMBUF))
        !           469:                        SET(tp->t_state, TS_CARR_ON);
        !           470:                else
        !           471:                        CLR(tp->t_state, TS_CARR_ON);
        !           472:        } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
        !           473:                error = EBUSY;
        !           474:                goto bad;
        !           475:        } else
        !           476:                s = spltty();
        !           477:
        !           478:        if (UCOMCUA(dev)) {
        !           479:                if (ISSET(tp->t_state, TS_ISOPEN)) {
        !           480:                        /* Someone is already dialed in */
        !           481:                        error = EBUSY;
        !           482:                        goto bad1;
        !           483:                }
        !           484:                sc->sc_cua = 1;
        !           485:        } else {
        !           486:                /* tty (not cua) device, wait for carrier */
        !           487:                if (ISSET(flag, O_NONBLOCK)) {
        !           488:                        if (sc->sc_cua) {
        !           489:                                error = EBUSY;
        !           490:                                goto bad1;
        !           491:                        }
        !           492:                } else {
        !           493:                        while (sc->sc_cua || (!ISSET(tp->t_cflag, CLOCAL) &&
        !           494:                            !ISSET(tp->t_state, TS_CARR_ON))) {
        !           495:                                SET(tp->t_state, TS_WOPEN);
        !           496:                                error = ttysleep(tp, &tp->t_rawq,
        !           497:                                    TTIPRI | PCATCH, ttopen, 0);
        !           498:                                /*
        !           499:                                 * If TS_WOPEN has been reset, that means the
        !           500:                                 * cua device has been closed.  We don't want
        !           501:                                 * to fail in that case, so just go around
        !           502:                                 * again.
        !           503:                                 */
        !           504:                                if (error && ISSET(tp->t_state, TS_WOPEN)) {
        !           505:                                        CLR(tp->t_state, TS_WOPEN);
        !           506:                                        goto bad1;
        !           507:                                }
        !           508:                        }
        !           509:                }
        !           510:        }
        !           511:        splx(s);
        !           512:
        !           513:        error = ttyopen(UCOMUNIT(dev), tp);
        !           514:        if (error)
        !           515:                goto bad;
        !           516:
        !           517:        error = (*LINESW(tp, l_open))(dev, tp);
        !           518:        if (error)
        !           519:                goto bad;
        !           520:
        !           521:        return (0);
        !           522:
        !           523: fail_4:
        !           524:        if (sc->sc_uhidev == NULL)
        !           525:                usbd_free_xfer(sc->sc_oxfer);
        !           526:        sc->sc_oxfer = NULL;
        !           527: fail_3:
        !           528:        usbd_free_xfer(sc->sc_ixfer);
        !           529:        sc->sc_ixfer = NULL;
        !           530: fail_2:
        !           531:        usbd_close_pipe(sc->sc_bulkout_pipe);
        !           532:        sc->sc_bulkout_pipe = NULL;
        !           533: fail_1:
        !           534:        usbd_close_pipe(sc->sc_bulkin_pipe);
        !           535:        sc->sc_bulkin_pipe = NULL;
        !           536: fail_0:
        !           537:        splx(s);
        !           538:        ucom_unlock(sc);
        !           539:        return (error);
        !           540:
        !           541: bad1:
        !           542:        splx(s);
        !           543: bad:
        !           544:        ucom_lock(sc);
        !           545:        ucom_cleanup(sc);
        !           546:        ucom_unlock(sc);
        !           547:
        !           548:        return (error);
        !           549: }
        !           550:
        !           551: int
        !           552: ucomclose(dev_t dev, int flag, int mode, struct proc *p)
        !           553: {
        !           554:        struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
        !           555:        struct tty *tp = sc->sc_tty;
        !           556:        int s;
        !           557:
        !           558:        if (!ISSET(tp->t_state, TS_ISOPEN))
        !           559:                return (0);
        !           560:
        !           561:        DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
        !           562:        ucom_lock(sc);
        !           563:
        !           564:        (*LINESW(tp, l_close))(tp, flag);
        !           565:        s = spltty();
        !           566:        CLR(tp->t_state, TS_BUSY | TS_FLUSH);
        !           567:        sc->sc_cua = 0;
        !           568:        ttyclose(tp);
        !           569:        ucom_cleanup(sc);
        !           570:        splx(s);
        !           571:
        !           572:        if (sc->sc_methods->ucom_close != NULL)
        !           573:                sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
        !           574:
        !           575:        ucom_unlock(sc);
        !           576:
        !           577:        return (0);
        !           578: }
        !           579:
        !           580: int
        !           581: ucomread(dev_t dev, struct uio *uio, int flag)
        !           582: {
        !           583:        struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
        !           584:        struct tty *tp = sc->sc_tty;
        !           585:        int error;
        !           586:
        !           587:        if (sc->sc_dying)
        !           588:                return (EIO);
        !           589:
        !           590:        sc->sc_refcnt++;
        !           591:        error = (*LINESW(tp, l_read))(tp, uio, flag);
        !           592:        if (--sc->sc_refcnt < 0)
        !           593:                usb_detach_wakeup(&sc->sc_dev);
        !           594:        return (error);
        !           595: }
        !           596:
        !           597: int
        !           598: ucomwrite(dev_t dev, struct uio *uio, int flag)
        !           599: {
        !           600:        struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
        !           601:        struct tty *tp = sc->sc_tty;
        !           602:        int error;
        !           603:
        !           604:        if (sc->sc_dying)
        !           605:                return (EIO);
        !           606:
        !           607:        sc->sc_refcnt++;
        !           608:        error = (*LINESW(tp, l_write))(tp, uio, flag);
        !           609:        if (--sc->sc_refcnt < 0)
        !           610:                usb_detach_wakeup(&sc->sc_dev);
        !           611:        return (error);
        !           612: }
        !           613:
        !           614: struct tty *
        !           615: ucomtty(dev_t dev)
        !           616: {
        !           617:        struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
        !           618:        struct tty *tp = sc->sc_tty;
        !           619:
        !           620:        return (tp);
        !           621: }
        !           622:
        !           623: int
        !           624: ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
        !           625: {
        !           626:        struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
        !           627:        int error;
        !           628:
        !           629:        sc->sc_refcnt++;
        !           630:        error = ucom_do_ioctl(sc, cmd, data, flag, p);
        !           631:        if (--sc->sc_refcnt < 0)
        !           632:                usb_detach_wakeup(&sc->sc_dev);
        !           633:        return (error);
        !           634: }
        !           635:
        !           636: int
        !           637: ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, caddr_t data,
        !           638:              int flag, struct proc *p)
        !           639: {
        !           640:        struct tty *tp = sc->sc_tty;
        !           641:        int error;
        !           642:        int s;
        !           643:
        !           644:        if (sc->sc_dying)
        !           645:                return (EIO);
        !           646:
        !           647:        DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
        !           648:
        !           649:        error = (*LINESW(tp, l_ioctl))(tp, cmd, data, flag, p);
        !           650:        if (error >= 0)
        !           651:                return (error);
        !           652:
        !           653:        error = ttioctl(tp, cmd, data, flag, p);
        !           654:        if (error >= 0)
        !           655:                return (error);
        !           656:
        !           657:        if (sc->sc_methods->ucom_ioctl != NULL) {
        !           658:                error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
        !           659:                            sc->sc_portno, cmd, data, flag, p);
        !           660:                if (error >= 0)
        !           661:                        return (error);
        !           662:        }
        !           663:
        !           664:        error = 0;
        !           665:
        !           666:        DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
        !           667:        s = spltty();
        !           668:
        !           669:        switch (cmd) {
        !           670:        case TIOCSBRK:
        !           671:                ucom_break(sc, 1);
        !           672:                break;
        !           673:
        !           674:        case TIOCCBRK:
        !           675:                ucom_break(sc, 0);
        !           676:                break;
        !           677:
        !           678:        case TIOCSDTR:
        !           679:                ucom_dtr(sc, 1);
        !           680:                break;
        !           681:
        !           682:        case TIOCCDTR:
        !           683:                ucom_dtr(sc, 0);
        !           684:                break;
        !           685:
        !           686:        case TIOCGFLAGS:
        !           687:                *(int *)data = sc->sc_swflags;
        !           688:                break;
        !           689:
        !           690:        case TIOCSFLAGS:
        !           691:                error = suser(p, 0);
        !           692:                if (error)
        !           693:                        break;
        !           694:                sc->sc_swflags = *(int *)data;
        !           695:                break;
        !           696:
        !           697:        case TIOCMSET:
        !           698:        case TIOCMBIS:
        !           699:        case TIOCMBIC:
        !           700:                tiocm_to_ucom(sc, cmd, *(int *)data);
        !           701:                break;
        !           702:
        !           703:        case TIOCMGET:
        !           704:                *(int *)data = ucom_to_tiocm(sc);
        !           705:                break;
        !           706:
        !           707:        default:
        !           708:                error = ENOTTY;
        !           709:                break;
        !           710:        }
        !           711:
        !           712:        splx(s);
        !           713:
        !           714:        return (error);
        !           715: }
        !           716:
        !           717: void
        !           718: tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
        !           719: {
        !           720:        u_char combits;
        !           721:
        !           722:        combits = 0;
        !           723:        if (ISSET(ttybits, TIOCM_DTR))
        !           724:                SET(combits, UMCR_DTR);
        !           725:        if (ISSET(ttybits, TIOCM_RTS))
        !           726:                SET(combits, UMCR_RTS);
        !           727:
        !           728:        switch (how) {
        !           729:        case TIOCMBIC:
        !           730:                CLR(sc->sc_mcr, combits);
        !           731:                break;
        !           732:
        !           733:        case TIOCMBIS:
        !           734:                SET(sc->sc_mcr, combits);
        !           735:                break;
        !           736:
        !           737:        case TIOCMSET:
        !           738:                CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
        !           739:                SET(sc->sc_mcr, combits);
        !           740:                break;
        !           741:        }
        !           742:
        !           743:        if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
        !           744:                ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
        !           745:        if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
        !           746:                ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
        !           747: }
        !           748:
        !           749: int
        !           750: ucom_to_tiocm(struct ucom_softc *sc)
        !           751: {
        !           752:        u_char combits;
        !           753:        int ttybits = 0;
        !           754:
        !           755:        combits = sc->sc_mcr;
        !           756:        if (ISSET(combits, UMCR_DTR))
        !           757:                SET(ttybits, TIOCM_DTR);
        !           758:        if (ISSET(combits, UMCR_RTS))
        !           759:                SET(ttybits, TIOCM_RTS);
        !           760:
        !           761:        combits = sc->sc_msr;
        !           762:        if (ISSET(combits, UMSR_DCD))
        !           763:                SET(ttybits, TIOCM_CD);
        !           764:        if (ISSET(combits, UMSR_CTS))
        !           765:                SET(ttybits, TIOCM_CTS);
        !           766:        if (ISSET(combits, UMSR_DSR))
        !           767:                SET(ttybits, TIOCM_DSR);
        !           768:        if (ISSET(combits, UMSR_RI | UMSR_TERI))
        !           769:                SET(ttybits, TIOCM_RI);
        !           770:
        !           771: #if 0
        !           772: XXX;
        !           773:        if (sc->sc_ier != 0)
        !           774:                SET(ttybits, TIOCM_LE);
        !           775: #endif
        !           776:
        !           777:        return (ttybits);
        !           778: }
        !           779:
        !           780: void
        !           781: ucom_break(sc, onoff)
        !           782:        struct ucom_softc *sc;
        !           783:        int onoff;
        !           784: {
        !           785:        DPRINTF(("ucom_break: onoff=%d\n", onoff));
        !           786:
        !           787:        if (sc->sc_methods->ucom_set != NULL)
        !           788:                sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
        !           789:                    UCOM_SET_BREAK, onoff);
        !           790: }
        !           791:
        !           792: void
        !           793: ucom_dtr(struct ucom_softc *sc, int onoff)
        !           794: {
        !           795:        DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
        !           796:
        !           797:        if (sc->sc_methods->ucom_set != NULL) {
        !           798:                sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
        !           799:                    UCOM_SET_DTR, onoff);
        !           800:                /* When not using CRTSCTS, RTS follows DTR. */
        !           801:                if (!(sc->sc_swflags & TIOCFLAG_CRTSCTS))
        !           802:                        ucom_rts(sc, onoff);
        !           803:        }
        !           804: }
        !           805:
        !           806: void
        !           807: ucom_rts(struct ucom_softc *sc, int onoff)
        !           808: {
        !           809:        DPRINTF(("ucom_rts: onoff=%d\n", onoff));
        !           810:
        !           811:        if (sc->sc_methods->ucom_set != NULL)
        !           812:                sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
        !           813:                    UCOM_SET_RTS, onoff);
        !           814: }
        !           815:
        !           816: void
        !           817: ucom_status_change(struct ucom_softc *sc)
        !           818: {
        !           819:        struct tty *tp = sc->sc_tty;
        !           820:        u_char old_msr;
        !           821:
        !           822:        if (sc->sc_methods->ucom_get_status != NULL) {
        !           823:                old_msr = sc->sc_msr;
        !           824:                sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
        !           825:                    &sc->sc_lsr, &sc->sc_msr);
        !           826:
        !           827:                ttytstamp(tp, old_msr & UMSR_CTS, sc->sc_msr & UMSR_CTS,
        !           828:                    old_msr & UMSR_DCD, sc->sc_msr & UMSR_DCD);
        !           829:
        !           830:                if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD))
        !           831:                        (*LINESW(tp, l_modem))(tp,
        !           832:                            ISSET(sc->sc_msr, UMSR_DCD));
        !           833:        } else {
        !           834:                sc->sc_lsr = 0;
        !           835:                sc->sc_msr = 0;
        !           836:        }
        !           837: }
        !           838:
        !           839: int
        !           840: ucomparam(struct tty *tp, struct termios *t)
        !           841: {
        !           842:        struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
        !           843:        int error;
        !           844:
        !           845:        if (sc->sc_dying)
        !           846:                return (EIO);
        !           847:
        !           848:        /* Check requested parameters. */
        !           849:        if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
        !           850:                return (EINVAL);
        !           851:
        !           852:        /*
        !           853:         * For the console, always force CLOCAL and !HUPCL, so that the port
        !           854:         * is always active.
        !           855:         */
        !           856:        if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
        !           857:                SET(t->c_cflag, CLOCAL);
        !           858:                CLR(t->c_cflag, HUPCL);
        !           859:        }
        !           860:
        !           861:        /*
        !           862:         * If there were no changes, don't do anything.  This avoids dropping
        !           863:         * input and improves performance when all we did was frob things like
        !           864:         * VMIN and VTIME.
        !           865:         */
        !           866:        if (tp->t_ospeed == t->c_ospeed &&
        !           867:            tp->t_cflag == t->c_cflag)
        !           868:                return (0);
        !           869:
        !           870:        /* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
        !           871:
        !           872:        /* And copy to tty. */
        !           873:        tp->t_ispeed = 0;
        !           874:        tp->t_ospeed = t->c_ospeed;
        !           875:        tp->t_cflag = t->c_cflag;
        !           876:
        !           877:        if (sc->sc_methods->ucom_param != NULL) {
        !           878:                error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
        !           879:                            t);
        !           880:                if (error)
        !           881:                        return (error);
        !           882:        }
        !           883:
        !           884:        /* XXX worry about CHWFLOW */
        !           885:
        !           886:        /*
        !           887:         * Update the tty layer's idea of the carrier bit, in case we changed
        !           888:         * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
        !           889:         * explicit request.
        !           890:         */
        !           891:        DPRINTF(("ucomparam: l_modem\n"));
        !           892:        (void) (*LINESW(tp, l_modem))(tp, 1 /* XXX carrier */ );
        !           893:
        !           894: #if 0
        !           895: XXX what if the hardware is not open
        !           896:        if (!ISSET(t->c_cflag, CHWFLOW)) {
        !           897:                if (sc->sc_tx_stopped) {
        !           898:                        sc->sc_tx_stopped = 0;
        !           899:                        ucomstart(tp);
        !           900:                }
        !           901:        }
        !           902: #endif
        !           903:
        !           904:        return (0);
        !           905: }
        !           906:
        !           907: /*
        !           908:  * (un)block input via hw flowcontrol
        !           909:  */
        !           910: void
        !           911: ucom_hwiflow(struct ucom_softc *sc)
        !           912: {
        !           913:        DPRINTF(("ucom_hwiflow:\n"));
        !           914: #if 0
        !           915: XXX
        !           916:        bus_space_tag_t iot = sc->sc_iot;
        !           917:        bus_space_handle_t ioh = sc->sc_ioh;
        !           918:
        !           919:        if (sc->sc_mcr_rts == 0)
        !           920:                return;
        !           921:
        !           922:        if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
        !           923:                CLR(sc->sc_mcr, sc->sc_mcr_rts);
        !           924:                CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
        !           925:        } else {
        !           926:                SET(sc->sc_mcr, sc->sc_mcr_rts);
        !           927:                SET(sc->sc_mcr_active, sc->sc_mcr_rts);
        !           928:        }
        !           929:        bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr_active);
        !           930: #endif
        !           931: }
        !           932:
        !           933: void
        !           934: ucomstart(struct tty *tp)
        !           935: {
        !           936:        struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
        !           937:        usbd_status err;
        !           938:        int s;
        !           939:        u_char *data;
        !           940:        int cnt;
        !           941:
        !           942:        if (sc->sc_dying)
        !           943:                return;
        !           944:
        !           945:        s = spltty();
        !           946:        if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
        !           947:                DPRINTFN(4,("ucomstart: no go, state=0x%x\n", tp->t_state));
        !           948:                goto out;
        !           949:        }
        !           950:        if (sc->sc_tx_stopped)
        !           951:                goto out;
        !           952:
        !           953:        if (tp->t_outq.c_cc <= tp->t_lowat) {
        !           954:                if (ISSET(tp->t_state, TS_ASLEEP)) {
        !           955:                        CLR(tp->t_state, TS_ASLEEP);
        !           956:                        wakeup(&tp->t_outq);
        !           957:                }
        !           958:                selwakeup(&tp->t_wsel);
        !           959:                if (tp->t_outq.c_cc == 0)
        !           960:                        goto out;
        !           961:        }
        !           962:
        !           963:        /* Grab the first contiguous region of buffer space. */
        !           964:        data = tp->t_outq.c_cf;
        !           965:        cnt = ndqb(&tp->t_outq, 0);
        !           966:
        !           967:        if (cnt == 0) {
        !           968:                DPRINTF(("ucomstart: cnt==0\n"));
        !           969:                goto out;
        !           970:        }
        !           971:
        !           972:        SET(tp->t_state, TS_BUSY);
        !           973:
        !           974:        if (cnt > sc->sc_obufsize) {
        !           975:                DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
        !           976:                cnt = sc->sc_obufsize;
        !           977:        }
        !           978:        if (sc->sc_methods->ucom_write != NULL)
        !           979:                sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
        !           980:                                           sc->sc_obuf, data, &cnt);
        !           981:        else
        !           982:                memcpy(sc->sc_obuf, data, cnt);
        !           983:
        !           984:        DPRINTFN(4,("ucomstart: %d chars\n", cnt));
        !           985: #ifdef DIAGNOSTIC
        !           986:        if (sc->sc_oxfer == NULL) {
        !           987:                printf("ucomstart: null oxfer\n");
        !           988:                goto out;
        !           989:        }
        !           990: #endif
        !           991:        if (sc->sc_bulkout_pipe != NULL) {
        !           992:                usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
        !           993:                    (usbd_private_handle)sc, sc->sc_obuf, cnt,
        !           994:                    USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
        !           995:        } else {
        !           996:                usbd_setup_xfer(sc->sc_oxfer, sc->sc_opipe,
        !           997:                    (usbd_private_handle)sc, sc->sc_obuf, cnt,
        !           998:                    USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
        !           999:        }
        !          1000:        /* What can we do on error? */
        !          1001:        err = usbd_transfer(sc->sc_oxfer);
        !          1002: #ifdef DIAGNOSTIC
        !          1003:        if (err != USBD_IN_PROGRESS)
        !          1004:                printf("ucomstart: err=%s\n", usbd_errstr(err));
        !          1005: #endif
        !          1006:
        !          1007: out:
        !          1008:        splx(s);
        !          1009: }
        !          1010:
        !          1011: int
        !          1012: ucomstop(struct tty *tp, int flag)
        !          1013: {
        !          1014:        DPRINTF(("ucomstop: flag=%d\n", flag));
        !          1015: #if 0
        !          1016:        /*struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];*/
        !          1017:        int s;
        !          1018:
        !          1019:        s = spltty();
        !          1020:        if (ISSET(tp->t_state, TS_BUSY)) {
        !          1021:                DPRINTF(("ucomstop: XXX\n"));
        !          1022:                /* sc->sc_tx_stopped = 1; */
        !          1023:                if (!ISSET(tp->t_state, TS_TTSTOP))
        !          1024:                        SET(tp->t_state, TS_FLUSH);
        !          1025:        }
        !          1026:        splx(s);
        !          1027: #endif
        !          1028:        return (0);
        !          1029: }
        !          1030:
        !          1031: void
        !          1032: ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
        !          1033: {
        !          1034:        struct ucom_softc *sc = (struct ucom_softc *)p;
        !          1035:        struct tty *tp = sc->sc_tty;
        !          1036:        u_int32_t cc;
        !          1037:        int s;
        !          1038:
        !          1039:        DPRINTFN(5,("ucomwritecb: %p %p status=%d\n", xfer, p, status));
        !          1040:
        !          1041:        if (status == USBD_CANCELLED || sc->sc_dying)
        !          1042:                goto error;
        !          1043:
        !          1044:        if (sc->sc_bulkin_pipe != NULL) {
        !          1045:                if (status) {
        !          1046:                        usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
        !          1047:                        /* XXX we should restart after some delay. */
        !          1048:                        goto error;
        !          1049:                }
        !          1050:                usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
        !          1051:        } else {
        !          1052:                usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
        !          1053:                // XXX above gives me wrong cc, no?
        !          1054:        }
        !          1055:
        !          1056:        DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));
        !          1057:        /* convert from USB bytes to tty bytes */
        !          1058:        cc -= sc->sc_opkthdrlen;
        !          1059:
        !          1060:        s = spltty();
        !          1061:        CLR(tp->t_state, TS_BUSY);
        !          1062:        if (ISSET(tp->t_state, TS_FLUSH))
        !          1063:                CLR(tp->t_state, TS_FLUSH);
        !          1064:        else
        !          1065:                ndflush(&tp->t_outq, cc);
        !          1066:        (*LINESW(tp, l_start))(tp);
        !          1067:        splx(s);
        !          1068:        return;
        !          1069:
        !          1070: error:
        !          1071:        s = spltty();
        !          1072:        CLR(tp->t_state, TS_BUSY);
        !          1073:        splx(s);
        !          1074: }
        !          1075:
        !          1076: usbd_status
        !          1077: ucomstartread(struct ucom_softc *sc)
        !          1078: {
        !          1079:        usbd_status err;
        !          1080:
        !          1081:        DPRINTFN(5,("ucomstartread: start\n"));
        !          1082: #ifdef DIAGNOSTIC
        !          1083:        if (sc->sc_ixfer == NULL) {
        !          1084:                DPRINTF(("ucomstartread: null ixfer\n"));
        !          1085:                return (USBD_INVAL);
        !          1086:        }
        !          1087: #endif
        !          1088:
        !          1089:        if (sc->sc_bulkin_pipe != NULL) {
        !          1090:                usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
        !          1091:                        (usbd_private_handle)sc,
        !          1092:                        sc->sc_ibuf, sc->sc_ibufsize,
        !          1093:                        USBD_SHORT_XFER_OK | USBD_NO_COPY,
        !          1094:                        USBD_NO_TIMEOUT, ucomreadcb);
        !          1095:                err = usbd_transfer(sc->sc_ixfer);
        !          1096:                if (err != USBD_IN_PROGRESS) {
        !          1097:                        DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
        !          1098:                        return (err);
        !          1099:                }
        !          1100:        }
        !          1101:
        !          1102:        return (USBD_NORMAL_COMPLETION);
        !          1103: }
        !          1104:
        !          1105: void
        !          1106: ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
        !          1107: {
        !          1108:        struct ucom_softc *sc = (struct ucom_softc *)p;
        !          1109:        struct tty *tp = sc->sc_tty;
        !          1110:        int (*rint)(int c, struct tty *tp) = LINESW(tp, l_rint);
        !          1111:        usbd_status err;
        !          1112:        u_int32_t cc;
        !          1113:        u_char *cp;
        !          1114:        int s;
        !          1115:
        !          1116:        DPRINTFN(5,("ucomreadcb: status=%d\n", status));
        !          1117:
        !          1118:        if (status == USBD_CANCELLED || status == USBD_IOERROR ||
        !          1119:            sc->sc_dying) {
        !          1120:                DPRINTF(("ucomreadcb: dying\n"));
        !          1121:                /* Send something to wake upper layer */
        !          1122:                s = spltty();
        !          1123:                (*rint)('\n', tp);
        !          1124:                ttwakeup(tp);
        !          1125:                splx(s);
        !          1126:                return;
        !          1127:        }
        !          1128:
        !          1129:        if (status) {
        !          1130:                if (sc->sc_bulkin_pipe != NULL) {
        !          1131:                        usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
        !          1132:                        /* XXX we should restart after some delay. */
        !          1133:                        return;
        !          1134:                }
        !          1135:        }
        !          1136:
        !          1137:        usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
        !          1138:        DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp));
        !          1139:        if (sc->sc_methods->ucom_read != NULL)
        !          1140:                sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
        !          1141:                                          &cp, &cc);
        !          1142:
        !          1143:        s = spltty();
        !          1144:        /* Give characters to tty layer. */
        !          1145:        while (cc-- > 0) {
        !          1146:                DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp));
        !          1147:                if ((*rint)(*cp++, tp) == -1) {
        !          1148:                        /* XXX what should we do? */
        !          1149:                        printf("%s: lost %d chars\n", sc->sc_dev.dv_xname,
        !          1150:                               cc);
        !          1151:                        break;
        !          1152:                }
        !          1153:        }
        !          1154:        splx(s);
        !          1155:
        !          1156:        err = ucomstartread(sc);
        !          1157:        if (err) {
        !          1158:                printf("%s: read start failed\n", sc->sc_dev.dv_xname);
        !          1159:                /* XXX what should we dow now? */
        !          1160:        }
        !          1161: }
        !          1162:
        !          1163: void
        !          1164: ucom_cleanup(struct ucom_softc *sc)
        !          1165: {
        !          1166:        if (--sc->sc_open == 0) {
        !          1167:                DPRINTF(("ucom_cleanup: closing pipes\n"));
        !          1168:
        !          1169:                ucom_shutdown(sc);
        !          1170:                if (sc->sc_bulkin_pipe != NULL) {
        !          1171:                        usbd_abort_pipe(sc->sc_bulkin_pipe);
        !          1172:                        usbd_close_pipe(sc->sc_bulkin_pipe);
        !          1173:                        sc->sc_bulkin_pipe = NULL;
        !          1174:                }
        !          1175:                if (sc->sc_bulkout_pipe != NULL) {
        !          1176:                        usbd_abort_pipe(sc->sc_bulkout_pipe);
        !          1177:                        usbd_close_pipe(sc->sc_bulkout_pipe);
        !          1178:                        sc->sc_bulkout_pipe = NULL;
        !          1179:                }
        !          1180:                if (sc->sc_ixfer != NULL) {
        !          1181:                        if (sc->sc_uhidev == NULL)
        !          1182:                                usbd_free_xfer(sc->sc_ixfer);
        !          1183:                        sc->sc_ixfer = NULL;
        !          1184:                }
        !          1185:                if (sc->sc_oxfer != NULL) {
        !          1186:                        usbd_free_buffer(sc->sc_oxfer);
        !          1187:                        if (sc->sc_uhidev == NULL)
        !          1188:                                usbd_free_xfer(sc->sc_oxfer);
        !          1189:                        sc->sc_oxfer = NULL;
        !          1190:                }
        !          1191:        }
        !          1192: }
        !          1193:
        !          1194: #endif /* NUCOM > 0 */
        !          1195:
        !          1196: int
        !          1197: ucomprint(void *aux, const char *pnp)
        !          1198: {
        !          1199:        struct ucom_attach_args *uca = aux;
        !          1200:
        !          1201:        if (pnp)
        !          1202:                printf("ucom at %s", pnp);
        !          1203:        if (uca->portno != UCOM_UNK_PORTNO)
        !          1204:                printf(" portno %d", uca->portno);
        !          1205:        return (UNCONF);
        !          1206: }
        !          1207:
        !          1208: int
        !          1209: ucomsubmatch(struct device *parent, void *match, void *aux)
        !          1210: {
        !          1211:         struct ucom_attach_args *uca = aux;
        !          1212:         struct cfdata *cf = match;
        !          1213:
        !          1214:        if (uca->portno != UCOM_UNK_PORTNO &&
        !          1215:            cf->ucomcf_portno != UCOM_UNK_PORTNO &&
        !          1216:            cf->ucomcf_portno != uca->portno)
        !          1217:                return (0);
        !          1218:        return ((*cf->cf_attach->ca_match)(parent, cf, aux));
        !          1219: }

CVSweb