[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.108.2.5

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

CVSweb <webmaster@jp.NetBSD.org>