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

Annotation of src/sys/dev/usb/ucom.c, Revision 1.105

1.105   ! dholland    1: /*     $NetBSD: ucom.c,v 1.104 2014/05/04 22:18:38 christos Exp $      */
1.1       augustss    2:
                      3: /*
1.22      augustss    4:  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
1.1       augustss    5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
1.23      augustss    8:  * by Lennart Augustsson (lennart@augustsson.net) at
1.1       augustss    9:  * Carlstedt Research & Technology.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     21:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     22:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     23:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     24:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     25:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     26:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     27:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     28:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     29:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     30:  * POSSIBILITY OF SUCH DAMAGE.
                     31:  */
1.22      augustss   32: /*
                     33:  * This code is very heavily based on the 16550 driver, com.c.
                     34:  */
1.40      lukem      35:
                     36: #include <sys/cdefs.h>
1.105   ! dholland   37: __KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.104 2014/05/04 22:18:38 christos Exp $");
1.1       augustss   38:
                     39: #include <sys/param.h>
                     40: #include <sys/systm.h>
                     41: #include <sys/kernel.h>
                     42: #include <sys/ioctl.h>
1.3       augustss   43: #include <sys/conf.h>
1.1       augustss   44: #include <sys/tty.h>
                     45: #include <sys/file.h>
                     46: #include <sys/select.h>
                     47: #include <sys/proc.h>
                     48: #include <sys/vnode.h>
1.12      augustss   49: #include <sys/device.h>
1.1       augustss   50: #include <sys/poll.h>
1.82      martin     51: #include <sys/queue.h>
1.63      elad       52: #include <sys/kauth.h>
1.31      explorer   53: #include <sys/rnd.h>
1.1       augustss   54:
                     55: #include <dev/usb/usb.h>
                     56:
                     57: #include <dev/usb/usbdi.h>
                     58: #include <dev/usb/usbdi_util.h>
                     59: #include <dev/usb/usbdevs.h>
                     60: #include <dev/usb/usb_quirks.h>
                     61:
1.12      augustss   62: #include <dev/usb/ucomvar.h>
                     63:
1.13      augustss   64: #include "ucom.h"
                     65:
1.53      drochner   66: #include "locators.h"
                     67:
1.13      augustss   68: #if NUCOM > 0
                     69:
1.12      augustss   70: #ifdef UCOM_DEBUG
1.85      dyoung     71: #define DPRINTFN(n, x) if (ucomdebug > (n)) printf x
1.12      augustss   72: int ucomdebug = 0;
1.1       augustss   73: #else
1.12      augustss   74: #define DPRINTFN(n, x)
1.1       augustss   75: #endif
1.12      augustss   76: #define DPRINTF(x) DPRINTFN(0, x)
                     77:
                     78: #define        UCOMUNIT_MASK           0x3ffff
                     79: #define        UCOMDIALOUT_MASK        0x80000
                     80: #define        UCOMCALLUNIT_MASK       0x40000
                     81:
                     82: #define        UCOMUNIT(x)             (minor(x) & UCOMUNIT_MASK)
                     83: #define        UCOMDIALOUT(x)          (minor(x) & UCOMDIALOUT_MASK)
                     84: #define        UCOMCALLUNIT(x)         (minor(x) & UCOMCALLUNIT_MASK)
                     85:
1.82      martin     86: /*
                     87:  * XXX: We can submit multiple input/output buffers to the usb stack
                     88:  * to improve throughput, but the usb stack is too lame to deal with this
                     89:  * in a number of places.
                     90:  */
                     91: #define        UCOM_IN_BUFFS   1
                     92: #define        UCOM_OUT_BUFFS  1
                     93:
                     94: struct ucom_buffer {
                     95:        SIMPLEQ_ENTRY(ucom_buffer) ub_link;
                     96:        usbd_xfer_handle ub_xfer;
                     97:        u_char *ub_data;
                     98:        u_int ub_len;
                     99:        u_int ub_index;
                    100: };
                    101:
1.1       augustss  102: struct ucom_softc {
1.85      dyoung    103:        device_t                sc_dev;         /* base device */
1.12      augustss  104:
                    105:        usbd_device_handle      sc_udev;        /* USB device */
                    106:
                    107:        usbd_interface_handle   sc_iface;       /* data interface */
                    108:
                    109:        int                     sc_bulkin_no;   /* bulk in endpoint address */
                    110:        usbd_pipe_handle        sc_bulkin_pipe; /* bulk in pipe */
1.19      augustss  111:        u_int                   sc_ibufsize;    /* read buffer size */
1.22      augustss  112:        u_int                   sc_ibufsizepad; /* read buffer size padded */
1.82      martin    113:        struct ucom_buffer      sc_ibuff[UCOM_IN_BUFFS];
                    114:        SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_empty;
                    115:        SIMPLEQ_HEAD(, ucom_buffer) sc_ibuff_full;
1.12      augustss  116:
                    117:        int                     sc_bulkout_no;  /* bulk out endpoint address */
                    118:        usbd_pipe_handle        sc_bulkout_pipe;/* bulk out pipe */
1.19      augustss  119:        u_int                   sc_obufsize;    /* write buffer size */
1.82      martin    120:        u_int                   sc_opkthdrlen;  /* header length of */
                    121:        struct ucom_buffer      sc_obuff[UCOM_OUT_BUFFS];
                    122:        SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_free;
                    123:        SIMPLEQ_HEAD(, ucom_buffer) sc_obuff_full;
                    124:
                    125:        void                    *sc_si;
1.12      augustss  126:
1.90      jakllsch  127:        const struct ucom_methods *sc_methods;
1.12      augustss  128:        void                    *sc_parent;
                    129:        int                     sc_portno;
                    130:
                    131:        struct tty              *sc_tty;        /* our tty */
                    132:        u_char                  sc_lsr;
                    133:        u_char                  sc_msr;
                    134:        u_char                  sc_mcr;
1.82      martin    135:        volatile u_char         sc_rx_stopped;
                    136:        u_char                  sc_rx_unblock;
1.12      augustss  137:        u_char                  sc_tx_stopped;
                    138:        int                     sc_swflags;
                    139:
                    140:        u_char                  sc_opening;     /* lock during open */
1.17      augustss  141:        int                     sc_refcnt;
1.12      augustss  142:        u_char                  sc_dying;       /* disconnecting */
1.31      explorer  143:
1.88      tls       144:        krndsource_t    sc_rndsource;   /* random source */
1.1       augustss  145: };
                    146:
