xref: /netbsd-src/sys/arch/arm/ep93xx/epcom.c (revision dbfa10e52a5827a2b548912aaaea11468b4c7f47)
1*dbfa10e5Sriastradh /*	$NetBSD: epcom.c,v 1.36 2022/10/26 23:38:06 riastradh Exp $ */
24e771f5dSjoff /*
34e771f5dSjoff  * Copyright (c) 1998, 1999, 2001, 2002, 2004 The NetBSD Foundation, Inc.
44e771f5dSjoff  * All rights reserved.
54e771f5dSjoff  *
64e771f5dSjoff  * This code is derived from software contributed to The NetBSD Foundation
74e771f5dSjoff  * by Jesse Off
84e771f5dSjoff  *
94e771f5dSjoff  * This code is derived from software contributed to The NetBSD Foundation
104e771f5dSjoff  * by Ichiro FUKUHARA and Naoto Shimazaki.
114e771f5dSjoff  *
124e771f5dSjoff  * This code is derived from software contributed to The NetBSD Foundation
134e771f5dSjoff  * by IWAMOTO Toshihiro.
144e771f5dSjoff  *
154e771f5dSjoff  * This code is derived from software contributed to The NetBSD Foundation
164e771f5dSjoff  * by Charles M. Hannum.
174e771f5dSjoff  *
184e771f5dSjoff  * Redistribution and use in source and binary forms, with or without
194e771f5dSjoff  * modification, are permitted provided that the following conditions
204e771f5dSjoff  * are met:
214e771f5dSjoff  * 1. Redistributions of source code must retain the above copyright
224e771f5dSjoff  *    notice, this list of conditions and the following disclaimer.
234e771f5dSjoff  * 2. Redistributions in binary form must reproduce the above copyright
244e771f5dSjoff  *    notice, this list of conditions and the following disclaimer in the
254e771f5dSjoff  *    documentation and/or other materials provided with the distribution.
264e771f5dSjoff  *
274e771f5dSjoff  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
284e771f5dSjoff  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
294e771f5dSjoff  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
304e771f5dSjoff  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
314e771f5dSjoff  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
324e771f5dSjoff  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
334e771f5dSjoff  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
344e771f5dSjoff  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
354e771f5dSjoff  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
364e771f5dSjoff  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
374e771f5dSjoff  * POSSIBILITY OF SUCH DAMAGE.
384e771f5dSjoff  */
394e771f5dSjoff 
404e771f5dSjoff /*
414e771f5dSjoff  * Copyright (c) 1991 The Regents of the University of California.
424e771f5dSjoff  * All rights reserved.
434e771f5dSjoff  *
444e771f5dSjoff  * Redistribution and use in source and binary forms, with or without
454e771f5dSjoff  * modification, are permitted provided that the following conditions
464e771f5dSjoff  * are met:
474e771f5dSjoff  * 1. Redistributions of source code must retain the above copyright
484e771f5dSjoff  *    notice, this list of conditions and the following disclaimer.
494e771f5dSjoff  * 2. Redistributions in binary form must reproduce the above copyright
504e771f5dSjoff  *    notice, this list of conditions and the following disclaimer in the
514e771f5dSjoff  *    documentation and/or other materials provided with the distribution.
524e771f5dSjoff  * 3. Neither the name of the University nor the names of its contributors
534e771f5dSjoff  *    may be used to endorse or promote products derived from this software
544e771f5dSjoff  *    without specific prior written permission.
554e771f5dSjoff  *
564e771f5dSjoff  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
574e771f5dSjoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
584e771f5dSjoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
594e771f5dSjoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
604e771f5dSjoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
614e771f5dSjoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
624e771f5dSjoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
634e771f5dSjoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
644e771f5dSjoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
654e771f5dSjoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
664e771f5dSjoff  * SUCH DAMAGE.
674e771f5dSjoff  *
684e771f5dSjoff  *      @(#)com.c       7.5 (Berkeley) 5/16/91
694e771f5dSjoff  */
704e771f5dSjoff 
714e771f5dSjoff /*
724e771f5dSjoff  * TODO: hardware flow control
734e771f5dSjoff  */
744e771f5dSjoff 
754e771f5dSjoff #include <sys/cdefs.h>
76*dbfa10e5Sriastradh __KERNEL_RCSID(0, "$NetBSD: epcom.c,v 1.36 2022/10/26 23:38:06 riastradh Exp $");
774e771f5dSjoff 
784e771f5dSjoff #include "opt_kgdb.h"
794e771f5dSjoff #include "epcom.h"
804e771f5dSjoff 
817b0b7dedStls #ifdef RND_COM
82445478ceSriastradh #include <sys/rndsource.h>
834e771f5dSjoff #endif
844e771f5dSjoff 
854e771f5dSjoff /*
864e771f5dSjoff  * Override cnmagic(9) macro before including <sys/systm.h>.
874e771f5dSjoff  * We need to know if cn_check_magic triggered debugger, so set a flag.
884e771f5dSjoff  * Callers of cn_check_magic must declare int cn_trapped = 0;
894e771f5dSjoff  * XXX: this is *ugly*!
904e771f5dSjoff  */
914e771f5dSjoff #define cn_trap()				\
924e771f5dSjoff 	do {					\
934e771f5dSjoff 		console_debugger();		\
944e771f5dSjoff 		cn_trapped = 1;			\
954e771f5dSjoff 	} while (/* CONSTCOND */ 0)
964e771f5dSjoff 
974e771f5dSjoff 
984e771f5dSjoff #include <sys/param.h>
994e771f5dSjoff #include <sys/systm.h>
1004e771f5dSjoff #include <sys/types.h>
1014e771f5dSjoff #include <sys/conf.h>
1024e771f5dSjoff #include <sys/file.h>
1034e771f5dSjoff #include <sys/device.h>
1044e771f5dSjoff #include <sys/kernel.h>
10538fdb085Sthorpej #include <sys/kmem.h>
1064e771f5dSjoff #include <sys/tty.h>
1074e771f5dSjoff #include <sys/uio.h>
1084e771f5dSjoff #include <sys/vnode.h>
1098ccb6c93Selad #include <sys/kauth.h>
1104e771f5dSjoff 
1114e771f5dSjoff #include <machine/intr.h>
112cf10107dSdyoung #include <sys/bus.h>
1134e771f5dSjoff 
114*dbfa10e5Sriastradh #include <ddb/db_active.h>
115*dbfa10e5Sriastradh 
1164e771f5dSjoff #include <arm/ep93xx/epcomreg.h>
1174e771f5dSjoff #include <arm/ep93xx/epcomvar.h>
1184e771f5dSjoff #include <arm/ep93xx/ep93xxreg.h>
1194e771f5dSjoff #include <arm/ep93xx/ep93xxvar.h>
1204e771f5dSjoff 
1214e771f5dSjoff #include <dev/cons.h>
1224e771f5dSjoff 
1234e771f5dSjoff static int	epcomparam(struct tty *, struct termios *);
1244e771f5dSjoff static void	epcomstart(struct tty *);
1254e771f5dSjoff static int	epcomhwiflow(struct tty *, int);
1264e771f5dSjoff 
1274e771f5dSjoff static u_int	cflag2lcrhi(tcflag_t);
1284e771f5dSjoff static void	epcom_iflush(struct epcom_softc *);
1294e771f5dSjoff static void	epcom_set(struct epcom_softc *);
1304e771f5dSjoff 
1314e771f5dSjoff int             epcomcngetc(dev_t);
1324e771f5dSjoff void            epcomcnputc(dev_t, int);
1334e771f5dSjoff void            epcomcnpollc(dev_t, int);
1344e771f5dSjoff 
1354e771f5dSjoff static void	epcomsoft(void* arg);
1364e771f5dSjoff inline static void	epcom_txsoft(struct epcom_softc *, struct tty *);
1374e771f5dSjoff inline static void	epcom_rxsoft(struct epcom_softc *, struct tty *);
1384e771f5dSjoff 
1394e771f5dSjoff void            epcomcnprobe(struct consdev *);
1404e771f5dSjoff void            epcomcninit(struct consdev *);
1414e771f5dSjoff 
1424e771f5dSjoff static struct epcom_cons_softc {
1434e771f5dSjoff 	bus_space_tag_t		sc_iot;
1444e771f5dSjoff 	bus_space_handle_t	sc_ioh;
1454e771f5dSjoff 	bus_addr_t		sc_hwbase;
1464e771f5dSjoff 	int			sc_ospeed;
1474e771f5dSjoff 	tcflag_t		sc_cflag;
1484e771f5dSjoff } epcomcn_sc;
1494e771f5dSjoff 
1509d134cf5Sskrll static int	epcom_common_getc(struct epcom_cons_softc *, dev_t);
1519d134cf5Sskrll static void	epcom_common_putc(struct epcom_cons_softc *, int);
1529d134cf5Sskrll static void	epcominit(struct epcom_cons_softc *, bus_space_tag_t,
1539d134cf5Sskrll 			  bus_addr_t, bus_space_handle_t, int, tcflag_t);
1549d134cf5Sskrll 
1554e771f5dSjoff static struct cnm_state epcom_cnm_state;
1564e771f5dSjoff 
1574e771f5dSjoff extern struct cfdriver epcom_cd;
1584e771f5dSjoff 
1594e771f5dSjoff dev_type_open(epcomopen);
1604e771f5dSjoff dev_type_close(epcomclose);
1614e771f5dSjoff dev_type_read(epcomread);
1624e771f5dSjoff dev_type_write(epcomwrite);
1634e771f5dSjoff dev_type_ioctl(epcomioctl);
1644e771f5dSjoff dev_type_stop(epcomstop);
1654e771f5dSjoff dev_type_tty(epcomtty);
1664e771f5dSjoff dev_type_poll(epcompoll);
1674e771f5dSjoff 
1684e771f5dSjoff const struct cdevsw epcom_cdevsw = {
169a68f9396Sdholland 	.d_open = epcomopen,
170a68f9396Sdholland 	.d_close = epcomclose,
171a68f9396Sdholland 	.d_read = epcomread,
172a68f9396Sdholland 	.d_write = epcomwrite,
173a68f9396Sdholland 	.d_ioctl = epcomioctl,
174a68f9396Sdholland 	.d_stop = epcomstop,
175a68f9396Sdholland 	.d_tty = epcomtty,
176a68f9396Sdholland 	.d_poll = epcompoll,
177a68f9396Sdholland 	.d_mmap = nommap,
178a68f9396Sdholland 	.d_kqfilter = ttykqfilter,
179f9228f42Sdholland 	.d_discard = nodiscard,
180a68f9396Sdholland 	.d_flag = D_TTY
1814e771f5dSjoff };
1824e771f5dSjoff 
1834e771f5dSjoff struct consdev epcomcons = {
1844e771f5dSjoff 	NULL, NULL, epcomcngetc, epcomcnputc, epcomcnpollc, NULL,
1854e771f5dSjoff 	NULL, NULL, NODEV, CN_NORMAL
1864e771f5dSjoff };
1874e771f5dSjoff 
1889d134cf5Sskrll #if defined(KGDB)
1899d134cf5Sskrll #include <sys/kgdb.h>
1909d134cf5Sskrll 
1919d134cf5Sskrll static int	epcom_kgdb_getc(void *);
1929d134cf5Sskrll static void	epcom_kgdb_putc(void *, int);
1939d134cf5Sskrll 
1949d134cf5Sskrll /*
1959d134cf5Sskrll  * Reuse the console softc structure because
1969d134cf5Sskrll  * we'll be reusing the console I/O code.
1979d134cf5Sskrll  */
1989d134cf5Sskrll static struct epcom_cons_softc kgdb_sc;
1999d134cf5Sskrll #endif
2009d134cf5Sskrll 
2014e771f5dSjoff #ifndef DEFAULT_COMSPEED
2024e771f5dSjoff #define DEFAULT_COMSPEED 115200
2034e771f5dSjoff #endif
2044e771f5dSjoff 
205a0a6c85fSchristos #define COMUNIT(x)	TTUNIT(x)
206a0a6c85fSchristos #define COMDIALOUT(x)	TTDIALOUT(x)
2074e771f5dSjoff 
2084e771f5dSjoff #define COM_ISALIVE(sc)	((sc)->enabled != 0 && \
209cbab9cadSchs 			device_is_active((sc)->sc_dev))
2104e771f5dSjoff 
2114e771f5dSjoff void
epcom_attach_subr(struct epcom_softc * sc)2120e9d2fc1Schristos epcom_attach_subr(struct epcom_softc *sc)
2134e771f5dSjoff {
2144e771f5dSjoff 	struct tty *tp;
2154e771f5dSjoff 
2164e771f5dSjoff 	if (sc->sc_iot == epcomcn_sc.sc_iot
2174e771f5dSjoff 	    && sc->sc_hwbase == epcomcn_sc.sc_hwbase) {
2184e771f5dSjoff 		sc->sc_lcrlo = EPCOMSPEED2BRD(epcomcn_sc.sc_ospeed) & 0xff;
2194e771f5dSjoff 		sc->sc_lcrmid = EPCOMSPEED2BRD(epcomcn_sc.sc_ospeed) >> 8;
2204e771f5dSjoff 
2214e771f5dSjoff 		/* Make sure the console is always "hardwired". */
2224e771f5dSjoff 		delay(10000);	/* wait for output to finish */
2234e771f5dSjoff 		SET(sc->sc_hwflags, COM_HW_CONSOLE);
2244e771f5dSjoff 		SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
2254e771f5dSjoff 	}
2264e771f5dSjoff 
2272626d576Srmind 	tp = tty_alloc();
2284e771f5dSjoff 	tp->t_oproc = epcomstart;
2294e771f5dSjoff 	tp->t_param = epcomparam;
2304e771f5dSjoff 	tp->t_hwiflow = epcomhwiflow;
2314e771f5dSjoff 
2324e771f5dSjoff 	sc->sc_tty = tp;
23338fdb085Sthorpej 	sc->sc_rbuf = kmem_alloc(EPCOM_RING_SIZE << 1, KM_SLEEP);
2344e771f5dSjoff 	sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
2354e771f5dSjoff 	sc->sc_rbavail = EPCOM_RING_SIZE;
2364e771f5dSjoff 	sc->sc_ebuf = sc->sc_rbuf + (EPCOM_RING_SIZE << 1);
2374e771f5dSjoff 	sc->sc_tbc = 0;
2384e771f5dSjoff 
2394e771f5dSjoff 	sc->sc_lcrlo = EPCOMSPEED2BRD(DEFAULT_COMSPEED) & 0xff;
2404e771f5dSjoff 	sc->sc_lcrmid = EPCOMSPEED2BRD(DEFAULT_COMSPEED) >> 8;
2414e771f5dSjoff 	sc->sc_lcrhi = cflag2lcrhi(CS8); /* 8N1 */
2424e771f5dSjoff 
2434e771f5dSjoff 	tty_attach(tp);
2444e771f5dSjoff 
2454e771f5dSjoff 	if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
2464e771f5dSjoff 		int maj;
2474e771f5dSjoff 
2484e771f5dSjoff 		/* locate the major number */
2494e771f5dSjoff 		maj = cdevsw_lookup_major(&epcom_cdevsw);
2504e771f5dSjoff 
251cbab9cadSchs 		cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev));
2524e771f5dSjoff 
253cbab9cadSchs 		aprint_normal("%s: console\n", device_xname(sc->sc_dev));
2544e771f5dSjoff 	}
2554e771f5dSjoff 
2569d134cf5Sskrll #ifdef KGDB
2579d134cf5Sskrll 	/*
2589d134cf5Sskrll 	 * Allow kgdb to "take over" this port.  If this is
2599d134cf5Sskrll 	 * the kgdb device, it has exclusive use.
2609d134cf5Sskrll 	 */
2619d134cf5Sskrll 	if (sc->sc_iot == kgdb_sc.sc_iot &&
2629d134cf5Sskrll 	    sc->sc_hwbase == kgdb_sc.sc_hwbase) {
2639d134cf5Sskrll 		SET(sc->sc_hwflags, COM_HW_KGDB);
2643aa5a3aeSriastradh 		device_printf(sc->sc_dev, "kgdb\n");
2659d134cf5Sskrll 	}
2669d134cf5Sskrll #endif
2679d134cf5Sskrll 
2680c0de807Smatt 	sc->sc_si = softint_establish(SOFTINT_SERIAL, epcomsoft, sc);
2694e771f5dSjoff 
2707b0b7dedStls #ifdef RND_COM
271cbab9cadSchs 	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
272ea6af427Stls 			  RND_TYPE_TTY, RND_FLAG_DEFAULT);
2734e771f5dSjoff #endif
2744e771f5dSjoff 
2754e771f5dSjoff 	/* if there are no enable/disable functions, assume the device
2764e771f5dSjoff 	   is always enabled */
2774e771f5dSjoff 	if (!sc->enable)
2784e771f5dSjoff 		sc->enabled = 1;
2794e771f5dSjoff 
2804e771f5dSjoff 	/* XXX configure register */
2814e771f5dSjoff 	/* xxx_config(sc) */
2824e771f5dSjoff 
2834e771f5dSjoff 	SET(sc->sc_hwflags, COM_HW_DEV_OK);
2844e771f5dSjoff }
2854e771f5dSjoff 
2864e771f5dSjoff static int
epcomparam(struct tty * tp,struct termios * t)2870e9d2fc1Schristos epcomparam(struct tty *tp, struct termios *t)
2884e771f5dSjoff {
2894e771f5dSjoff 	struct epcom_softc *sc
2905402ae69Scegger 		= device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev));
2914e771f5dSjoff 	int s;
2924e771f5dSjoff 
2934e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
2944e771f5dSjoff 		return (EIO);
2954e771f5dSjoff 
2964e771f5dSjoff 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
2974e771f5dSjoff 		return (EINVAL);
2984e771f5dSjoff 
2994e771f5dSjoff 	/*
3004e771f5dSjoff 	 * For the console, always force CLOCAL and !HUPCL, so that the port
3014e771f5dSjoff 	 * is always active.
3024e771f5dSjoff 	 */
3034e771f5dSjoff 	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
3044e771f5dSjoff 	    ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
3054e771f5dSjoff 		SET(t->c_cflag, CLOCAL);
3064e771f5dSjoff 		CLR(t->c_cflag, HUPCL);
3074e771f5dSjoff 	}
3084e771f5dSjoff 
3094e771f5dSjoff 	/*
3104e771f5dSjoff 	 * If there were no changes, don't do anything.  This avoids dropping
3114e771f5dSjoff 	 * input and improves performance when all we did was frob things like
3124e771f5dSjoff 	 * VMIN and VTIME.
3134e771f5dSjoff 	 */
3144e771f5dSjoff 	if (tp->t_ospeed == t->c_ospeed &&
3154e771f5dSjoff 	    tp->t_cflag == t->c_cflag)
3164e771f5dSjoff 		return (0);
3174e771f5dSjoff 
3184e771f5dSjoff 	s = splserial();
3194e771f5dSjoff 
3204e771f5dSjoff 	sc->sc_lcrhi = cflag2lcrhi(t->c_cflag);
3214e771f5dSjoff 	sc->sc_lcrlo = EPCOMSPEED2BRD(t->c_ospeed) & 0xff;
3224e771f5dSjoff 	sc->sc_lcrmid = EPCOMSPEED2BRD(t->c_ospeed) >> 8;
3234e771f5dSjoff 
3244e771f5dSjoff 	/* And copy to tty. */
3254e771f5dSjoff 	tp->t_ispeed = 0;
3264e771f5dSjoff 	tp->t_ospeed = t->c_ospeed;
3274e771f5dSjoff 	tp->t_cflag = t->c_cflag;
3284e771f5dSjoff 	epcom_set(sc);
3294e771f5dSjoff 
3304e771f5dSjoff 	splx(s);
3314e771f5dSjoff 
3324e771f5dSjoff 	/*
3334e771f5dSjoff 	 * Update the tty layer's idea of the carrier bit.
3344e771f5dSjoff 	 * We tell tty the carrier is always on.
3354e771f5dSjoff 	 */
3364e771f5dSjoff 	(void) (*tp->t_linesw->l_modem)(tp, 1);
3374e771f5dSjoff 
3384e771f5dSjoff #ifdef COM_DEBUG
3394e771f5dSjoff 	if (com_debug)
3404e771f5dSjoff 		comstatus(sc, "comparam ");
3414e771f5dSjoff #endif
3424e771f5dSjoff 
3434e771f5dSjoff 	if (!ISSET(t->c_cflag, CHWFLOW)) {
3444e771f5dSjoff 		if (sc->sc_tx_stopped) {
3454e771f5dSjoff 			sc->sc_tx_stopped = 0;
3464e771f5dSjoff 			epcomstart(tp);
3474e771f5dSjoff 		}
3484e771f5dSjoff 	}
3494e771f5dSjoff 
3504e771f5dSjoff 	return (0);
3514e771f5dSjoff }
3524e771f5dSjoff 
3534e771f5dSjoff static int
epcomhwiflow(struct tty * tp,int block)3540e9d2fc1Schristos epcomhwiflow(struct tty *tp, int block)
3554e771f5dSjoff {
3564e771f5dSjoff 	return (0);
3574e771f5dSjoff }
3584e771f5dSjoff 
3594e771f5dSjoff static void
epcom_filltx(struct epcom_softc * sc)3604e771f5dSjoff epcom_filltx(struct epcom_softc *sc)
3614e771f5dSjoff {
3624e771f5dSjoff 	bus_space_tag_t iot = sc->sc_iot;
3634e771f5dSjoff 	bus_space_handle_t ioh = sc->sc_ioh;
3644e771f5dSjoff 	int n;
3654e771f5dSjoff 
3664e771f5dSjoff 	n = 0;
3674e771f5dSjoff         while ((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFF) == 0) {
3684e771f5dSjoff 		if (n >= sc->sc_tbc)
3694e771f5dSjoff 			break;
3704e771f5dSjoff 		bus_space_write_4(iot, ioh, EPCOM_Data,
3714e771f5dSjoff 				  0xff & *(sc->sc_tba + n));
3724e771f5dSjoff 		n++;
3734e771f5dSjoff         }
3744e771f5dSjoff         sc->sc_tbc -= n;
3754e771f5dSjoff         sc->sc_tba += n;
3764e771f5dSjoff }
3774e771f5dSjoff 
3784e771f5dSjoff static void
epcomstart(struct tty * tp)3790e9d2fc1Schristos epcomstart(struct tty *tp)
3804e771f5dSjoff {
3814e771f5dSjoff 	struct epcom_softc *sc
3825402ae69Scegger 		= device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev));
3834e771f5dSjoff 	int s;
3844e771f5dSjoff 
3854e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
3864e771f5dSjoff 		return;
3874e771f5dSjoff 
3884e771f5dSjoff 	s = spltty();
3894e771f5dSjoff 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
3904e771f5dSjoff 		goto out;
3914e771f5dSjoff 	if (sc->sc_tx_stopped)
3924e771f5dSjoff 		goto out;
393dc26833bSad 	if (!ttypull(tp))
3944e771f5dSjoff 		goto out;
3954e771f5dSjoff 
3964e771f5dSjoff 	/* Grab the first contiguous region of buffer space. */
3974e771f5dSjoff 	{
3984e771f5dSjoff 		u_char *tba;
3994e771f5dSjoff 		int tbc;
4004e771f5dSjoff 
4014e771f5dSjoff 		tba = tp->t_outq.c_cf;
4024e771f5dSjoff 		tbc = ndqb(&tp->t_outq, 0);
4034e771f5dSjoff 
4044e771f5dSjoff 		(void)splserial();
4054e771f5dSjoff 
4064e771f5dSjoff 		sc->sc_tba = tba;
4074e771f5dSjoff 		sc->sc_tbc = tbc;
4084e771f5dSjoff 	}
4094e771f5dSjoff 
4104e771f5dSjoff 	SET(tp->t_state, TS_BUSY);
4114e771f5dSjoff 	sc->sc_tx_busy = 1;
4124e771f5dSjoff 
4135beb7d30Sjoff 	/* Output the first chunk of the contiguous buffer. */
4145beb7d30Sjoff 	epcom_filltx(sc);
4155beb7d30Sjoff 
4164e771f5dSjoff 	if (!ISSET(sc->sc_ctrl, Ctrl_TIE)) {
4174e771f5dSjoff 		SET(sc->sc_ctrl, Ctrl_TIE);
4184e771f5dSjoff 		epcom_set(sc);
4194e771f5dSjoff 	}
4204e771f5dSjoff 
4214e771f5dSjoff out:
4224e771f5dSjoff 	splx(s);
4234e771f5dSjoff 	return;
4244e771f5dSjoff }
4254e771f5dSjoff 
4264e771f5dSjoff static void
epcom_break(struct epcom_softc * sc,int onoff)4274e771f5dSjoff epcom_break(struct epcom_softc *sc, int onoff)
4284e771f5dSjoff {
4294e771f5dSjoff 	if (onoff)
4304e771f5dSjoff 		SET(sc->sc_lcrhi, LinCtrlHigh_BRK);
4314e771f5dSjoff 	else
4324e771f5dSjoff 		CLR(sc->sc_lcrhi, LinCtrlHigh_BRK);
4334e771f5dSjoff 	epcom_set(sc);
4344e771f5dSjoff }
4354e771f5dSjoff 
4364e771f5dSjoff static void
epcom_shutdown(struct epcom_softc * sc)4374e771f5dSjoff epcom_shutdown(struct epcom_softc *sc)
4384e771f5dSjoff {
4394e771f5dSjoff 	int s;
4404e771f5dSjoff 
4414e771f5dSjoff 	s = splserial();
4424e771f5dSjoff 
4434e771f5dSjoff 	/* Turn off interrupts. */
4444e771f5dSjoff 	CLR(sc->sc_ctrl, (Ctrl_TIE|Ctrl_RTIE|Ctrl_RIE));
4454e771f5dSjoff 
4464e771f5dSjoff 	/* Clear any break condition set with TIOCSBRK. */
4474e771f5dSjoff 	epcom_break(sc, 0);
4484e771f5dSjoff 	epcom_set(sc);
4494e771f5dSjoff 
4504e771f5dSjoff 	if (sc->disable) {
4514e771f5dSjoff #ifdef DIAGNOSTIC
4524e771f5dSjoff 		if (!sc->enabled)
4534e771f5dSjoff 			panic("epcom_shutdown: not enabled?");
4544e771f5dSjoff #endif
4554e771f5dSjoff 		(*sc->disable)(sc);
4564e771f5dSjoff 		sc->enabled = 0;
4574e771f5dSjoff 	}
4584e771f5dSjoff 	splx(s);
4594e771f5dSjoff }
4604e771f5dSjoff 
4614e771f5dSjoff int
epcomopen(dev_t dev,int flag,int mode,struct lwp * l)4620e9d2fc1Schristos epcomopen(dev_t dev, int flag, int mode, struct lwp *l)
4634e771f5dSjoff {
4644e771f5dSjoff 	struct epcom_softc *sc;
4654e771f5dSjoff 	struct tty *tp;
4664e771f5dSjoff 	int s, s2;
4674e771f5dSjoff 	int error;
4684e771f5dSjoff 
4695402ae69Scegger 	sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
4704e771f5dSjoff 	if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK) ||
4714e771f5dSjoff 		sc->sc_rbuf == NULL)
4724e771f5dSjoff 		return (ENXIO);
4734e771f5dSjoff 
474cbab9cadSchs 	if (!device_is_active(sc->sc_dev))
4754e771f5dSjoff 		return (ENXIO);
4764e771f5dSjoff 
4774e771f5dSjoff #ifdef KGDB
4784e771f5dSjoff 	/*
4794e771f5dSjoff 	 * If this is the kgdb port, no other use is permitted.
4804e771f5dSjoff 	 */
4814e771f5dSjoff 	if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
4824e771f5dSjoff 		return (EBUSY);
4834e771f5dSjoff #endif
4844e771f5dSjoff 
4854e771f5dSjoff 	tp = sc->sc_tty;
4864e771f5dSjoff 
487e8373398Selad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
4884e771f5dSjoff 		return (EBUSY);
4894e771f5dSjoff 
4904e771f5dSjoff 	s = spltty();
4914e771f5dSjoff 
4924e771f5dSjoff 	/*
4934e771f5dSjoff 	 * Do the following iff this is a first open.
4944e771f5dSjoff 	 */
4954e771f5dSjoff 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
4964e771f5dSjoff 		struct termios t;
4974e771f5dSjoff 
4984e771f5dSjoff 		tp->t_dev = dev;
4994e771f5dSjoff 
5004e771f5dSjoff 		s2 = splserial();
5014e771f5dSjoff 
5024e771f5dSjoff 		if (sc->enable) {
5034e771f5dSjoff 			if ((*sc->enable)(sc)) {
5044e771f5dSjoff 				splx(s2);
5054e771f5dSjoff 				splx(s);
5064e771f5dSjoff 				printf("%s: device enable failed\n",
507cbab9cadSchs 				       device_xname(sc->sc_dev));
5084e771f5dSjoff 				return (EIO);
5094e771f5dSjoff 			}
5104e771f5dSjoff 			sc->enabled = 1;
5114e771f5dSjoff #if 0
5124e771f5dSjoff /* XXXXXXXXXXXXXXX */
5134e771f5dSjoff 			com_config(sc);
5144e771f5dSjoff #endif
5154e771f5dSjoff 		}
5164e771f5dSjoff 
5174e771f5dSjoff 		/* Turn on interrupts. */
5184e771f5dSjoff 		SET(sc->sc_ctrl, (Ctrl_UARTE|Ctrl_RIE|Ctrl_RTIE));
5194e771f5dSjoff 		epcom_set(sc);
5204e771f5dSjoff 
5214e771f5dSjoff #if 0
5224e771f5dSjoff 		/* Fetch the current modem control status, needed later. */
5234e771f5dSjoff 		sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_msr);
5244e771f5dSjoff 
5254e771f5dSjoff 		/* Clear PPS capture state on first open. */
5264e771f5dSjoff 		sc->sc_ppsmask = 0;
5274e771f5dSjoff 		sc->ppsparam.mode = 0;
5284e771f5dSjoff #endif
5294e771f5dSjoff 
5304e771f5dSjoff 		splx(s2);
5314e771f5dSjoff 
5324e771f5dSjoff 		/*
5334e771f5dSjoff 		 * Initialize the termios status to the defaults.  Add in the
5344e771f5dSjoff 		 * sticky bits from TIOCSFLAGS.
5354e771f5dSjoff 		 */
5364e771f5dSjoff 		t.c_ispeed = 0;
5374e771f5dSjoff 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
5384e771f5dSjoff 			t.c_ospeed = epcomcn_sc.sc_ospeed;
5394e771f5dSjoff 			t.c_cflag = epcomcn_sc.sc_cflag;
5404e771f5dSjoff 		} else {
5414e771f5dSjoff 			t.c_ospeed = TTYDEF_SPEED;
5424e771f5dSjoff 			t.c_cflag = TTYDEF_CFLAG;
5434e771f5dSjoff 		}
5444e771f5dSjoff 		if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
5454e771f5dSjoff 			SET(t.c_cflag, CLOCAL);
5464e771f5dSjoff 		if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
5474e771f5dSjoff 			SET(t.c_cflag, CRTSCTS);
5484e771f5dSjoff 		if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
5494e771f5dSjoff 			SET(t.c_cflag, MDMBUF);
5504e771f5dSjoff 		/* Make sure epcomparam() will do something. */
5514e771f5dSjoff 		tp->t_ospeed = 0;
5524e771f5dSjoff 		(void) epcomparam(tp, &t);
5534e771f5dSjoff 		tp->t_iflag = TTYDEF_IFLAG;
5544e771f5dSjoff 		tp->t_oflag = TTYDEF_OFLAG;
5554e771f5dSjoff 		tp->t_lflag = TTYDEF_LFLAG;
5564e771f5dSjoff 		ttychars(tp);
5574e771f5dSjoff 		ttsetwater(tp);
5584e771f5dSjoff 
5594e771f5dSjoff 		s2 = splserial();
5604e771f5dSjoff 
5614e771f5dSjoff 		/* Clear the input ring, and unblock. */
5624e771f5dSjoff 		sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
5634e771f5dSjoff 		sc->sc_rbavail = EPCOM_RING_SIZE;
5644e771f5dSjoff 		epcom_iflush(sc);
5654e771f5dSjoff 		CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
5664e771f5dSjoff 
5674e771f5dSjoff #ifdef COM_DEBUG
5684e771f5dSjoff 		if (epcom_debug)
5694e771f5dSjoff 			comstatus(sc, "epcomopen  ");
5704e771f5dSjoff #endif
5714e771f5dSjoff 
5724e771f5dSjoff 		splx(s2);
5734e771f5dSjoff 	}
5744e771f5dSjoff 
5754e771f5dSjoff 	splx(s);
5764e771f5dSjoff 
5774e771f5dSjoff 	error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
5784e771f5dSjoff 	if (error)
5794e771f5dSjoff 		goto bad;
5804e771f5dSjoff 
5814e771f5dSjoff 	error = (*tp->t_linesw->l_open)(dev, tp);
5824e771f5dSjoff 	if (error)
5834e771f5dSjoff 		goto bad;
5844e771f5dSjoff 
5854e771f5dSjoff 	return (0);
5864e771f5dSjoff 
5874e771f5dSjoff bad:
5884e771f5dSjoff 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
5894e771f5dSjoff 		/*
5904e771f5dSjoff 		 * We failed to open the device, and nobody else had it opened.
5914e771f5dSjoff 		 * Clean up the state as appropriate.
5924e771f5dSjoff 		 */
5934e771f5dSjoff 		epcom_shutdown(sc);
5944e771f5dSjoff 	}
5954e771f5dSjoff 
5964e771f5dSjoff 	return (error);
5974e771f5dSjoff }
5984e771f5dSjoff 
5994e771f5dSjoff int
epcomclose(dev_t dev,int flag,int mode,struct lwp * l)6000e9d2fc1Schristos epcomclose(dev_t dev, int flag, int mode, struct lwp *l)
6014e771f5dSjoff {
6025402ae69Scegger 	struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
6034e771f5dSjoff 	struct tty *tp = sc->sc_tty;
6044e771f5dSjoff 
6054e771f5dSjoff 	/* XXX This is for cons.c. */
6064e771f5dSjoff 	if (!ISSET(tp->t_state, TS_ISOPEN))
6074e771f5dSjoff 		return (0);
6084e771f5dSjoff 
6094e771f5dSjoff 	(*tp->t_linesw->l_close)(tp, flag);
6104e771f5dSjoff 	ttyclose(tp);
6114e771f5dSjoff 
6124e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
6134e771f5dSjoff 		return (0);
6144e771f5dSjoff 
6154e771f5dSjoff 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
6164e771f5dSjoff 		/*
6174e771f5dSjoff 		 * Although we got a last close, the device may still be in
6184e771f5dSjoff 		 * use; e.g. if this was the dialout node, and there are still
6194e771f5dSjoff 		 * processes waiting for carrier on the non-dialout node.
6204e771f5dSjoff 		 */
6214e771f5dSjoff 		epcom_shutdown(sc);
6224e771f5dSjoff 	}
6234e771f5dSjoff 
6244e771f5dSjoff 	return (0);
6254e771f5dSjoff }
6264e771f5dSjoff 
6274e771f5dSjoff int
epcomread(dev_t dev,struct uio * uio,int flag)6280e9d2fc1Schristos epcomread(dev_t dev, struct uio *uio, int flag)
6294e771f5dSjoff {
6305402ae69Scegger 	struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
6314e771f5dSjoff 	struct tty *tp = sc->sc_tty;
6324e771f5dSjoff 
6334e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
6344e771f5dSjoff 		return (EIO);
6354e771f5dSjoff 
6364e771f5dSjoff 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
6374e771f5dSjoff }
6384e771f5dSjoff 
6394e771f5dSjoff int
epcomwrite(dev_t dev,struct uio * uio,int flag)6400e9d2fc1Schristos epcomwrite(dev_t dev, struct uio *uio, int flag)
6414e771f5dSjoff {
6425402ae69Scegger 	struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
6434e771f5dSjoff 	struct tty *tp = sc->sc_tty;
6444e771f5dSjoff 
6454e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
6464e771f5dSjoff 		return (EIO);
6474e771f5dSjoff 
6484e771f5dSjoff 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
6494e771f5dSjoff }
6504e771f5dSjoff 
6514e771f5dSjoff int
epcompoll(dev_t dev,int events,struct lwp * l)6520e9d2fc1Schristos epcompoll(dev_t dev, int events, struct lwp *l)
6534e771f5dSjoff {
6545402ae69Scegger 	struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
6554e771f5dSjoff 	struct tty *tp = sc->sc_tty;
6564e771f5dSjoff 
6574e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
6584e771f5dSjoff 		return (EIO);
6594e771f5dSjoff 
6600e9d2fc1Schristos 	return ((*tp->t_linesw->l_poll)(tp, events, l));
6614e771f5dSjoff }
6624e771f5dSjoff 
6634e771f5dSjoff struct tty *
epcomtty(dev_t dev)6640e9d2fc1Schristos epcomtty(dev_t dev)
6654e771f5dSjoff {
6665402ae69Scegger 	struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
6674e771f5dSjoff 	struct tty *tp = sc->sc_tty;
6684e771f5dSjoff 
6694e771f5dSjoff 	return (tp);
6704e771f5dSjoff }
6714e771f5dSjoff 
6724e771f5dSjoff int
epcomioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)67353524e44Schristos epcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
6744e771f5dSjoff {
6755402ae69Scegger 	struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev));
6764e771f5dSjoff 	struct tty *tp = sc->sc_tty;
6774e771f5dSjoff 	int error;
6784e771f5dSjoff 	int s;
6794e771f5dSjoff 
6804e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
6814e771f5dSjoff 		return (EIO);
6824e771f5dSjoff 
6830e9d2fc1Schristos 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
6844e771f5dSjoff 	if (error != EPASSTHROUGH)
6854e771f5dSjoff 		return (error);
6864e771f5dSjoff 
6870e9d2fc1Schristos 	error = ttioctl(tp, cmd, data, flag, l);
6884e771f5dSjoff 	if (error != EPASSTHROUGH)
6894e771f5dSjoff 		return (error);
6904e771f5dSjoff 
6914e771f5dSjoff 	error = 0;
6924e771f5dSjoff 
6934e771f5dSjoff 	s = splserial();
6944e771f5dSjoff 
6954e771f5dSjoff 	switch (cmd) {
6964e771f5dSjoff 	case TIOCSBRK:
6974e771f5dSjoff 		epcom_break(sc, 1);
6984e771f5dSjoff 		break;
6994e771f5dSjoff 
7004e771f5dSjoff 	case TIOCCBRK:
7014e771f5dSjoff 		epcom_break(sc, 0);
7024e771f5dSjoff 		break;
7034e771f5dSjoff 
7044e771f5dSjoff 	case TIOCGFLAGS:
7054e771f5dSjoff 		*(int *)data = sc->sc_swflags;
7064e771f5dSjoff 		break;
7074e771f5dSjoff 
7084e771f5dSjoff 	case TIOCSFLAGS:
70965792a03Selad 		error = kauth_authorize_device_tty(l->l_cred,
71065792a03Selad 		    KAUTH_DEVICE_TTY_PRIVSET, tp);
7114e771f5dSjoff 		if (error)
7124e771f5dSjoff 			break;
7134e771f5dSjoff 		sc->sc_swflags = *(int *)data;
7144e771f5dSjoff 		break;
7154e771f5dSjoff 
7164e771f5dSjoff 	default:
7174e771f5dSjoff 		error = EPASSTHROUGH;
7184e771f5dSjoff 		break;
7194e771f5dSjoff 	}
7204e771f5dSjoff 
7214e771f5dSjoff 	splx(s);
7224e771f5dSjoff 
7234e771f5dSjoff 	return (error);
7244e771f5dSjoff }
7254e771f5dSjoff 
7264e771f5dSjoff /*
7274e771f5dSjoff  * Stop output on a line.
7284e771f5dSjoff  */
7294e771f5dSjoff void
epcomstop(struct tty * tp,int flag)7300e9d2fc1Schristos epcomstop(struct tty *tp, int flag)
7314e771f5dSjoff {
7324e771f5dSjoff 	struct epcom_softc *sc
7335402ae69Scegger 		= device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev));
7344e771f5dSjoff 	int s;
7354e771f5dSjoff 
7364e771f5dSjoff 	s = splserial();
7374e771f5dSjoff 	if (ISSET(tp->t_state, TS_BUSY)) {
7384e771f5dSjoff 		/* Stop transmitting at the next chunk. */
7394e771f5dSjoff 		sc->sc_tbc = 0;
7404e771f5dSjoff 		if (!ISSET(tp->t_state, TS_TTSTOP))
7414e771f5dSjoff 			SET(tp->t_state, TS_FLUSH);
7424e771f5dSjoff 	}
7434e771f5dSjoff 	splx(s);
7444e771f5dSjoff }
7454e771f5dSjoff 
7464e771f5dSjoff static u_int
cflag2lcrhi(tcflag_t cflag)7470e9d2fc1Schristos cflag2lcrhi(tcflag_t cflag)
7484e771f5dSjoff {
7494e771f5dSjoff 	u_int lcrhi;
7504e771f5dSjoff 
7514e771f5dSjoff 	switch (cflag & CSIZE) {
7524e771f5dSjoff 	case CS7:
7534e771f5dSjoff 		lcrhi = 0x40;
7544e771f5dSjoff 		break;
7554e771f5dSjoff 	case CS6:
7564e771f5dSjoff 		lcrhi = 0x20;
7574e771f5dSjoff 		break;
7584e771f5dSjoff 	case CS8:
7594e771f5dSjoff 	default:
7604e771f5dSjoff 		lcrhi = 0x60;
7614e771f5dSjoff 		break;
7624e771f5dSjoff 	}
7634e771f5dSjoff 	lcrhi |= (cflag & PARENB) ? LinCtrlHigh_PEN : 0;
7644e771f5dSjoff 	lcrhi |= (cflag & PARODD) ? 0 : LinCtrlHigh_EPS;
7654e771f5dSjoff 	lcrhi |= (cflag & CSTOPB) ? LinCtrlHigh_STP2 : 0;
7664e771f5dSjoff 	lcrhi |= LinCtrlHigh_FEN;  /* FIFO always enabled */
7674e771f5dSjoff 
7684e771f5dSjoff 	return (lcrhi);
7694e771f5dSjoff }
7704e771f5dSjoff 
7714e771f5dSjoff static void
epcom_iflush(struct epcom_softc * sc)7720e9d2fc1Schristos epcom_iflush(struct epcom_softc *sc)
7734e771f5dSjoff {
7744e771f5dSjoff 	bus_space_tag_t iot = sc->sc_iot;
7754e771f5dSjoff 	bus_space_handle_t ioh = sc->sc_ioh;
7764e771f5dSjoff #ifdef DIAGNOSTIC
7774e771f5dSjoff 	int reg;
7784e771f5dSjoff #endif
7794e771f5dSjoff 	int timo;
7804e771f5dSjoff 
7814e771f5dSjoff #ifdef DIAGNOSTIC
7824e771f5dSjoff 	reg = 0xffff;
7834e771f5dSjoff #endif
7844e771f5dSjoff 	timo = 50000;
7854e771f5dSjoff 	/* flush any pending I/O */
7864e771f5dSjoff 	while ((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_RXFE) == 0
7874e771f5dSjoff 	       && --timo)
7884e771f5dSjoff #ifdef DIAGNOSTIC
7894e771f5dSjoff 		reg =
7904e771f5dSjoff #else
7914e771f5dSjoff 			(void)
7924e771f5dSjoff #endif
7934e771f5dSjoff 			bus_space_read_4(iot, ioh, EPCOM_Data);
7944e771f5dSjoff #ifdef DIAGNOSTIC
7954e771f5dSjoff 	if (!timo)
796cbab9cadSchs 		printf("%s: com_iflush timeout %02x\n", device_xname(sc->sc_dev),
7974e771f5dSjoff 		       reg);
7984e771f5dSjoff #endif
7994e771f5dSjoff }
8004e771f5dSjoff 
8014e771f5dSjoff static void
epcom_set(struct epcom_softc * sc)8024e771f5dSjoff epcom_set(struct epcom_softc *sc)
8034e771f5dSjoff {
8044e771f5dSjoff 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlLow,
8054e771f5dSjoff 			  sc->sc_lcrlo);
8064e771f5dSjoff 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlMid,
8074e771f5dSjoff 			  sc->sc_lcrmid);
8084e771f5dSjoff 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlHigh,
8094e771f5dSjoff 			  sc->sc_lcrhi);
8104e771f5dSjoff 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_Ctrl,
8114e771f5dSjoff 			  sc->sc_ctrl);
8124e771f5dSjoff }
8134e771f5dSjoff 
8144e771f5dSjoff int
epcomcnattach(bus_space_tag_t iot,bus_addr_t iobase,bus_space_handle_t ioh,int ospeed,tcflag_t cflag)8150e9d2fc1Schristos epcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh,
8160e9d2fc1Schristos     int ospeed, tcflag_t cflag)
8174e771f5dSjoff {
8184e771f5dSjoff 	cn_tab = &epcomcons;
8194e771f5dSjoff 	cn_init_magic(&epcom_cnm_state);
8204e771f5dSjoff 	cn_set_magic("\047\001");
8214e771f5dSjoff 
8229d134cf5Sskrll 	epcominit(&epcomcn_sc, iot, iobase, ioh, ospeed, cflag);
8234e771f5dSjoff 
8244e771f5dSjoff 	return (0);
8254e771f5dSjoff }
8264e771f5dSjoff 
8274e771f5dSjoff void
epcomcnprobe(struct consdev * cp)8280e9d2fc1Schristos epcomcnprobe(struct consdev *cp)
8294e771f5dSjoff {
8304e771f5dSjoff 	cp->cn_pri = CN_REMOTE;
8314e771f5dSjoff }
8324e771f5dSjoff 
8334e771f5dSjoff void
epcomcnpollc(dev_t dev,int on)8340e9d2fc1Schristos epcomcnpollc(dev_t dev, int on)
8354e771f5dSjoff {
8364e771f5dSjoff }
8374e771f5dSjoff 
8384e771f5dSjoff void
epcomcnputc(dev_t dev,int c)8390e9d2fc1Schristos epcomcnputc(dev_t dev, int c)
8404e771f5dSjoff {
8419d134cf5Sskrll 	epcom_common_putc(&epcomcn_sc, c);
8429d134cf5Sskrll }
8439d134cf5Sskrll 
8449d134cf5Sskrll static void
epcom_common_putc(struct epcom_cons_softc * sc,int c)8459d134cf5Sskrll epcom_common_putc(struct epcom_cons_softc *sc, int c)
8469d134cf5Sskrll {
8474e771f5dSjoff 	int			s;
8489d134cf5Sskrll 	bus_space_tag_t		iot = sc->sc_iot;
8499d134cf5Sskrll 	bus_space_handle_t	ioh = sc->sc_ioh;
8504e771f5dSjoff 
8514e771f5dSjoff 	s = splserial();
8524e771f5dSjoff 
8534e771f5dSjoff 	while((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFF) != 0)
8544e771f5dSjoff 		;
8554e771f5dSjoff 
8564e771f5dSjoff 	bus_space_write_4(iot, ioh, EPCOM_Data, c);
8574e771f5dSjoff 
8584e771f5dSjoff #ifdef DEBUG
8594e771f5dSjoff 	if (c == '\r') {
8604e771f5dSjoff 		while((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFE) == 0)
8614e771f5dSjoff 			;
8624e771f5dSjoff 	}
8634e771f5dSjoff #endif
8644e771f5dSjoff 
8654e771f5dSjoff 	splx(s);
8664e771f5dSjoff }
8674e771f5dSjoff 
8684e771f5dSjoff int
epcomcngetc(dev_t dev)8690e9d2fc1Schristos epcomcngetc(dev_t dev)
8704e771f5dSjoff {
8719d134cf5Sskrll 	return epcom_common_getc (&epcomcn_sc, dev);
8729d134cf5Sskrll }
8739d134cf5Sskrll 
8749d134cf5Sskrll static int
epcom_common_getc(struct epcom_cons_softc * sc,dev_t dev)8759d134cf5Sskrll epcom_common_getc(struct epcom_cons_softc *sc, dev_t dev)
8769d134cf5Sskrll {
8774e771f5dSjoff 	int			c, sts;
8784e771f5dSjoff 	int			s;
8799d134cf5Sskrll 	bus_space_tag_t		iot = sc->sc_iot;
8809d134cf5Sskrll 	bus_space_handle_t	ioh = sc->sc_ioh;
8814e771f5dSjoff 
8824e771f5dSjoff         s = splserial();
8834e771f5dSjoff 
8844e771f5dSjoff 	while ((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_RXFE) != 0)
885*dbfa10e5Sriastradh 		continue;
8864e771f5dSjoff 
8874e771f5dSjoff 	c = bus_space_read_4(iot, ioh, EPCOM_Data);
8884e771f5dSjoff 	sts = bus_space_read_4(iot, ioh, EPCOM_RXSts);
889*dbfa10e5Sriastradh 	if (ISSET(sts, RXSts_BE))
890*dbfa10e5Sriastradh 		c = CNC_BREAK;
891*dbfa10e5Sriastradh 	if (!db_active) {
8929180e146Sskrll 		int cn_trapped __unused = 0;
8934e771f5dSjoff 
8944e771f5dSjoff 		cn_check_magic(dev, c, epcom_cnm_state);
8954e771f5dSjoff 	}
8964e771f5dSjoff 	c &= 0xff;
8974e771f5dSjoff 	splx(s);
8984e771f5dSjoff 
8994e771f5dSjoff 	return (c);
9004e771f5dSjoff }
9014e771f5dSjoff 
9024e771f5dSjoff inline static void
epcom_txsoft(struct epcom_softc * sc,struct tty * tp)9030e9d2fc1Schristos epcom_txsoft(struct epcom_softc *sc, struct tty *tp)
9044e771f5dSjoff {
9054e771f5dSjoff 	CLR(tp->t_state, TS_BUSY);
9064e771f5dSjoff 	if (ISSET(tp->t_state, TS_FLUSH))
9074e771f5dSjoff 		CLR(tp->t_state, TS_FLUSH);
9084e771f5dSjoff         else
9094e771f5dSjoff 		ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
9104e771f5dSjoff 	(*tp->t_linesw->l_start)(tp);
9114e771f5dSjoff }
9124e771f5dSjoff 
9134e771f5dSjoff inline static void
epcom_rxsoft(struct epcom_softc * sc,struct tty * tp)9140e9d2fc1Schristos epcom_rxsoft(struct epcom_softc *sc, struct tty *tp)
9154e771f5dSjoff {
91602cdf4d2Sdsl 	int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
9174e771f5dSjoff 	u_char *get, *end;
9184e771f5dSjoff 	u_int cc, scc;
9194e771f5dSjoff 	u_char sts;
9204e771f5dSjoff 	int code;
9214e771f5dSjoff 	int s;
9224e771f5dSjoff 
9234e771f5dSjoff 	end = sc->sc_ebuf;
9244e771f5dSjoff 	get = sc->sc_rbget;
9254e771f5dSjoff 	scc = cc = EPCOM_RING_SIZE - sc->sc_rbavail;
9264e771f5dSjoff #if 0
9274e771f5dSjoff 	if (cc == EPCOM_RING_SIZE) {
9284e771f5dSjoff 		sc->sc_floods++;
9294e771f5dSjoff 		if (sc->sc_errors++ == 0)
9304e771f5dSjoff 			callout_reset(&sc->sc_diag_callout, 60 * hz,
9314e771f5dSjoff 			    comdiag, sc);
9324e771f5dSjoff 	}
9334e771f5dSjoff #endif
9344e771f5dSjoff 	while (cc) {
9354e771f5dSjoff 		code = get[0];
9364e771f5dSjoff 		sts = get[1];
9374e771f5dSjoff 		if (ISSET(sts, RXSts_OE | RXSts_FE | RXSts_PE | RXSts_BE)) {
9384e771f5dSjoff #if 0
9394e771f5dSjoff 			if (ISSET(lsr, DR_ROR)) {
9404e771f5dSjoff 				sc->sc_overflows++;
9414e771f5dSjoff 				if (sc->sc_errors++ == 0)
9424e771f5dSjoff 					callout_reset(&sc->sc_diag_callout,
9434e771f5dSjoff 					    60 * hz, comdiag, sc);
9444e771f5dSjoff 			}
9454e771f5dSjoff #endif
9464e771f5dSjoff 			if (ISSET(sts, (RXSts_FE|RXSts_BE)))
9474e771f5dSjoff 				SET(code, TTY_FE);
9484e771f5dSjoff 			if (ISSET(sts, RXSts_PE))
9494e771f5dSjoff 				SET(code, TTY_PE);
9504e771f5dSjoff 		}
9514e771f5dSjoff 		if ((*rint)(code, tp) == -1) {
9524e771f5dSjoff 			/*
9534e771f5dSjoff 			 * The line discipline's buffer is out of space.
9544e771f5dSjoff 			 */
9554e771f5dSjoff 			if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
9564e771f5dSjoff 				/*
9574e771f5dSjoff 				 * We're either not using flow control, or the
9584e771f5dSjoff 				 * line discipline didn't tell us to block for
9594e771f5dSjoff 				 * some reason.  Either way, we have no way to
9604e771f5dSjoff 				 * know when there's more space available, so
9614e771f5dSjoff 				 * just drop the rest of the data.
9624e771f5dSjoff 				 */
9634e771f5dSjoff 				get += cc << 1;
9644e771f5dSjoff 				if (get >= end)
9654e771f5dSjoff 					get -= EPCOM_RING_SIZE << 1;
9664e771f5dSjoff 				cc = 0;
9674e771f5dSjoff 			} else {
9684e771f5dSjoff 				/*
9694e771f5dSjoff 				 * Don't schedule any more receive processing
9704e771f5dSjoff 				 * until the line discipline tells us there's
9714e771f5dSjoff 				 * space available (through comhwiflow()).
9724e771f5dSjoff 				 * Leave the rest of the data in the input
9734e771f5dSjoff 				 * buffer.
9744e771f5dSjoff 				 */
9754e771f5dSjoff 				SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
9764e771f5dSjoff 			}
9774e771f5dSjoff 			break;
9784e771f5dSjoff 		}
9794e771f5dSjoff 		get += 2;
9804e771f5dSjoff 		if (get >= end)
9814e771f5dSjoff 			get = sc->sc_rbuf;
9824e771f5dSjoff 		cc--;
9834e771f5dSjoff 	}
9844e771f5dSjoff 
9854e771f5dSjoff 	if (cc != scc) {
9864e771f5dSjoff 		sc->sc_rbget = get;
9874e771f5dSjoff 		s = splserial();
9884e771f5dSjoff 
9894e771f5dSjoff 		cc = sc->sc_rbavail += scc - cc;
9904e771f5dSjoff 		/* Buffers should be ok again, release possible block. */
9914e771f5dSjoff 		if (cc >= 1) {
9924e771f5dSjoff 			if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
9934e771f5dSjoff 				CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
9944e771f5dSjoff 				SET(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE));
9954e771f5dSjoff 				epcom_set(sc);
9964e771f5dSjoff 			}
9974e771f5dSjoff 			if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
9984e771f5dSjoff 				CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
9994e771f5dSjoff #if 0
10004e771f5dSjoff 				com_hwiflow(sc);
10014e771f5dSjoff #endif
10024e771f5dSjoff 			}
10034e771f5dSjoff 		}
10044e771f5dSjoff 		splx(s);
10054e771f5dSjoff 	}
10064e771f5dSjoff }
10074e771f5dSjoff 
10084e771f5dSjoff static void
epcomsoft(void * arg)10094e771f5dSjoff epcomsoft(void* arg)
10104e771f5dSjoff {
10114e771f5dSjoff 	struct epcom_softc *sc = arg;
10124e771f5dSjoff 
10134e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
10144e771f5dSjoff 		return;
10154e771f5dSjoff 
10164e771f5dSjoff 	if (sc->sc_rx_ready) {
10174e771f5dSjoff 		sc->sc_rx_ready = 0;
10184e771f5dSjoff 		epcom_rxsoft(sc, sc->sc_tty);
10194e771f5dSjoff 	}
10204e771f5dSjoff 	if (sc->sc_tx_done) {
10214e771f5dSjoff 		sc->sc_tx_done = 0;
10224e771f5dSjoff 		epcom_txsoft(sc, sc->sc_tty);
10234e771f5dSjoff 	}
10244e771f5dSjoff }
10254e771f5dSjoff 
10264e771f5dSjoff int
epcomintr(void * arg)10274e771f5dSjoff epcomintr(void* arg)
10284e771f5dSjoff {
10294e771f5dSjoff 	struct epcom_softc *sc = arg;
10304e771f5dSjoff 	bus_space_tag_t iot = sc->sc_iot;
10314e771f5dSjoff 	bus_space_handle_t ioh = sc->sc_ioh;
10324e771f5dSjoff 	u_char *put, *end;
10334e771f5dSjoff 	u_int cc;
10344e771f5dSjoff 	u_int flagr;
103508a4aba7Sskrll 	uint32_t c, csts;
10364e771f5dSjoff 
10379180e146Sskrll 	(void) bus_space_read_4(iot, ioh, EPCOM_IntIDIntClr);
10384e771f5dSjoff 
10394e771f5dSjoff 	if (COM_ISALIVE(sc) == 0)
10404e771f5dSjoff 		panic("intr on disabled epcom");
10414e771f5dSjoff 
10424e771f5dSjoff 	flagr = bus_space_read_4(iot, ioh, EPCOM_Flag);
10434e771f5dSjoff 
10444e771f5dSjoff 	end = sc->sc_ebuf;
10454e771f5dSjoff 	put = sc->sc_rbput;
10464e771f5dSjoff 	cc = sc->sc_rbavail;
10474e771f5dSjoff 
10484e771f5dSjoff 	if (!(ISSET(flagr, Flag_RXFE))) {
10494e771f5dSjoff 		if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
10504e771f5dSjoff 			while (cc > 0) {
10514e771f5dSjoff 				if (ISSET(flagr, Flag_RXFE))
10524e771f5dSjoff 					break;
10534e771f5dSjoff 				c = bus_space_read_4(iot, ioh, EPCOM_Data);
10544e771f5dSjoff 				csts = bus_space_read_4(iot, ioh, EPCOM_RXSts);
10554e771f5dSjoff 				if (ISSET(csts, RXSts_BE)) {
10564e771f5dSjoff 					int cn_trapped = 0;
10574e771f5dSjoff 
10584e771f5dSjoff 					cn_check_magic(sc->sc_tty->t_dev,
10594e771f5dSjoff 					  CNC_BREAK, epcom_cnm_state);
10604e771f5dSjoff 					if (cn_trapped)
10614e771f5dSjoff 						goto next;
10624e771f5dSjoff #if defined(KGDB) && !defined(DDB)
10634e771f5dSjoff 					if (ISSET(sc->sc_hwflags, COM_HW_KGDB)){
10644e771f5dSjoff 						kgdb_connect(1);
10654e771f5dSjoff 						goto next;
10664e771f5dSjoff 					}
10674e771f5dSjoff #endif
10684e771f5dSjoff 				} else {
10694e771f5dSjoff 					int cn_trapped = 0;
10704e771f5dSjoff 
10714e771f5dSjoff 					cn_check_magic(sc->sc_tty->t_dev,
10724e771f5dSjoff 					  (c & 0xff), epcom_cnm_state);
10734e771f5dSjoff 					if (cn_trapped)
10744e771f5dSjoff 						goto next;
10754e771f5dSjoff 				}
10764e771f5dSjoff 
10774e771f5dSjoff 
10784e771f5dSjoff 				put[0] = c & 0xff;
10794e771f5dSjoff 				put[1] = csts & 0xf;
10804e771f5dSjoff 				put += 2;
10814e771f5dSjoff 				if (put >= end)
10824e771f5dSjoff 					put = sc->sc_rbuf;
10834e771f5dSjoff 				cc--;
10844e771f5dSjoff 			next:
10854e771f5dSjoff 				flagr = bus_space_read_4(iot, ioh, EPCOM_Flag);
10864e771f5dSjoff 			}
10874e771f5dSjoff 
10884e771f5dSjoff 			/*
10894e771f5dSjoff 			 * Current string of incoming characters ended because
10904e771f5dSjoff 			 * no more data was available or we ran out of space.
10914e771f5dSjoff 			 * Schedule a receive event if any data was received.
10924e771f5dSjoff 			 * If we're out of space, turn off receive interrupts.
10934e771f5dSjoff 			 */
10944e771f5dSjoff 			sc->sc_rbput = put;
10954e771f5dSjoff 			sc->sc_rbavail = cc;
10964e771f5dSjoff 			if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
10974e771f5dSjoff 				sc->sc_rx_ready = 1;
10984e771f5dSjoff 
10994e771f5dSjoff 			/*
11004e771f5dSjoff 			 * See if we are in danger of overflowing a buffer. If
11014e771f5dSjoff 			 * so, use hardware flow control to ease the pressure.
11024e771f5dSjoff 			 */
11034e771f5dSjoff 
11044e771f5dSjoff 			/* but epcom cannot. X-( */
11054e771f5dSjoff 
11064e771f5dSjoff 			/*
11074e771f5dSjoff 			 * If we're out of space, disable receive interrupts
11084e771f5dSjoff 			 * until the queue has drained a bit.
11094e771f5dSjoff 			 */
11104e771f5dSjoff 			if (!cc) {
11114e771f5dSjoff 				SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
11124e771f5dSjoff 				CLR(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE));
11134e771f5dSjoff 				epcom_set(sc);
11144e771f5dSjoff 			}
11154e771f5dSjoff 		} else {
11164e771f5dSjoff #ifdef DIAGNOSTIC
11174e771f5dSjoff 			panic("epcomintr: we shouldn't reach here");
11184e771f5dSjoff #endif
11194e771f5dSjoff 			CLR(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE));
11204e771f5dSjoff 			epcom_set(sc);
11214e771f5dSjoff 		}
11224e771f5dSjoff 	}
11234e771f5dSjoff 
11244e771f5dSjoff 	/*
11254e771f5dSjoff 	 * Done handling any receive interrupts. See if data can be
11264e771f5dSjoff 	 * transmitted as well. Schedule tx done event if no data left
11274e771f5dSjoff 	 * and tty was marked busy.
11284e771f5dSjoff 	 */
11294e771f5dSjoff 
11305beb7d30Sjoff 	if (!ISSET(flagr, Flag_TXFF) && sc->sc_tbc > 0) {
11314e771f5dSjoff 		/* Output the next chunk of the contiguous buffer, if any. */
11324e771f5dSjoff 		epcom_filltx(sc);
11334e771f5dSjoff 	} else {
11344e771f5dSjoff 		/* Disable transmit completion interrupts if necessary. */
11354e771f5dSjoff 		if (ISSET(sc->sc_ctrl, Ctrl_TIE)) {
11364e771f5dSjoff 			CLR(sc->sc_ctrl, Ctrl_TIE);
11374e771f5dSjoff 			epcom_set(sc);
11384e771f5dSjoff 		}
11394e771f5dSjoff 		if (sc->sc_tx_busy) {
11404e771f5dSjoff 			sc->sc_tx_busy = 0;
11414e771f5dSjoff 			sc->sc_tx_done = 1;
11424e771f5dSjoff 		}
11434e771f5dSjoff 	}
11444e771f5dSjoff 
11454e771f5dSjoff 	/* Wake up the poller. */
11460c0de807Smatt 	softint_schedule(sc->sc_si);
11474e771f5dSjoff 
11484e771f5dSjoff #if 0 /* XXX: broken */
11497b0b7dedStls #ifdef RND_COM
11504e771f5dSjoff 	rnd_add_uint32(&sc->rnd_source, intr ^ flagr);
11514e771f5dSjoff #endif
11524e771f5dSjoff #endif
11534e771f5dSjoff 	return (1);
11544e771f5dSjoff }
11559d134cf5Sskrll 
11569d134cf5Sskrll #ifdef KGDB
11579d134cf5Sskrll int
epcom_kgdb_attach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)11589d134cf5Sskrll epcom_kgdb_attach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
11599d134cf5Sskrll 		  tcflag_t cflag)
11609d134cf5Sskrll {
11619d134cf5Sskrll 	bus_space_handle_t ioh;
11629d134cf5Sskrll 
11639d134cf5Sskrll 	if (iot == epcomcn_sc.sc_iot && iobase == epcomcn_sc.sc_hwbase) {
11649d134cf5Sskrll #if !defined(DDB)
11659d134cf5Sskrll 		return EBUSY; /* cannot share with console */
11669d134cf5Sskrll #else
11679d134cf5Sskrll 		/*
11689d134cf5Sskrll 		 * XXX I have no intention of ever testing and code path
11699d134cf5Sskrll 		 * implied by getting here
11709d134cf5Sskrll 		 */
11719d134cf5Sskrll 		kgdb_sc = epcomcn_sc;
11729d134cf5Sskrll #endif
11739d134cf5Sskrll 	} else {
11749d134cf5Sskrll 		bus_space_map(iot, iobase, EP93XX_APB_UART_SIZE, 0, &ioh);
11759d134cf5Sskrll 		epcominit(&kgdb_sc, iot, iobase, ioh, rate, cflag);
11769d134cf5Sskrll 	}
11779d134cf5Sskrll 
11789d134cf5Sskrll 	kgdb_attach(epcom_kgdb_getc, epcom_kgdb_putc, &kgdb_sc);
11799d134cf5Sskrll 	kgdb_dev = 123; /* unneeded, only to satisfy some tests */
11809d134cf5Sskrll 
11819d134cf5Sskrll 	return 0;
11829d134cf5Sskrll }
11839d134cf5Sskrll 
11849d134cf5Sskrll static int
epcom_kgdb_getc(void * sc)11859d134cf5Sskrll epcom_kgdb_getc (void *sc)
11869d134cf5Sskrll {
11879d134cf5Sskrll 	return epcom_common_getc(sc, NODEV);
11889d134cf5Sskrll }
11899d134cf5Sskrll 
11909d134cf5Sskrll static void
epcom_kgdb_putc(void * sc,int c)11919d134cf5Sskrll epcom_kgdb_putc (void *sc, int c)
11929d134cf5Sskrll {
11939d134cf5Sskrll 	epcom_common_putc(sc, c);
11949d134cf5Sskrll }
11959d134cf5Sskrll #endif	/* KGDB */
11969d134cf5Sskrll 
11979d134cf5Sskrll /*
11989d134cf5Sskrll  * Common code used for initialisation of the console or KGDB connection
11999d134cf5Sskrll  */
12009d134cf5Sskrll static void
epcominit(struct epcom_cons_softc * sc,bus_space_tag_t iot,bus_addr_t iobase,bus_space_handle_t ioh,int rate,tcflag_t cflag)12019d134cf5Sskrll epcominit(struct epcom_cons_softc *sc, bus_space_tag_t iot,
12029d134cf5Sskrll 	  bus_addr_t iobase, bus_space_handle_t ioh, int rate, tcflag_t cflag)
12039d134cf5Sskrll {
12049d134cf5Sskrll 	u_int lcrlo, lcrmid, lcrhi, ctrl, pwrcnt;
12059d134cf5Sskrll 	bus_space_handle_t syscon_ioh;
12069d134cf5Sskrll 
12079d134cf5Sskrll 	sc->sc_iot = iot;
12089d134cf5Sskrll 	sc->sc_ioh = ioh;
12099d134cf5Sskrll 	sc->sc_hwbase = iobase;
12109d134cf5Sskrll 	sc->sc_ospeed = rate;
12119d134cf5Sskrll 	sc->sc_cflag = cflag;
12129d134cf5Sskrll 
12139d134cf5Sskrll 	lcrhi = cflag2lcrhi(cflag);
12149d134cf5Sskrll 	lcrlo = EPCOMSPEED2BRD(rate) & 0xff;
12159d134cf5Sskrll 	lcrmid = EPCOMSPEED2BRD(rate) >> 8;
12169d134cf5Sskrll 	ctrl = Ctrl_UARTE;
12179d134cf5Sskrll 
12189d134cf5Sskrll 	/* Make sure the UARTs are clocked at the system default rate */
12199d134cf5Sskrll 	bus_space_map(iot, EP93XX_APB_HWBASE + EP93XX_APB_SYSCON,
12209d134cf5Sskrll 		EP93XX_APB_SYSCON_SIZE, 0, &syscon_ioh);
12219d134cf5Sskrll 	pwrcnt = bus_space_read_4(iot, syscon_ioh, EP93XX_SYSCON_PwrCnt);
12229d134cf5Sskrll 	pwrcnt &= ~(PwrCnt_UARTBAUD);
12239d134cf5Sskrll 	bus_space_write_4(iot, syscon_ioh, EP93XX_SYSCON_PwrCnt, pwrcnt);
12249d134cf5Sskrll 	bus_space_unmap(iot, syscon_ioh, EP93XX_APB_SYSCON_SIZE);
12259d134cf5Sskrll 
12269d134cf5Sskrll 	bus_space_write_4(iot, ioh, EPCOM_LinCtrlLow, lcrlo);
12279d134cf5Sskrll 	bus_space_write_4(iot, ioh, EPCOM_LinCtrlMid, lcrmid);
12289d134cf5Sskrll 	bus_space_write_4(iot, ioh, EPCOM_LinCtrlHigh, lcrhi);
12299d134cf5Sskrll 	bus_space_write_4(iot, ioh, EPCOM_Ctrl, ctrl);
12309d134cf5Sskrll }
1231