ucom.c revision 1.69.10.2
11.69.10.1Sitohy/*	$NetBSD: ucom.c,v 1.69.10.2 2007/06/16 04:12:30 itohy Exp $	*/
21.1Saugustss
31.1Saugustss/*
41.22Saugustss * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
51.1Saugustss * All rights reserved.
61.1Saugustss *
71.1Saugustss * This code is derived from software contributed to The NetBSD Foundation
81.23Saugustss * by Lennart Augustsson (lennart@augustsson.net) at
91.1Saugustss * Carlstedt Research & Technology.
101.1Saugustss *
111.1Saugustss * Redistribution and use in source and binary forms, with or without
121.1Saugustss * modification, are permitted provided that the following conditions
131.1Saugustss * are met:
141.1Saugustss * 1. Redistributions of source code must retain the above copyright
151.1Saugustss *    notice, this list of conditions and the following disclaimer.
161.1Saugustss * 2. Redistributions in binary form must reproduce the above copyright
171.1Saugustss *    notice, this list of conditions and the following disclaimer in the
181.1Saugustss *    documentation and/or other materials provided with the distribution.
191.1Saugustss * 3. All advertising materials mentioning features or use of this software
201.1Saugustss *    must display the following acknowledgement:
211.1Saugustss *        This product includes software developed by the NetBSD
221.1Saugustss *        Foundation, Inc. and its contributors.
231.1Saugustss * 4. Neither the name of The NetBSD Foundation nor the names of its
241.1Saugustss *    contributors may be used to endorse or promote products derived
251.1Saugustss *    from this software without specific prior written permission.
261.1Saugustss *
271.1Saugustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
281.1Saugustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
291.1Saugustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
301.1Saugustss * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
311.1Saugustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
321.1Saugustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
331.1Saugustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
341.1Saugustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
351.1Saugustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
361.1Saugustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
371.1Saugustss * POSSIBILITY OF SUCH DAMAGE.
381.1Saugustss */
391.22Saugustss/*
401.22Saugustss * This code is very heavily based on the 16550 driver, com.c.
411.22Saugustss */
421.40Slukem
431.40Slukem#include <sys/cdefs.h>
441.69.10.1Sitohy__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.69.10.2 2007/06/16 04:12:30 itohy Exp $");
451.1Saugustss
461.1Saugustss#include <sys/param.h>
471.1Saugustss#include <sys/systm.h>
481.1Saugustss#include <sys/kernel.h>
491.1Saugustss#include <sys/ioctl.h>
501.3Saugustss#include <sys/conf.h>
511.1Saugustss#include <sys/tty.h>
521.1Saugustss#include <sys/file.h>
531.1Saugustss#include <sys/select.h>
541.1Saugustss#include <sys/proc.h>
551.1Saugustss#include <sys/vnode.h>
561.12Saugustss#include <sys/device.h>
571.1Saugustss#include <sys/poll.h>
581.63Selad#include <sys/kauth.h>
591.31Sexplorer#if defined(__NetBSD__)
601.31Sexplorer#include "rnd.h"
611.31Sexplorer#if NRND > 0
621.31Sexplorer#include <sys/rnd.h>
631.31Sexplorer#endif
641.31Sexplorer#endif
651.1Saugustss
661.1Saugustss#include <dev/usb/usb.h>
671.1Saugustss
681.1Saugustss#include <dev/usb/usbdi.h>
691.1Saugustss#include <dev/usb/usbdi_util.h>
701.1Saugustss#include <dev/usb/usbdevs.h>
711.1Saugustss#include <dev/usb/usb_quirks.h>
721.1Saugustss
731.12Saugustss#include <dev/usb/ucomvar.h>
741.12Saugustss
751.13Saugustss#include "ucom.h"
761.13Saugustss
771.53Sdrochner#include "locators.h"
781.53Sdrochner
791.13Saugustss#if NUCOM > 0
801.13Saugustss
811.12Saugustss#ifdef UCOM_DEBUG
821.12Saugustss#define DPRINTFN(n, x)	if (ucomdebug > (n)) logprintf x
831.12Saugustssint ucomdebug = 0;
841.1Saugustss#else
851.12Saugustss#define DPRINTFN(n, x)
861.1Saugustss#endif
871.12Saugustss#define DPRINTF(x) DPRINTFN(0, x)
881.12Saugustss
891.12Saugustss#define	UCOMUNIT_MASK		0x3ffff
901.12Saugustss#define	UCOMDIALOUT_MASK	0x80000
911.12Saugustss#define	UCOMCALLUNIT_MASK	0x40000
921.12Saugustss
931.12Saugustss#define	UCOMUNIT(x)		(minor(x) & UCOMUNIT_MASK)
941.12Saugustss#define	UCOMDIALOUT(x)		(minor(x) & UCOMDIALOUT_MASK)
951.12Saugustss#define	UCOMCALLUNIT(x)		(minor(x) & UCOMCALLUNIT_MASK)
961.12Saugustss
971.1Saugustssstruct ucom_softc {
981.12Saugustss	USBBASEDEVICE		sc_dev;		/* base device */
991.12Saugustss
1001.12Saugustss	usbd_device_handle	sc_udev;	/* USB device */
1011.12Saugustss
1021.12Saugustss	usbd_interface_handle	sc_iface;	/* data interface */
1031.12Saugustss
1041.12Saugustss	int			sc_bulkin_no;	/* bulk in endpoint address */
1051.12Saugustss	usbd_pipe_handle	sc_bulkin_pipe;	/* bulk in pipe */
1061.12Saugustss	usbd_xfer_handle	sc_ixfer;	/* read request */
1071.12Saugustss	u_char			*sc_ibuf;	/* read buffer */
1081.19Saugustss	u_int			sc_ibufsize;	/* read buffer size */
1091.22Saugustss	u_int			sc_ibufsizepad;	/* read buffer size padded */
1101.12Saugustss
1111.12Saugustss	int			sc_bulkout_no;	/* bulk out endpoint address */
1121.12Saugustss	usbd_pipe_handle	sc_bulkout_pipe;/* bulk out pipe */
1131.12Saugustss	usbd_xfer_handle	sc_oxfer;	/* write request */
1141.12Saugustss	u_char			*sc_obuf;	/* write buffer */
1151.19Saugustss	u_int			sc_obufsize;	/* write buffer size */
1161.25Saugustss	u_int			sc_opkthdrlen;	/* header length of
1171.25Saugustss						 * output packet */
1181.12Saugustss
1191.12Saugustss	struct ucom_methods     *sc_methods;
1201.12Saugustss	void                    *sc_parent;
1211.12Saugustss	int			sc_portno;
1221.12Saugustss
1231.12Saugustss	struct tty		*sc_tty;	/* our tty */
1241.12Saugustss	u_char			sc_lsr;
1251.12Saugustss	u_char			sc_msr;
1261.12Saugustss	u_char			sc_mcr;
1271.12Saugustss	u_char			sc_tx_stopped;
1281.12Saugustss	int			sc_swflags;
1291.12Saugustss
1301.12Saugustss	u_char			sc_opening;	/* lock during open */
1311.17Saugustss	int			sc_refcnt;
1321.12Saugustss	u_char			sc_dying;	/* disconnecting */
1331.31Sexplorer
1341.31Sexplorer#if defined(__NetBSD__) && NRND > 0
1351.31Sexplorer	rndsource_element_t	sc_rndsource;	/* random source */
1361.31Sexplorer#endif
1371.1Saugustss};
1381.1Saugustss
1391.44Sgehennadev_type_open(ucomopen);
1401.44Sgehennadev_type_close(ucomclose);
1411.44Sgehennadev_type_read(ucomread);
1421.44Sgehennadev_type_write(ucomwrite);
1431.44Sgehennadev_type_ioctl(ucomioctl);
1441.44Sgehennadev_type_stop(ucomstop);
1451.44Sgehennadev_type_tty(ucomtty);
1461.44Sgehennadev_type_poll(ucompoll);
1471.44Sgehenna
1481.44Sgehennaconst struct cdevsw ucom_cdevsw = {
1491.44Sgehenna	ucomopen, ucomclose, ucomread, ucomwrite, ucomioctl,
1501.47Sjdolecek	ucomstop, ucomtty, ucompoll, nommap, ttykqfilter, D_TTY
1511.44Sgehenna};
1521.12Saugustss
1531.24SaugustssStatic void	ucom_cleanup(struct ucom_softc *);
1541.24SaugustssStatic void	ucom_hwiflow(struct ucom_softc *);
1551.24SaugustssStatic int	ucomparam(struct tty *, struct termios *);
1561.24SaugustssStatic void	ucomstart(struct tty *);
1571.24SaugustssStatic void	ucom_shutdown(struct ucom_softc *);
1581.24SaugustssStatic int	ucom_do_ioctl(struct ucom_softc *, u_long, caddr_t,
1591.69.10.1Sitohy			      int, usb_proc_ptr);
1601.24SaugustssStatic void	ucom_dtr(struct ucom_softc *, int);
1611.24SaugustssStatic void	ucom_rts(struct ucom_softc *, int);
1621.24SaugustssStatic void	ucom_break(struct ucom_softc *, int);
1631.24SaugustssStatic usbd_status ucomstartread(struct ucom_softc *);
1641.24SaugustssStatic void	ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
1651.24SaugustssStatic void	ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
1661.29StoshiiStatic void	tiocm_to_ucom(struct ucom_softc *, u_long, int);
1671.24SaugustssStatic int	ucom_to_tiocm(struct ucom_softc *);
1681.1Saugustss
1691.3SaugustssUSB_DECLARE_DRIVER(ucom);
1701.1Saugustss
1711.3SaugustssUSB_MATCH(ucom)
1721.1Saugustss{
1731.12Saugustss	return (1);
1741.1Saugustss}
1751.1Saugustss
1761.3SaugustssUSB_ATTACH(ucom)
1771.1Saugustss{
1781.12Saugustss	struct ucom_softc *sc = (struct ucom_softc *)self;
1791.12Saugustss	struct ucom_attach_args *uca = aux;
1801.12Saugustss	struct tty *tp;
1811.12Saugustss
1821.35Saugustss	if (uca->info != NULL)
1831.59Sitohy		printf(": %s", uca->info);
1841.12Saugustss	printf("\n");
1851.12Saugustss
1861.12Saugustss	sc->sc_udev = uca->device;
1871.12Saugustss	sc->sc_iface = uca->iface;
1881.12Saugustss	sc->sc_bulkout_no = uca->bulkout;
1891.12Saugustss	sc->sc_bulkin_no = uca->bulkin;
1901.19Saugustss	sc->sc_ibufsize = uca->ibufsize;
1911.22Saugustss	sc->sc_ibufsizepad = uca->ibufsizepad;
1921.19Saugustss	sc->sc_obufsize = uca->obufsize;
1931.25Saugustss	sc->sc_opkthdrlen = uca->opkthdrlen;
1941.12Saugustss	sc->sc_methods = uca->methods;
1951.12Saugustss	sc->sc_parent = uca->arg;
1961.12Saugustss	sc->sc_portno = uca->portno;
1971.12Saugustss
1981.12Saugustss	tp = ttymalloc();
1991.12Saugustss	tp->t_oproc = ucomstart;
2001.12Saugustss	tp->t_param = ucomparam;
2011.12Saugustss	sc->sc_tty = tp;
2021.12Saugustss
2031.12Saugustss	DPRINTF(("ucom_attach: tty_attach %p\n", tp));
2041.12Saugustss	tty_attach(tp);
2051.12Saugustss
2061.31Sexplorer#if defined(__NetBSD__) && NRND > 0
2071.31Sexplorer	rnd_attach_source(&sc->sc_rndsource, USBDEVNAME(sc->sc_dev),
2081.31Sexplorer			  RND_TYPE_TTY, 0);
2091.31Sexplorer#endif
2101.31Sexplorer
2111.12Saugustss	USB_ATTACH_SUCCESS_RETURN;
2121.12Saugustss}
2131.12Saugustss
2141.12SaugustssUSB_DETACH(ucom)
2151.12Saugustss{
2161.12Saugustss	struct ucom_softc *sc = (struct ucom_softc *)self;
2171.36Saugustss	struct tty *tp = sc->sc_tty;
2181.12Saugustss	int maj, mn;
2191.17Saugustss	int s;
2201.12Saugustss
2211.43Saugustss	DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
2221.36Saugustss		 sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
2231.12Saugustss
2241.12Saugustss	sc->sc_dying = 1;
2251.12Saugustss
2261.33Saugustss	if (sc->sc_bulkin_pipe != NULL)
2271.33Saugustss		usbd_abort_pipe(sc->sc_bulkin_pipe);
2281.33Saugustss	if (sc->sc_bulkout_pipe != NULL)
2291.33Saugustss		usbd_abort_pipe(sc->sc_bulkout_pipe);
2301.12Saugustss
2311.17Saugustss	s = splusb();
2321.17Saugustss	if (--sc->sc_refcnt >= 0) {
2331.35Saugustss		/* Wake up anyone waiting */
2341.36Saugustss		if (tp != NULL) {
2351.36Saugustss			CLR(tp->t_state, TS_CARR_ON);
2361.36Saugustss			CLR(tp->t_cflag, CLOCAL | MDMBUF);
2371.36Saugustss			ttyflush(tp, FREAD|FWRITE);
2381.36Saugustss		}
2391.17Saugustss		/* Wait for processes to go away. */
2401.17Saugustss		usb_detach_wait(USBDEV(sc->sc_dev));
2411.17Saugustss	}
2421.17Saugustss	splx(s);
2431.12Saugustss
2441.12Saugustss	/* locate the major number */
2451.44Sgehenna	maj = cdevsw_lookup_major(&ucom_cdevsw);
2461.12Saugustss
2471.12Saugustss	/* Nuke the vnodes for any open instances. */
2481.62Sthorpej	mn = device_unit(self);
2491.17Saugustss	DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn));
2501.12Saugustss	vdevgone(maj, mn, mn, VCHR);
2511.22Saugustss	vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR);
2521.22Saugustss	vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR);
2531.12Saugustss
2541.12Saugustss	/* Detach and free the tty. */
2551.36Saugustss	if (tp != NULL) {
2561.36Saugustss		tty_detach(tp);
2571.36Saugustss		ttyfree(tp);
2581.33Saugustss		sc->sc_tty = NULL;
2591.33Saugustss	}
2601.12Saugustss
2611.31Sexplorer	/* Detach the random source */
2621.31Sexplorer#if defined(__NetBSD__) && NRND > 0
2631.31Sexplorer	rnd_detach_source(&sc->sc_rndsource);
2641.31Sexplorer#endif
2651.31Sexplorer
2661.12Saugustss	return (0);
2671.12Saugustss}
2681.12Saugustss
2691.12Saugustssint
2701.24Saugustssucom_activate(device_ptr_t self, enum devact act)
2711.12Saugustss{
2721.12Saugustss	struct ucom_softc *sc = (struct ucom_softc *)self;
2731.12Saugustss
2741.34Saugustss	DPRINTFN(5,("ucom_activate: %d\n", act));
2751.34Saugustss
2761.12Saugustss	switch (act) {
2771.12Saugustss	case DVACT_ACTIVATE:
2781.12Saugustss		return (EOPNOTSUPP);
2791.12Saugustss
2801.12Saugustss	case DVACT_DEACTIVATE:
2811.12Saugustss		sc->sc_dying = 1;
2821.12Saugustss		break;
2831.12Saugustss	}
2841.12Saugustss	return (0);
2851.12Saugustss}
2861.12Saugustss
2871.12Saugustssvoid
2881.24Saugustssucom_shutdown(struct ucom_softc *sc)
2891.12Saugustss{
2901.12Saugustss	struct tty *tp = sc->sc_tty;
2911.12Saugustss
2921.12Saugustss	DPRINTF(("ucom_shutdown\n"));
2931.12Saugustss	/*
2941.12Saugustss	 * Hang up if necessary.  Wait a bit, so the other side has time to
2951.12Saugustss	 * notice even if we immediately open the port again.
2961.12Saugustss	 */
2971.12Saugustss	if (ISSET(tp->t_cflag, HUPCL)) {
2981.12Saugustss		ucom_dtr(sc, 0);
2991.12Saugustss		(void)tsleep(sc, TTIPRI, ttclos, hz);
3001.12Saugustss	}
3011.12Saugustss}
3021.12Saugustss
3031.12Saugustssint
3041.69.10.1Sitohyucomopen(dev_t dev, int flag, int mode, usb_proc_ptr l)
3051.12Saugustss{
3061.12Saugustss	int unit = UCOMUNIT(dev);
3071.12Saugustss	usbd_status err;
3081.12Saugustss	struct ucom_softc *sc;
3091.12Saugustss	struct tty *tp;
3101.12Saugustss	int s;
3111.12Saugustss	int error;
3121.43Saugustss
3131.12Saugustss	if (unit >= ucom_cd.cd_ndevs)
3141.12Saugustss		return (ENXIO);
3151.12Saugustss	sc = ucom_cd.cd_devs[unit];
3161.12Saugustss	if (sc == NULL)
3171.12Saugustss		return (ENXIO);
3181.12Saugustss
3191.12Saugustss	if (sc->sc_dying)
3201.12Saugustss		return (EIO);
3211.12Saugustss
3221.61Sthorpej	if (!device_is_active(&sc->sc_dev))
3231.12Saugustss		return (ENXIO);
3241.12Saugustss
3251.12Saugustss	tp = sc->sc_tty;
3261.12Saugustss
3271.12Saugustss	DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
3281.12Saugustss
3291.66Selad	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
3301.12Saugustss		return (EBUSY);
3311.12Saugustss
3321.12Saugustss	s = spltty();
3331.12Saugustss
3341.12Saugustss	/*
3351.12Saugustss	 * Do the following iff this is a first open.
3361.12Saugustss	 */
3371.12Saugustss	while (sc->sc_opening)
3381.12Saugustss		tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
3391.17Saugustss
3401.17Saugustss	if (sc->sc_dying) {
3411.17Saugustss		splx(s);
3421.17Saugustss		return (EIO);
3431.17Saugustss	}
3441.12Saugustss	sc->sc_opening = 1;
3451.43Saugustss
3461.12Saugustss	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
3471.12Saugustss		struct termios t;
3481.12Saugustss
3491.12Saugustss		tp->t_dev = dev;
3501.12Saugustss
3511.22Saugustss		if (sc->sc_methods->ucom_open != NULL) {
3521.22Saugustss			error = sc->sc_methods->ucom_open(sc->sc_parent,
3531.22Saugustss							  sc->sc_portno);
3541.22Saugustss			if (error) {
3551.22Saugustss				ucom_cleanup(sc);
3561.26Stoshii				sc->sc_opening = 0;
3571.26Stoshii				wakeup(&sc->sc_opening);
3581.26Stoshii				splx(s);
3591.22Saugustss				return (error);
3601.22Saugustss			}
3611.22Saugustss		}
3621.22Saugustss
3631.12Saugustss		ucom_status_change(sc);
3641.12Saugustss
3651.12Saugustss		/*
3661.12Saugustss		 * Initialize the termios status to the defaults.  Add in the
3671.12Saugustss		 * sticky bits from TIOCSFLAGS.
3681.12Saugustss		 */
3691.12Saugustss		t.c_ispeed = 0;
3701.12Saugustss		t.c_ospeed = TTYDEF_SPEED;
3711.12Saugustss		t.c_cflag = TTYDEF_CFLAG;
3721.12Saugustss		if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
3731.12Saugustss			SET(t.c_cflag, CLOCAL);
3741.12Saugustss		if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
3751.12Saugustss			SET(t.c_cflag, CRTSCTS);
3761.12Saugustss		if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
3771.12Saugustss			SET(t.c_cflag, MDMBUF);
3781.12Saugustss		/* Make sure ucomparam() will do something. */
3791.12Saugustss		tp->t_ospeed = 0;
3801.12Saugustss		(void) ucomparam(tp, &t);
3811.12Saugustss		tp->t_iflag = TTYDEF_IFLAG;
3821.12Saugustss		tp->t_oflag = TTYDEF_OFLAG;
3831.12Saugustss		tp->t_lflag = TTYDEF_LFLAG;
3841.12Saugustss		ttychars(tp);
3851.12Saugustss		ttsetwater(tp);
3861.12Saugustss
3871.12Saugustss		/*
3881.12Saugustss		 * Turn on DTR.  We must always do this, even if carrier is not
3891.12Saugustss		 * present, because otherwise we'd have to use TIOCSDTR
3901.12Saugustss		 * immediately after setting CLOCAL, which applications do not
3911.12Saugustss		 * expect.  We always assert DTR while the device is open
3921.64Sgson		 * unless explicitly requested to deassert it.  Ditto RTS.
3931.12Saugustss		 */
3941.12Saugustss		ucom_dtr(sc, 1);
3951.64Sgson		ucom_rts(sc, 1);
3961.12Saugustss
3971.30Saugustss		/* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/
3981.12Saugustss		ucom_hwiflow(sc);
3991.12Saugustss
4001.12Saugustss		DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
4011.12Saugustss			 sc->sc_bulkin_no, sc->sc_bulkout_no));
4021.12Saugustss
4031.12Saugustss		/* Open the bulk pipes */
4041.12Saugustss		err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
4051.12Saugustss				     &sc->sc_bulkin_pipe);
4061.12Saugustss		if (err) {
4071.52Snathanw			DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
4081.43Saugustss				 USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
4091.12Saugustss				 usbd_errstr(err)));
4101.28Stoshii			error = EIO;
4111.26Stoshii			goto fail_0;
4121.12Saugustss		}
4131.12Saugustss		err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
4141.12Saugustss				     USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
4151.12Saugustss		if (err) {
4161.52Snathanw			DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
4171.12Saugustss				 USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
4181.12Saugustss				 usbd_errstr(err)));
4191.28Stoshii			error = EIO;
4201.26Stoshii			goto fail_1;
4211.12Saugustss		}
4221.43Saugustss
4231.12Saugustss		/* Allocate a request and an input buffer and start reading. */
4241.69.10.1Sitohy		sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev, sc->sc_bulkin_pipe);
4251.28Stoshii		if (sc->sc_ixfer == NULL) {
4261.28Stoshii			error = ENOMEM;
4271.26Stoshii			goto fail_2;
4281.28Stoshii		}
4291.26Stoshii
4301.22Saugustss		sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
4311.22Saugustss						sc->sc_ibufsizepad);
4321.28Stoshii		if (sc->sc_ibuf == NULL) {
4331.28Stoshii			error = ENOMEM;
4341.26Stoshii			goto fail_3;
4351.28Stoshii		}
4361.12Saugustss
4371.69.10.1Sitohy		sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev,
4381.69.10.1Sitohy		    sc->sc_bulkout_pipe);
4391.28Stoshii		if (sc->sc_oxfer == NULL) {
4401.28Stoshii			error = ENOMEM;
4411.26Stoshii			goto fail_3;
4421.28Stoshii		}
4431.26Stoshii
4441.22Saugustss		sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
4451.25Saugustss						sc->sc_obufsize +
4461.25Saugustss						sc->sc_opkthdrlen);
4471.28Stoshii		if (sc->sc_obuf == NULL) {
4481.28Stoshii			error = ENOMEM;
4491.26Stoshii			goto fail_4;
4501.28Stoshii		}
4511.12Saugustss
4521.12Saugustss		ucomstartread(sc);
4531.12Saugustss	}
4541.12Saugustss	sc->sc_opening = 0;
4551.12Saugustss	wakeup(&sc->sc_opening);
4561.12Saugustss	splx(s);
4571.12Saugustss
4581.12Saugustss	error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
4591.12Saugustss	if (error)
4601.12Saugustss		goto bad;
4611.12Saugustss
4621.32Seeh	error = (*tp->t_linesw->l_open)(dev, tp);
4631.12Saugustss	if (error)
4641.12Saugustss		goto bad;
4651.12Saugustss
4661.12Saugustss	return (0);
4671.26Stoshii
4681.26Stoshiifail_4:
4691.26Stoshii	usbd_free_xfer(sc->sc_oxfer);
4701.34Saugustss	sc->sc_oxfer = NULL;
4711.26Stoshiifail_3:
4721.26Stoshii	usbd_free_xfer(sc->sc_ixfer);
4731.34Saugustss	sc->sc_ixfer = NULL;
4741.26Stoshiifail_2:
4751.26Stoshii	usbd_close_pipe(sc->sc_bulkout_pipe);
4761.34Saugustss	sc->sc_bulkout_pipe = NULL;
4771.26Stoshiifail_1:
4781.26Stoshii	usbd_close_pipe(sc->sc_bulkin_pipe);
4791.34Saugustss	sc->sc_bulkin_pipe = NULL;
4801.26Stoshiifail_0:
4811.26Stoshii	sc->sc_opening = 0;
4821.26Stoshii	wakeup(&sc->sc_opening);
4831.26Stoshii	splx(s);
4841.28Stoshii	return (error);
4851.12Saugustss
4861.12Saugustssbad:
4871.12Saugustss	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
4881.12Saugustss		/*
4891.12Saugustss		 * We failed to open the device, and nobody else had it opened.
4901.12Saugustss		 * Clean up the state as appropriate.
4911.12Saugustss		 */
4921.12Saugustss		ucom_cleanup(sc);
4931.12Saugustss	}
4941.12Saugustss
4951.12Saugustss	return (error);
4961.12Saugustss}
4971.12Saugustss
4981.12Saugustssint
4991.69.10.1Sitohyucomclose(dev_t dev, int flag, int mode, usb_proc_ptr l)
5001.12Saugustss{
5011.12Saugustss	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
5021.12Saugustss	struct tty *tp = sc->sc_tty;
5031.12Saugustss
5041.12Saugustss	DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
5051.12Saugustss	if (!ISSET(tp->t_state, TS_ISOPEN))
5061.12Saugustss		return (0);
5071.12Saugustss
5081.17Saugustss	sc->sc_refcnt++;
5091.17Saugustss
5101.32Seeh	(*tp->t_linesw->l_close)(tp, flag);
5111.12Saugustss	ttyclose(tp);
5121.12Saugustss
5131.12Saugustss	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
5141.12Saugustss		/*
5151.12Saugustss		 * Although we got a last close, the device may still be in
5161.12Saugustss		 * use; e.g. if this was the dialout node, and there are still
5171.12Saugustss		 * processes waiting for carrier on the non-dialout node.
5181.12Saugustss		 */
5191.12Saugustss		ucom_cleanup(sc);
5201.12Saugustss	}
5211.12Saugustss
5221.14Saugustss	if (sc->sc_methods->ucom_close != NULL)
5231.14Saugustss		sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
5241.14Saugustss
5251.17Saugustss	if (--sc->sc_refcnt < 0)
5261.17Saugustss		usb_detach_wakeup(USBDEV(sc->sc_dev));
5271.17Saugustss
5281.12Saugustss	return (0);
5291.12Saugustss}
5301.43Saugustss
5311.12Saugustssint
5321.24Saugustssucomread(dev_t dev, struct uio *uio, int flag)
5331.12Saugustss{
5341.12Saugustss	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
5351.12Saugustss	struct tty *tp = sc->sc_tty;
5361.17Saugustss	int error;
5371.12Saugustss
5381.12Saugustss	if (sc->sc_dying)
5391.12Saugustss		return (EIO);
5401.43Saugustss
5411.17Saugustss	sc->sc_refcnt++;
5421.32Seeh	error = ((*tp->t_linesw->l_read)(tp, uio, flag));
5431.17Saugustss	if (--sc->sc_refcnt < 0)
5441.17Saugustss		usb_detach_wakeup(USBDEV(sc->sc_dev));
5451.17Saugustss	return (error);
5461.12Saugustss}
5471.43Saugustss
5481.12Saugustssint
5491.24Saugustssucomwrite(dev_t dev, struct uio *uio, int flag)
5501.12Saugustss{
5511.12Saugustss	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
5521.12Saugustss	struct tty *tp = sc->sc_tty;
5531.17Saugustss	int error;
5541.12Saugustss
5551.12Saugustss	if (sc->sc_dying)
5561.12Saugustss		return (EIO);
5571.43Saugustss
5581.17Saugustss	sc->sc_refcnt++;
5591.32Seeh	error = ((*tp->t_linesw->l_write)(tp, uio, flag));
5601.38Sscw	if (--sc->sc_refcnt < 0)
5611.38Sscw		usb_detach_wakeup(USBDEV(sc->sc_dev));
5621.38Sscw	return (error);
5631.38Sscw}
5641.38Sscw
5651.38Sscwint
5661.69.10.1Sitohyucompoll(dev_t dev, int events, usb_proc_ptr l)
5671.38Sscw{
5681.38Sscw	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
5691.38Sscw	struct tty *tp = sc->sc_tty;
5701.56Sws	int revents;
5711.38Sscw
5721.38Sscw	if (sc->sc_dying)
5731.56Sws		return (POLLHUP);
5741.43Saugustss
5751.38Sscw	sc->sc_refcnt++;
5761.60Schristos	revents = ((*tp->t_linesw->l_poll)(tp, events, l));
5771.17Saugustss	if (--sc->sc_refcnt < 0)
5781.17Saugustss		usb_detach_wakeup(USBDEV(sc->sc_dev));
5791.56Sws	return (revents);
5801.12Saugustss}
5811.12Saugustss
5821.12Saugustssstruct tty *
5831.24Saugustssucomtty(dev_t dev)
5841.12Saugustss{
5851.12Saugustss	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
5861.12Saugustss	struct tty *tp = sc->sc_tty;
5871.12Saugustss
5881.12Saugustss	return (tp);
5891.12Saugustss}
5901.12Saugustss
5911.12Saugustssint
5921.69.10.1Sitohyucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr l)
5931.12Saugustss{
5941.12Saugustss	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
5951.17Saugustss	int error;
5961.17Saugustss
5971.17Saugustss	sc->sc_refcnt++;
5981.60Schristos	error = ucom_do_ioctl(sc, cmd, data, flag, l);
5991.17Saugustss	if (--sc->sc_refcnt < 0)
6001.17Saugustss		usb_detach_wakeup(USBDEV(sc->sc_dev));
6011.17Saugustss	return (error);
6021.17Saugustss}
6031.17Saugustss
6041.17SaugustssStatic int
6051.24Saugustssucom_do_ioctl(struct ucom_softc *sc, u_long cmd, caddr_t data,
6061.69.10.1Sitohy	      int flag, usb_proc_ptr l)
6071.17Saugustss{
6081.12Saugustss	struct tty *tp = sc->sc_tty;
6091.12Saugustss	int error;
6101.12Saugustss	int s;
6111.12Saugustss
6121.12Saugustss	if (sc->sc_dying)
6131.12Saugustss		return (EIO);
6141.43Saugustss
6151.12Saugustss	DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
6161.12Saugustss
6171.60Schristos	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
6181.42Satatat	if (error != EPASSTHROUGH)
6191.12Saugustss		return (error);
6201.12Saugustss
6211.60Schristos	error = ttioctl(tp, cmd, data, flag, l);
6221.42Satatat	if (error != EPASSTHROUGH)
6231.12Saugustss		return (error);
6241.12Saugustss
6251.12Saugustss	if (sc->sc_methods->ucom_ioctl != NULL) {
6261.12Saugustss		error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
6271.69.10.1Sitohy			    sc->sc_portno, cmd, data, flag, l);
6281.42Satatat		if (error != EPASSTHROUGH)
6291.12Saugustss			return (error);
6301.12Saugustss	}
6311.12Saugustss
6321.12Saugustss	error = 0;
6331.12Saugustss
6341.12Saugustss	DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
6351.12Saugustss	s = spltty();
6361.12Saugustss
6371.12Saugustss	switch (cmd) {
6381.12Saugustss	case TIOCSBRK:
6391.12Saugustss		ucom_break(sc, 1);
6401.12Saugustss		break;
6411.12Saugustss
6421.12Saugustss	case TIOCCBRK:
6431.12Saugustss		ucom_break(sc, 0);
6441.12Saugustss		break;
6451.12Saugustss
6461.12Saugustss	case TIOCSDTR:
6471.12Saugustss		ucom_dtr(sc, 1);
6481.12Saugustss		break;
6491.12Saugustss
6501.12Saugustss	case TIOCCDTR:
6511.12Saugustss		ucom_dtr(sc, 0);
6521.12Saugustss		break;
6531.12Saugustss
6541.12Saugustss	case TIOCGFLAGS:
6551.12Saugustss		*(int *)data = sc->sc_swflags;
6561.12Saugustss		break;
6571.12Saugustss
6581.12Saugustss	case TIOCSFLAGS:
6591.67Selad		error = kauth_authorize_device_tty(l->l_cred,
6601.67Selad		    KAUTH_DEVICE_TTY_PRIVSET, tp);
6611.12Saugustss		if (error)
6621.12Saugustss			break;
6631.12Saugustss		sc->sc_swflags = *(int *)data;
6641.12Saugustss		break;
6651.12Saugustss
6661.12Saugustss	case TIOCMSET:
6671.12Saugustss	case TIOCMBIS:
6681.12Saugustss	case TIOCMBIC:
6691.12Saugustss		tiocm_to_ucom(sc, cmd, *(int *)data);
6701.12Saugustss		break;
6711.12Saugustss
6721.12Saugustss	case TIOCMGET:
6731.12Saugustss		*(int *)data = ucom_to_tiocm(sc);
6741.12Saugustss		break;
6751.12Saugustss
6761.12Saugustss	default:
6771.42Satatat		error = EPASSTHROUGH;
6781.12Saugustss		break;
6791.12Saugustss	}
6801.12Saugustss
6811.12Saugustss	splx(s);
6821.12Saugustss
6831.12Saugustss	return (error);
6841.12Saugustss}
6851.12Saugustss
6861.17SaugustssStatic void
6871.29Stoshiitiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
6881.12Saugustss{
6891.12Saugustss	u_char combits;
6901.3Saugustss
6911.12Saugustss	combits = 0;
6921.12Saugustss	if (ISSET(ttybits, TIOCM_DTR))
6931.12Saugustss		SET(combits, UMCR_DTR);
6941.12Saugustss	if (ISSET(ttybits, TIOCM_RTS))
6951.12Saugustss		SET(combits, UMCR_RTS);
6961.43Saugustss
6971.12Saugustss	switch (how) {
6981.12Saugustss	case TIOCMBIC:
6991.12Saugustss		CLR(sc->sc_mcr, combits);
7001.12Saugustss		break;
7011.12Saugustss
7021.12Saugustss	case TIOCMBIS:
7031.12Saugustss		SET(sc->sc_mcr, combits);
7041.12Saugustss		break;
7051.12Saugustss
7061.12Saugustss	case TIOCMSET:
7071.12Saugustss		CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
7081.12Saugustss		SET(sc->sc_mcr, combits);
7091.12Saugustss		break;
7101.12Saugustss	}
7111.12Saugustss
7121.27Stoshii	if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
7131.27Stoshii		ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
7141.27Stoshii	if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
7151.27Stoshii		ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
7161.12Saugustss}
7171.12Saugustss
7181.17SaugustssStatic int
7191.24Saugustssucom_to_tiocm(struct ucom_softc *sc)
7201.12Saugustss{
7211.12Saugustss	u_char combits;
7221.12Saugustss	int ttybits = 0;
7231.12Saugustss
7241.12Saugustss	combits = sc->sc_mcr;
7251.12Saugustss	if (ISSET(combits, UMCR_DTR))
7261.12Saugustss		SET(ttybits, TIOCM_DTR);
7271.12Saugustss	if (ISSET(combits, UMCR_RTS))
7281.12Saugustss		SET(ttybits, TIOCM_RTS);
7291.12Saugustss
7301.12Saugustss	combits = sc->sc_msr;
7311.12Saugustss	if (ISSET(combits, UMSR_DCD))
7321.12Saugustss		SET(ttybits, TIOCM_CD);
7331.12Saugustss	if (ISSET(combits, UMSR_CTS))
7341.12Saugustss		SET(ttybits, TIOCM_CTS);
7351.12Saugustss	if (ISSET(combits, UMSR_DSR))
7361.12Saugustss		SET(ttybits, TIOCM_DSR);
7371.12Saugustss	if (ISSET(combits, UMSR_RI | UMSR_TERI))
7381.12Saugustss		SET(ttybits, TIOCM_RI);
7391.12Saugustss
7401.12Saugustss#if 0
7411.12SaugustssXXX;
7421.12Saugustss	if (sc->sc_ier != 0)
7431.12Saugustss		SET(ttybits, TIOCM_LE);
7441.12Saugustss#endif
7451.12Saugustss
7461.12Saugustss	return (ttybits);
7471.12Saugustss}
7481.12Saugustss
7491.17SaugustssStatic void
7501.12Saugustssucom_break(sc, onoff)
7511.12Saugustss	struct ucom_softc *sc;
7521.12Saugustss	int onoff;
7531.12Saugustss{
7541.12Saugustss	DPRINTF(("ucom_break: onoff=%d\n", onoff));
7551.12Saugustss
7561.14Saugustss	if (sc->sc_methods->ucom_set != NULL)
7571.14Saugustss		sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
7581.14Saugustss		    UCOM_SET_BREAK, onoff);
7591.12Saugustss}
7601.12Saugustss
7611.17SaugustssStatic void
7621.24Saugustssucom_dtr(struct ucom_softc *sc, int onoff)
7631.12Saugustss{
7641.12Saugustss	DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
7651.12Saugustss
7661.14Saugustss	if (sc->sc_methods->ucom_set != NULL)
7671.43Saugustss		sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
7681.14Saugustss		    UCOM_SET_DTR, onoff);
7691.12Saugustss}
7701.12Saugustss
7711.17SaugustssStatic void
7721.24Saugustssucom_rts(struct ucom_softc *sc, int onoff)
7731.12Saugustss{
7741.12Saugustss	DPRINTF(("ucom_rts: onoff=%d\n", onoff));
7751.12Saugustss
7761.14Saugustss	if (sc->sc_methods->ucom_set != NULL)
7771.43Saugustss		sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
7781.14Saugustss		    UCOM_SET_RTS, onoff);
7791.12Saugustss}
7801.12Saugustss
7811.22Saugustssvoid
7821.24Saugustssucom_status_change(struct ucom_softc *sc)
7831.12Saugustss{
7841.27Stoshii	struct tty *tp = sc->sc_tty;
7851.27Stoshii	u_char old_msr;
7861.27Stoshii
7871.14Saugustss	if (sc->sc_methods->ucom_get_status != NULL) {
7881.27Stoshii		old_msr = sc->sc_msr;
7891.14Saugustss		sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
7901.14Saugustss		    &sc->sc_lsr, &sc->sc_msr);
7911.27Stoshii		if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD))
7921.32Seeh			(*tp->t_linesw->l_modem)(tp,
7931.27Stoshii			    ISSET(sc->sc_msr, UMSR_DCD));
7941.14Saugustss	} else {
7951.14Saugustss		sc->sc_lsr = 0;
7961.54Saugustss		/* Assume DCD is present, if we have no chance to check it. */
7971.54Saugustss		sc->sc_msr = UMSR_DCD;
7981.14Saugustss	}
7991.12Saugustss}
8001.12Saugustss
8011.17SaugustssStatic int
8021.24Saugustssucomparam(struct tty *tp, struct termios *t)
8031.12Saugustss{
8041.12Saugustss	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
8051.14Saugustss	int error;
8061.12Saugustss
8071.12Saugustss	if (sc->sc_dying)
8081.12Saugustss		return (EIO);
8091.12Saugustss
8101.12Saugustss	/* Check requested parameters. */
8111.12Saugustss	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
8121.12Saugustss		return (EINVAL);
8131.12Saugustss
8141.12Saugustss	/*
8151.12Saugustss	 * For the console, always force CLOCAL and !HUPCL, so that the port
8161.12Saugustss	 * is always active.
8171.12Saugustss	 */
8181.12Saugustss	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
8191.12Saugustss		SET(t->c_cflag, CLOCAL);
8201.12Saugustss		CLR(t->c_cflag, HUPCL);
8211.12Saugustss	}
8221.12Saugustss
8231.12Saugustss	/*
8241.12Saugustss	 * If there were no changes, don't do anything.  This avoids dropping
8251.12Saugustss	 * input and improves performance when all we did was frob things like
8261.12Saugustss	 * VMIN and VTIME.
8271.12Saugustss	 */
8281.12Saugustss	if (tp->t_ospeed == t->c_ospeed &&
8291.12Saugustss	    tp->t_cflag == t->c_cflag)
8301.12Saugustss		return (0);
8311.12Saugustss
8321.30Saugustss	/* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
8331.12Saugustss
8341.12Saugustss	/* And copy to tty. */
8351.12Saugustss	tp->t_ispeed = 0;
8361.12Saugustss	tp->t_ospeed = t->c_ospeed;
8371.12Saugustss	tp->t_cflag = t->c_cflag;
8381.12Saugustss
8391.14Saugustss	if (sc->sc_methods->ucom_param != NULL) {
8401.14Saugustss		error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
8411.14Saugustss			    t);
8421.14Saugustss		if (error)
8431.14Saugustss			return (error);
8441.14Saugustss	}
8451.12Saugustss
8461.30Saugustss	/* XXX worry about CHWFLOW */
8471.12Saugustss
8481.12Saugustss	/*
8491.12Saugustss	 * Update the tty layer's idea of the carrier bit, in case we changed
8501.12Saugustss	 * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
8511.12Saugustss	 * explicit request.
8521.12Saugustss	 */
8531.12Saugustss	DPRINTF(("ucomparam: l_modem\n"));
8541.54Saugustss	(void) (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_msr, UMSR_DCD));
8551.12Saugustss
8561.12Saugustss#if 0
8571.12SaugustssXXX what if the hardware is not open
8581.12Saugustss	if (!ISSET(t->c_cflag, CHWFLOW)) {
8591.12Saugustss		if (sc->sc_tx_stopped) {
8601.12Saugustss			sc->sc_tx_stopped = 0;
8611.12Saugustss			ucomstart(tp);
8621.12Saugustss		}
8631.12Saugustss	}
8641.12Saugustss#endif
8651.12Saugustss
8661.12Saugustss	return (0);
8671.12Saugustss}
8681.12Saugustss
8691.12Saugustss/*
8701.12Saugustss * (un)block input via hw flowcontrol
8711.12Saugustss */
8721.17SaugustssStatic void
8731.69Schristosucom_hwiflow(struct ucom_softc *sc)
8741.12Saugustss{
8751.19Saugustss	DPRINTF(("ucom_hwiflow:\n"));
8761.12Saugustss#if 0
8771.12SaugustssXXX
8781.12Saugustss	bus_space_tag_t iot = sc->sc_iot;
8791.12Saugustss	bus_space_handle_t ioh = sc->sc_ioh;
8801.12Saugustss
8811.12Saugustss	if (sc->sc_mcr_rts == 0)
8821.12Saugustss		return;
8831.12Saugustss
8841.12Saugustss	if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
8851.12Saugustss		CLR(sc->sc_mcr, sc->sc_mcr_rts);
8861.12Saugustss		CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
8871.12Saugustss	} else {
8881.12Saugustss		SET(sc->sc_mcr, sc->sc_mcr_rts);
8891.12Saugustss		SET(sc->sc_mcr_active, sc->sc_mcr_rts);
8901.12Saugustss	}
8911.12Saugustss	bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr_active);
8921.12Saugustss#endif
8931.1Saugustss}
8941.3Saugustss
8951.17SaugustssStatic void
8961.24Saugustssucomstart(struct tty *tp)
8971.12Saugustss{
8981.12Saugustss	struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
8991.12Saugustss	usbd_status err;
9001.12Saugustss	int s;
9011.12Saugustss	u_char *data;
9021.12Saugustss	int cnt;
9031.12Saugustss
9041.12Saugustss	if (sc->sc_dying)
9051.12Saugustss		return;
9061.12Saugustss
9071.12Saugustss	s = spltty();
9081.12Saugustss	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
9091.19Saugustss		DPRINTFN(4,("ucomstart: no go, state=0x%x\n", tp->t_state));
9101.12Saugustss		goto out;
9111.12Saugustss	}
9121.12Saugustss	if (sc->sc_tx_stopped)
9131.12Saugustss		goto out;
9141.12Saugustss
9151.12Saugustss	if (tp->t_outq.c_cc <= tp->t_lowat) {
9161.12Saugustss		if (ISSET(tp->t_state, TS_ASLEEP)) {
9171.12Saugustss			CLR(tp->t_state, TS_ASLEEP);
9181.12Saugustss			wakeup(&tp->t_outq);
9191.12Saugustss		}
9201.12Saugustss		selwakeup(&tp->t_wsel);
9211.12Saugustss		if (tp->t_outq.c_cc == 0)
9221.12Saugustss			goto out;
9231.12Saugustss	}
9241.12Saugustss
9251.12Saugustss	/* Grab the first contiguous region of buffer space. */
9261.12Saugustss	data = tp->t_outq.c_cf;
9271.12Saugustss	cnt = ndqb(&tp->t_outq, 0);
9281.12Saugustss
9291.12Saugustss	if (cnt == 0) {
9301.12Saugustss		DPRINTF(("ucomstart: cnt==0\n"));
9311.12Saugustss		goto out;
9321.12Saugustss	}
9331.12Saugustss
9341.12Saugustss	SET(tp->t_state, TS_BUSY);
9351.12Saugustss
9361.19Saugustss	if (cnt > sc->sc_obufsize) {
9371.12Saugustss		DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
9381.19Saugustss		cnt = sc->sc_obufsize;
9391.12Saugustss	}
9401.22Saugustss	if (sc->sc_methods->ucom_write != NULL)
9411.22Saugustss		sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
9421.22Saugustss					   sc->sc_obuf, data, &cnt);
9431.22Saugustss	else
9441.22Saugustss		memcpy(sc->sc_obuf, data, cnt);
9451.12Saugustss
9461.12Saugustss	DPRINTFN(4,("ucomstart: %d chars\n", cnt));
9471.43Saugustss	usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
9481.12Saugustss			(usbd_private_handle)sc, sc->sc_obuf, cnt,
9491.12Saugustss			USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
9501.12Saugustss	/* What can we do on error? */
9511.12Saugustss	err = usbd_transfer(sc->sc_oxfer);
9521.12Saugustss#ifdef DIAGNOSTIC
9531.12Saugustss	if (err != USBD_IN_PROGRESS)
9541.12Saugustss		printf("ucomstart: err=%s\n", usbd_errstr(err));
9551.3Saugustss#endif
9561.3Saugustss
9571.12Saugustssout:
9581.12Saugustss	splx(s);
9591.12Saugustss}
9601.12Saugustss
9611.21Sitojunvoid
9621.69Schristosucomstop(struct tty *tp, int flag)
9631.12Saugustss{
9641.19Saugustss	DPRINTF(("ucomstop: flag=%d\n", flag));
9651.19Saugustss#if 0
9661.19Saugustss	/*struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];*/
9671.12Saugustss	int s;
9681.12Saugustss
9691.12Saugustss	s = spltty();
9701.12Saugustss	if (ISSET(tp->t_state, TS_BUSY)) {
9711.12Saugustss		DPRINTF(("ucomstop: XXX\n"));
9721.19Saugustss		/* sc->sc_tx_stopped = 1; */
9731.12Saugustss		if (!ISSET(tp->t_state, TS_TTSTOP))
9741.12Saugustss			SET(tp->t_state, TS_FLUSH);
9751.12Saugustss	}
9761.12Saugustss	splx(s);
9771.19Saugustss#endif
9781.12Saugustss}
9791.12Saugustss
9801.17SaugustssStatic void
9811.24Saugustssucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
9821.12Saugustss{
9831.12Saugustss	struct ucom_softc *sc = (struct ucom_softc *)p;
9841.12Saugustss	struct tty *tp = sc->sc_tty;
9851.12Saugustss	u_int32_t cc;
9861.12Saugustss	int s;
9871.12Saugustss
9881.12Saugustss	DPRINTFN(5,("ucomwritecb: status=%d\n", status));
9891.12Saugustss
9901.34Saugustss	if (status == USBD_CANCELLED || sc->sc_dying)
9911.39Saugustss		goto error;
9921.12Saugustss
9931.12Saugustss	if (status) {
9941.12Saugustss		DPRINTF(("ucomwritecb: status=%d\n", status));
9951.12Saugustss		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
9961.12Saugustss		/* XXX we should restart after some delay. */
9971.39Saugustss		goto error;
9981.12Saugustss	}
9991.12Saugustss
10001.15Saugustss	usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
10011.31Sexplorer#if defined(__NetBSD__) && NRND > 0
10021.31Sexplorer	rnd_add_uint32(&sc->sc_rndsource, cc);
10031.31Sexplorer#endif
10041.12Saugustss	DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));
10051.25Saugustss	/* convert from USB bytes to tty bytes */
10061.25Saugustss	cc -= sc->sc_opkthdrlen;
10071.12Saugustss
10081.12Saugustss	s = spltty();
10091.12Saugustss	CLR(tp->t_state, TS_BUSY);
10101.12Saugustss	if (ISSET(tp->t_state, TS_FLUSH))
10111.12Saugustss		CLR(tp->t_state, TS_FLUSH);
10121.12Saugustss	else
10131.12Saugustss		ndflush(&tp->t_outq, cc);
10141.32Seeh	(*tp->t_linesw->l_start)(tp);
10151.39Saugustss	splx(s);
10161.39Saugustss	return;
10171.39Saugustss
10181.39Saugustsserror:
10191.39Saugustss	s = spltty();
10201.39Saugustss	CLR(tp->t_state, TS_BUSY);
10211.12Saugustss	splx(s);
10221.12Saugustss}
10231.12Saugustss
10241.17SaugustssStatic usbd_status
10251.24Saugustssucomstartread(struct ucom_softc *sc)
10261.12Saugustss{
10271.12Saugustss	usbd_status err;
10281.12Saugustss
10291.12Saugustss	DPRINTFN(5,("ucomstartread: start\n"));
10301.43Saugustss	usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
10311.43Saugustss			(usbd_private_handle)sc,
10321.19Saugustss			sc->sc_ibuf, sc->sc_ibufsize,
10331.12Saugustss			USBD_SHORT_XFER_OK | USBD_NO_COPY,
10341.12Saugustss			USBD_NO_TIMEOUT, ucomreadcb);
10351.12Saugustss	err = usbd_transfer(sc->sc_ixfer);
10361.12Saugustss	if (err != USBD_IN_PROGRESS) {
10371.12Saugustss		DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
10381.12Saugustss		return (err);
10391.12Saugustss	}
10401.12Saugustss	return (USBD_NORMAL_COMPLETION);
10411.12Saugustss}
10421.43Saugustss
10431.17SaugustssStatic void
10441.24Saugustssucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
10451.12Saugustss{
10461.12Saugustss	struct ucom_softc *sc = (struct ucom_softc *)p;
10471.12Saugustss	struct tty *tp = sc->sc_tty;
10481.55Schristos	int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
10491.12Saugustss	usbd_status err;
10501.12Saugustss	u_int32_t cc;
10511.12Saugustss	u_char *cp;
10521.12Saugustss	int s;
10531.12Saugustss
10541.34Saugustss	DPRINTFN(5,("ucomreadcb: status=%d\n", status));
10551.34Saugustss
10561.34Saugustss	if (status == USBD_CANCELLED || status == USBD_IOERROR ||
10571.34Saugustss	    sc->sc_dying) {
10581.34Saugustss		DPRINTF(("ucomreadcb: dying\n"));
10591.34Saugustss		/* Send something to wake upper layer */
10601.34Saugustss		s = spltty();
10611.34Saugustss		(*rint)('\n', tp);
10621.34Saugustss		ttwakeup(tp);
10631.34Saugustss		splx(s);
10641.12Saugustss		return;
10651.34Saugustss	}
10661.12Saugustss
10671.12Saugustss	if (status) {
10681.12Saugustss		usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
10691.12Saugustss		/* XXX we should restart after some delay. */
10701.12Saugustss		return;
10711.12Saugustss	}
10721.12Saugustss
10731.48Sthorpej	usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
10741.31Sexplorer#if defined(__NetBSD__) && NRND > 0
10751.31Sexplorer	rnd_add_uint32(&sc->sc_rndsource, cc);
10761.31Sexplorer#endif
10771.12Saugustss	DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp));
10781.22Saugustss	if (sc->sc_methods->ucom_read != NULL)
10791.22Saugustss		sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
10801.22Saugustss					  &cp, &cc);
10811.22Saugustss
10821.12Saugustss	s = spltty();
10831.12Saugustss	/* Give characters to tty layer. */
10841.12Saugustss	while (cc-- > 0) {
10851.12Saugustss		DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp));
10861.12Saugustss		if ((*rint)(*cp++, tp) == -1) {
10871.12Saugustss			/* XXX what should we do? */
10881.19Saugustss			printf("%s: lost %d chars\n", USBDEVNAME(sc->sc_dev),
10891.19Saugustss			       cc);
10901.12Saugustss			break;
10911.12Saugustss		}
10921.12Saugustss	}
10931.12Saugustss	splx(s);
10941.12Saugustss
10951.12Saugustss	err = ucomstartread(sc);
10961.12Saugustss	if (err) {
10971.12Saugustss		printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev));
10981.12Saugustss		/* XXX what should we dow now? */
10991.12Saugustss	}
11001.12Saugustss}
11011.12Saugustss
11021.17SaugustssStatic void
11031.24Saugustssucom_cleanup(struct ucom_softc *sc)
11041.12Saugustss{
11051.12Saugustss	DPRINTF(("ucom_cleanup: closing pipes\n"));
11061.12Saugustss
11071.12Saugustss	ucom_shutdown(sc);
11081.69.10.2Sitohy	if (sc->sc_bulkin_pipe != NULL)
11091.33Saugustss		usbd_abort_pipe(sc->sc_bulkin_pipe);
11101.69.10.2Sitohy	if (sc->sc_bulkout_pipe != NULL)
11111.33Saugustss		usbd_abort_pipe(sc->sc_bulkout_pipe);
11121.33Saugustss	if (sc->sc_ixfer != NULL) {
11131.33Saugustss		usbd_free_xfer(sc->sc_ixfer);
11141.33Saugustss		sc->sc_ixfer = NULL;
11151.33Saugustss	}
11161.33Saugustss	if (sc->sc_oxfer != NULL) {
11171.33Saugustss		usbd_free_xfer(sc->sc_oxfer);
11181.33Saugustss		sc->sc_oxfer = NULL;
11191.33Saugustss	}
11201.69.10.2Sitohy	if (sc->sc_bulkin_pipe != NULL) {
11211.69.10.2Sitohy		usbd_close_pipe(sc->sc_bulkin_pipe);
11221.69.10.2Sitohy		sc->sc_bulkin_pipe = NULL;
11231.69.10.2Sitohy	}
11241.69.10.2Sitohy	if (sc->sc_bulkout_pipe != NULL) {
11251.69.10.2Sitohy		usbd_close_pipe(sc->sc_bulkout_pipe);
11261.69.10.2Sitohy		sc->sc_bulkout_pipe = NULL;
11271.69.10.2Sitohy	}
11281.12Saugustss}
11291.13Saugustss
11301.13Saugustss#endif /* NUCOM > 0 */
11311.12Saugustss
11321.20Saugustssint
11331.24Saugustssucomprint(void *aux, const char *pnp)
11341.12Saugustss{
11351.37Saugustss	struct ucom_attach_args *uca = aux;
11361.12Saugustss
11371.12Saugustss	if (pnp)
11381.49Sthorpej		aprint_normal("ucom at %s", pnp);
11391.37Saugustss	if (uca->portno != UCOM_UNK_PORTNO)
11401.49Sthorpej		aprint_normal(" portno %d", uca->portno);
11411.12Saugustss	return (UNCONF);
11421.12Saugustss}
11431.12Saugustss
11441.20Saugustssint
11451.53Sdrochnerucomsubmatch(struct device *parent, struct cfdata *cf,
11461.69Schristos	     const int *ldesc, void *aux)
11471.12Saugustss{
11481.12Saugustss	struct ucom_attach_args *uca = aux;
11491.12Saugustss
11501.12Saugustss	if (uca->portno != UCOM_UNK_PORTNO &&
11511.53Sdrochner	    cf->cf_loc[UCOMBUSCF_PORTNO] != UCOMBUSCF_PORTNO_DEFAULT &&
11521.53Sdrochner	    cf->cf_loc[UCOMBUSCF_PORTNO] != uca->portno)
11531.12Saugustss		return (0);
11541.46Sthorpej	return (config_match(parent, cf, aux));
11551.12Saugustss}
1156