1.44      gehenna   147: dev_type_open(ucomopen);
                    148: dev_type_close(ucomclose);
                    149: dev_type_read(ucomread);
                    150: dev_type_write(ucomwrite);
                    151: dev_type_ioctl(ucomioctl);
                    152: dev_type_stop(ucomstop);
                    153: dev_type_tty(ucomtty);
                    154: dev_type_poll(ucompoll);
                    155:
                    156: const struct cdevsw ucom_cdevsw = {
1.103     dholland  157:        .d_open = ucomopen,
                    158:        .d_close = ucomclose,
                    159:        .d_read = ucomread,
                    160:        .d_write = ucomwrite,
                    161:        .d_ioctl = ucomioctl,
                    162:        .d_stop = ucomstop,
                    163:        .d_tty = ucomtty,
                    164:        .d_poll = ucompoll,
                    165:        .d_mmap = nommap,
                    166:        .d_kqfilter = ttykqfilter,
1.105   ! dholland  167:        .d_discard = nodiscard,
1.103     dholland  168:        .d_flag = D_TTY
1.44      gehenna   169: };
1.12      augustss  170:
1.82      martin    171: static void    ucom_cleanup(struct ucom_softc *);
                    172: static int     ucomparam(struct tty *, struct termios *);
                    173: static int     ucomhwiflow(struct tty *, int);
                    174: static void    ucomstart(struct tty *);
                    175: static void    ucom_shutdown(struct ucom_softc *);
                    176: static int     ucom_do_ioctl(struct ucom_softc *, u_long, void *,
1.60      christos  177:                              int, struct lwp *);
1.82      martin    178: static void    ucom_dtr(struct ucom_softc *, int);
                    179: static void    ucom_rts(struct ucom_softc *, int);
                    180: static void    ucom_break(struct ucom_softc *, int);
                    181: static void    tiocm_to_ucom(struct ucom_softc *, u_long, int);
                    182: static int     ucom_to_tiocm(struct ucom_softc *);
                    183:
                    184: static void    ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
                    185: static void    ucom_submit_write(struct ucom_softc *, struct ucom_buffer *);
                    186: static void    ucom_write_status(struct ucom_softc *, struct ucom_buffer *,
                    187:                        usbd_status);
                    188:
                    189: static void    ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
                    190: static void    ucom_read_complete(struct ucom_softc *);
                    191: static usbd_status ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
                    192: static void    ucom_softintr(void *);
1.1       augustss  193:
1.85      dyoung    194: int ucom_match(device_t, cfdata_t, void *);
                    195: void ucom_attach(device_t, device_t, void *);
                    196: int ucom_detach(device_t, int);
                    197: int ucom_activate(device_t, enum devact);
                    198: extern struct cfdriver ucom_cd;
                    199: CFATTACH_DECL_NEW(ucom, sizeof(struct ucom_softc), ucom_match, ucom_attach,
                    200:     ucom_detach, ucom_activate);
1.1       augustss  201:
1.85      dyoung    202: int
                    203: ucom_match(device_t parent, cfdata_t match, void *aux)
1.1       augustss  204: {
1.12      augustss  205:        return (1);
1.1       augustss  206: }
                    207:
1.85      dyoung    208: void
                    209: ucom_attach(device_t parent, device_t self, void *aux)
1.1       augustss  210: {
1.77      cube      211:        struct ucom_softc *sc = device_private(self);
1.12      augustss  212:        struct ucom_attach_args *uca = aux;
                    213:        struct tty *tp;
                    214:
1.35      augustss  215:        if (uca->info != NULL)
1.83      pooka     216:                aprint_normal(": %s", uca->info);
                    217:        aprint_normal("\n");
1.12      augustss  218:
1.77      cube      219:        sc->sc_dev = self;
1.12      augustss  220:        sc->sc_udev = uca->device;
                    221:        sc->sc_iface = uca->iface;
                    222:        sc->sc_bulkout_no = uca->bulkout;
                    223:        sc->sc_bulkin_no = uca->bulkin;
1.19      augustss  224:        sc->sc_ibufsize = uca->ibufsize;
1.22      augustss  225:        sc->sc_ibufsizepad = uca->ibufsizepad;
1.19      augustss  226:        sc->sc_obufsize = uca->obufsize;
1.25      augustss  227:        sc->sc_opkthdrlen = uca->opkthdrlen;
1.12      augustss  228:        sc->sc_methods = uca->methods;
                    229:        sc->sc_parent = uca->arg;
                    230:        sc->sc_portno = uca->portno;
                    231:
1.82      martin    232:        sc->sc_lsr = 0;
                    233:        sc->sc_msr = 0;
                    234:        sc->sc_mcr = 0;
                    235:        sc->sc_tx_stopped = 0;
                    236:        sc->sc_swflags = 0;
                    237:        sc->sc_opening = 0;
                    238:        sc->sc_refcnt = 0;
                    239:        sc->sc_dying = 0;
                    240:
                    241:        sc->sc_si = softint_establish(SOFTINT_NET, ucom_softintr, sc);
                    242:
1.87      rmind     243:        tp = tty_alloc();
1.12      augustss  244:        tp->t_oproc = ucomstart;
                    245:        tp->t_param = ucomparam;
1.82      martin    246:        tp->t_hwiflow = ucomhwiflow;
1.12      augustss  247:        sc->sc_tty = tp;
                    248:
                    249:        DPRINTF(("ucom_attach: tty_attach %p\n", tp));
                    250:        tty_attach(tp);
                    251:
1.85      dyoung    252:        rnd_attach_source(&sc->sc_rndsource, device_xname(sc->sc_dev),
1.31      explorer  253:                          RND_TYPE_TTY, 0);
                    254:
1.74      smb       255:        if (!pmf_device_register(self, NULL, NULL))
                    256:                aprint_error_dev(self, "couldn't establish power handler\n");
1.85      dyoung    257:        return;
1.12      augustss  258: }
                    259:
1.85      dyoung    260: int
                    261: ucom_detach(device_t self, int flags)
1.12      augustss  262: {
1.77      cube      263:        struct ucom_softc *sc = device_private(self);
1.36      augustss  264:        struct tty *tp = sc->sc_tty;
1.12      augustss  265:        int maj, mn;
1.82      martin    266:        int s, i;
1.12      augustss  267:
1.43      augustss  268:        DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
1.36      augustss  269:                 sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
1.12      augustss  270:
                    271:        sc->sc_dying = 1;
1.74      smb       272:        pmf_device_deregister(self);
1.12      augustss  273:
1.33      augustss  274:        if (sc->sc_bulkin_pipe != NULL)
                    275:                usbd_abort_pipe(sc->sc_bulkin_pipe);
                    276:        if (sc->sc_bulkout_pipe != NULL)
                    277:                usbd_abort_pipe(sc->sc_bulkout_pipe);
1.12      augustss  278:
1.17      augustss  279:        s = splusb();
                    280:        if (--sc->sc_refcnt >= 0) {
1.35      augustss  281:                /* Wake up anyone waiting */
1.36      augustss  282:                if (tp != NULL) {
1.71      ad        283:                        mutex_spin_enter(&tty_lock);
1.36      augustss  284:                        CLR(tp->t_state, TS_CARR_ON);
                    285:                        CLR(tp->t_cflag, CLOCAL | MDMBUF);
                    286:                        ttyflush(tp, FREAD|FWRITE);
1.71      ad        287:                        mutex_spin_exit(&tty_lock);
1.36      augustss  288:                }
1.17      augustss  289:                /* Wait for processes to go away. */
1.99      mrg       290:                usb_detach_waitold(sc->sc_dev);
1.17      augustss  291:        }
1.82      martin    292:
                    293:        softint_disestablish(sc->sc_si);
1.17      augustss  294:        splx(s);
1.12      augustss  295:
                    296:        /* locate the major number */
1.44      gehenna   297:        maj = cdevsw_lookup_major(&ucom_cdevsw);
1.12      augustss  298:
                    299:        /* Nuke the vnodes for any open instances. */
1.62      thorpej   300:        mn = device_unit(self);
1.17      augustss  301:        DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn));
1.12      augustss  302:        vdevgone(maj, mn, mn, VCHR);
1.22      augustss  303:        vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR);
                    304:        vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR);
1.12      augustss  305:
                    306:        /* Detach and free the tty. */
1.36      augustss  307:        if (tp != NULL) {
                    308:                tty_detach(tp);
1.87      rmind     309:                tty_free(tp);
1.33      augustss  310:                sc->sc_tty = NULL;
                    311:        }
