Home | History | Annotate | Line # | Download | only in dev
siotty.c revision 1.31
      1  1.31   tsutsui /* $NetBSD: siotty.c,v 1.31 2011/07/27 11:54:40 tsutsui Exp $ */
      2   1.1  nisimura 
      3   1.1  nisimura /*-
      4   1.1  nisimura  * Copyright (c) 2000 The NetBSD Foundation, Inc.
      5   1.1  nisimura  * All rights reserved.
      6   1.1  nisimura  *
      7   1.1  nisimura  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  nisimura  * by Tohru Nishimura.
      9   1.1  nisimura  *
     10   1.1  nisimura  * Redistribution and use in source and binary forms, with or without
     11   1.1  nisimura  * modification, are permitted provided that the following conditions
     12   1.1  nisimura  * are met:
     13   1.1  nisimura  * 1. Redistributions of source code must retain the above copyright
     14   1.1  nisimura  *    notice, this list of conditions and the following disclaimer.
     15   1.1  nisimura  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  nisimura  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  nisimura  *    documentation and/or other materials provided with the distribution.
     18   1.1  nisimura  *
     19   1.1  nisimura  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  nisimura  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  nisimura  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  nisimura  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  nisimura  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  nisimura  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  nisimura  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  nisimura  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  nisimura  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  nisimura  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  nisimura  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  nisimura  */
     31   1.1  nisimura 
     32   1.1  nisimura #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     33   1.1  nisimura 
     34  1.31   tsutsui __KERNEL_RCSID(0, "$NetBSD: siotty.c,v 1.31 2011/07/27 11:54:40 tsutsui Exp $");
     35   1.1  nisimura 
     36   1.1  nisimura #include "opt_ddb.h"
     37   1.1  nisimura 
     38   1.1  nisimura #include <sys/param.h>
     39   1.1  nisimura #include <sys/systm.h>
     40   1.1  nisimura #include <sys/device.h>
     41   1.1  nisimura #include <sys/conf.h>
     42   1.1  nisimura #include <sys/ioctl.h>
     43   1.1  nisimura #include <sys/proc.h>
     44   1.1  nisimura #include <sys/tty.h>
     45   1.1  nisimura #include <sys/uio.h>
     46   1.1  nisimura #include <sys/callout.h>
     47   1.1  nisimura #include <sys/fcntl.h>
     48   1.1  nisimura #include <dev/cons.h>
     49  1.17      elad #include <sys/kauth.h>
     50   1.1  nisimura 
     51   1.1  nisimura #include <machine/cpu.h>
     52   1.1  nisimura 
     53   1.1  nisimura #include <luna68k/dev/sioreg.h>
     54   1.1  nisimura #include <luna68k/dev/siovar.h>
     55   1.1  nisimura 
     56  1.31   tsutsui #include "ioconf.h"
     57  1.31   tsutsui 
     58   1.1  nisimura #define	TIOCM_BREAK 01000 /* non standard use */
     59   1.1  nisimura 
     60   1.1  nisimura static const u_int8_t ch0_regs[6] = {
     61   1.1  nisimura 	WR0_RSTINT,				/* reset E/S interrupt */
     62   1.1  nisimura 	WR1_RXALLS | WR1_TXENBL,	 	/* Rx per char, Tx */
     63   1.1  nisimura 	0,					/* */
     64   1.1  nisimura 	WR3_RX8BIT | WR3_RXENBL,		/* Rx */
     65   1.1  nisimura 	WR4_BAUD96 | WR4_STOP1,			/* Tx/Rx */
     66   1.1  nisimura 	WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
     67   1.1  nisimura };
     68   1.1  nisimura 
     69  1.14      matt static const struct speedtab siospeedtab[] = {
     70   1.1  nisimura 	{ 2400,	WR4_BAUD24, },
     71   1.1  nisimura 	{ 4800,	WR4_BAUD48, },
     72   1.1  nisimura 	{ 9600,	WR4_BAUD96, },
     73   1.1  nisimura 	{ -1,	0, },
     74   1.1  nisimura };
     75   1.1  nisimura 
     76   1.1  nisimura struct siotty_softc {
     77  1.31   tsutsui 	device_t	sc_dev;
     78   1.1  nisimura 	struct tty	*sc_tty;
     79   1.1  nisimura 	struct sioreg	*sc_ctl;
     80   1.1  nisimura 	u_int 		sc_flags;
     81   1.1  nisimura 	u_int8_t	sc_wr[6];
     82   1.1  nisimura };
     83   1.1  nisimura 
     84   1.1  nisimura #include "siotty.h"
     85  1.24       dsl static void siostart(struct tty *);
     86  1.24       dsl static int  sioparam(struct tty *, struct termios *);
     87  1.24       dsl static void siottyintr(int);
     88  1.24       dsl static int  siomctl(struct siotty_softc *, int, int);
     89   1.1  nisimura 
     90  1.31   tsutsui static int  siotty_match(device_t, cfdata_t, void *);
     91  1.31   tsutsui static void siotty_attach(device_t, device_t, void *);
     92   1.1  nisimura 
     93  1.31   tsutsui CFATTACH_DECL_NEW(siotty, sizeof(struct siotty_softc),
     94  1.11   thorpej     siotty_match, siotty_attach, NULL, NULL);
     95   1.1  nisimura 
     96  1.10   gehenna dev_type_open(sioopen);
     97  1.10   gehenna dev_type_close(sioclose);
     98  1.10   gehenna dev_type_read(sioread);
     99  1.10   gehenna dev_type_write(siowrite);
    100  1.10   gehenna dev_type_ioctl(sioioctl);
    101  1.10   gehenna dev_type_stop(siostop);
    102  1.10   gehenna dev_type_tty(siotty);
    103  1.10   gehenna dev_type_poll(siopoll);
    104  1.10   gehenna 
    105  1.10   gehenna const struct cdevsw siotty_cdevsw = {
    106  1.10   gehenna 	sioopen, sioclose, sioread, siowrite, sioioctl,
    107  1.12  jdolecek 	siostop, siotty, siopoll, nommap, ttykqfilter, D_TTY
    108  1.10   gehenna };
    109  1.10   gehenna 
    110   1.1  nisimura static int
    111  1.31   tsutsui siotty_match(device_t parent, cfdata_t cf, void *aux)
    112   1.1  nisimura {
    113   1.1  nisimura 	struct sio_attach_args *args = aux;
    114   1.1  nisimura 
    115   1.1  nisimura 	if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
    116   1.1  nisimura 		return 0;
    117   1.1  nisimura 	return 1;
    118   1.1  nisimura }
    119   1.1  nisimura 
    120   1.1  nisimura static void
    121  1.26       dsl siotty_attach(struct device *parent, struct device *self, void *aux)
    122   1.1  nisimura {
    123  1.31   tsutsui 	struct sio_softc *scp = device_private(parent);
    124  1.31   tsutsui 	struct siotty_softc *sc = device_private(self);
    125   1.1  nisimura 	struct sio_attach_args *args = aux;
    126   1.1  nisimura 
    127  1.31   tsutsui 	sc->sc_dev = self;
    128   1.1  nisimura 	sc->sc_ctl = (struct sioreg *)scp->scp_ctl + args->channel;
    129  1.28    cegger 	memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs));
    130   1.1  nisimura 	scp->scp_intr[args->channel] = siottyintr;
    131   1.1  nisimura 
    132   1.1  nisimura 	if (args->hwflags == 1) {
    133  1.31   tsutsui 		aprint_normal(" (console)");
    134   1.1  nisimura 		sc->sc_flags = TIOCFLAG_SOFTCAR;
    135   1.1  nisimura 	}
    136   1.1  nisimura 	else {
    137   1.1  nisimura 		setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
    138   1.1  nisimura 		setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1);
    139   1.1  nisimura 		setsioreg(sc->sc_ctl, WR2B, 0);
    140   1.1  nisimura 		setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
    141   1.1  nisimura 		setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
    142   1.1  nisimura 		setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
    143   1.1  nisimura 		setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
    144   1.1  nisimura 		setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
    145   1.1  nisimura 	}
    146   1.1  nisimura 	setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
    147   1.1  nisimura 
    148  1.31   tsutsui 	aprint_normal("\n");
    149   1.1  nisimura }
    150   1.1  nisimura 
    151   1.1  nisimura /*--------------------  low level routine --------------------*/
    152   1.1  nisimura 
    153   1.1  nisimura static void
    154  1.23    cegger siottyintr(int chan)
    155   1.1  nisimura {
    156   1.1  nisimura 	struct siotty_softc *sc;
    157   1.1  nisimura 	struct sioreg *sio;
    158   1.1  nisimura 	struct tty *tp;
    159   1.1  nisimura 	unsigned int code;
    160   1.1  nisimura 	int rr;
    161   1.1  nisimura 
    162  1.23    cegger 	sc = device_lookup_private(&siotty_cd, chan);
    163  1.23    cegger 	if (sc == NULL)
    164   1.1  nisimura 		return;
    165  1.23    cegger 
    166   1.1  nisimura 	tp = sc->sc_tty;
    167   1.1  nisimura 	sio = sc->sc_ctl;
    168   1.1  nisimura 	rr = getsiocsr(sio);
    169   1.1  nisimura 	if (rr & RR_RXRDY) {
    170   1.1  nisimura 		do {
    171   1.1  nisimura 			code = sio->sio_data;
    172   1.1  nisimura 			if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) {
    173   1.1  nisimura 				sio->sio_cmd = WR0_ERRRST;
    174   1.1  nisimura 				if (sio->sio_stat & RR_FRAMING)
    175   1.1  nisimura 					code |= TTY_FE;
    176   1.1  nisimura 				else if (sio->sio_stat & RR_PARITY)
    177   1.1  nisimura 					code |= TTY_PE;
    178   1.1  nisimura 			}
    179   1.1  nisimura 			if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
    180   1.1  nisimura 				continue;
    181   1.3  nisimura #if 0 && defined(DDB) /* ?!?! fails to resume ?!?! */
    182   1.3  nisimura 			if ((rr & RR_BREAK) && tp->t_dev == cn_tab->cn_dev) {
    183   1.2  nisimura 				cpu_Debugger();
    184   1.3  nisimura 				return;
    185   1.3  nisimura 			}
    186   1.2  nisimura #endif
    187   1.5       eeh 			(*tp->t_linesw->l_rint)(code, tp);
    188   1.1  nisimura 		} while ((rr = getsiocsr(sio)) & RR_RXRDY);
    189   1.1  nisimura 	}
    190   1.1  nisimura 	if (rr & RR_TXRDY) {
    191   1.1  nisimura 		sio->sio_cmd = WR0_RSTPEND;
    192   1.1  nisimura 		if (tp != NULL) {
    193   1.1  nisimura 			tp->t_state &= ~(TS_BUSY|TS_FLUSH);
    194   1.7     enami 			(*tp->t_linesw->l_start)(tp);
    195   1.1  nisimura 		}
    196   1.1  nisimura 	}
    197   1.1  nisimura }
    198   1.1  nisimura 
    199   1.1  nisimura static void
    200  1.23    cegger siostart(struct tty *tp)
    201   1.1  nisimura {
    202  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(tp->t_dev));
    203   1.1  nisimura 	int s, c;
    204   1.1  nisimura 
    205   1.1  nisimura 	s = spltty();
    206   1.1  nisimura 	if (tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP))
    207   1.1  nisimura 		goto out;
    208  1.21        ad 	if (!ttypull(tp))
    209   1.1  nisimura 		goto out;
    210   1.1  nisimura 	tp->t_state |= TS_BUSY;
    211   1.1  nisimura 	while (getsiocsr(sc->sc_ctl) & RR_TXRDY) {
    212   1.1  nisimura 		if ((c = getc(&tp->t_outq)) == -1)
    213   1.1  nisimura 			break;
    214   1.1  nisimura 		sc->sc_ctl->sio_data = c;
    215   1.1  nisimura 	}
    216   1.1  nisimura out:
    217   1.1  nisimura 	splx(s);
    218   1.1  nisimura }
    219   1.1  nisimura 
    220   1.1  nisimura void
    221  1.25       dsl siostop(struct tty *tp, int flag)
    222   1.1  nisimura {
    223   1.1  nisimura 	int s;
    224   1.1  nisimura 
    225   1.1  nisimura         s = spltty();
    226   1.1  nisimura         if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
    227   1.1  nisimura                 /*
    228   1.1  nisimura                  * Device is transmitting; must stop it.
    229   1.1  nisimura                  */
    230   1.1  nisimura 		tp->t_state |= TS_FLUSH;
    231   1.1  nisimura         }
    232   1.1  nisimura         splx(s);
    233   1.1  nisimura }
    234   1.1  nisimura 
    235   1.1  nisimura static int
    236  1.23    cegger sioparam(struct tty *tp, struct termios *t)
    237   1.1  nisimura {
    238  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(tp->t_dev));
    239   1.1  nisimura 	int wr4, s;
    240   1.1  nisimura 
    241   1.1  nisimura 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
    242   1.1  nisimura 		return EINVAL;
    243   1.1  nisimura 	wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
    244   1.1  nisimura 	if (wr4 < 0)
    245   1.1  nisimura 		return EINVAL;
    246   1.1  nisimura 
    247   1.1  nisimura 	if (sc->sc_flags & TIOCFLAG_SOFTCAR) {
    248   1.1  nisimura 		t->c_cflag |= CLOCAL;
    249   1.1  nisimura 		t->c_cflag &= ~HUPCL;
    250   1.1  nisimura 	}
    251   1.1  nisimura 	if (sc->sc_flags & TIOCFLAG_CLOCAL)
    252   1.1  nisimura 		t->c_cflag |= CLOCAL;
    253   1.1  nisimura 
    254   1.1  nisimura 	/*
    255   1.1  nisimura 	 * If there were no changes, don't do anything.  This avoids dropping
    256   1.1  nisimura 	 * input and improves performance when all we did was frob things like
    257   1.1  nisimura 	 * VMIN and VTIME.
    258   1.1  nisimura 	 */
    259   1.1  nisimura 	if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
    260   1.1  nisimura 		return 0;
    261   1.1  nisimura 
    262   1.1  nisimura 	tp->t_ispeed = t->c_ispeed;
    263   1.1  nisimura 	tp->t_ospeed = t->c_ospeed;
    264   1.1  nisimura 	tp->t_cflag = t->c_cflag;
    265   1.1  nisimura 
    266   1.1  nisimura 	sc->sc_wr[WR3] &= 0x3f;
    267   1.1  nisimura 	sc->sc_wr[WR5] &= 0x9f;
    268   1.1  nisimura 	switch (tp->t_cflag & CSIZE) {
    269   1.1  nisimura 	case CS7:
    270   1.1  nisimura 		sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT;
    271   1.1  nisimura 		break;
    272   1.1  nisimura 	case CS8:
    273   1.1  nisimura 		sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT;
    274   1.1  nisimura 		break;
    275   1.1  nisimura 	}
    276   1.1  nisimura 	if (tp->t_cflag & PARENB) {
    277   1.1  nisimura 		wr4 |= WR4_PARENAB;
    278   1.1  nisimura 		if ((tp->t_cflag & PARODD) == 0)
    279   1.1  nisimura 			wr4 |= WR4_EPARITY;
    280   1.1  nisimura 	}
    281   1.1  nisimura 	wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
    282   1.1  nisimura 	sc->sc_wr[WR4] = wr4;
    283   1.1  nisimura 
    284   1.1  nisimura 	s = spltty();
    285   1.1  nisimura 	setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
    286   1.1  nisimura 	setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
    287   1.1  nisimura 	setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
    288   1.1  nisimura 	splx(s);
    289   1.1  nisimura 
    290   1.1  nisimura 	return 0;
    291   1.1  nisimura }
    292   1.1  nisimura 
    293   1.1  nisimura static int
    294  1.26       dsl siomctl(struct siotty_softc *sc, int control, int op)
    295   1.1  nisimura {
    296   1.1  nisimura 	int val, s, wr5, rr;
    297   1.1  nisimura 
    298   1.1  nisimura 	val = 0;
    299   1.1  nisimura 	if (control & TIOCM_BREAK)
    300   1.1  nisimura 		val |= WR5_BREAK;
    301   1.1  nisimura 	if (control & TIOCM_DTR)
    302   1.1  nisimura 		val |= WR5_DTR;
    303   1.1  nisimura 	if (control & TIOCM_RTS)
    304   1.1  nisimura 		val |= WR5_RTS;
    305   1.1  nisimura 	s = spltty();
    306   1.1  nisimura 	wr5 = sc->sc_wr[WR5];
    307   1.1  nisimura 	switch (op) {
    308   1.1  nisimura 	case DMSET:
    309   1.1  nisimura 		wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
    310   1.1  nisimura 		/* FALLTHRU */
    311   1.1  nisimura 	case DMBIS:
    312   1.1  nisimura 		wr5 |= val;
    313   1.1  nisimura 		break;
    314   1.1  nisimura 	case DMBIC:
    315   1.1  nisimura 		wr5 &= ~val;
    316   1.1  nisimura 		break;
    317   1.1  nisimura 	case DMGET:
    318   1.1  nisimura 		val = 0;
    319   1.1  nisimura 		rr = getsiocsr(sc->sc_ctl);
    320   1.1  nisimura 		if (wr5 & WR5_DTR)
    321   1.1  nisimura 			val |= TIOCM_DTR;
    322   1.1  nisimura 		if (wr5 & WR5_RTS)
    323   1.1  nisimura 			val |= TIOCM_RTS;
    324   1.1  nisimura 		if (rr & RR_CTS)
    325   1.1  nisimura 			val |= TIOCM_CTS;
    326   1.1  nisimura 		if (rr & RR_DCD)
    327   1.1  nisimura 			val |= TIOCM_CD;
    328   1.1  nisimura 		goto done;
    329   1.1  nisimura 	}
    330   1.1  nisimura 	sc->sc_wr[WR5] = wr5;
    331   1.1  nisimura 	setsioreg(sc->sc_ctl, WR5, wr5);
    332   1.1  nisimura 	val = 0;
    333   1.1  nisimura   done:
    334   1.1  nisimura 	splx(s);
    335   1.1  nisimura 	return val;
    336   1.1  nisimura }
    337   1.1  nisimura 
    338   1.1  nisimura /*--------------------  cdevsw[] interface --------------------*/
    339   1.1  nisimura 
    340   1.1  nisimura int
    341  1.23    cegger sioopen(dev_t dev, int flag, int mode, struct lwp *l)
    342   1.1  nisimura {
    343   1.1  nisimura 	struct siotty_softc *sc;
    344   1.1  nisimura 	struct tty *tp;
    345   1.1  nisimura 	int error;
    346   1.1  nisimura 
    347  1.23    cegger 	sc = device_lookup_private(&siotty_cd, minor(dev));
    348  1.23    cegger 	if (sc == NULL)
    349   1.1  nisimura 		return ENXIO;
    350   1.1  nisimura 	if ((tp = sc->sc_tty) == NULL) {
    351  1.30     rmind 		tp = sc->sc_tty = tty_alloc();
    352   1.1  nisimura 		tty_attach(tp);
    353  1.30     rmind 	}
    354   1.1  nisimura 
    355   1.1  nisimura 	tp->t_oproc = siostart;
    356   1.1  nisimura 	tp->t_param = sioparam;
    357   1.1  nisimura 	tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
    358   1.1  nisimura 	tp->t_dev = dev;
    359  1.19      elad 
    360  1.19      elad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    361  1.19      elad 		return (EBUSY);
    362  1.19      elad 
    363   1.1  nisimura 	if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
    364   1.1  nisimura 		struct termios t;
    365   1.1  nisimura 
    366   1.1  nisimura 		t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
    367   1.1  nisimura 		t.c_cflag = TTYDEF_CFLAG;
    368   1.1  nisimura 		tp->t_ospeed = 0; /* force register update */
    369   1.1  nisimura 		(void)sioparam(tp, &t);
    370   1.1  nisimura 		tp->t_iflag = TTYDEF_IFLAG;
    371   1.1  nisimura 		tp->t_oflag = TTYDEF_OFLAG;
    372   1.1  nisimura 		tp->t_lflag = TTYDEF_LFLAG;
    373   1.1  nisimura 		ttychars(tp);
    374   1.1  nisimura 		ttsetwater(tp);
    375   1.1  nisimura 		/* raise RTS and DTR here; but, DTR lead is not wired */
    376   1.1  nisimura 		/* then check DCD condition; but, DCD lead is not wired */
    377   1.1  nisimura 		tp->t_state |= TS_CARR_ON; /* assume detected all the time */
    378   1.1  nisimura #if 0
    379   1.1  nisimura 		if ((sc->sc_flags & TIOCFLAG_SOFTCAR)
    380   1.1  nisimura 		    || (tp->t_cflag & MDMBUF)
    381   1.1  nisimura 		    || (getsiocsr(sc->sc_ctl) & RR_DCD))
    382   1.1  nisimura 			tp->t_state |= TS_CARR_ON;
    383   1.1  nisimura 		else
    384   1.1  nisimura 			tp->t_state &= ~TS_CARR_ON;
    385   1.1  nisimura #endif
    386   1.1  nisimura 	}
    387   1.1  nisimura 
    388   1.1  nisimura 	error = ttyopen(tp, 0, (flag & O_NONBLOCK));
    389   1.1  nisimura 	if (error > 0)
    390   1.1  nisimura 		return error;
    391   1.5       eeh 	return (*tp->t_linesw->l_open)(dev, tp);
    392   1.1  nisimura }
    393   1.1  nisimura 
    394   1.1  nisimura int
    395  1.23    cegger sioclose(dev_t dev, int flag, int mode, struct lwp *l)
    396   1.1  nisimura {
    397  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
    398   1.1  nisimura 	struct tty *tp = sc->sc_tty;
    399   1.1  nisimura 	int s;
    400   1.1  nisimura 
    401   1.5       eeh 	(*tp->t_linesw->l_close)(tp, flag);
    402   1.1  nisimura 
    403   1.1  nisimura 	s = spltty();
    404   1.1  nisimura 	siomctl(sc, TIOCM_BREAK, DMBIC);
    405   1.1  nisimura #if 0 /* because unable to feed DTR signal */
    406   1.1  nisimura 	if ((tp->t_cflag & HUPCL)
    407   1.1  nisimura 	    || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
    408   1.1  nisimura 		siomctl(sc, TIOCM_DTR, DMBIC);
    409   1.1  nisimura 		/* Yield CPU time to others for 1 second, then ... */
    410   1.1  nisimura 		siomctl(sc, TIOCM_DTR, DMBIS);
    411   1.1  nisimura 	}
    412   1.1  nisimura #endif
    413   1.1  nisimura 	splx(s);
    414   1.1  nisimura 	return ttyclose(tp);
    415   1.1  nisimura }
    416   1.1  nisimura 
    417   1.1  nisimura int
    418  1.23    cegger sioread(dev_t dev, struct uio *uio, int flag)
    419   1.1  nisimura {
    420  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
    421   1.1  nisimura 	struct tty *tp = sc->sc_tty;
    422   1.1  nisimura 
    423   1.5       eeh 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    424   1.1  nisimura }
    425   1.1  nisimura 
    426   1.1  nisimura int
    427  1.23    cegger siowrite(dev_t dev, struct uio *uio, int flag)
    428   1.1  nisimura {
    429  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
    430   1.1  nisimura 	struct tty *tp = sc->sc_tty;
    431   1.1  nisimura 
    432   1.5       eeh 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    433   1.8       scw }
    434   1.8       scw 
    435   1.8       scw int
    436  1.23    cegger siopoll(dev_t dev, int events, struct lwp *l)
    437   1.8       scw {
    438  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
    439   1.8       scw 	struct tty *tp = sc->sc_tty;
    440   1.8       scw 
    441  1.16  christos 	return ((*tp->t_linesw->l_poll)(tp, events, l));
    442   1.1  nisimura }
    443   1.1  nisimura 
    444   1.1  nisimura int
    445  1.23    cegger sioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    446   1.1  nisimura {
    447  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
    448   1.1  nisimura 	struct tty *tp = sc->sc_tty;
    449   1.1  nisimura 	int error;
    450   1.1  nisimura 
    451  1.16  christos 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    452   1.9    atatat 	if (error != EPASSTHROUGH)
    453   1.1  nisimura 		return error;
    454   1.9    atatat 
    455  1.16  christos 	error = ttioctl(tp, cmd, data, flag, l);
    456   1.9    atatat 	if (error != EPASSTHROUGH)
    457   1.1  nisimura 		return error;
    458   1.1  nisimura 
    459   1.1  nisimura 	/* the last resort for TIOC ioctl tranversing */
    460   1.1  nisimura 	switch (cmd) {
    461   1.1  nisimura 	case TIOCSBRK: /* Set the hardware into BREAK condition */
    462   1.1  nisimura 		siomctl(sc, TIOCM_BREAK, DMBIS);
    463   1.1  nisimura 		break;
    464   1.1  nisimura 	case TIOCCBRK: /* Clear the hardware BREAK condition */
    465   1.1  nisimura 		siomctl(sc, TIOCM_BREAK, DMBIC);
    466   1.1  nisimura 		break;
    467   1.1  nisimura 	case TIOCSDTR: /* Assert DTR signal */
    468   1.1  nisimura 		siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
    469   1.1  nisimura 		break;
    470   1.1  nisimura 	case TIOCCDTR: /* Clear DTR signal */
    471   1.1  nisimura 		siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
    472   1.1  nisimura 		break;
    473   1.1  nisimura 	case TIOCMSET: /* Set modem state replacing current one */
    474   1.1  nisimura 		siomctl(sc, *(int *)data, DMSET);
    475   1.1  nisimura 		break;
    476   1.1  nisimura 	case TIOCMGET: /* Return current modem state */
    477   1.1  nisimura 		*(int *)data = siomctl(sc, 0, DMGET);
    478   1.1  nisimura 		break;
    479   1.1  nisimura 	case TIOCMBIS: /* Set individual bits of modem state */
    480   1.1  nisimura 		siomctl(sc, *(int *)data, DMBIS);
    481   1.1  nisimura 		break;
    482   1.1  nisimura 	case TIOCMBIC: /* Clear individual bits of modem state */
    483   1.1  nisimura 		siomctl(sc, *(int *)data, DMBIC);
    484   1.1  nisimura 		break;
    485   1.1  nisimura 	case TIOCSFLAGS: /* Instruct how serial port behaves */
    486   1.1  nisimura 		sc->sc_flags = *(int *)data;
    487   1.1  nisimura 		break;
    488   1.1  nisimura 	case TIOCGFLAGS: /* Return current serial port state */
    489   1.1  nisimura 		*(int *)data = sc->sc_flags;
    490   1.1  nisimura 		break;
    491   1.1  nisimura 	default:
    492   1.9    atatat 		return EPASSTHROUGH;
    493   1.1  nisimura 	}
    494   1.1  nisimura 	return 0;
    495   1.1  nisimura }
    496   1.1  nisimura 
    497   1.1  nisimura /* ARSGUSED */
    498   1.1  nisimura struct tty *
    499  1.23    cegger siotty(dev_t dev)
    500   1.1  nisimura {
    501  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
    502   1.1  nisimura 
    503   1.1  nisimura 	return sc->sc_tty;
    504   1.1  nisimura }
    505   1.1  nisimura 
    506   1.1  nisimura /*--------------------  miscelleneous routine --------------------*/
    507   1.1  nisimura 
    508   1.1  nisimura /* EXPORT */ void
    509  1.23    cegger setsioreg(struct sioreg *sio, int regno, int val)
    510   1.1  nisimura {
    511   1.1  nisimura 	if (regno != 0)
    512   1.1  nisimura 		sio->sio_cmd = regno;	/* DELAY(); */
    513   1.1  nisimura 	sio->sio_cmd = val;		/* DELAY(); */
    514   1.1  nisimura }
    515   1.1  nisimura 
    516   1.1  nisimura /* EXPORT */ int
    517  1.23    cegger getsiocsr(struct sioreg *sio)
    518   1.1  nisimura {
    519   1.1  nisimura 	int val;
    520   1.1  nisimura 
    521   1.1  nisimura 	val = sio->sio_stat << 8;	/* DELAY(); */
    522   1.1  nisimura 	sio->sio_cmd = 1;		/* DELAY(); */
    523   1.1  nisimura 	val |= sio->sio_stat;		/* DELAY(); */
    524   1.1  nisimura 	return val;
    525   1.1  nisimura }
    526   1.1  nisimura 
    527   1.1  nisimura /*---------------------  console interface ----------------------*/
    528   1.1  nisimura 
    529  1.24       dsl void syscnattach(int);
    530  1.24       dsl int  syscngetc(dev_t);
    531  1.24       dsl void syscnputc(dev_t, int);
    532   1.1  nisimura 
    533   1.1  nisimura struct consdev syscons = {
    534   1.1  nisimura 	NULL,
    535   1.1  nisimura 	NULL,
    536   1.1  nisimura 	syscngetc,
    537   1.1  nisimura 	syscnputc,
    538   1.1  nisimura 	nullcnpollc,
    539  1.13        he 	NULL,
    540  1.13        he 	NULL,
    541   1.4   thorpej 	NULL,
    542   1.1  nisimura 	NODEV,
    543   1.1  nisimura 	CN_REMOTE,
    544   1.1  nisimura };
    545   1.1  nisimura 
    546   1.1  nisimura /* EXPORT */ void
    547  1.25       dsl syscnattach(int channel)
    548   1.1  nisimura {
    549   1.1  nisimura /*
    550   1.1  nisimura  * Channel A is immediately initialized with 9600N1 right after cold
    551   1.1  nisimura  * boot/reset/poweron.  ROM monitor emits one line message on CH.A.
    552   1.1  nisimura  */
    553   1.1  nisimura 	struct sioreg *sio;
    554   1.1  nisimura 	sio = (struct sioreg *)0x51000000 + channel;
    555   1.1  nisimura 
    556  1.10   gehenna 	syscons.cn_dev = makedev(cdevsw_lookup_major(&siotty_cdevsw),
    557  1.10   gehenna 				 channel);
    558   1.1  nisimura 	cn_tab = &syscons;
    559   1.1  nisimura 
    560   1.1  nisimura 	setsioreg(sio, WR0, WR0_CHANRST);
    561   1.1  nisimura 	setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1);
    562   1.1  nisimura 	setsioreg(sio, WR2B, 0);
    563   1.1  nisimura 	setsioreg(sio, WR0, ch0_regs[WR0]);
    564   1.1  nisimura 	setsioreg(sio, WR4, ch0_regs[WR4]);
    565   1.1  nisimura 	setsioreg(sio, WR3, ch0_regs[WR3]);
    566   1.1  nisimura 	setsioreg(sio, WR5, ch0_regs[WR5]);
    567   1.1  nisimura 	setsioreg(sio, WR0, ch0_regs[WR0]);
    568   1.1  nisimura }
    569   1.1  nisimura 
    570   1.1  nisimura /* EXPORT */ int
    571  1.25       dsl syscngetc(dev_t dev)
    572   1.1  nisimura {
    573   1.1  nisimura 	struct sioreg *sio;
    574   1.1  nisimura 	int s, c;
    575   1.1  nisimura 
    576   1.1  nisimura 	sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
    577   1.1  nisimura 	s = splhigh();
    578   1.1  nisimura 	while ((getsiocsr(sio) & RR_RXRDY) == 0)
    579   1.1  nisimura 		;
    580   1.1  nisimura 	c = sio->sio_data;
    581   1.1  nisimura 	splx(s);
    582   1.1  nisimura 
    583   1.1  nisimura 	return c;
    584   1.1  nisimura }
    585   1.1  nisimura 
    586   1.1  nisimura /* EXPORT */ void
    587  1.25       dsl syscnputc(dev_t dev, int c)
    588   1.1  nisimura {
    589   1.1  nisimura 	struct sioreg *sio;
    590   1.1  nisimura 	int s;
    591   1.1  nisimura 
    592   1.1  nisimura 	sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
    593   1.1  nisimura 	s = splhigh();
    594   1.1  nisimura 	while ((getsiocsr(sio) & RR_TXRDY) == 0)
    595   1.1  nisimura 		;
    596   1.1  nisimura 	sio->sio_cmd = WR0_RSTPEND;
    597   1.1  nisimura 	sio->sio_data = c;
    598   1.1  nisimura 	splx(s);
    599   1.1  nisimura }
    600