Home | History | Annotate | Line # | Download | only in dev
siotty.c revision 1.41
      1  1.41   tsutsui /* $NetBSD: siotty.c,v 1.41 2014/07/18 18:02:08 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.41   tsutsui __KERNEL_RCSID(0, "$NetBSD: siotty.c,v 1.41 2014/07/18 18:02:08 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.37   tsutsui #include <sys/kmem.h>
     51   1.1  nisimura 
     52   1.1  nisimura #include <machine/cpu.h>
     53   1.1  nisimura 
     54   1.1  nisimura #include <luna68k/dev/sioreg.h>
     55   1.1  nisimura #include <luna68k/dev/siovar.h>
     56   1.1  nisimura 
     57  1.31   tsutsui #include "ioconf.h"
     58  1.31   tsutsui 
     59   1.1  nisimura #define	TIOCM_BREAK 01000 /* non standard use */
     60   1.1  nisimura 
     61  1.32   tsutsui static const uint8_t ch0_regs[6] = {
     62   1.1  nisimura 	WR0_RSTINT,				/* reset E/S interrupt */
     63  1.35   tsutsui 	WR1_RXALLS | WR1_TXENBL,		/* Rx per char, Tx */
     64   1.1  nisimura 	0,					/* */
     65   1.1  nisimura 	WR3_RX8BIT | WR3_RXENBL,		/* Rx */
     66   1.1  nisimura 	WR4_BAUD96 | WR4_STOP1,			/* Tx/Rx */
     67   1.1  nisimura 	WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
     68   1.1  nisimura };
     69   1.1  nisimura 
     70  1.14      matt static const struct speedtab siospeedtab[] = {
     71   1.1  nisimura 	{ 2400,	WR4_BAUD24, },
     72   1.1  nisimura 	{ 4800,	WR4_BAUD48, },
     73   1.1  nisimura 	{ 9600,	WR4_BAUD96, },
     74   1.1  nisimura 	{ -1,	0, },
     75   1.1  nisimura };
     76   1.1  nisimura 
     77   1.1  nisimura struct siotty_softc {
     78  1.31   tsutsui 	device_t	sc_dev;
     79   1.1  nisimura 	struct tty	*sc_tty;
     80   1.1  nisimura 	struct sioreg	*sc_ctl;
     81  1.35   tsutsui 	u_int		sc_flags;
     82  1.32   tsutsui 	uint8_t		sc_wr[6];
     83  1.37   tsutsui 	void		*sc_si;		/* software interrupt handler */
     84  1.37   tsutsui 	u_int		sc_hwflags;
     85  1.37   tsutsui #define	SIOTTY_HW_CONSOLE	0x0001
     86  1.37   tsutsui 
     87  1.37   tsutsui 	uint8_t		*sc_rbuf;
     88  1.37   tsutsui 	uint8_t		*sc_rbufend;
     89  1.37   tsutsui 	uint8_t	* volatile sc_rbget;
     90  1.37   tsutsui 	uint8_t	* volatile sc_rbput;
     91  1.37   tsutsui 	volatile u_int	sc_rbavail;
     92  1.37   tsutsui 
     93  1.37   tsutsui 	uint8_t		*sc_tba;
     94  1.37   tsutsui 	u_int		sc_tbc;
     95  1.37   tsutsui 
     96  1.37   tsutsui 	bool		sc_rx_ready;
     97  1.37   tsutsui 	bool		sc_tx_busy;
     98  1.37   tsutsui 	bool		sc_tx_done;
     99   1.1  nisimura };
    100   1.1  nisimura 
    101  1.37   tsutsui #define	SIOTTY_RING_SIZE	2048
    102  1.37   tsutsui u_int siotty_rbuf_size = SIOTTY_RING_SIZE;
    103  1.37   tsutsui 
    104  1.37   tsutsui static struct cnm_state	siotty_cnm_state;
    105  1.37   tsutsui 
    106   1.1  nisimura #include "siotty.h"
    107  1.24       dsl static void siostart(struct tty *);
    108  1.24       dsl static int  sioparam(struct tty *, struct termios *);
    109  1.39   tsutsui static void siottyintr(void *);
    110  1.37   tsutsui static void siottysoft(void *);
    111  1.37   tsutsui static void siotty_rxsoft(struct siotty_softc *, struct tty *);
    112  1.37   tsutsui static void siotty_txsoft(struct siotty_softc *, struct tty *);
    113  1.24       dsl static int  siomctl(struct siotty_softc *, int, int);
    114   1.1  nisimura 
    115  1.31   tsutsui static int  siotty_match(device_t, cfdata_t, void *);
    116  1.31   tsutsui static void siotty_attach(device_t, device_t, void *);
    117   1.1  nisimura 
    118  1.31   tsutsui CFATTACH_DECL_NEW(siotty, sizeof(struct siotty_softc),
    119  1.11   thorpej     siotty_match, siotty_attach, NULL, NULL);
    120   1.1  nisimura 
    121  1.10   gehenna dev_type_open(sioopen);
    122  1.10   gehenna dev_type_close(sioclose);
    123  1.10   gehenna dev_type_read(sioread);
    124  1.10   gehenna dev_type_write(siowrite);
    125  1.10   gehenna dev_type_ioctl(sioioctl);
    126  1.10   gehenna dev_type_stop(siostop);
    127  1.10   gehenna dev_type_tty(siotty);
    128  1.10   gehenna dev_type_poll(siopoll);
    129  1.10   gehenna 
    130  1.10   gehenna const struct cdevsw siotty_cdevsw = {
    131  1.40  dholland 	.d_open = sioopen,
    132  1.40  dholland 	.d_close = sioclose,
    133  1.40  dholland 	.d_read = sioread,
    134  1.40  dholland 	.d_write = siowrite,
    135  1.40  dholland 	.d_ioctl = sioioctl,
    136  1.40  dholland 	.d_stop = siostop,
    137  1.40  dholland 	.d_tty = siotty,
    138  1.40  dholland 	.d_poll = siopoll,
    139  1.40  dholland 	.d_mmap = nommap,
    140  1.40  dholland 	.d_kqfilter = ttykqfilter,
    141  1.40  dholland 	.d_flag = D_TTY
    142  1.10   gehenna };
    143  1.10   gehenna 
    144  1.35   tsutsui static int
    145  1.31   tsutsui siotty_match(device_t parent, cfdata_t cf, void *aux)
    146   1.1  nisimura {
    147   1.1  nisimura 	struct sio_attach_args *args = aux;
    148   1.1  nisimura 
    149   1.1  nisimura 	if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
    150   1.1  nisimura 		return 0;
    151   1.1  nisimura 	return 1;
    152   1.1  nisimura }
    153   1.1  nisimura 
    154  1.35   tsutsui static void
    155  1.34   tsutsui siotty_attach(device_t parent, device_t self, void *aux)
    156   1.1  nisimura {
    157  1.39   tsutsui 	struct sio_softc *siosc = device_private(parent);
    158  1.31   tsutsui 	struct siotty_softc *sc = device_private(self);
    159   1.1  nisimura 	struct sio_attach_args *args = aux;
    160  1.39   tsutsui 	int channel;
    161  1.37   tsutsui 	struct tty *tp;
    162   1.1  nisimura 
    163  1.31   tsutsui 	sc->sc_dev = self;
    164  1.39   tsutsui 	channel = args->channel;
    165  1.39   tsutsui 	sc->sc_ctl = &siosc->sc_ctl[channel];
    166  1.28    cegger 	memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs));
    167  1.39   tsutsui 	siosc->sc_intrhand[channel].ih_func = siottyintr;
    168  1.39   tsutsui 	siosc->sc_intrhand[channel].ih_arg = sc;
    169  1.37   tsutsui 	if (args->hwflags == 1)
    170  1.37   tsutsui 		sc->sc_hwflags |= SIOTTY_HW_CONSOLE;
    171   1.1  nisimura 
    172  1.37   tsutsui 	if ((sc->sc_hwflags & SIOTTY_HW_CONSOLE) != 0) {
    173  1.31   tsutsui 		aprint_normal(" (console)");
    174   1.1  nisimura 		sc->sc_flags = TIOCFLAG_SOFTCAR;
    175  1.32   tsutsui 	} else {
    176   1.1  nisimura 		setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
    177   1.1  nisimura 		setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1);
    178   1.1  nisimura 		setsioreg(sc->sc_ctl, WR2B, 0);
    179   1.1  nisimura 		setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
    180   1.1  nisimura 		setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
    181   1.1  nisimura 		setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
    182   1.1  nisimura 		setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
    183   1.1  nisimura 		setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
    184   1.1  nisimura 	}
    185   1.1  nisimura 	setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
    186   1.1  nisimura 
    187  1.31   tsutsui 	aprint_normal("\n");
    188  1.37   tsutsui 
    189  1.37   tsutsui 	sc->sc_rbuf = kmem_alloc(siotty_rbuf_size * 2, KM_NOSLEEP);
    190  1.37   tsutsui 	if (sc->sc_rbuf == NULL) {
    191  1.37   tsutsui 		aprint_error_dev(self, "unable to allocate ring buffer\n");
    192  1.37   tsutsui 		return;
    193  1.37   tsutsui 	}
    194  1.37   tsutsui 	sc->sc_rbufend = sc->sc_rbuf + (siotty_rbuf_size * 2);
    195  1.37   tsutsui 	sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
    196  1.37   tsutsui 	sc->sc_rbavail = siotty_rbuf_size;
    197  1.37   tsutsui 
    198  1.37   tsutsui 	tp = tty_alloc();
    199  1.37   tsutsui 	tp->t_oproc = siostart;
    200  1.37   tsutsui 	tp->t_param = sioparam;
    201  1.37   tsutsui 	tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
    202  1.37   tsutsui 	if ((sc->sc_hwflags & SIOTTY_HW_CONSOLE) != 0)
    203  1.37   tsutsui 		tp->t_dev = cn_tab->cn_dev;
    204  1.37   tsutsui 	sc->sc_tty = tp;
    205  1.37   tsutsui 
    206  1.37   tsutsui 	tty_attach(tp);
    207  1.37   tsutsui 
    208  1.37   tsutsui 	sc->sc_si = softint_establish(SOFTINT_SERIAL, siottysoft, sc);
    209   1.1  nisimura }
    210   1.1  nisimura 
    211   1.1  nisimura /*--------------------  low level routine --------------------*/
    212   1.1  nisimura 
    213   1.1  nisimura static void
    214  1.39   tsutsui siottyintr(void *arg)
    215   1.1  nisimura {
    216   1.1  nisimura 	struct siotty_softc *sc;
    217   1.1  nisimura 	struct sioreg *sio;
    218  1.37   tsutsui 	uint8_t *put, *end;
    219  1.37   tsutsui 	uint8_t c;
    220  1.37   tsutsui 	uint16_t rr;
    221  1.37   tsutsui 	int cc;
    222   1.1  nisimura 
    223  1.39   tsutsui 	sc = arg;
    224  1.37   tsutsui 	end = sc->sc_rbufend;
    225  1.37   tsutsui 	put = sc->sc_rbput;
    226  1.37   tsutsui 	cc = sc->sc_rbavail;
    227  1.37   tsutsui 
    228   1.1  nisimura 	sio = sc->sc_ctl;
    229   1.1  nisimura 	rr = getsiocsr(sio);
    230  1.37   tsutsui 	if ((rr & RR_BREAK) != 0) {
    231  1.37   tsutsui 		sio->sio_cmd = WR0_RSTINT;
    232  1.37   tsutsui 		cn_check_magic(sc->sc_tty->t_dev, CNC_BREAK, siotty_cnm_state);
    233  1.37   tsutsui 	}
    234  1.41   tsutsui 	if ((rr & RR_RXRDY) != 0) {
    235   1.1  nisimura 		do {
    236  1.37   tsutsui 			if (cc > 0) {
    237  1.37   tsutsui 				c = sio->sio_data;
    238  1.37   tsutsui 				cn_check_magic(sc->sc_tty->t_dev, c,
    239  1.37   tsutsui 				    siotty_cnm_state);
    240  1.37   tsutsui 				put[0] = c;
    241  1.37   tsutsui 				put[1] = rr & 0xff;
    242  1.37   tsutsui 				put += 2;
    243  1.37   tsutsui 				if (put >= end)
    244  1.37   tsutsui 					put = sc->sc_rbuf;
    245  1.37   tsutsui 				cc--;
    246  1.37   tsutsui 			}
    247  1.37   tsutsui 			if ((rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) != 0)
    248   1.1  nisimura 				sio->sio_cmd = WR0_ERRRST;
    249  1.37   tsutsui 
    250  1.37   tsutsui 			sc->sc_rbput = put;
    251  1.37   tsutsui 			sc->sc_rbavail = cc;
    252  1.37   tsutsui 			sc->sc_rx_ready = true;
    253  1.41   tsutsui 		} while (((rr = getsiocsr(sio)) & RR_RXRDY) != 0);
    254   1.1  nisimura 	}
    255  1.41   tsutsui 	if ((rr & RR_TXRDY) != 0) {
    256   1.1  nisimura 		sio->sio_cmd = WR0_RSTPEND;
    257  1.37   tsutsui 		if (sc->sc_tbc > 0) {
    258  1.37   tsutsui 			sio->sio_data = *sc->sc_tba;
    259  1.37   tsutsui 			sc->sc_tba++;
    260  1.37   tsutsui 			sc->sc_tbc--;
    261  1.37   tsutsui 		} else {
    262  1.37   tsutsui 			if (sc->sc_tx_busy) {
    263  1.37   tsutsui 				sc->sc_tx_busy = false;
    264  1.37   tsutsui 				sc->sc_tx_done = true;
    265  1.37   tsutsui 			}
    266   1.1  nisimura 		}
    267   1.1  nisimura 	}
    268  1.37   tsutsui 	softint_schedule(sc->sc_si);
    269  1.37   tsutsui }
    270  1.37   tsutsui 
    271  1.37   tsutsui static void
    272  1.37   tsutsui siottysoft(void *arg)
    273  1.37   tsutsui {
    274  1.37   tsutsui 	struct siotty_softc *sc;
    275  1.37   tsutsui 	struct tty *tp;
    276  1.37   tsutsui 
    277  1.37   tsutsui 	sc = arg;
    278  1.37   tsutsui 	tp = sc->sc_tty;
    279  1.37   tsutsui 
    280  1.37   tsutsui 	if (sc->sc_rx_ready) {
    281  1.37   tsutsui 		sc->sc_rx_ready = false;
    282  1.37   tsutsui 		siotty_rxsoft(sc, tp);
    283  1.37   tsutsui 	}
    284  1.37   tsutsui 	if (sc->sc_tx_done) {
    285  1.37   tsutsui 		sc->sc_tx_done = false;
    286  1.37   tsutsui 		siotty_txsoft(sc, tp);
    287  1.37   tsutsui 	}
    288  1.37   tsutsui }
    289  1.37   tsutsui 
    290  1.37   tsutsui static void
    291  1.37   tsutsui siotty_rxsoft(struct siotty_softc *sc, struct tty *tp)
    292  1.37   tsutsui {
    293  1.37   tsutsui 	uint8_t *get, *end;
    294  1.37   tsutsui 	u_int cc, scc;
    295  1.37   tsutsui 	unsigned int code;
    296  1.37   tsutsui 	uint8_t stat;
    297  1.37   tsutsui 	int s;
    298  1.37   tsutsui 
    299  1.37   tsutsui 	end = sc->sc_rbufend;
    300  1.37   tsutsui 	get = sc->sc_rbget;
    301  1.37   tsutsui 	scc = cc = siotty_rbuf_size - sc->sc_rbavail;
    302  1.37   tsutsui 
    303  1.37   tsutsui 	if (cc == siotty_rbuf_size) {
    304  1.37   tsutsui 		printf("%s: rx buffer overflow\n", device_xname(sc->sc_dev));
    305  1.37   tsutsui 	}
    306  1.37   tsutsui 
    307  1.37   tsutsui 	while (cc > 0) {
    308  1.37   tsutsui 		code = get[0];
    309  1.37   tsutsui 		stat = get[1];
    310  1.37   tsutsui 		if ((stat & RR_FRAMING) != 0)
    311  1.37   tsutsui 			code |= TTY_FE;
    312  1.37   tsutsui 		else if ((stat & RR_PARITY) != 0)
    313  1.37   tsutsui 			code |= TTY_PE;
    314  1.37   tsutsui 
    315  1.37   tsutsui 		(*tp->t_linesw->l_rint)(code, tp);
    316  1.37   tsutsui 		get += 2;
    317  1.37   tsutsui 		if (get >= end)
    318  1.37   tsutsui 			get = sc->sc_rbuf;
    319  1.37   tsutsui 		cc--;
    320  1.37   tsutsui 	}
    321  1.37   tsutsui 
    322  1.37   tsutsui 	if (cc != scc) {
    323  1.37   tsutsui 		s = splserial();
    324  1.37   tsutsui 		sc->sc_rbget = get;
    325  1.37   tsutsui 		sc->sc_rbavail += scc - cc;
    326  1.37   tsutsui 		splx(s);
    327  1.37   tsutsui 	}
    328  1.37   tsutsui }
    329  1.37   tsutsui 
    330  1.37   tsutsui static void
    331  1.37   tsutsui siotty_txsoft(struct siotty_softc *sc, struct tty *tp)
    332  1.37   tsutsui {
    333  1.37   tsutsui 
    334  1.37   tsutsui 	tp->t_state &= ~TS_BUSY;
    335  1.37   tsutsui 	if ((tp->t_state & TS_FLUSH) != 0)
    336  1.37   tsutsui 		tp->t_state &= ~TS_FLUSH;
    337  1.37   tsutsui 	else
    338  1.37   tsutsui 		ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
    339  1.37   tsutsui 	(*tp->t_linesw->l_start)(tp);
    340   1.1  nisimura }
    341   1.1  nisimura 
    342   1.1  nisimura static void
    343  1.23    cegger siostart(struct tty *tp)
    344   1.1  nisimura {
    345  1.32   tsutsui 	struct siotty_softc *sc;
    346  1.37   tsutsui 	int s;
    347  1.37   tsutsui 	uint8_t *tba;
    348  1.37   tsutsui 	int tbc;
    349  1.35   tsutsui 
    350  1.32   tsutsui 	sc = device_lookup_private(&siotty_cd, minor(tp->t_dev));
    351  1.33   tsutsui 	s = splserial();
    352  1.41   tsutsui 	if ((tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP)) != 0)
    353   1.1  nisimura 		goto out;
    354  1.21        ad 	if (!ttypull(tp))
    355   1.1  nisimura 		goto out;
    356   1.1  nisimura 	tp->t_state |= TS_BUSY;
    357  1.37   tsutsui 
    358  1.37   tsutsui 	tba = tp->t_outq.c_cf;
    359  1.37   tsutsui 	tbc = ndqb(&tp->t_outq, 0);
    360  1.37   tsutsui 
    361  1.37   tsutsui 	sc->sc_tba = tba;
    362  1.37   tsutsui 	sc->sc_tbc = tbc;
    363  1.37   tsutsui 	sc->sc_tx_busy = true;
    364  1.37   tsutsui 
    365  1.37   tsutsui 	sc->sc_ctl->sio_data = *sc->sc_tba;
    366  1.37   tsutsui 	sc->sc_tba++;
    367  1.37   tsutsui 	sc->sc_tbc--;
    368   1.1  nisimura out:
    369   1.1  nisimura 	splx(s);
    370   1.1  nisimura }
    371   1.1  nisimura 
    372   1.1  nisimura void
    373  1.25       dsl siostop(struct tty *tp, int flag)
    374   1.1  nisimura {
    375   1.1  nisimura 	int s;
    376   1.1  nisimura 
    377  1.35   tsutsui 	s = splserial();
    378  1.35   tsutsui 	if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
    379  1.35   tsutsui 		/*
    380  1.35   tsutsui 		 * Device is transmitting; must stop it.
    381  1.35   tsutsui 		 */
    382   1.1  nisimura 		tp->t_state |= TS_FLUSH;
    383  1.35   tsutsui 	}
    384  1.35   tsutsui 	splx(s);
    385   1.1  nisimura }
    386   1.1  nisimura 
    387   1.1  nisimura static int
    388  1.23    cegger sioparam(struct tty *tp, struct termios *t)
    389   1.1  nisimura {
    390  1.32   tsutsui 	struct siotty_softc *sc;
    391   1.1  nisimura 	int wr4, s;
    392   1.1  nisimura 
    393  1.32   tsutsui 	sc = device_lookup_private(&siotty_cd, minor(tp->t_dev));
    394   1.1  nisimura 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
    395   1.1  nisimura 		return EINVAL;
    396   1.1  nisimura 	wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
    397   1.1  nisimura 	if (wr4 < 0)
    398   1.1  nisimura 		return EINVAL;
    399   1.1  nisimura 
    400  1.41   tsutsui 	if ((sc->sc_flags & TIOCFLAG_SOFTCAR) != 0) {
    401   1.1  nisimura 		t->c_cflag |= CLOCAL;
    402   1.1  nisimura 		t->c_cflag &= ~HUPCL;
    403   1.1  nisimura 	}
    404  1.41   tsutsui 	if ((sc->sc_flags & TIOCFLAG_CLOCAL) != 0)
    405   1.1  nisimura 		t->c_cflag |= CLOCAL;
    406   1.1  nisimura 
    407   1.1  nisimura 	/*
    408   1.1  nisimura 	 * If there were no changes, don't do anything.  This avoids dropping
    409   1.1  nisimura 	 * input and improves performance when all we did was frob things like
    410   1.1  nisimura 	 * VMIN and VTIME.
    411   1.1  nisimura 	 */
    412   1.1  nisimura 	if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
    413   1.1  nisimura 		return 0;
    414   1.1  nisimura 
    415   1.1  nisimura 	tp->t_ispeed = t->c_ispeed;
    416   1.1  nisimura 	tp->t_ospeed = t->c_ospeed;
    417   1.1  nisimura 	tp->t_cflag = t->c_cflag;
    418   1.1  nisimura 
    419   1.1  nisimura 	sc->sc_wr[WR3] &= 0x3f;
    420   1.1  nisimura 	sc->sc_wr[WR5] &= 0x9f;
    421   1.1  nisimura 	switch (tp->t_cflag & CSIZE) {
    422   1.1  nisimura 	case CS7:
    423   1.1  nisimura 		sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT;
    424   1.1  nisimura 		break;
    425   1.1  nisimura 	case CS8:
    426   1.1  nisimura 		sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT;
    427   1.1  nisimura 		break;
    428   1.1  nisimura 	}
    429  1.41   tsutsui 	if ((tp->t_cflag & PARENB) != 0) {
    430   1.1  nisimura 		wr4 |= WR4_PARENAB;
    431   1.1  nisimura 		if ((tp->t_cflag & PARODD) == 0)
    432   1.1  nisimura 			wr4 |= WR4_EPARITY;
    433   1.1  nisimura 	}
    434  1.36   tsutsui 	wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
    435   1.1  nisimura 	sc->sc_wr[WR4] = wr4;
    436   1.1  nisimura 
    437  1.33   tsutsui 	s = splserial();
    438   1.1  nisimura 	setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
    439   1.1  nisimura 	setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
    440   1.1  nisimura 	setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
    441   1.1  nisimura 	splx(s);
    442   1.1  nisimura 
    443   1.1  nisimura 	return 0;
    444   1.1  nisimura }
    445   1.1  nisimura 
    446   1.1  nisimura static int
    447  1.26       dsl siomctl(struct siotty_softc *sc, int control, int op)
    448   1.1  nisimura {
    449  1.37   tsutsui 	int val, s;
    450  1.37   tsutsui 	uint8_t wr5;
    451  1.37   tsutsui 	uint16_t rr;
    452   1.1  nisimura 
    453   1.1  nisimura 	val = 0;
    454  1.41   tsutsui 	if ((control & TIOCM_BREAK) != 0)
    455   1.1  nisimura 		val |= WR5_BREAK;
    456  1.41   tsutsui 	if ((control & TIOCM_DTR) != 0)
    457   1.1  nisimura 		val |= WR5_DTR;
    458  1.41   tsutsui 	if ((control & TIOCM_RTS) != 0)
    459   1.1  nisimura 		val |= WR5_RTS;
    460  1.33   tsutsui 	s = splserial();
    461   1.1  nisimura 	wr5 = sc->sc_wr[WR5];
    462   1.1  nisimura 	switch (op) {
    463   1.1  nisimura 	case DMSET:
    464   1.1  nisimura 		wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
    465   1.1  nisimura 		/* FALLTHRU */
    466   1.1  nisimura 	case DMBIS:
    467   1.1  nisimura 		wr5 |= val;
    468   1.1  nisimura 		break;
    469   1.1  nisimura 	case DMBIC:
    470   1.1  nisimura 		wr5 &= ~val;
    471   1.1  nisimura 		break;
    472   1.1  nisimura 	case DMGET:
    473   1.1  nisimura 		val = 0;
    474   1.1  nisimura 		rr = getsiocsr(sc->sc_ctl);
    475  1.41   tsutsui 		if ((wr5 & WR5_DTR) != 0)
    476   1.1  nisimura 			val |= TIOCM_DTR;
    477  1.41   tsutsui 		if ((wr5 & WR5_RTS) != 0)
    478   1.1  nisimura 			val |= TIOCM_RTS;
    479  1.41   tsutsui 		if ((rr & RR_CTS) != 0)
    480   1.1  nisimura 			val |= TIOCM_CTS;
    481  1.41   tsutsui 		if ((rr & RR_DCD) != 0)
    482   1.1  nisimura 			val |= TIOCM_CD;
    483   1.1  nisimura 		goto done;
    484   1.1  nisimura 	}
    485   1.1  nisimura 	sc->sc_wr[WR5] = wr5;
    486   1.1  nisimura 	setsioreg(sc->sc_ctl, WR5, wr5);
    487   1.1  nisimura 	val = 0;
    488  1.35   tsutsui  done:
    489   1.1  nisimura 	splx(s);
    490   1.1  nisimura 	return val;
    491   1.1  nisimura }
    492   1.1  nisimura 
    493   1.1  nisimura /*--------------------  cdevsw[] interface --------------------*/
    494   1.1  nisimura 
    495   1.1  nisimura int
    496  1.23    cegger sioopen(dev_t dev, int flag, int mode, struct lwp *l)
    497   1.1  nisimura {
    498   1.1  nisimura 	struct siotty_softc *sc;
    499   1.1  nisimura 	struct tty *tp;
    500   1.1  nisimura 	int error;
    501  1.37   tsutsui 	int s;
    502   1.1  nisimura 
    503  1.23    cegger 	sc = device_lookup_private(&siotty_cd, minor(dev));
    504  1.23    cegger 	if (sc == NULL)
    505   1.1  nisimura 		return ENXIO;
    506   1.1  nisimura 
    507  1.37   tsutsui 	tp = sc->sc_tty;
    508  1.19      elad 
    509  1.19      elad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    510  1.32   tsutsui 		return EBUSY;
    511  1.19      elad 
    512   1.1  nisimura 	if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
    513   1.1  nisimura 		struct termios t;
    514   1.1  nisimura 
    515  1.37   tsutsui 		tp->t_dev = dev;
    516   1.1  nisimura 		t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
    517   1.1  nisimura 		t.c_cflag = TTYDEF_CFLAG;
    518   1.1  nisimura 		tp->t_ospeed = 0; /* force register update */
    519   1.1  nisimura 		(void)sioparam(tp, &t);
    520   1.1  nisimura 		tp->t_iflag = TTYDEF_IFLAG;
    521   1.1  nisimura 		tp->t_oflag = TTYDEF_OFLAG;
    522   1.1  nisimura 		tp->t_lflag = TTYDEF_LFLAG;
    523   1.1  nisimura 		ttychars(tp);
    524   1.1  nisimura 		ttsetwater(tp);
    525   1.1  nisimura 		/* raise RTS and DTR here; but, DTR lead is not wired */
    526   1.1  nisimura 		/* then check DCD condition; but, DCD lead is not wired */
    527   1.1  nisimura #if 0
    528  1.41   tsutsui 		if ((sc->sc_flags & TIOCFLAG_SOFTCAR) != 0
    529  1.41   tsutsui 		    || (tp->t_cflag & MDMBUF) != 0
    530  1.41   tsutsui 		    || (getsiocsr(sc->sc_ctl) & RR_DCD) != 0)
    531   1.1  nisimura 			tp->t_state |= TS_CARR_ON;
    532   1.1  nisimura 		else
    533   1.1  nisimura 			tp->t_state &= ~TS_CARR_ON;
    534  1.37   tsutsui #else
    535  1.37   tsutsui 		tp->t_state |= TS_CARR_ON; /* assume detected all the time */
    536   1.1  nisimura #endif
    537  1.37   tsutsui 
    538  1.37   tsutsui 		s = splserial();
    539  1.37   tsutsui 		sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
    540  1.37   tsutsui 		sc->sc_rbavail = siotty_rbuf_size;
    541  1.37   tsutsui 		splx(s);
    542   1.1  nisimura 	}
    543   1.1  nisimura 
    544   1.1  nisimura 	error = ttyopen(tp, 0, (flag & O_NONBLOCK));
    545   1.1  nisimura 	if (error > 0)
    546   1.1  nisimura 		return error;
    547   1.5       eeh 	return (*tp->t_linesw->l_open)(dev, tp);
    548   1.1  nisimura }
    549  1.35   tsutsui 
    550   1.1  nisimura int
    551  1.23    cegger sioclose(dev_t dev, int flag, int mode, struct lwp *l)
    552   1.1  nisimura {
    553  1.23    cegger 	struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
    554   1.1  nisimura 	struct tty *tp = sc->sc_tty;
    555   1.1  nisimura 	int s;
    556   1.1  nisimura 
    557   1.5       eeh 	(*tp->t_linesw->l_close)(tp, flag);
    558   1.1  nisimura 
    559  1.33   tsutsui 	s = splserial();
    560   1.1  nisimura 	siomctl(sc, TIOCM_BREAK, DMBIC);
    561   1.1  nisimura #if 0 /* because unable to feed DTR signal */
    562  1.41   tsutsui 	if ((tp->t_cflag & HUPCL) != 0
    563   1.1  nisimura 	    || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
    564   1.1  nisimura 		siomctl(sc, TIOCM_DTR, DMBIC);
    565   1.1  nisimura 		/* Yield CPU time to others for 1 second, then ... */
    566   1.1  nisimura 		siomctl(sc, TIOCM_DTR, DMBIS);
    567   1.1  nisimura 	}
    568   1.1  nisimura #endif
    569   1.1  nisimura 	splx(s);
    570   1.1  nisimura 	return ttyclose(tp);
    571   1.1  nisimura }
    572  1.35   tsutsui 
    573   1.1  nisimura int
    574  1.23    cegger sioread(dev_t dev, struct uio *uio, int flag)
    575   1.1  nisimura {
    576  1.32   tsutsui 	struct siotty_softc *sc;
    577  1.32   tsutsui 	struct tty *tp;
    578  1.35   tsutsui 
    579  1.32   tsutsui 	sc = device_lookup_private(&siotty_cd, minor(dev));
    580  1.32   tsutsui 	tp = sc->sc_tty;
    581   1.5       eeh 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    582   1.1  nisimura }
    583  1.35   tsutsui 
    584   1.1  nisimura int
    585  1.23    cegger siowrite(dev_t dev, struct uio *uio, int flag)
    586   1.1  nisimura {
    587  1.32   tsutsui 	struct siotty_softc *sc;
    588  1.32   tsutsui 	struct tty *tp;
    589  1.35   tsutsui 
    590  1.32   tsutsui 	sc = device_lookup_private(&siotty_cd, minor(dev));
    591  1.32   tsutsui 	tp = sc->sc_tty;
    592   1.5       eeh 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    593   1.8       scw }
    594   1.8       scw 
    595   1.8       scw int
    596  1.23    cegger siopoll(dev_t dev, int events, struct lwp *l)
    597   1.8       scw {
    598  1.32   tsutsui 	struct siotty_softc *sc;
    599  1.32   tsutsui 	struct tty *tp;
    600  1.35   tsutsui 
    601  1.32   tsutsui 	sc = device_lookup_private(&siotty_cd, minor(dev));
    602  1.32   tsutsui 	tp = sc->sc_tty;
    603  1.16  christos 	return ((*tp->t_linesw->l_poll)(tp, events, l));
    604   1.1  nisimura }
    605   1.1  nisimura 
    606   1.1  nisimura int
    607  1.23    cegger sioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    608   1.1  nisimura {
    609  1.32   tsutsui 	struct siotty_softc *sc;
    610  1.32   tsutsui 	struct tty *tp;
    611   1.1  nisimura 	int error;
    612   1.1  nisimura 
    613  1.32   tsutsui 	sc = device_lookup_private(&siotty_cd, minor(dev));
    614  1.32   tsutsui 	tp = sc->sc_tty;
    615  1.16  christos 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    616   1.9    atatat 	if (error != EPASSTHROUGH)
    617   1.1  nisimura 		return error;
    618   1.9    atatat 
    619  1.16  christos 	error = ttioctl(tp, cmd, data, flag, l);
    620   1.9    atatat 	if (error != EPASSTHROUGH)
    621   1.1  nisimura 		return error;
    622   1.1  nisimura 
    623   1.1  nisimura 	/* the last resort for TIOC ioctl tranversing */
    624   1.1  nisimura 	switch (cmd) {
    625   1.1  nisimura 	case TIOCSBRK: /* Set the hardware into BREAK condition */
    626   1.1  nisimura 		siomctl(sc, TIOCM_BREAK, DMBIS);
    627   1.1  nisimura 		break;
    628   1.1  nisimura 	case TIOCCBRK: /* Clear the hardware BREAK condition */
    629   1.1  nisimura 		siomctl(sc, TIOCM_BREAK, DMBIC);
    630   1.1  nisimura 		break;
    631   1.1  nisimura 	case TIOCSDTR: /* Assert DTR signal */
    632   1.1  nisimura 		siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
    633   1.1  nisimura 		break;
    634   1.1  nisimura 	case TIOCCDTR: /* Clear DTR signal */
    635   1.1  nisimura 		siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
    636   1.1  nisimura 		break;
    637   1.1  nisimura 	case TIOCMSET: /* Set modem state replacing current one */
    638   1.1  nisimura 		siomctl(sc, *(int *)data, DMSET);
    639   1.1  nisimura 		break;
    640   1.1  nisimura 	case TIOCMGET: /* Return current modem state */
    641   1.1  nisimura 		*(int *)data = siomctl(sc, 0, DMGET);
    642   1.1  nisimura 		break;
    643   1.1  nisimura 	case TIOCMBIS: /* Set individual bits of modem state */
    644   1.1  nisimura 		siomctl(sc, *(int *)data, DMBIS);
    645   1.1  nisimura 		break;
    646   1.1  nisimura 	case TIOCMBIC: /* Clear individual bits of modem state */
    647   1.1  nisimura 		siomctl(sc, *(int *)data, DMBIC);
    648   1.1  nisimura 		break;
    649   1.1  nisimura 	case TIOCSFLAGS: /* Instruct how serial port behaves */
    650   1.1  nisimura 		sc->sc_flags = *(int *)data;
    651   1.1  nisimura 		break;
    652   1.1  nisimura 	case TIOCGFLAGS: /* Return current serial port state */
    653   1.1  nisimura 		*(int *)data = sc->sc_flags;
    654   1.1  nisimura 		break;
    655   1.1  nisimura 	default:
    656   1.9    atatat 		return EPASSTHROUGH;
    657   1.1  nisimura 	}
    658   1.1  nisimura 	return 0;
    659   1.1  nisimura }
    660   1.1  nisimura 
    661   1.1  nisimura /* ARSGUSED */
    662   1.1  nisimura struct tty *
    663  1.23    cegger siotty(dev_t dev)
    664   1.1  nisimura {
    665  1.32   tsutsui 	struct siotty_softc *sc;
    666  1.35   tsutsui 
    667  1.32   tsutsui 	sc = device_lookup_private(&siotty_cd, minor(dev));
    668   1.1  nisimura 	return sc->sc_tty;
    669   1.1  nisimura }
    670   1.1  nisimura 
    671   1.1  nisimura /*--------------------  miscelleneous routine --------------------*/
    672   1.1  nisimura 
    673   1.1  nisimura /* EXPORT */ void
    674  1.23    cegger setsioreg(struct sioreg *sio, int regno, int val)
    675   1.1  nisimura {
    676  1.32   tsutsui 
    677   1.1  nisimura 	if (regno != 0)
    678   1.1  nisimura 		sio->sio_cmd = regno;	/* DELAY(); */
    679   1.1  nisimura 	sio->sio_cmd = val;		/* DELAY(); */
    680   1.1  nisimura }
    681   1.1  nisimura 
    682  1.37   tsutsui /* EXPORT */ uint16_t
    683  1.23    cegger getsiocsr(struct sioreg *sio)
    684   1.1  nisimura {
    685   1.1  nisimura 	int val;
    686   1.1  nisimura 
    687   1.1  nisimura 	val = sio->sio_stat << 8;	/* DELAY(); */
    688   1.1  nisimura 	sio->sio_cmd = 1;		/* DELAY(); */
    689   1.1  nisimura 	val |= sio->sio_stat;		/* DELAY(); */
    690   1.1  nisimura 	return val;
    691   1.1  nisimura }
    692   1.1  nisimura 
    693   1.1  nisimura /*---------------------  console interface ----------------------*/
    694   1.1  nisimura 
    695  1.24       dsl void syscnattach(int);
    696  1.24       dsl int  syscngetc(dev_t);
    697  1.24       dsl void syscnputc(dev_t, int);
    698   1.1  nisimura 
    699   1.1  nisimura struct consdev syscons = {
    700   1.1  nisimura 	NULL,
    701   1.1  nisimura 	NULL,
    702   1.1  nisimura 	syscngetc,
    703   1.1  nisimura 	syscnputc,
    704   1.1  nisimura 	nullcnpollc,
    705  1.13        he 	NULL,
    706  1.13        he 	NULL,
    707   1.4   thorpej 	NULL,
    708   1.1  nisimura 	NODEV,
    709   1.1  nisimura 	CN_REMOTE,
    710   1.1  nisimura };
    711   1.1  nisimura 
    712   1.1  nisimura /* EXPORT */ void
    713  1.25       dsl syscnattach(int channel)
    714   1.1  nisimura {
    715   1.1  nisimura /*
    716   1.1  nisimura  * Channel A is immediately initialized with 9600N1 right after cold
    717   1.1  nisimura  * boot/reset/poweron.  ROM monitor emits one line message on CH.A.
    718   1.1  nisimura  */
    719   1.1  nisimura 	struct sioreg *sio;
    720   1.1  nisimura 	sio = (struct sioreg *)0x51000000 + channel;
    721   1.1  nisimura 
    722  1.10   gehenna 	syscons.cn_dev = makedev(cdevsw_lookup_major(&siotty_cdevsw),
    723  1.10   gehenna 				 channel);
    724   1.1  nisimura 	cn_tab = &syscons;
    725  1.37   tsutsui 	cn_init_magic(&siotty_cnm_state);
    726  1.37   tsutsui 	cn_set_magic("\047\001");
    727   1.1  nisimura 
    728   1.1  nisimura 	setsioreg(sio, WR0, WR0_CHANRST);
    729   1.1  nisimura 	setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1);
    730   1.1  nisimura 	setsioreg(sio, WR2B, 0);
    731   1.1  nisimura 	setsioreg(sio, WR0, ch0_regs[WR0]);
    732   1.1  nisimura 	setsioreg(sio, WR4, ch0_regs[WR4]);
    733   1.1  nisimura 	setsioreg(sio, WR3, ch0_regs[WR3]);
    734   1.1  nisimura 	setsioreg(sio, WR5, ch0_regs[WR5]);
    735   1.1  nisimura 	setsioreg(sio, WR0, ch0_regs[WR0]);
    736   1.1  nisimura }
    737   1.1  nisimura 
    738   1.1  nisimura /* EXPORT */ int
    739  1.25       dsl syscngetc(dev_t dev)
    740   1.1  nisimura {
    741   1.1  nisimura 	struct sioreg *sio;
    742   1.1  nisimura 	int s, c;
    743   1.1  nisimura 
    744   1.1  nisimura 	sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
    745   1.1  nisimura 	s = splhigh();
    746   1.1  nisimura 	while ((getsiocsr(sio) & RR_RXRDY) == 0)
    747  1.32   tsutsui 		continue;
    748   1.1  nisimura 	c = sio->sio_data;
    749   1.1  nisimura 	splx(s);
    750   1.1  nisimura 
    751   1.1  nisimura 	return c;
    752   1.1  nisimura }
    753   1.1  nisimura 
    754   1.1  nisimura /* EXPORT */ void
    755  1.25       dsl syscnputc(dev_t dev, int c)
    756   1.1  nisimura {
    757   1.1  nisimura 	struct sioreg *sio;
    758   1.1  nisimura 	int s;
    759   1.1  nisimura 
    760   1.1  nisimura 	sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
    761   1.1  nisimura 	s = splhigh();
    762   1.1  nisimura 	while ((getsiocsr(sio) & RR_TXRDY) == 0)
    763  1.32   tsutsui 		continue;
    764   1.1  nisimura 	sio->sio_cmd = WR0_RSTPEND;
    765   1.1  nisimura 	sio->sio_data = c;
    766   1.1  nisimura 	splx(s);
    767   1.1  nisimura }
    768