1.12      augustss  312:
1.82      martin    313:        for (i = 0; i < UCOM_IN_BUFFS; i++) {
                    314:                if (sc->sc_ibuff[i].ub_xfer != NULL)
                    315:                        usbd_free_xfer(sc->sc_ibuff[i].ub_xfer);
                    316:        }
                    317:
                    318:        for (i = 0; i < UCOM_OUT_BUFFS; i++) {
                    319:                if (sc->sc_obuff[i].ub_xfer != NULL)
                    320:                        usbd_free_xfer(sc->sc_obuff[i].ub_xfer);
                    321:        }
                    322:
1.31      explorer  323:        /* Detach the random source */
                    324:        rnd_detach_source(&sc->sc_rndsource);
                    325:
1.12      augustss  326:        return (0);
                    327: }
                    328:
                    329: int
1.85      dyoung    330: ucom_activate(device_t self, enum devact act)
1.12      augustss  331: {
1.77      cube      332:        struct ucom_softc *sc = device_private(self);
1.12      augustss  333:
1.34      augustss  334:        DPRINTFN(5,("ucom_activate: %d\n", act));
                    335:
1.12      augustss  336:        switch (act) {
                    337:        case DVACT_DEACTIVATE:
                    338:                sc->sc_dying = 1;
1.81      dyoung    339:                return 0;
                    340:        default:
                    341:                return EOPNOTSUPP;
1.12      augustss  342:        }
                    343: }
                    344:
                    345: void
1.24      augustss  346: ucom_shutdown(struct ucom_softc *sc)
1.12      augustss  347: {
                    348:        struct tty *tp = sc->sc_tty;
                    349:
                    350:        DPRINTF(("ucom_shutdown\n"));
                    351:        /*
                    352:         * Hang up if necessary.  Wait a bit, so the other side has time to
                    353:         * notice even if we immediately open the port again.
                    354:         */
                    355:        if (ISSET(tp->t_cflag, HUPCL)) {
                    356:                ucom_dtr(sc, 0);
                    357:                (void)tsleep(sc, TTIPRI, ttclos, hz);
                    358:        }
                    359: }
                    360:
                    361: int
1.69      christos  362: ucomopen(dev_t dev, int flag, int mode, struct lwp *l)
1.12      augustss  363: {
                    364:        int unit = UCOMUNIT(dev);
                    365:        usbd_status err;
1.77      cube      366:        struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
1.82      martin    367:        struct ucom_buffer *ub;
1.12      augustss  368:        struct tty *tp;
1.82      martin    369:        int s, i;
1.12      augustss  370:        int error;
1.43      augustss  371:
1.12      augustss  372:        if (sc == NULL)
                    373:                return (ENXIO);
                    374:
                    375:        if (sc->sc_dying)
                    376:                return (EIO);
                    377:
1.77      cube      378:        if (!device_is_active(sc->sc_dev))
1.12      augustss  379:                return (ENXIO);
                    380:
                    381:        tp = sc->sc_tty;
                    382:
                    383:        DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
                    384:
1.66      elad      385:        if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
1.12      augustss  386:                return (EBUSY);
                    387:
                    388:        s = spltty();
                    389:
                    390:        /*
                    391:         * Do the following iff this is a first open.
                    392:         */
                    393:        while (sc->sc_opening)
                    394:                tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
1.17      augustss  395:
                    396:        if (sc->sc_dying) {
                    397:                splx(s);
                    398:                return (EIO);
                    399:        }
1.12      augustss  400:        sc->sc_opening = 1;
1.43      augustss  401:
1.12      augustss  402:        if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
                    403:                struct termios t;
                    404:
                    405:                tp->t_dev = dev;
                    406:
1.22      augustss  407:                if (sc->sc_methods->ucom_open != NULL) {
                    408:                        error = sc->sc_methods->ucom_open(sc->sc_parent,
                    409:                                                          sc->sc_portno);
                    410:                        if (error) {
                    411:                                ucom_cleanup(sc);
1.26      toshii    412:                                sc->sc_opening = 0;
                    413:                                wakeup(&sc->sc_opening);
                    414:                                splx(s);
1.22      augustss  415:                                return (error);
                    416:                        }
                    417:                }
                    418:
1.12      augustss  419:                ucom_status_change(sc);
                    420:
                    421:                /*
                    422:                 * Initialize the termios status to the defaults.  Add in the
                    423:                 * sticky bits from TIOCSFLAGS.
                    424:                 */
                    425:                t.c_ispeed = 0;
                    426:                t.c_ospeed = TTYDEF_SPEED;
                    427:                t.c_cflag = TTYDEF_CFLAG;
                    428:                if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
                    429:                        SET(t.c_cflag, CLOCAL);
                    430:                if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
                    431:                        SET(t.c_cflag, CRTSCTS);
                    432:                if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
                    433:                        SET(t.c_cflag, MDMBUF);
                    434:                /* Make sure ucomparam() will do something. */
                    435:                tp->t_ospeed = 0;
                    436:                (void) ucomparam(tp, &t);
                    437:                tp->t_iflag = TTYDEF_IFLAG;
                    438:                tp->t_oflag = TTYDEF_OFLAG;
                    439:                tp->t_lflag = TTYDEF_LFLAG;
                    440:                ttychars(tp);
                    441:                ttsetwater(tp);
                    442:
                    443:                /*
                    444:                 * Turn on DTR.  We must always do this, even if carrier is not
                    445:                 * present, because otherwise we'd have to use TIOCSDTR
                    446:                 * immediately after setting CLOCAL, which applications do not
                    447:                 * expect.  We always assert DTR while the device is open
1.64      gson      448:                 * unless explicitly requested to deassert it.  Ditto RTS.
1.12      augustss  449:                 */
                    450:                ucom_dtr(sc, 1);
1.102     jakllsch  451:                ucom_rts(sc, 1);
1.12      augustss  452:
                    453:                DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
                    454:                         sc->sc_bulkin_no, sc->sc_bulkout_no));
                    455:
                    456:                /* Open the bulk pipes */
1.82      martin    457:                err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no,
                    458:                                     USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
1.12      augustss  459:                if (err) {
1.52      nathanw   460:                        DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
1.85      dyoung    461:                                 device_xname(sc->sc_dev), sc->sc_bulkin_no,
1.12      augustss  462:                                 usbd_errstr(err)));
1.28      toshii    463:                        error = EIO;
1.26      toshii    464:                        goto fail_0;
1.12      augustss  465:                }
                    466:                err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
                    467:                                     USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
                    468:                if (err) {
1.52      nathanw   469:                        DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
1.85      dyoung    470:                                 device_xname(sc->sc_dev), sc->sc_bulkout_no,
1.12      augustss  471:                                 usbd_errstr(err)));
1.28      toshii    472:                        error = EIO;
1.26      toshii    473:                        goto fail_1;
1.12      augustss  474:                }
1.43      augustss  475:
1.82      martin    476:                sc->sc_rx_unblock = 0;
                    477:                sc->sc_rx_stopped = 0;
                    478:                sc->sc_tx_stopped = 0;
                    479:
                    480:                memset(sc->sc_ibuff, 0, sizeof(sc->sc_ibuff));
                    481:                memset(sc->sc_obuff, 0, sizeof(sc->sc_obuff));
                    482:
                    483:                SIMPLEQ_INIT(&sc->sc_ibuff_empty);
                    484:                SIMPLEQ_INIT(&sc->sc_ibuff_full);
                    485:                SIMPLEQ_INIT(&sc->sc_obuff_free);
                    486:                SIMPLEQ_INIT(&sc->sc_obuff_full);
                    487:
                    488:                /* Allocate input buffers */
                    489:                for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
                    490:                    ub++) {
                    491:                        ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev);
                    492:                        if (ub->ub_xfer == NULL) {
                    493:                                error = ENOMEM;
                    494:                                goto fail_2;
                    495:                        }
                    496:                        ub->ub_data = usbd_alloc_buffer(ub->ub_xfer,
                    497:                            sc->sc_ibufsizepad);
                    498:                        if (ub->ub_data == NULL) {
                    499:                                error = ENOMEM;
                    500:                                goto fail_2;
                    501:                        }
