File:  [DragonFly] / src / sys / dev / usbmisc / ucom / ucom.c
Revision 1.14: download - view: text, annotated - select for diffs
Thu May 13 23:49:21 2004 UTC (9 years, 11 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*
    2:  * $NetBSD: ucom.c,v 1.39 2001/08/16 22:31:24 augustss Exp $
    3:  * $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $
    4:  * $FreeBSD: src/sys/dev/usb/ucom.c,v 1.35 2003/11/16 11:58:21 akiyama Exp $
    5:  * $DragonFly: src/sys/dev/usbmisc/ucom/ucom.c,v 1.14 2004/05/13 23:49:21 dillon Exp $
    6:  */
    7: /*-
    8:  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
    9:  * All rights reserved.
   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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30:  * SUCH DAMAGE.
   31:  */
   32: 
   33: /*
   34:  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
   35:  * All rights reserved.
   36:  *
   37:  * This code is derived from software contributed to The NetBSD Foundation
   38:  * by Lennart Augustsson (lennart@augustsson.net) at
   39:  * Carlstedt Research & Technology.
   40:  *
   41:  * Redistribution and use in source and binary forms, with or without
   42:  * modification, are permitted provided that the following conditions
   43:  * are met:
   44:  * 1. Redistributions of source code must retain the above copyright
   45:  *    notice, this list of conditions and the following disclaimer.
   46:  * 2. Redistributions in binary form must reproduce the above copyright
   47:  *    notice, this list of conditions and the following disclaimer in the
   48:  *    documentation and/or other materials provided with the distribution.
   49:  * 3. All advertising materials mentioning features or use of this software
   50:  *    must display the following acknowledgement:
   51:  *        This product includes software developed by the NetBSD
   52:  *        Foundation, Inc. and its contributors.
   53:  * 4. Neither the name of The NetBSD Foundation nor the names of its
   54:  *    contributors may be used to endorse or promote products derived
   55:  *    from this software without specific prior written permission.
   56:  *
   57:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   58:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   59:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   60:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   61:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   62:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   63:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   64:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   65:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   66:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   67:  * POSSIBILITY OF SUCH DAMAGE.
   68:  */
   69: 
   70: /*
   71:  * TODO:
   72:  * 1. How do I handle hotchar?
   73:  */
   74: 
   75: #include <sys/param.h>
   76: #include <sys/systm.h>
   77: #include <sys/kernel.h>
   78: #include <sys/malloc.h>
   79: #include <sys/bus.h>
   80: #include <sys/ioccom.h>
   81: #include <sys/fcntl.h>
   82: #include <sys/conf.h>
   83: #include <sys/tty.h>
   84: #include <sys/clist.h>
   85: #include <sys/file.h>
   86: #if defined(__FreeBSD__) && __FreeBSD_version >= 500014
   87: #include <sys/selinfo.h>
   88: #else
   89: #include <sys/select.h>
   90: #endif
   91: #include <sys/proc.h>
   92: #include <sys/vnode.h>
   93: #include <sys/poll.h>
   94: #include <sys/sysctl.h>
   95: 
   96: #include <bus/usb/usb.h>
   97: #include <bus/usb/usbcdc.h>
   98: 
   99: #include <bus/usb/usbdi.h>
  100: #include <bus/usb/usbdi_util.h>
  101: #include <bus/usb/usbdevs.h>
  102: #include <bus/usb/usb_quirks.h>
  103: 
  104: #include "ucomvar.h"
  105: 
  106: #ifdef USB_DEBUG
  107: static int	ucomdebug = 0;
  108: SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
  109: SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW,
  110: 	   &ucomdebug, 0, "ucom debug level");
  111: #define DPRINTF(x)	do { \
  112: 				if (ucomdebug) \
  113: 					logprintf x; \
  114: 			} while (0)
  115: 
  116: #define DPRINTFN(n, x)	do { \
  117: 				if (ucomdebug > (n)) \
  118: 					logprintf x; \
  119: 			} while (0)
  120: #else
  121: #define DPRINTF(x)
  122: #define DPRINTFN(n, x)
  123: #endif
  124: 
  125: Static d_open_t  ucomopen;
  126: Static d_close_t ucomclose;
  127: Static d_read_t  ucomread;
  128: Static d_write_t ucomwrite;
  129: Static d_ioctl_t ucomioctl;
  130: 
  131: #define UCOM_CDEV_MAJOR  138
  132: 
  133: static struct cdevsw ucom_cdevsw = {
  134: 	/* name */      "ucom",
  135: 	/* maj */       UCOM_CDEV_MAJOR,
  136: 	/* flags */     D_TTY | D_KQFILTER,
  137: 	/* port */	NULL,
  138: 	/* clone */	NULL,
  139: 
  140: 	/* open */      ucomopen,
  141: 	/* close */     ucomclose,
  142: 	/* read */      ucomread,
  143: 	/* write */     ucomwrite,
  144: 	/* ioctl */     ucomioctl,
  145: 	/* poll */      ttypoll,
  146: 	/* mmap */      nommap,
  147: 	/* strategy */  nostrategy,
  148: 	/* dump */      nodump,
  149: 	/* psize */     nopsize,
  150: 	/* kqfilter */	ttykqfilter
  151: };
  152: 
  153: Static void ucom_cleanup(struct ucom_softc *);
  154: Static int ucomctl(struct ucom_softc *, int, int);
  155: Static int ucomparam(struct tty *, struct termios *);
  156: Static void ucomstart(struct tty *);
  157: Static void ucomstop(struct tty *, int);
  158: Static void ucom_shutdown(struct ucom_softc *);
  159: Static void ucom_dtr(struct ucom_softc *, int);
  160: Static void ucom_rts(struct ucom_softc *, int);
  161: Static void ucom_break(struct ucom_softc *, int);
  162: Static usbd_status ucomstartread(struct ucom_softc *);
  163: Static void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
  164: Static void ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
  165: Static void ucomstopread(struct ucom_softc *);
  166: static void disc_optim(struct tty *, struct termios *, struct ucom_softc *);
  167: 
  168: devclass_t ucom_devclass;
  169: 
  170: static moduledata_t ucom_mod = {
  171: 	"ucom",
  172: 	NULL,
  173: 	NULL
  174: };
  175: 
  176: DECLARE_MODULE(ucom, ucom_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
  177: MODULE_DEPEND(ucom, usb, 1, 1, 1);
  178: MODULE_VERSION(ucom, UCOM_MODVER);
  179: 
  180: int
  181: ucom_attach(struct ucom_softc *sc)
  182: {
  183: 	struct tty *tp;
  184: 	int unit;
  185: 
  186: 	unit = device_get_unit(sc->sc_dev);
  187: 
  188: 	sc->sc_tty = tp = ttymalloc(sc->sc_tty);
  189: 	tp->t_oproc = ucomstart;
  190: 	tp->t_param = ucomparam;
  191: 	tp->t_stop = ucomstop;
  192: 
  193: 	DPRINTF(("ucom_attach: tty_attach tp = %p\n", tp));
  194: 
  195: 	DPRINTF(("ucom_attach: make_dev: ucom%d\n", unit));
  196: 
  197: 	sc->dev = make_dev(&ucom_cdevsw, unit | UCOM_CALLOUT_MASK,
  198: 			UID_UUCP, GID_DIALER, 0660,
  199: 			"ucom%d", unit);
  200: 	sc->dev->si_tty = tp;
  201: 
  202: 	return (0);
  203: }
  204: 
  205: int
  206: ucom_detach(struct ucom_softc *sc)
  207: {
  208: 	struct tty *tp = sc->sc_tty;
  209: 	int s;
  210: 
  211: 	DPRINTF(("ucom_detach: sc = %p, tp = %p\n", sc, sc->sc_tty));
  212: 
  213: 	sc->sc_dying = 1;
  214: 
  215: 	if (sc->sc_bulkin_pipe != NULL)
  216: 		usbd_abort_pipe(sc->sc_bulkin_pipe);
  217: 	if (sc->sc_bulkout_pipe != NULL)
  218: 		usbd_abort_pipe(sc->sc_bulkout_pipe);
  219: 
  220: 	if (tp != NULL) {
  221: 		if (tp->t_state & TS_ISOPEN) {
  222: 			device_printf(sc->sc_dev,
  223: 				      "still open, forcing close\n");
  224: 			(*linesw[tp->t_line].l_close)(tp, 0);
  225: 			tp->t_gen++;
  226: 			ttyclose(tp);
  227: 			ttwakeup(tp);
  228: 			ttwwakeup(tp);
  229: 		}
  230: 	} else {
  231: 		DPRINTF(("ucom_detach: no tty\n"));
  232: 		return (0);
  233: 	}
  234: 
  235: 	s = splusb();
  236: 	if (--sc->sc_refcnt >= 0) {
  237: 		/* Wait for processes to go away. */
  238: 		usb_detach_wait(USBDEV(sc->sc_dev));
  239: 	}
  240: 	splx(s);
  241: 
  242: 	destroy_dev(sc->dev);
  243: 
  244: 	return (0);
  245: }
  246: 
  247: Static void
  248: ucom_shutdown(struct ucom_softc *sc)
  249: {
  250: 	struct tty *tp = sc->sc_tty;
  251: 
  252: 	DPRINTF(("ucom_shutdown\n"));
  253: 	/*
  254: 	 * Hang up if necessary.  Wait a bit, so the other side has time to
  255: 	 * notice even if we immediately open the port again.
  256: 	 */
  257: 	if (ISSET(tp->t_cflag, HUPCL)) {
  258: 		(void)ucomctl(sc, TIOCM_DTR, DMBIC);
  259: 		(void)tsleep(sc, 0, "ucomsd", hz);
  260: 	}
  261: }
  262: 
  263: Static int
  264: ucomopen(dev_t dev, int flag, int mode, usb_proc_ptr td)
  265: {
  266: 	int unit = UCOMUNIT(dev);
  267: 	struct ucom_softc *sc;
  268: 	usbd_status err;
  269: 	struct tty *tp;
  270: 	int s;
  271: 	int error;
  272: 
  273: 	KKASSERT(td != NULL);
  274: 
  275: 	USB_GET_SC_OPEN(ucom, unit, sc);
  276: 
  277: 	if (sc->sc_dying)
  278: 		return (ENXIO);
  279: 
  280: 	tp = sc->sc_tty;
  281: 
  282: 	DPRINTF(("%s: ucomopen: tp = %p\n", USBDEVNAME(sc->sc_dev), tp));
  283: 
  284: 	if (ISSET(tp->t_state, TS_ISOPEN) &&
  285: 	    ISSET(tp->t_state, TS_XCLUDE) &&
  286: 	    suser(td)
  287: 	) {
  288: 		return (EBUSY);
  289: 	}
  290: 
  291: 	/*
  292: 	 * Do the following iff this is a first open.
  293: 	 */
  294: 	s = spltty();
  295: 	while (sc->sc_opening)
  296: 		tsleep(&sc->sc_opening, 0, "ucomop", 0);
  297: 	sc->sc_opening = 1;
  298: 
  299: 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
  300: 		struct termios t;
  301: 
  302: 		sc->sc_poll = 0;
  303: 		sc->sc_lsr = sc->sc_msr = sc->sc_mcr = 0;
  304: 
  305: 		tp->t_dev = dev;
  306: 
  307: 		/*
  308: 		 * Initialize the termios status to the defaults.  Add in the
  309: 		 * sticky bits from TIOCSFLAGS.
  310: 		 */
  311: 		t.c_ispeed = 0;
  312: 		t.c_ospeed = TTYDEF_SPEED;
  313: 		t.c_cflag = TTYDEF_CFLAG;
  314: 		/* Make sure ucomparam() will do something. */
  315: 		tp->t_ospeed = 0;
  316: 		(void)ucomparam(tp, &t);
  317: 		tp->t_iflag = TTYDEF_IFLAG;
  318: 		tp->t_oflag = TTYDEF_OFLAG;
  319: 		tp->t_lflag = TTYDEF_LFLAG;
  320: 		ttychars(tp);
  321: 		ttsetwater(tp);
  322: 
  323: 		/*
  324: 		 * Turn on DTR.  We must always do this, even if carrier is not
  325: 		 * present, because otherwise we'd have to use TIOCSDTR
  326: 		 * immediately after setting CLOCAL, which applications do not
  327: 		 * expect.  We always assert DTR while the device is open
  328: 		 * unless explicitly requested to deassert it.
  329: 		 */
  330: 		(void)ucomctl(sc, TIOCM_DTR | TIOCM_RTS, DMBIS);
  331: 
  332: 		/* Device specific open */
  333: 		if (sc->sc_callback->ucom_open != NULL) {
  334: 			error = sc->sc_callback->ucom_open(sc->sc_parent,
  335: 							   sc->sc_portno);
  336: 			if (error) {
  337: 				ucom_cleanup(sc);
  338: 				sc->sc_opening = 0;
  339: 				wakeup(&sc->sc_opening);
  340: 				splx(s);
  341: 				return (error);
  342: 			}
  343: 		}
  344: 
  345: 		DPRINTF(("ucomopen: open pipes in = %d out = %d\n",
  346: 			 sc->sc_bulkin_no, sc->sc_bulkout_no));
  347: 
  348: 		/* Open the bulk pipes */
  349: 		/* Bulk-in pipe */
  350: 		err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
  351: 				     &sc->sc_bulkin_pipe);
  352: 		if (err) {
  353: 			printf("%s: open bulk in error (addr %d): %s\n",
  354: 			       USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
  355: 			       usbd_errstr(err));
  356: 			error = EIO;
  357: 			goto fail_0;
  358: 		}
  359: 		/* Bulk-out pipe */
  360: 		err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
  361: 				     USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
  362: 		if (err) {
  363: 			printf("%s: open bulk out error (addr %d): %s\n",
  364: 			       USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
  365: 			       usbd_errstr(err));
  366: 			error = EIO;
  367: 			goto fail_1;
  368: 		}
  369: 
  370: 		/* Allocate a request and an input buffer and start reading. */
  371: 		sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
  372: 		if (sc->sc_ixfer == NULL) {
  373: 			error = ENOMEM;
  374: 			goto fail_2;
  375: 		}
  376: 
  377: 		sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
  378: 						sc->sc_ibufsizepad);
  379: 		if (sc->sc_ibuf == NULL) {
  380: 			error = ENOMEM;
  381: 			goto fail_3;
  382: 		}
  383: 
  384: 		sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
  385: 		if (sc->sc_oxfer == NULL) {
  386: 			error = ENOMEM;
  387: 			goto fail_3;
  388: 		}
  389: 
  390: 		sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
  391: 						sc->sc_obufsize +
  392: 						sc->sc_opkthdrlen);
  393: 		if (sc->sc_obuf == NULL) {
  394: 			error = ENOMEM;
  395: 			goto fail_4;
  396: 		}
  397: 
  398: 		/*
  399: 		 * Handle initial DCD.
  400: 		 */
  401: 		if (ISSET(sc->sc_msr, UMSR_DCD) ||
  402: 		    (minor(dev) & UCOM_CALLOUT_MASK))
  403: 			(*linesw[tp->t_line].l_modem)(tp, 1);
  404: 
  405: 		ucomstartread(sc);
  406: 	}
  407: 
  408: 	sc->sc_opening = 0;
  409: 	wakeup(&sc->sc_opening);
  410: 	splx(s);
  411: 
  412: 	error = ttyopen(dev, tp);
  413: 	if (error)
  414: 		goto bad;
  415: 
  416: 	error = (*linesw[tp->t_line].l_open)(dev, tp);
  417: 	if (error)
  418: 		goto bad;
  419: 
  420: 	disc_optim(tp, &tp->t_termios, sc);
  421: 
  422: 	DPRINTF(("%s: ucomopen: success\n", USBDEVNAME(sc->sc_dev)));
  423: 
  424: 	sc->sc_poll = 1;
  425: 	sc->sc_refcnt++;
  426: 
  427: 	return (0);
  428: 
  429: fail_4:
  430: 	usbd_free_xfer(sc->sc_oxfer);
  431: 	sc->sc_oxfer = NULL;
  432: fail_3:
  433: 	usbd_free_xfer(sc->sc_ixfer);
  434: 	sc->sc_ixfer = NULL;
  435: fail_2:
  436: 	usbd_close_pipe(sc->sc_bulkout_pipe);
  437: 	sc->sc_bulkout_pipe = NULL;
  438: fail_1:
  439: 	usbd_close_pipe(sc->sc_bulkin_pipe);
  440: 	sc->sc_bulkin_pipe = NULL;
  441: fail_0:
  442: 	sc->sc_opening = 0;
  443: 	wakeup(&sc->sc_opening);
  444: 	splx(s);
  445: 	return (error);
  446: 
  447: bad:
  448: 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
  449: 		/*
  450: 		 * We failed to open the device, and nobody else had it opened.
  451: 		 * Clean up the state as appropriate.
  452: 		 */
  453: 		ucom_cleanup(sc);
  454: 	}
  455: 
  456: 	DPRINTF(("%s: ucomopen: failed\n", USBDEVNAME(sc->sc_dev)));
  457: 
  458: 	return (error);
  459: }
  460: 
  461: static int
  462: ucomclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
  463: {
  464: 	struct ucom_softc *sc;
  465: 	struct tty *tp;
  466: 	int s;
  467: 
  468: 	USB_GET_SC(ucom, UCOMUNIT(dev), sc);
  469: 
  470: 	tp = sc->sc_tty;
  471: 
  472: 	DPRINTF(("%s: ucomclose: unit = %d\n",
  473: 		USBDEVNAME(sc->sc_dev), UCOMUNIT(dev)));
  474: 
  475: 	if (!ISSET(tp->t_state, TS_ISOPEN))
  476: 		goto quit;
  477: 
  478: 	s = spltty();
  479: 	(*linesw[tp->t_line].l_close)(tp, flag);
  480: 	disc_optim(tp, &tp->t_termios, sc);
  481: 	ttyclose(tp);
  482: 	splx(s);
  483: 
  484: 	if (sc->sc_dying)
  485: 		goto quit;
  486: 
  487: 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
  488: 		/*
  489: 		 * Although we got a last close, the device may still be in
  490: 		 * use; e.g. if this was the dialout node, and there are still
  491: 		 * processes waiting for carrier on the non-dialout node.
  492: 		 */
  493: 		ucom_cleanup(sc);
  494: 	}
  495: 
  496: 	if (sc->sc_callback->ucom_close != NULL)
  497: 		sc->sc_callback->ucom_close(sc->sc_parent, sc->sc_portno);
  498: 
  499:     quit:
  500: 	if (--sc->sc_refcnt < 0)
  501: 		usb_detach_wakeup(USBDEV(sc->sc_dev));
  502: 
  503: 	return (0);
  504: }
  505: 
  506: static int
  507: ucomread(dev_t dev, struct uio *uio, int flag)
  508: {
  509: 	struct ucom_softc *sc;
  510: 	struct tty *tp;
  511: 	int error;
  512: 
  513: 	USB_GET_SC(ucom, UCOMUNIT(dev), sc);
  514: 	tp = sc->sc_tty;
  515: 
  516: 	DPRINTF(("ucomread: tp = %p, flag = 0x%x\n", tp, flag));
  517: 
  518: 	if (sc->sc_dying)
  519: 		return (EIO);
  520: 
  521: 	error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
  522: 
  523: 	DPRINTF(("ucomread: error = %d\n", error));
  524: 
  525: 	return (error);
  526: }
  527: 
  528: static int
  529: ucomwrite(dev_t dev, struct uio *uio, int flag)
  530: {
  531: 	struct ucom_softc *sc;
  532: 	struct tty *tp;
  533: 	int error;
  534: 
  535: 	USB_GET_SC(ucom, UCOMUNIT(dev), sc);
  536: 	tp = sc->sc_tty;
  537: 
  538: 	DPRINTF(("ucomwrite: tp = %p, flag = 0x%x\n", tp, flag));
  539: 
  540: 	if (sc->sc_dying)
  541: 		return (EIO);
  542: 
  543: 	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
  544: 
  545: 	DPRINTF(("ucomwrite: error = %d\n", error));
  546: 
  547: 	return (error);
  548: }
  549: 
  550: static int
  551: ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
  552: {
  553: 	struct ucom_softc *sc;
  554: 	struct tty *tp;
  555: 	int error;
  556: 	int s;
  557: 	int d;
  558: 
  559: 	USB_GET_SC(ucom, UCOMUNIT(dev), sc);
  560: 	tp = sc->sc_tty;
  561: 
  562: 	if (sc->sc_dying)
  563: 		return (EIO);
  564: 
  565: 	DPRINTF(("ucomioctl: cmd = 0x%08lx\n", cmd));
  566: 
  567: 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
  568: 	if (error != ENOIOCTL) {
  569: 		DPRINTF(("ucomioctl: l_ioctl: error = %d\n", error));
  570: 		return (error);
  571: 	}
  572: 
  573: 	s = spltty();
  574: 
  575: 	error = ttioctl(tp, cmd, data, flag);
  576: 	disc_optim(tp, &tp->t_termios, sc);
  577: 	if (error != ENOIOCTL) {
  578: 		splx(s);
  579: 		DPRINTF(("ucomioctl: ttioctl: error = %d\n", error));
  580: 		return (error);
  581: 	}
  582: 
  583: 	if (sc->sc_callback->ucom_ioctl != NULL) {
  584: 		/* XXX splx(s) ? */
  585: 		error = sc->sc_callback->ucom_ioctl(sc->sc_parent,
  586: 						    sc->sc_portno,
  587: 						    cmd, data, flag, p);
  588: 		if (error >= 0)
  589: 			return (error);
  590: 	}
  591: 
  592: 	error = 0;
  593: 
  594: 	DPRINTF(("ucomioctl: our cmd = 0x%08lx\n", cmd));
  595: 
  596: 	switch (cmd) {
  597: 	case TIOCSBRK:
  598: 		DPRINTF(("ucomioctl: TIOCSBRK\n"));
  599: 		ucom_break(sc, 1);
  600: 		break;
  601: 	case TIOCCBRK:
  602: 		DPRINTF(("ucomioctl: TIOCCBRK\n"));
  603: 		ucom_break(sc, 0);
  604: 		break;
  605: 
  606: 	case TIOCSDTR:
  607: 		DPRINTF(("ucomioctl: TIOCSDTR\n"));
  608: 		(void)ucomctl(sc, TIOCM_DTR, DMBIS);
  609: 		break;
  610: 	case TIOCCDTR:
  611: 		DPRINTF(("ucomioctl: TIOCCDTR\n"));
  612: 		(void)ucomctl(sc, TIOCM_DTR, DMBIC);
  613: 		break;
  614: 
  615: 	case TIOCMSET:
  616: 		d = *(int *)data;
  617: 		DPRINTF(("ucomioctl: TIOCMSET, 0x%x\n", d));
  618: 		(void)ucomctl(sc, d, DMSET);
  619: 		break;
  620: 	case TIOCMBIS:
  621: 		d = *(int *)data;
  622: 		DPRINTF(("ucomioctl: TIOCMBIS, 0x%x\n", d));
  623: 		(void)ucomctl(sc, d, DMBIS);
  624: 		break;
  625: 	case TIOCMBIC:
  626: 		d = *(int *)data;
  627: 		DPRINTF(("ucomioctl: TIOCMBIC, 0x%x\n", d));
  628: 		(void)ucomctl(sc, d, DMBIC);
  629: 		break;
  630: 	case TIOCMGET:
  631: 		d = ucomctl(sc, 0, DMGET);
  632: 		DPRINTF(("ucomioctl: TIOCMGET, 0x%x\n", d));
  633: 		*(int *)data = d;
  634: 		break;
  635: 
  636: 	default:
  637: 		DPRINTF(("ucomioctl: error: our cmd = 0x%08lx\n", cmd));
  638: 		error = ENOTTY;
  639: 		break;
  640: 	}
  641: 
  642: 	splx(s);
  643: 
  644: 	return (error);
  645: }
  646: 
  647: Static int
  648: ucomctl(struct ucom_softc *sc, int bits, int how)
  649: {
  650: 	int	mcr;
  651: 	int	msr;
  652: 	int	onoff;
  653: 
  654: 	DPRINTF(("ucomctl: bits = 0x%x, how = %d\n", bits, how));
  655: 
  656: 	if (how == DMGET) {
  657: 		SET(bits, TIOCM_LE);		/* always set TIOCM_LE bit */
  658: 		DPRINTF(("ucomctl: DMGET: LE"));
  659: 
  660: 		mcr = sc->sc_mcr;
  661: 		if (ISSET(mcr, UMCR_DTR)) {
  662: 			SET(bits, TIOCM_DTR);
  663: 			DPRINTF((" DTR"));
  664: 		}
  665: 		if (ISSET(mcr, UMCR_RTS)) {
  666: 			SET(bits, TIOCM_RTS);
  667: 			DPRINTF((" RTS"));
  668: 		}
  669: 
  670: 		msr = sc->sc_msr;
  671: 		if (ISSET(msr, UMSR_CTS)) {
  672: 			SET(bits, TIOCM_CTS);
  673: 			DPRINTF((" CTS"));
  674: 		}
  675: 		if (ISSET(msr, UMSR_DCD)) {
  676: 			SET(bits, TIOCM_CD);
  677: 			DPRINTF((" CD"));
  678: 		}
  679: 		if (ISSET(msr, UMSR_DSR)) {
  680: 			SET(bits, TIOCM_DSR);
  681: 			DPRINTF((" DSR"));
  682: 		}
  683: 		if (ISSET(msr, UMSR_RI)) {
  684: 			SET(bits, TIOCM_RI);
  685: 			DPRINTF((" RI"));
  686: 		}
  687: 
  688: 		DPRINTF(("\n"));
  689: 
  690: 		return (bits);
  691: 	}
  692: 
  693: 	mcr = 0;
  694: 	if (ISSET(bits, TIOCM_DTR))
  695: 		SET(mcr, UMCR_DTR);
  696: 	if (ISSET(bits, TIOCM_RTS))
  697: 		SET(mcr, UMCR_RTS);
  698: 
  699: 	switch (how) {
  700: 	case DMSET:
  701: 		sc->sc_mcr = mcr;
  702: 		break;
  703: 	case DMBIS:
  704: 		sc->sc_mcr |= mcr;
  705: 		break;
  706: 	case DMBIC:
  707: 		sc->sc_mcr &= ~mcr;
  708: 		break;
  709: 	}
  710: 
  711: 	onoff = ISSET(sc->sc_mcr, UMCR_DTR) ? 1 : 0;
  712: 	ucom_dtr(sc, onoff);
  713: 
  714: 	onoff = ISSET(sc->sc_mcr, UMCR_RTS) ? 1 : 0;
  715: 	ucom_rts(sc, onoff);
  716: 
  717: 	return (0);
  718: }
  719: 
  720: Static void
  721: ucom_break(struct ucom_softc *sc, int onoff)
  722: {
  723: 	DPRINTF(("ucom_break: onoff = %d\n", onoff));
  724: 
  725: 	if (sc->sc_callback->ucom_set == NULL)
  726: 		return;
  727: 	sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
  728: 				  UCOM_SET_BREAK, onoff);
  729: }
  730: 
  731: Static void
  732: ucom_dtr(struct ucom_softc *sc, int onoff)
  733: {
  734: 	DPRINTF(("ucom_dtr: onoff = %d\n", onoff));
  735: 
  736: 	if (sc->sc_callback->ucom_set == NULL)
  737: 		return;
  738: 	sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
  739: 				  UCOM_SET_DTR, onoff);
  740: }
  741: 
  742: Static void
  743: ucom_rts(struct ucom_softc *sc, int onoff)
  744: {
  745: 	DPRINTF(("ucom_rts: onoff = %d\n", onoff));
  746: 
  747: 	if (sc->sc_callback->ucom_set == NULL)
  748: 		return;
  749: 	sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
  750: 				  UCOM_SET_RTS, onoff);
  751: }
  752: 
  753: void
  754: ucom_status_change(struct ucom_softc *sc)
  755: {
  756: 	struct tty *tp = sc->sc_tty;
  757: 	u_char old_msr;
  758: 	int onoff;
  759: 
  760: 	if (sc->sc_callback->ucom_get_status == NULL) {
  761: 		sc->sc_lsr = 0;
  762: 		sc->sc_msr = 0;
  763: 		return;
  764: 	}
  765: 
  766: 	old_msr = sc->sc_msr;
  767: 	sc->sc_callback->ucom_get_status(sc->sc_parent, sc->sc_portno,
  768: 					 &sc->sc_lsr, &sc->sc_msr);
  769: 	if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD)) {
  770: 		if (sc->sc_poll == 0)
  771: 			return;
  772: 		onoff = ISSET(sc->sc_msr, UMSR_DCD) ? 1 : 0;
  773: 		DPRINTF(("ucom_status_change: DCD changed to %d\n", onoff));
  774: 		(*linesw[tp->t_line].l_modem)(tp, onoff);
  775: 	}
  776: }
  777: 
  778: Static int
  779: ucomparam(struct tty *tp, struct termios *t)
  780: {
  781: 	struct ucom_softc *sc;
  782: 	int error;
  783: 	usbd_status uerr;
  784: 
  785: 	USB_GET_SC(ucom, UCOMUNIT(tp->t_dev), sc);
  786: 
  787: 	if (sc->sc_dying)
  788: 		return (EIO);
  789: 
  790: 	DPRINTF(("ucomparam: sc = %p\n", sc));
  791: 
  792: 	/* Check requested parameters. */
  793: 	if (t->c_ospeed < 0) {
  794: 		DPRINTF(("ucomparam: negative ospeed\n"));
  795: 		return (EINVAL);
  796: 	}
  797: 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed) {
  798: 		DPRINTF(("ucomparam: mismatch ispeed and ospeed\n"));
  799: 		return (EINVAL);
  800: 	}
  801: 
  802: 	/*
  803: 	 * If there were no changes, don't do anything.  This avoids dropping
  804: 	 * input and improves performance when all we did was frob things like
  805: 	 * VMIN and VTIME.
  806: 	 */
  807: 	if (tp->t_ospeed == t->c_ospeed &&
  808: 	    tp->t_cflag == t->c_cflag)
  809: 		return (0);
  810: 
  811: 	/* And copy to tty. */
  812: 	tp->t_ispeed = 0;
  813: 	tp->t_ospeed = t->c_ospeed;
  814: 	tp->t_cflag = t->c_cflag;
  815: 
  816: 	if (sc->sc_callback->ucom_param == NULL)
  817: 		return (0);
  818: 
  819: 	ucomstopread(sc);
  820: 
  821: 	error = sc->sc_callback->ucom_param(sc->sc_parent, sc->sc_portno, t);
  822: 	if (error) {
  823: 		DPRINTF(("ucomparam: callback: error = %d\n", error));
  824: 		return (error);
  825: 	}
  826: 
  827: 	ttsetwater(tp);
  828: 
  829: 	if (t->c_cflag & CRTS_IFLOW) {
  830: 		sc->sc_state |= UCS_RTS_IFLOW;
  831: 	} else if (sc->sc_state & UCS_RTS_IFLOW) {
  832: 		sc->sc_state &= ~UCS_RTS_IFLOW;
  833: 		(void)ucomctl(sc, UMCR_RTS, DMBIS);
  834: 	}
  835: 
  836: 	disc_optim(tp, t, sc);
  837: 
  838: 	uerr = ucomstartread(sc);
  839: 	if (uerr != USBD_NORMAL_COMPLETION)
  840: 		return (EIO);
  841: 
  842: 	return (0);
  843: }
  844: 
  845: Static void
  846: ucomstart(struct tty *tp)
  847: {
  848: 	struct ucom_softc *sc;
  849: 	struct cblock *cbp;
  850: 	usbd_status err;
  851: 	int s;
  852: 	u_char *data;
  853: 	int cnt;
  854: 
  855: 	USB_GET_SC(ucom, UCOMUNIT(tp->t_dev), sc);
  856: 	DPRINTF(("ucomstart: sc = %p\n", sc));
  857: 
  858: 	if (sc->sc_dying)
  859: 		return;
  860: 
  861: 	s = spltty();
  862: 
  863: 	if (tp->t_state & TS_TBLOCK) {
  864: 		if (ISSET(sc->sc_mcr, UMCR_RTS) &&
  865: 		    ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
  866: 			DPRINTF(("ucomstart: clear RTS\n"));
  867: 			(void)ucomctl(sc, UMCR_RTS, DMBIC);
  868: 		}
  869: 	} else {
  870: 		if (!ISSET(sc->sc_mcr, UMCR_RTS) &&
  871: 		    tp->t_rawq.c_cc <= tp->t_ilowat &&
  872: 		    ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
  873: 			DPRINTF(("ucomstart: set RTS\n"));
  874: 			(void)ucomctl(sc, UMCR_RTS, DMBIS);
  875: 		}
  876: 	}
  877: 
  878: 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
  879: 		ttwwakeup(tp);
  880: 		DPRINTF(("ucomstart: stopped\n"));
  881: 		goto out;
  882: 	}
  883: 
  884: 	if (tp->t_outq.c_cc <= tp->t_olowat) {
  885: 		if (ISSET(tp->t_state, TS_SO_OLOWAT)) {
  886: 			CLR(tp->t_state, TS_SO_OLOWAT);
  887: 			wakeup(TSA_OLOWAT(tp));
  888: 		}
  889: 		selwakeuppri(&tp->t_wsel, TTIPRI);
  890: 		if (tp->t_outq.c_cc == 0) {
  891: 			if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
  892: 			    TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
  893: 				CLR(tp->t_state, TS_SO_OCOMPLETE);
  894: 				wakeup(TSA_OCOMPLETE(tp));
  895: 			}
  896: 			goto out;
  897: 		}
  898: 	}
  899: 
  900: 	/* Grab the first contiguous region of buffer space. */
  901: 	data = tp->t_outq.c_cf;
  902: 	cbp = (struct cblock *) ((intptr_t) tp->t_outq.c_cf & ~CROUND);
  903: 	cnt = min((char *) (cbp+1) - tp->t_outq.c_cf, tp->t_outq.c_cc);
  904: 
  905: 	if (cnt == 0) {
  906: 		DPRINTF(("ucomstart: cnt == 0\n"));
  907: 		goto out;
  908: 	}
  909: 
  910: 	SET(tp->t_state, TS_BUSY);
  911: 
  912: 	if (cnt > sc->sc_obufsize) {
  913: 		DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
  914: 		cnt = sc->sc_obufsize;
  915: 	}
  916: 	if (sc->sc_callback->ucom_write != NULL)
  917: 		sc->sc_callback->ucom_write(sc->sc_parent, sc->sc_portno,
  918: 					    sc->sc_obuf, data, &cnt);
  919: 	else
  920: 		memcpy(sc->sc_obuf, data, cnt);
  921: 
  922: 	DPRINTF(("ucomstart: %d chars\n", cnt));
  923: 	usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
  924: 			(usbd_private_handle)sc, sc->sc_obuf, cnt,
  925: 			USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
  926: 	/* What can we do on error? */
  927: 	err = usbd_transfer(sc->sc_oxfer);
  928: 	if (err != USBD_IN_PROGRESS)
  929: 		printf("ucomstart: err=%s\n", usbd_errstr(err));
  930: 
  931: 	ttwwakeup(tp);
  932: 
  933:     out:
  934: 	splx(s);
  935: }
  936: 
  937: Static void
  938: ucomstop(struct tty *tp, int flag)
  939: {
  940: 	struct ucom_softc *sc;
  941: 	int s;
  942: 
  943: 	USB_GET_SC(ucom, UCOMUNIT(tp->t_dev), sc);
  944: 
  945: 	DPRINTF(("ucomstop: %d\n", flag));
  946: 
  947: 	if (flag & FREAD) {
  948: 		DPRINTF(("ucomstop: read\n"));
  949: 		ucomstopread(sc);
  950: 	}
  951: 
  952: 	if (flag & FWRITE) {
  953: 		DPRINTF(("ucomstop: write\n"));
  954: 		s = spltty();
  955: 		if (ISSET(tp->t_state, TS_BUSY)) {
  956: 			/* XXX do what? */
  957: 			if (!ISSET(tp->t_state, TS_TTSTOP))
  958: 				SET(tp->t_state, TS_FLUSH);
  959: 		}
  960: 		splx(s);
  961: 	}
  962: 
  963: 	DPRINTF(("ucomstop: done\n"));
  964: }
  965: 
  966: Static void
  967: ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
  968: {
  969: 	struct ucom_softc *sc = (struct ucom_softc *)p;
  970: 	struct tty *tp = sc->sc_tty;
  971: 	u_int32_t cc;
  972: 	int s;
  973: 
  974: 	DPRINTF(("ucomwritecb: status = %d\n", status));
  975: 
  976: 	if (status == USBD_CANCELLED || sc->sc_dying)
  977: 		goto error;
  978: 
  979: 	if (status != USBD_NORMAL_COMPLETION) {
  980: 		printf("%s: ucomwritecb: %s\n",
  981: 		       USBDEVNAME(sc->sc_dev), usbd_errstr(status));
  982: 		if (status == USBD_STALLED)
  983: 			usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
  984: 		/* XXX we should restart after some delay. */
  985: 		goto error;
  986: 	}
  987: 
  988: 	usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
  989: 	DPRINTF(("ucomwritecb: cc = %d\n", cc));
  990: 	if (cc <= sc->sc_opkthdrlen) {
  991: 		printf("%s: sent size too small, cc = %d\n",
  992: 			USBDEVNAME(sc->sc_dev), cc);
  993: 		goto error;
  994: 	}
  995: 
  996: 	/* convert from USB bytes to tty bytes */
  997: 	cc -= sc->sc_opkthdrlen;
  998: 
  999: 	s = spltty();
 1000: 	CLR(tp->t_state, TS_BUSY);
 1001: 	if (ISSET(tp->t_state, TS_FLUSH))
 1002: 		CLR(tp->t_state, TS_FLUSH);
 1003: 	else
 1004: 		ndflush(&tp->t_outq, cc);
 1005: 	(*linesw[tp->t_line].l_start)(tp);
 1006: 	splx(s);
 1007: 
 1008: 	return;
 1009: 
 1010:   error:
 1011: 	s = spltty();
 1012: 	CLR(tp->t_state, TS_BUSY);
 1013: 	splx(s);
 1014: 	return;
 1015: }
 1016: 
 1017: Static usbd_status
 1018: ucomstartread(struct ucom_softc *sc)
 1019: {
 1020: 	usbd_status err;
 1021: 
 1022: 	DPRINTF(("ucomstartread: start\n"));
 1023: 
 1024: 	sc->sc_state &= ~UCS_RXSTOP;
 1025: 
 1026: 	if (sc->sc_bulkin_pipe == NULL)
 1027: 		return (USBD_NORMAL_COMPLETION);
 1028: 
 1029: 	usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
 1030: 			(usbd_private_handle)sc,
 1031: 			sc->sc_ibuf, sc->sc_ibufsize,
 1032: 			USBD_SHORT_XFER_OK | USBD_NO_COPY,
 1033: 			USBD_NO_TIMEOUT, ucomreadcb);
 1034: 
 1035: 	err = usbd_transfer(sc->sc_ixfer);
 1036: 	if (err != USBD_IN_PROGRESS) {
 1037: 		DPRINTF(("ucomstartread: err = %s\n", usbd_errstr(err)));
 1038: 		return (err);
 1039: 	}
 1040: 
 1041: 	return (USBD_NORMAL_COMPLETION);
 1042: }
 1043: 
 1044: Static void
 1045: ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
 1046: {
 1047: 	struct ucom_softc *sc = (struct ucom_softc *)p;
 1048: 	struct tty *tp = sc->sc_tty;
 1049: 	int (*rint) (int c, struct tty *tp) = linesw[tp->t_line].l_rint;
 1050: 	usbd_status err;
 1051: 	u_int32_t cc;
 1052: 	u_char *cp;
 1053: 	int lostcc;
 1054: 	int s;
 1055: 
 1056: 	DPRINTF(("ucomreadcb: status = %d\n", status));
 1057: 
 1058: 	if (status != USBD_NORMAL_COMPLETION) {
 1059: 		if (!(sc->sc_state & UCS_RXSTOP))
 1060: 			printf("%s: ucomreadcb: %s\n",
 1061: 			       USBDEVNAME(sc->sc_dev), usbd_errstr(status));
 1062: 		if (status == USBD_STALLED)
 1063: 			usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
 1064: 		/* XXX we should restart after some delay. */
 1065: 		return;
 1066: 	}
 1067: 
 1068: 	usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL);
 1069: 	DPRINTF(("ucomreadcb: got %d chars, tp = %p\n", cc, tp));
 1070: 	if (cc == 0)
 1071: 		goto resubmit;
 1072: 
 1073: 	if (sc->sc_callback->ucom_read != NULL) {
 1074: 		sc->sc_callback->ucom_read(sc->sc_parent, sc->sc_portno,
 1075: 					   &cp, &cc);
 1076: 	}
 1077: 
 1078: 	if (cc > sc->sc_ibufsize) {
 1079: 		printf("%s: invalid receive data size, %d chars\n",
 1080: 			USBDEVNAME(sc->sc_dev), cc);
 1081: 		goto resubmit;
 1082: 	}
 1083: 	if (cc < 1)
 1084: 		goto resubmit;
 1085: 
 1086: 	s = spltty();
 1087: 	if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
 1088: 		if (tp->t_rawq.c_cc + cc > tp->t_ihiwat
 1089: 		    && (sc->sc_state & UCS_RTS_IFLOW
 1090: 			|| tp->t_iflag & IXOFF)
 1091: 		    && !(tp->t_state & TS_TBLOCK))
 1092: 			ttyblock(tp);
 1093: 		lostcc = b_to_q((char *)cp, cc, &tp->t_rawq);
 1094: 		tp->t_rawcc += cc;
 1095: 		ttwakeup(tp);
 1096: 		if (tp->t_state & TS_TTSTOP
 1097: 		    && (tp->t_iflag & IXANY
 1098: 			|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
 1099: 			tp->t_state &= ~TS_TTSTOP;
 1100: 			tp->t_lflag &= ~FLUSHO;
 1101: 			ucomstart(tp);
 1102: 		}
 1103: 		if (lostcc > 0)
 1104: 			printf("%s: lost %d chars\n", USBDEVNAME(sc->sc_dev),
 1105: 			       lostcc);
 1106: 	} else {
 1107: 		/* Give characters to tty layer. */
 1108: 		while (cc > 0) {
 1109: 			DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp));
 1110: 			if ((*rint)(*cp, tp) == -1) {
 1111: 				/* XXX what should we do? */
 1112: 				printf("%s: lost %d chars\n",
 1113: 				       USBDEVNAME(sc->sc_dev), cc);
 1114: 				break;
 1115: 			}
 1116: 			cc--;
 1117: 			cp++;
 1118: 		}
 1119: 	}
 1120: 	splx(s);
 1121: 
 1122: resubmit:
 1123: 	err = ucomstartread(sc);
 1124: 	if (err) {
 1125: 		printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev));
 1126: 		/* XXX what should we dow now? */
 1127: 	}
 1128: 
 1129: 	if ((sc->sc_state & UCS_RTS_IFLOW) && !ISSET(sc->sc_mcr, UMCR_RTS)
 1130: 	    && !(tp->t_state & TS_TBLOCK))
 1131: 		ucomctl(sc, UMCR_RTS, DMBIS);
 1132: }
 1133: 
 1134: Static void
 1135: ucom_cleanup(struct ucom_softc *sc)
 1136: {
 1137: 	DPRINTF(("ucom_cleanup: closing pipes\n"));
 1138: 
 1139: 	ucom_shutdown(sc);
 1140: 	if (sc->sc_bulkin_pipe != NULL) {
 1141: 		usbd_abort_pipe(sc->sc_bulkin_pipe);
 1142: 		usbd_close_pipe(sc->sc_bulkin_pipe);
 1143: 		sc->sc_bulkin_pipe = NULL;
 1144: 	}
 1145: 	if (sc->sc_bulkout_pipe != NULL) {
 1146: 		usbd_abort_pipe(sc->sc_bulkout_pipe);
 1147: 		usbd_close_pipe(sc->sc_bulkout_pipe);
 1148: 		sc->sc_bulkout_pipe = NULL;
 1149: 	}
 1150: 	if (sc->sc_ixfer != NULL) {
 1151: 		usbd_free_xfer(sc->sc_ixfer);
 1152: 		sc->sc_ixfer = NULL;
 1153: 	}
 1154: 	if (sc->sc_oxfer != NULL) {
 1155: 		usbd_free_xfer(sc->sc_oxfer);
 1156: 		sc->sc_oxfer = NULL;
 1157: 	}
 1158: }
 1159: 
 1160: Static void
 1161: ucomstopread(struct ucom_softc *sc)
 1162: {
 1163: 	usbd_status err;
 1164: 
 1165: 	DPRINTF(("ucomstopread: enter\n"));
 1166: 
 1167: 	if (!(sc->sc_state & UCS_RXSTOP)) {
 1168: 		sc->sc_state |= UCS_RXSTOP;
 1169: 		if (sc->sc_bulkin_pipe == NULL) {
 1170: 			DPRINTF(("ucomstopread: bulkin pipe NULL\n"));
 1171: 			return;
 1172: 		}
 1173: 		err = usbd_abort_pipe(sc->sc_bulkin_pipe);
 1174: 		if (err) {
 1175: 			DPRINTF(("ucomstopread: err = %s\n",
 1176: 				 usbd_errstr(err)));
 1177: 		}
 1178: 	}
 1179: 
 1180: 	DPRINTF(("ucomstopread: leave\n"));
 1181: }
 1182: 
 1183: static void
 1184: disc_optim(struct tty *tp, struct termios *t, struct ucom_softc *sc)
 1185: {
 1186: 	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
 1187: 	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
 1188: 	    && (!(t->c_iflag & PARMRK)
 1189: 		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
 1190: 	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
 1191: 	    && linesw[tp->t_line].l_rint == ttyinput) {
 1192: 		DPRINTF(("disc_optim: bypass l_rint\n"));
 1193: 		tp->t_state |= TS_CAN_BYPASS_L_RINT;
 1194: 	} else {
 1195: 		DPRINTF(("disc_optim: can't bypass l_rint\n"));
 1196: 		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
 1197: 	}
 1198: 	sc->hotchar = linesw[tp->t_line].l_hotchar;
 1199: }