1.26      toshii    502:
1.82      martin    503:                        if (ucomsubmitread(sc, ub) != USBD_NORMAL_COMPLETION) {
                    504:                                error = EIO;
                    505:                                goto fail_2;
                    506:                        }
1.28      toshii    507:                }
1.12      augustss  508:
1.82      martin    509:                for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
                    510:                    ub++) {
                    511:                        ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev);
                    512:                        if (ub->ub_xfer == NULL) {
                    513:                                error = ENOMEM;
                    514:                                goto fail_2;
                    515:                        }
                    516:                        ub->ub_data = usbd_alloc_buffer(ub->ub_xfer,
                    517:                            sc->sc_obufsize);
                    518:                        if (ub->ub_data == NULL) {
                    519:                                error = ENOMEM;
                    520:                                goto fail_2;
                    521:                        }
1.26      toshii    522:
1.82      martin    523:                        SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
1.28      toshii    524:                }
1.12      augustss  525:
                    526:        }
                    527:        sc->sc_opening = 0;
                    528:        wakeup(&sc->sc_opening);
                    529:        splx(s);
                    530:
                    531:        error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
                    532:        if (error)
                    533:                goto bad;
                    534:
1.32      eeh       535:        error = (*tp->t_linesw->l_open)(dev, tp);
1.12      augustss  536:        if (error)
                    537:                goto bad;
                    538:
                    539:        return (0);
1.26      toshii    540:
                    541: fail_2:
1.82      martin    542:        usbd_abort_pipe(sc->sc_bulkin_pipe);
                    543:        for (i = 0; i < UCOM_IN_BUFFS; i++) {
                    544:                if (sc->sc_ibuff[i].ub_xfer != NULL) {
                    545:                        usbd_free_xfer(sc->sc_ibuff[i].ub_xfer);
                    546:                        sc->sc_ibuff[i].ub_xfer = NULL;
                    547:                        sc->sc_ibuff[i].ub_data = NULL;
                    548:                }
                    549:        }
                    550:        usbd_abort_pipe(sc->sc_bulkout_pipe);
                    551:        for (i = 0; i < UCOM_OUT_BUFFS; i++) {
                    552:                if (sc->sc_obuff[i].ub_xfer != NULL) {
                    553:                        usbd_free_xfer(sc->sc_obuff[i].ub_xfer);
                    554:                        sc->sc_obuff[i].ub_xfer = NULL;
                    555:                        sc->sc_obuff[i].ub_data = NULL;
                    556:                }
                    557:        }
                    558:
1.26      toshii    559:        usbd_close_pipe(sc->sc_bulkout_pipe);
1.34      augustss  560:        sc->sc_bulkout_pipe = NULL;
1.26      toshii    561: fail_1:
                    562:        usbd_close_pipe(sc->sc_bulkin_pipe);
1.34      augustss  563:        sc->sc_bulkin_pipe = NULL;
1.26      toshii    564: fail_0:
                    565:        sc->sc_opening = 0;
                    566:        wakeup(&sc->sc_opening);
                    567:        splx(s);
1.28      toshii    568:        return (error);
1.12      augustss  569:
                    570: bad:
1.82      martin    571:        s = spltty();
                    572:        CLR(tp->t_state, TS_BUSY);
1.12      augustss  573:        if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
                    574:                /*
                    575:                 * We failed to open the device, and nobody else had it opened.
                    576:                 * Clean up the state as appropriate.
                    577:                 */
                    578:                ucom_cleanup(sc);
                    579:        }
1.82      martin    580:        splx(s);
1.12      augustss  581:
                    582:        return (error);
                    583: }
                    584:
                    585: int
1.69      christos  586: ucomclose(dev_t dev, int flag, int mode, struct lwp *l)
1.12      augustss  587: {
1.77      cube      588:        struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.101     jakllsch  589:        struct tty *tp;
1.82      martin    590:        int s;
1.12      augustss  591:
1.79      drochner  592:        DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
1.101     jakllsch  593:
                    594:        if (sc == NULL)
                    595:                return 0;
                    596:
                    597:        tp = sc->sc_tty;
                    598:
1.12      augustss  599:        if (!ISSET(tp->t_state, TS_ISOPEN))
                    600:                return (0);
                    601:
1.82      martin    602:        s = spltty();
1.17      augustss  603:        sc->sc_refcnt++;
                    604:
1.32      eeh       605:        (*tp->t_linesw->l_close)(tp, flag);
1.12      augustss  606:        ttyclose(tp);
                    607:
                    608:        if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
                    609:                /*
                    610:                 * Although we got a last close, the device may still be in
                    611:                 * use; e.g. if this was the dialout node, and there are still
                    612:                 * processes waiting for carrier on the non-dialout node.
                    613:                 */
                    614:                ucom_cleanup(sc);
                    615:        }
                    616:
1.14      augustss  617:        if (sc->sc_methods->ucom_close != NULL)
                    618:                sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
                    619:
1.17      augustss  620:        if (--sc->sc_refcnt < 0)
1.99      mrg       621:                usb_detach_wakeupold(sc->sc_dev);
1.82      martin    622:        splx(s);
1.17      augustss  623:
1.12      augustss  624:        return (0);
                    625: }
1.43      augustss  626:
1.12      augustss  627: int
1.24      augustss  628: ucomread(dev_t dev, struct uio *uio, int flag)
1.12      augustss  629: {
1.77      cube      630:        struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.101     jakllsch  631:        struct tty *tp;
1.17      augustss  632:        int error;
1.12      augustss  633:
1.101     jakllsch  634:        if (sc == NULL || sc->sc_dying)
1.12      augustss  635:                return (EIO);
1.43      augustss  636:
1.101     jakllsch  637:        tp = sc->sc_tty;
                    638:
1.17      augustss  639:        sc->sc_refcnt++;
1.32      eeh       640:        error = ((*tp->t_linesw->l_read)(tp, uio, flag));
1.17      augustss  641:        if (--sc->sc_refcnt < 0)
1.99      mrg       642:                usb_detach_wakeupold(sc->sc_dev);
1.17      augustss  643:        return (error);
1.12      augustss  644: }
1.43      augustss  645:
1.12      augustss  646: int
1.24      augustss  647: ucomwrite(dev_t dev, struct uio *uio, int flag)
1.12      augustss  648: {
1.77      cube      649:        struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.101     jakllsch  650:        struct tty *tp;
1.17      augustss  651:        int error;
1.12      augustss  652:
1.101     jakllsch  653:        if (sc == NULL || sc->sc_dying)
1.12      augustss  654:                return (EIO);
1.43      augustss  655:
1.101     jakllsch  656:        tp = sc->sc_tty;
                    657:
1.17      augustss  658:        sc->sc_refcnt++;
1.32      eeh       659:        error = ((*tp->t_linesw->l_write)(tp, uio, flag));
1.38      scw       660:        if (--sc->sc_refcnt < 0)
1.99      mrg       661:                usb_detach_wakeupold(sc->sc_dev);
1.38      scw       662:        return (error);
                    663: }
                    664:
                    665: int
1.60      christos  666: ucompoll(dev_t dev, int events, struct lwp *l)
1.38      scw       667: {
1.94      jakllsch  668:        struct ucom_softc *sc;
                    669:        struct tty *tp;
1.56      ws        670:        int revents;
1.38      scw       671:
1.94      jakllsch  672:        sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
                    673:        if (sc == NULL || sc->sc_dying)
1.56      ws        674:                return (POLLHUP);
1.43      augustss  675:
1.94      jakllsch  676:        tp = sc->sc_tty;
                    677:
1.38      scw       678:        sc->sc_refcnt++;
1.60      christos  679:        revents = ((*tp->t_linesw->l_poll)(tp, events, l));
1.17      augustss  680:        if (--sc->sc_refcnt < 0)
1.99      mrg       681:                usb_detach_wakeupold(sc->sc_dev);
1.56      ws        682:        return (revents);
1.12      augustss  683: }
                    684:
                    685: struct tty *
1.24      augustss  686: ucomtty(dev_t dev)
1.12      augustss  687: {
1.77      cube      688:        struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.12      augustss  689:
1.101     jakllsch  690:        return ((sc != NULL) ? sc->sc_tty : NULL);
1.12      augustss  691: }
                    692:
                    693: int
1.70      christos  694: ucomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1.12      augustss  695: {
1.77      cube      696:        struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
1.17      augustss  697:        int error;
                    698:
1.101     jakllsch  699:        if (sc == NULL || sc->sc_dying)
                    700:                return (EIO);
                    701:
1.17      augustss  702:        sc->sc_refcnt++;
1.60      christos  703:        error = ucom_do_ioctl(sc, cmd, data, flag, l);
1.17      augustss  704:        if (--sc->sc_refcnt < 0)
1.99      mrg       705:                usb_detach_wakeupold(sc->sc_dev);
1.17      augustss  706:        return (error);
                    707: }
                    708:
1.82      martin    709: static int
1.70      christos  710: ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, void *data,
1.60      christos  711:              int flag, struct lwp *l)
1.17      augustss  712: {
1.12      augustss  713:        struct tty *tp = sc->sc_tty;
                    714:        int error;
                    715:        int s;
                    716:
                    717:        DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
                    718:
1.60      christos  719:        error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
1.42      atatat    720:        if (error != EPASSTHROUGH)
1.12      augustss  721:                return (error);
                    722:
1.60      christos  723:        error = ttioctl(tp, cmd, data, flag, l);
1.42      atatat    724:        if (error != EPASSTHROUGH)
1.12      augustss  725:                return (error);
                    726:
                    727:        if (sc->sc_methods->ucom_ioctl != NULL) {
                    728:                error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
1.60      christos  729:                            sc->sc_portno, cmd, data, flag, l->l_proc);
1.42      atatat    730:                if (error != EPASSTHROUGH)
1.12      augustss  731:                        return (error);
                    732:        }
                    733:
                    734:        error = 0;
                    735:
                    736:        DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
                    737:        s = spltty();
                    738:
                    739:        switch (cmd) {
                    740:        case TIOCSBRK:
                    741:                ucom_break(sc, 1);
                    742:                break;
                    743:
                    744:        case TIOCCBRK:
                    745:                ucom_break(sc, 0);
                    746:                break;
                    747:
                    748:        case TIOCSDTR:
                    749:                ucom_dtr(sc, 1);
                    750:                break;
                    751:
                    752:        case TIOCCDTR:
                    753:                ucom_dtr(sc, 0);
                    754:                break;
                    755:
                    756:        case TIOCGFLAGS:
                    757:                *(int *)data = sc->sc_swflags;
                    758:                break;
                    759:
                    760:        case TIOCSFLAGS:
1.67      elad      761:                error = kauth_authorize_device_tty(l->l_cred,
                    762:                    KAUTH_DEVICE_TTY_PRIVSET, tp);
1.12      augustss  763:                if (error)
                    764:                        break;
                    765:                sc->sc_swflags = *(int *)data;
                    766:                break;
                    767:
                    768:        case TIOCMSET:
                    769:        case TIOCMBIS:
                    770:        case TIOCMBIC:
                    771:                tiocm_to_ucom(sc, cmd, *(int *)data);
                    772:                break;
                    773:
                    774:        case TIOCMGET:
                    775:                *(int *)data = ucom_to_tiocm(sc);
                    776:                break;
                    777:
                    778:        default:
1.42      atatat    779:                error = EPASSTHROUGH;
1.12      augustss  780:                break;
                    781:        }
                    782:
                    783:        splx(s);
                    784:
                    785:        return (error);
                    786: }
                    787:
1.82      martin    788: static void
1.29      toshii    789: tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
1.12      augustss  790: {
                    791:        u_char combits;
1.3       augustss  792:
1.12      augustss  793:        combits = 0;
                    794:        if (ISSET(ttybits, TIOCM_DTR))
                    795:                SET(combits, UMCR_DTR);
                    796:        if (ISSET(ttybits, TIOCM_RTS))
                    797:                SET(combits, UMCR_RTS);
1.43      augustss  798:
1.12      augustss  799:        switch (how) {
                    800:        case TIOCMBIC:
                    801:                CLR(sc->sc_mcr, combits);
                    802:                break;
                    803:
                    804:        case TIOCMBIS:
                    805:                SET(sc->sc_mcr, combits);
                    806:                break;
                    807:
                    808:        case TIOCMSET:
                    809:                CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
                    810:                SET(sc->sc_mcr, combits);
                    811:                break;
                    812:        }
                    813:
1.27      toshii    814:        if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
                    815:                ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
                    816:        if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
                    817:                ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
1.12      augustss  818: }
                    819:
1.82      martin    820: static int
1.24      augustss  821: ucom_to_tiocm(struct ucom_softc *sc)
1.12      augustss  822: {
                    823:        u_char combits;
                    824:        int ttybits = 0;
                    825:
                    826:        combits = sc->sc_mcr;
                    827:        if (ISSET(combits, UMCR_DTR))
                    828:                SET(ttybits, TIOCM_DTR);
                    829:        if (ISSET(combits, UMCR_RTS))
                    830:                SET(ttybits, TIOCM_RTS);
                    831:
                    832:        combits = sc->sc_msr;
                    833:        if (ISSET(combits, UMSR_DCD))
                    834:                SET(ttybits, TIOCM_CD);
                    835:        if (ISSET(combits, UMSR_CTS))
                    836:                SET(ttybits, TIOCM_CTS);
                    837:        if (ISSET(combits, UMSR_DSR))
                    838:                SET(ttybits, TIOCM_DSR);
                    839:        if (ISSET(combits, UMSR_RI | UMSR_TERI))
                    840:                SET(ttybits, TIOCM_RI);
                    841:
                    842: #if 0
                    843: XXX;
                    844:        if (sc->sc_ier != 0)
                    845:                SET(ttybits, TIOCM_LE);
                    846: #endif
                    847:
                    848:        return (ttybits);
                    849: }
                    850:
1.82      martin    851: static void
1.77      cube      852: ucom_break(struct ucom_softc *sc, int onoff)
1.12      augustss  853: {
                    854:        DPRINTF(("ucom_break: onoff=%d\n", onoff));
                    855:
1.14      augustss  856:        if (sc->sc_methods->ucom_set != NULL)
                    857:                sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
                    858:                    UCOM_SET_BREAK, onoff);
1.12      augustss  859: }
                    860:
1.82      martin    861: static void
1.24      augustss  862: ucom_dtr(struct ucom_softc *sc, int onoff)
1.12      augustss  863: {
                    864:        DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
                    865:
1.14      augustss  866:        if (sc->sc_methods->ucom_set != NULL)
1.43      augustss  867:                sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
1.14      augustss  868:                    UCOM_SET_DTR, onoff);
1.12      augustss  869: }
                    870:
1.82      martin    871: static void
1.24      augustss  872: ucom_rts(struct ucom_softc *sc, int onoff)
1.12      augustss  873: {
                    874:        DPRINTF(("ucom_rts: onoff=%d\n", onoff));
                    875:
1.14      augustss  876:        if (sc->sc_methods->ucom_set != NULL)
1.43      augustss  877:                sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
1.14      augustss  878:                    UCOM_SET_RTS, onoff);
1.12      augustss  879: }
                    880:
1.22      augustss  881: void
1.24      augustss  882: ucom_status_change(struct ucom_softc *sc)
1.12      augustss  883: {
1.27      toshii    884:        struct tty *tp = sc->sc_tty;
                    885:        u_char old_msr;
                    886:
1.14      augustss  887:        if (sc->sc_methods->ucom_get_status != NULL) {
1.27      toshii    888:                old_msr = sc->sc_msr;
1.14      augustss  889:                sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
                    890:                    &sc->sc_lsr, &sc->sc_msr);
1.27      toshii    891:                if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD))
1.32      eeh       892:                        (*tp->t_linesw->l_modem)(tp,
1.27      toshii    893:                            ISSET(sc->sc_msr, UMSR_DCD));
1.14      augustss  894:        } else {
                    895:                sc->sc_lsr = 0;
1.54      augustss  896:                /* Assume DCD is present, if we have no chance to check it. */
                    897:                sc->sc_msr = UMSR_DCD;
1.14      augustss  898:        }
1.12      augustss  899: }
                    900:
1.82      martin    901: static int
1.24      augustss  902: ucomparam(struct tty *tp, struct termios *t)
1.12      augustss  903: {
1.77      cube      904:        struct ucom_softc *sc = device_lookup_private(&ucom_cd,
                    905:            UCOMUNIT(tp->t_dev));
1.14      augustss  906:        int error;
1.12      augustss  907:
1.101     jakllsch  908:        if (sc == NULL || sc->sc_dying)
1.12      augustss  909:                return (EIO);
                    910:
                    911:        /* Check requested parameters. */
                    912:        if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
                    913:                return (EINVAL);
                    914:
                    915:        /*
                    916:         * For the console, always force CLOCAL and !HUPCL, so that the port
                    917:         * is always active.
                    918:         */
                    919:        if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
                    920:                SET(t->c_cflag, CLOCAL);
                    921:                CLR(t->c_cflag, HUPCL);
                    922:        }
                    923:
                    924:        /*
                    925:         * If there were no changes, don't do anything.  This avoids dropping
                    926:         * input and improves performance when all we did was frob things like
                    927:         * VMIN and VTIME.
                    928:         */
                    929:        if (tp->t_ospeed == t->c_ospeed &&
                    930:            tp->t_cflag == t->c_cflag)
                    931:                return (0);
                    932:
1.30      augustss  933:        /* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
1.12      augustss  934:
                    935:        /* And copy to tty. */
                    936:        tp->t_ispeed = 0;
                    937:        tp->t_ospeed = t->c_ospeed;
                    938:        tp->t_cflag = t->c_cflag;
                    939:
1.14      augustss  940:        if (sc->sc_methods->ucom_param != NULL) {
                    941:                error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
                    942:                            t);
                    943:                if (error)
                    944:                        return (error);
                    945:        }
1.12      augustss  946:
1.30      augustss  947:        /* XXX worry about CHWFLOW */
1.12      augustss  948:
                    949:        /*
                    950:         * Update the tty layer's idea of the carrier bit, in case we changed
                    951:         * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
                    952:         * explicit request.
                    953:         */
                    954:        DPRINTF(("ucomparam: l_modem\n"));
1.54      augustss  955:        (void) (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_msr, UMSR_DCD));
1.12      augustss  956:
                    957: #if 0
                    958: XXX what if the hardware is not open
                    959:        if (!ISSET(t->c_cflag, CHWFLOW)) {
                    960:                if (sc->sc_tx_stopped) {
                    961:                        sc->sc_tx_stopped = 0;
                    962:                        ucomstart(tp);
                    963:                }
                    964:        }
                    965: #endif
                    966:
                    967:        return (0);
                    968: }
                    969:
1.82      martin    970: static int
                    971: ucomhwiflow(struct tty *tp, int block)
1.12      augustss  972: {
1.82      martin    973:        struct ucom_softc *sc = device_lookup_private(&ucom_cd,
                    974:            UCOMUNIT(tp->t_dev));
                    975:        int old;
1.12      augustss  976:
1.101     jakllsch  977:        if (sc == NULL)
                    978:                return (0);
                    979:
1.82      martin    980:        old = sc->sc_rx_stopped;
                    981:        sc->sc_rx_stopped = (u_char)block;
1.12      augustss  982:
1.82      martin    983:        if (old && !block) {
                    984:                int s = splusb();
                    985:                sc->sc_rx_unblock = 1;
                    986:                softint_schedule(sc->sc_si);
                    987:                splx(s);
1.12      augustss  988:        }
1.82      martin    989:
                    990:        return (1);
1.1       augustss  991: }
1.3       augustss  992:
1.82      martin    993: static void
1.24      augustss  994: ucomstart(struct tty *tp)
1.12      augustss  995: {
1.77      cube      996:        struct ucom_softc *sc = device_lookup_private(&ucom_cd,
                    997:            UCOMUNIT(tp->t_dev));
1.82      martin    998:        struct ucom_buffer *ub;
1.12      augustss  999:        int s;
                   1000:        u_char *data;
                   1001:        int cnt;
                   1002:
1.101     jakllsch 1003:        if (sc == NULL || sc->sc_dying)
1.12      augustss 1004:                return;
                   1005:
                   1006:        s = spltty();
1.84      christos 1007:        if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
1.12      augustss 1008:                goto out;
                   1009:        if (sc->sc_tx_stopped)
                   1010:                goto out;
                   1011:
1.82      martin   1012:        if (!ttypull(tp))
1.73      ad       1013:                goto out;
1.12      augustss 1014:
                   1015:        /* Grab the first contiguous region of buffer space. */
                   1016:        data = tp->t_outq.c_cf;
                   1017:        cnt = ndqb(&tp->t_outq, 0);
                   1018:
1.84      christos 1019:        if (cnt == 0)
1.12      augustss 1020:                goto out;
                   1021:
1.82      martin   1022:        ub = SIMPLEQ_FIRST(&sc->sc_obuff_free);
1.100     mlelstv  1023:        if (ub == NULL) {
                   1024:                SET(tp->t_state, TS_BUSY);
                   1025:                goto out;
                   1026:        }
1.82      martin   1027:        SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_free, ub_link);
1.12      augustss 1028:
1.82      martin   1029:        if (SIMPLEQ_FIRST(&sc->sc_obuff_free) == NULL)
                   1030:                SET(tp->t_state, TS_BUSY);
                   1031:
                   1032:        if (cnt > sc->sc_obufsize)
1.19      augustss 1033:                cnt = sc->sc_obufsize;
1.82      martin   1034:
1.22      augustss 1035:        if (sc->sc_methods->ucom_write != NULL)
                   1036:                sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
1.82      martin   1037:                                           ub->ub_data, data, &cnt);
1.22      augustss 1038:        else
1.82      martin   1039:                memcpy(ub->ub_data, data, cnt);
                   1040:
                   1041:        ub->ub_len = cnt;
                   1042:        ub->ub_index = 0;
1.12      augustss 1043:
1.82      martin   1044:        SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_full, ub, ub_link);
                   1045:
                   1046:        softint_schedule(sc->sc_si);
1.3       augustss 1047:
1.82      martin   1048:  out:
1.12      augustss 1049:        splx(s);
                   1050: }
                   1051:
1.21      itojun   1052: void
1.69      christos 1053: ucomstop(struct tty *tp, int flag)
1.12      augustss 1054: {
1.19      augustss 1055: #if 0
1.77      cube     1056:        /*struct ucom_softc *sc =
1.91      jakllsch 1057:            device_lookup_private(&ucom_cd, UCOMUNIT(tp->t_dev));*/
1.12      augustss 1058:        int s;
                   1059:
                   1060:        s = spltty();
                   1061:        if (ISSET(tp->t_state, TS_BUSY)) {
1.19      augustss 1062:                /* sc->sc_tx_stopped = 1; */
1.12      augustss 1063:                if (!ISSET(tp->t_state, TS_TTSTOP))
                   1064:                        SET(tp->t_state, TS_FLUSH);
                   1065:        }
                   1066:        splx(s);
1.19      augustss 1067: #endif
1.12      augustss 1068: }
                   1069:
1.82      martin   1070: static void
                   1071: ucom_write_status(struct ucom_softc *sc, struct ucom_buffer *ub,
                   1072:     usbd_status err)
                   1073: {
                   1074:        struct tty *tp = sc->sc_tty;
                   1075:        uint32_t cc = ub->ub_len;
                   1076:
                   1077:        switch (err) {
                   1078:        case USBD_IN_PROGRESS:
                   1079:                ub->ub_index = ub->ub_len;
                   1080:                break;
                   1081:        case USBD_STALLED:
                   1082:                ub->ub_index = 0;
                   1083:                softint_schedule(sc->sc_si);
                   1084:                break;
                   1085:        case USBD_NORMAL_COMPLETION:
                   1086:                usbd_get_xfer_status(ub->ub_xfer, NULL, NULL, &cc, NULL);
                   1087:                rnd_add_uint32(&sc->sc_rndsource, cc);
                   1088:                /*FALLTHROUGH*/
                   1089:        default:
                   1090:                SIMPLEQ_REMOVE_HEAD(&sc->sc_obuff_full, ub_link);
                   1091:                SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
                   1092:                cc -= sc->sc_opkthdrlen;
                   1093:
1.100     mlelstv  1094:                mutex_spin_enter(&tty_lock);
1.82      martin   1095:                CLR(tp->t_state, TS_BUSY);
                   1096:                if (ISSET(tp->t_state, TS_FLUSH))
                   1097:                        CLR(tp->t_state, TS_FLUSH);
                   1098:                else
                   1099:                        ndflush(&tp->t_outq, cc);
1.100     mlelstv  1100:                mutex_spin_exit(&tty_lock);
1.82      martin   1101:
                   1102:                if (err != USBD_CANCELLED && err != USBD_IOERROR &&
                   1103:                    !sc->sc_dying) {
                   1104:                        if ((ub = SIMPLEQ_FIRST(&sc->sc_obuff_full)) != NULL)
                   1105:                                ucom_submit_write(sc, ub);
                   1106:
                   1107:                        (*tp->t_linesw->l_start)(tp);
                   1108:                }
                   1109:                break;
                   1110:        }
                   1111: }
                   1112:
                   1113: /* Call at spltty() */
                   1114: static void
                   1115: ucom_submit_write(struct ucom_softc *sc, struct ucom_buffer *ub)
                   1116: {
                   1117:
                   1118:        usbd_setup_xfer(ub->ub_xfer, sc->sc_bulkout_pipe,
                   1119:            (usbd_private_handle)sc, ub->ub_data, ub->ub_len,
                   1120:            USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
                   1121:
                   1122:        ucom_write_status(sc, ub, usbd_transfer(ub->ub_xfer));
                   1123: }
                   1124:
                   1125: static void
1.24      augustss 1126: ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1.12      augustss 1127: {
                   1128:        struct ucom_softc *sc = (struct ucom_softc *)p;
1.82      martin   1129:        int s;
                   1130:
                   1131:        s = spltty();
                   1132:
                   1133:        ucom_write_status(sc, SIMPLEQ_FIRST(&sc->sc_obuff_full), status);
                   1134:
                   1135:        splx(s);
                   1136: }
                   1137:
                   1138: static void
                   1139: ucom_softintr(void *arg)
                   1140: {
                   1141:        struct ucom_softc *sc = arg;
1.12      augustss 1142:        struct tty *tp = sc->sc_tty;
1.82      martin   1143:        struct ucom_buffer *ub;
1.12      augustss 1144:        int s;
                   1145:
1.82      martin   1146:        if (!ISSET(tp->t_state, TS_ISOPEN))
                   1147:                return;
1.12      augustss 1148:
1.82      martin   1149:        s = spltty();
1.12      augustss 1150:
1.82      martin   1151:        ub = SIMPLEQ_FIRST(&sc->sc_obuff_full);
                   1152:
                   1153:        if (ub != NULL && ub->ub_index == 0)
                   1154:                ucom_submit_write(sc, ub);
1.12      augustss 1155:
1.82      martin   1156:        if (sc->sc_rx_unblock)
                   1157:                ucom_read_complete(sc);
1.12      augustss 1158:
1.39      augustss 1159:        splx(s);
1.82      martin   1160: }
                   1161:
                   1162: static void
                   1163: ucom_read_complete(struct ucom_softc *sc)
                   1164: {
                   1165:        int (*rint)(int, struct tty *);
                   1166:        struct ucom_buffer *ub;
                   1167:        struct tty *tp;
                   1168:        int s;
                   1169:
                   1170:        tp = sc->sc_tty;
                   1171:        rint = tp->t_linesw->l_rint;
                   1172:        ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full);
1.39      augustss 1173:
1.82      martin   1174:        while (ub != NULL && !sc->sc_rx_stopped) {
                   1175:
                   1176:                s = spltty();
                   1177:
                   1178:                while (ub->ub_index < ub->ub_len && !sc->sc_rx_stopped) {
                   1179:                        /* Give characters to tty layer. */
                   1180:                        if ((*rint)(ub->ub_data[ub->ub_index], tp) == -1) {
                   1181:                                /* Overflow: drop remainder */
                   1182:                                ub->ub_index = ub->ub_len;
                   1183:                        } else
                   1184:                                ub->ub_index++;
                   1185:                }
                   1186:
                   1187:                splx(s);
                   1188:
                   1189:                if (ub->ub_index == ub->ub_len) {
                   1190:                        SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_full, ub_link);
                   1191:
                   1192:                        ucomsubmitread(sc, ub);
                   1193:
                   1194:                        ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full);
                   1195:                }
                   1196:        }
                   1197:
                   1198:        sc->sc_rx_unblock = (ub != NULL);
1.12      augustss 1199: }
                   1200:
1.82      martin   1201: static usbd_status
                   1202: ucomsubmitread(struct ucom_softc *sc, struct ucom_buffer *ub)
1.12      augustss 1203: {
                   1204:        usbd_status err;
                   1205:
1.82      martin   1206:        usbd_setup_xfer(ub->ub_xfer, sc->sc_bulkin_pipe,
                   1207:            (usbd_private_handle)sc, ub->ub_data, sc->sc_ibufsize,
                   1208:            USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, ucomreadcb);
                   1209:
                   1210:        if ((err = usbd_transfer(ub->ub_xfer)) != USBD_IN_PROGRESS) {
                   1211:                /* XXX: Recover from this, please! */
                   1212:                printf("ucomsubmitread: err=%s\n", usbd_errstr(err));
1.12      augustss 1213:                return (err);
                   1214:        }
1.82      martin   1215:
                   1216:        SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_empty, ub, ub_link);
                   1217:
1.12      augustss 1218:        return (USBD_NORMAL_COMPLETION);
                   1219: }
1.43      augustss 1220:
1.82      martin   1221: static void
1.24      augustss 1222: ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
1.12      augustss 1223: {
                   1224:        struct ucom_softc *sc = (struct ucom_softc *)p;
                   1225:        struct tty *tp = sc->sc_tty;
1.82      martin   1226:        struct ucom_buffer *ub;
1.12      augustss 1227:        u_int32_t cc;
                   1228:        u_char *cp;
                   1229:        int s;
                   1230:
1.82      martin   1231:        ub = SIMPLEQ_FIRST(&sc->sc_ibuff_empty);
                   1232:        SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_empty, ub_link);
1.34      augustss 1233:
                   1234:        if (status == USBD_CANCELLED || status == USBD_IOERROR ||
                   1235:            sc->sc_dying) {
                   1236:                DPRINTF(("ucomreadcb: dying\n"));
1.82      martin   1237:                ub->ub_index = ub->ub_len = 0;
1.34      augustss 1238:                /* Send something to wake upper layer */
                   1239:                s = spltty();
1.82      martin   1240:                if (status != USBD_CANCELLED) {
                   1241:                        (tp->t_linesw->l_rint)('\n', tp);
                   1242:                        mutex_spin_enter(&tty_lock);    /* XXX */
                   1243:                        ttwakeup(tp);
                   1244:                        mutex_spin_exit(&tty_lock);     /* XXX */
                   1245:                }
1.34      augustss 1246:                splx(s);
1.12      augustss 1247:                return;
1.34      augustss 1248:        }
1.12      augustss 1249:
1.82      martin   1250:        if (status == USBD_STALLED) {
1.12      augustss 1251:                usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1.82      martin   1252:                ucomsubmitread(sc, ub);
                   1253:                return;
                   1254:        }
                   1255:
                   1256:        if (status != USBD_NORMAL_COMPLETION) {
                   1257:                printf("ucomreadcb: wonky status=%s\n", usbd_errstr(status));
1.12      augustss 1258:                return;
                   1259:        }
                   1260:
1.48      thorpej  1261:        usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
1.82      martin   1262:
1.95      jakllsch 1263: #ifdef UCOM_DEBUG
                   1264:        /* This is triggered by uslsa(4) occasionally. */
                   1265:        if ((ucomdebug > 0) && (cc == 0)) {
                   1266:                device_printf(sc->sc_dev, "ucomreadcb: zero length xfer!\n");
1.82      martin   1267:        }
1.95      jakllsch 1268: #endif
1.82      martin   1269:
                   1270:        KDASSERT(cp == ub->ub_data);
                   1271:
1.31      explorer 1272:        rnd_add_uint32(&sc->sc_rndsource, cc);
1.82      martin   1273:
                   1274:        if (sc->sc_opening) {
                   1275:                ucomsubmitread(sc, ub);
                   1276:                return;
                   1277:        }
                   1278:
                   1279:        if (sc->sc_methods->ucom_read != NULL) {
1.22      augustss 1280:                sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
1.82      martin   1281:                    &cp, &cc);
                   1282:                ub->ub_index = (u_int)(cp - ub->ub_data);
                   1283:        } else
                   1284:                ub->ub_index = 0;
                   1285:
                   1286:        ub->ub_len = cc;
1.22      augustss 1287:
1.82      martin   1288:        SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_full, ub, ub_link);
1.12      augustss 1289:
1.82      martin   1290:        ucom_read_complete(sc);
1.12      augustss 1291: }
                   1292:
1.82      martin   1293: static void
1.24      augustss 1294: ucom_cleanup(struct ucom_softc *sc)
1.12      augustss 1295: {
1.82      martin   1296:        struct ucom_buffer *ub;
                   1297:
1.12      augustss 1298:        DPRINTF(("ucom_cleanup: closing pipes\n"));
                   1299:
                   1300:        ucom_shutdown(sc);
1.33      augustss 1301:        if (sc->sc_bulkin_pipe != NULL) {
                   1302:                usbd_abort_pipe(sc->sc_bulkin_pipe);
                   1303:                usbd_close_pipe(sc->sc_bulkin_pipe);
                   1304:                sc->sc_bulkin_pipe = NULL;
                   1305:        }
                   1306:        if (sc->sc_bulkout_pipe != NULL) {
                   1307:                usbd_abort_pipe(sc->sc_bulkout_pipe);
                   1308:                usbd_close_pipe(sc->sc_bulkout_pipe);
                   1309:                sc->sc_bulkout_pipe = NULL;
                   1310:        }
1.82      martin   1311:        for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS]; ub++) {
                   1312:                if (ub->ub_xfer != NULL) {
                   1313:                        usbd_free_xfer(ub->ub_xfer);
                   1314:                        ub->ub_xfer = NULL;
                   1315:                        ub->ub_data = NULL;
                   1316:                }
                   1317:        }
                   1318:        for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS]; ub++){
                   1319:                if (ub->ub_xfer != NULL) {
                   1320:                        usbd_free_xfer(ub->ub_xfer);
                   1321:                        ub->ub_xfer = NULL;
                   1322:                        ub->ub_data = NULL;
                   1323:                }
1.33      augustss 1324:        }
1.12      augustss 1325: }
1.13      augustss 1326:
                   1327: #endif /* NUCOM > 0 */
1.12      augustss 1328:
1.20      augustss 1329: int
1.24      augustss 1330: ucomprint(void *aux, const char *pnp)
1.12      augustss 1331: {
1.37      augustss 1332:        struct ucom_attach_args *uca = aux;
1.12      augustss 1333:
                   1334:        if (pnp)
1.49      thorpej  1335:                aprint_normal("ucom at %s", pnp);
1.37      augustss 1336:        if (uca->portno != UCOM_UNK_PORTNO)
1.49      thorpej  1337:                aprint_normal(" portno %d", uca->portno);
1.12      augustss 1338:        return (UNCONF);
                   1339: }
                   1340:
1.20      augustss 1341: int
1.77      cube     1342: ucomsubmatch(device_t parent, cfdata_t cf,
1.69      christos 1343:             const int *ldesc, void *aux)
1.12      augustss 1344: {
                   1345:        struct ucom_attach_args *uca = aux;
                   1346:
                   1347:        if (uca->portno != UCOM_UNK_PORTNO &&
1.53      drochner 1348:            cf->cf_loc[UCOMBUSCF_PORTNO] != UCOMBUSCF_PORTNO_DEFAULT &&
                   1349:            cf->cf_loc[UCOMBUSCF_PORTNO] != uca->portno)
1.12      augustss 1350:                return (0);
1.46      thorpej  1351:        return (config_match(parent, cf, aux));
1.12      augustss 1352: }

CVSweb <webmaster@jp.NetBSD.org>