1*dfc190eaSaoyama /* $OpenBSD: siotty.c,v 1.25 2021/01/09 02:34:21 aoyama Exp $ */
202b01b5eSaoyama /* $NetBSD: siotty.c,v 1.9 2002/03/17 19:40:43 atatat Exp $ */
302b01b5eSaoyama
402b01b5eSaoyama /*-
502b01b5eSaoyama * Copyright (c) 2000 The NetBSD Foundation, Inc.
602b01b5eSaoyama * All rights reserved.
702b01b5eSaoyama *
802b01b5eSaoyama * This code is derived from software contributed to The NetBSD Foundation
902b01b5eSaoyama * by Tohru Nishimura.
1002b01b5eSaoyama *
1102b01b5eSaoyama * Redistribution and use in source and binary forms, with or without
1202b01b5eSaoyama * modification, are permitted provided that the following conditions
1302b01b5eSaoyama * are met:
1402b01b5eSaoyama * 1. Redistributions of source code must retain the above copyright
1502b01b5eSaoyama * notice, this list of conditions and the following disclaimer.
1602b01b5eSaoyama * 2. Redistributions in binary form must reproduce the above copyright
1702b01b5eSaoyama * notice, this list of conditions and the following disclaimer in the
1802b01b5eSaoyama * documentation and/or other materials provided with the distribution.
1902b01b5eSaoyama *
2002b01b5eSaoyama * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2102b01b5eSaoyama * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2202b01b5eSaoyama * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2302b01b5eSaoyama * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2402b01b5eSaoyama * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2502b01b5eSaoyama * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2602b01b5eSaoyama * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2702b01b5eSaoyama * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2802b01b5eSaoyama * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2902b01b5eSaoyama * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3002b01b5eSaoyama * POSSIBILITY OF SUCH DAMAGE.
3102b01b5eSaoyama */
3202b01b5eSaoyama
3302b01b5eSaoyama #include <sys/param.h>
3402b01b5eSaoyama #include <sys/systm.h>
3502b01b5eSaoyama #include <sys/device.h>
3602b01b5eSaoyama #include <sys/conf.h>
3702b01b5eSaoyama #include <sys/ioctl.h>
3865958cb6Saoyama #include <sys/malloc.h>
3902b01b5eSaoyama #include <sys/proc.h>
4002b01b5eSaoyama #include <sys/tty.h>
4102b01b5eSaoyama #include <sys/uio.h>
4202b01b5eSaoyama #include <sys/fcntl.h>
4302b01b5eSaoyama #include <dev/cons.h>
4402b01b5eSaoyama
458aed167bSmiod #include <machine/board.h>
4602b01b5eSaoyama #include <machine/cpu.h>
4702b01b5eSaoyama
4802b01b5eSaoyama #include <luna88k/dev/sioreg.h>
4902b01b5eSaoyama #include <luna88k/dev/siovar.h>
5002b01b5eSaoyama
5102b01b5eSaoyama #define TIOCM_BREAK 01000 /* non standard use */
5202b01b5eSaoyama
5302b01b5eSaoyama static const u_int8_t ch0_regs[6] = {
5402b01b5eSaoyama WR0_RSTINT, /* reset E/S interrupt */
5502b01b5eSaoyama WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */
5602b01b5eSaoyama 0, /* */
5702b01b5eSaoyama WR3_RX8BIT | WR3_RXENBL, /* Rx */
5802b01b5eSaoyama WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */
5902b01b5eSaoyama WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
6002b01b5eSaoyama };
6102b01b5eSaoyama
6265cd0f3cSmickey static const struct speedtab siospeedtab[] = {
6302b01b5eSaoyama { 2400, WR4_BAUD24, },
6402b01b5eSaoyama { 4800, WR4_BAUD48, },
6502b01b5eSaoyama { 9600, WR4_BAUD96, },
6602b01b5eSaoyama { -1, 0, },
6702b01b5eSaoyama };
6802b01b5eSaoyama
6902b01b5eSaoyama struct siotty_softc {
7002b01b5eSaoyama struct device sc_dev;
7102b01b5eSaoyama struct tty *sc_tty;
7202b01b5eSaoyama struct sioreg *sc_ctl;
7302b01b5eSaoyama u_int sc_flags;
7402b01b5eSaoyama u_int8_t sc_wr[6];
7565958cb6Saoyama void *sc_si; /* software interrupt handler */
7665958cb6Saoyama u_int sc_hwflags;
7765958cb6Saoyama #define SIOTTY_HW_CONSOLE 0x0001
7865958cb6Saoyama
7965958cb6Saoyama u_int8_t *sc_rbuf;
8065958cb6Saoyama u_int8_t *sc_rbufend;
8165958cb6Saoyama u_int8_t * volatile sc_rbget;
8265958cb6Saoyama u_int8_t * volatile sc_rbput;
8365958cb6Saoyama volatile u_int sc_rbavail;
8465958cb6Saoyama
8565958cb6Saoyama u_int8_t *sc_tba;
8665958cb6Saoyama u_int sc_tbc;
8765958cb6Saoyama
8865958cb6Saoyama bool sc_rx_ready;
8965958cb6Saoyama bool sc_tx_busy;
9065958cb6Saoyama bool sc_tx_done;
9102b01b5eSaoyama };
9202b01b5eSaoyama
9365958cb6Saoyama #define SIOTTY_RING_SIZE 2048
9465958cb6Saoyama u_int siotty_rbuf_size = SIOTTY_RING_SIZE;
9565958cb6Saoyama
9602b01b5eSaoyama cdev_decl(sio);
9702b01b5eSaoyama void siostart(struct tty *);
9802b01b5eSaoyama int sioparam(struct tty *, struct termios *);
99b6c895f4Saoyama void siottyintr(void *);
10065958cb6Saoyama void siottysoft(void *);
10165958cb6Saoyama void siotty_rxsoft(struct siotty_softc *, struct tty *);
10265958cb6Saoyama void siotty_txsoft(struct siotty_softc *, struct tty *);
10302b01b5eSaoyama int siomctl(struct siotty_softc *, int, int);
10402b01b5eSaoyama
10502b01b5eSaoyama int siotty_match(struct device *, void *, void *);
10602b01b5eSaoyama void siotty_attach(struct device *, struct device *, void *);
10702b01b5eSaoyama
10802b01b5eSaoyama const struct cfattach siotty_ca = {
10902b01b5eSaoyama sizeof(struct siotty_softc), siotty_match, siotty_attach
11002b01b5eSaoyama };
11102b01b5eSaoyama
11210e8dd75Smiod struct cfdriver siotty_cd = {
11302b01b5eSaoyama NULL, "siotty", DV_TTY
11402b01b5eSaoyama };
11502b01b5eSaoyama
11602b01b5eSaoyama int
siotty_match(struct device * parent,void * cf,void * aux)11780bc78ddSaoyama siotty_match(struct device *parent, void *cf, void *aux)
11802b01b5eSaoyama {
11902b01b5eSaoyama struct sio_attach_args *args = aux;
12002b01b5eSaoyama
12102b01b5eSaoyama if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
12202b01b5eSaoyama return 0;
12302b01b5eSaoyama return 1;
12402b01b5eSaoyama }
12502b01b5eSaoyama
12602b01b5eSaoyama void
siotty_attach(struct device * parent,struct device * self,void * aux)12780bc78ddSaoyama siotty_attach(struct device *parent, struct device *self, void *aux)
12802b01b5eSaoyama {
129b6c895f4Saoyama struct sio_softc *siosc = (void *)parent;
13002b01b5eSaoyama struct siotty_softc *sc = (void *)self;
13102b01b5eSaoyama struct sio_attach_args *args = aux;
132b6c895f4Saoyama int channel;
13365958cb6Saoyama struct tty *tp;
13402b01b5eSaoyama
135b6c895f4Saoyama channel = args->channel;
136b6c895f4Saoyama sc->sc_ctl = &siosc->sc_ctl[channel];
137b6c895f4Saoyama memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs));
138b6c895f4Saoyama siosc->sc_intrhand[channel].ih_func = siottyintr;
139b6c895f4Saoyama siosc->sc_intrhand[channel].ih_arg = sc;
14065958cb6Saoyama if (args->hwflags == 1)
14165958cb6Saoyama sc->sc_hwflags |= SIOTTY_HW_CONSOLE;
14202b01b5eSaoyama
14365958cb6Saoyama if (sc->sc_hwflags & SIOTTY_HW_CONSOLE) {
14402b01b5eSaoyama printf(" (console)");
14502b01b5eSaoyama sc->sc_flags = TIOCFLAG_SOFTCAR;
14665958cb6Saoyama } else {
14702b01b5eSaoyama setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
14802b01b5eSaoyama setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1);
14902b01b5eSaoyama setsioreg(sc->sc_ctl, WR2B, 0);
15002b01b5eSaoyama setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
15102b01b5eSaoyama setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
15202b01b5eSaoyama setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
15302b01b5eSaoyama setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
15402b01b5eSaoyama setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
15502b01b5eSaoyama }
15602b01b5eSaoyama setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
15702b01b5eSaoyama
15802b01b5eSaoyama printf("\n");
15965958cb6Saoyama
16065958cb6Saoyama sc->sc_rbuf = malloc(siotty_rbuf_size * 2, M_DEVBUF, M_NOWAIT);
16165958cb6Saoyama if (sc->sc_rbuf == NULL) {
16265958cb6Saoyama printf("%s: unable to allocate ring buffer\n",
16365958cb6Saoyama (sc->sc_dev).dv_xname);
16465958cb6Saoyama return;
16565958cb6Saoyama }
16665958cb6Saoyama sc->sc_rbufend = sc->sc_rbuf + (siotty_rbuf_size * 2);
16765958cb6Saoyama sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
16865958cb6Saoyama sc->sc_rbavail = siotty_rbuf_size;
16965958cb6Saoyama
17065958cb6Saoyama tp = ttymalloc(0);
17165958cb6Saoyama tp->t_oproc = siostart;
17265958cb6Saoyama tp->t_param = sioparam;
17365958cb6Saoyama tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
17465958cb6Saoyama if (sc->sc_hwflags & SIOTTY_HW_CONSOLE)
17565958cb6Saoyama tp->t_dev = cn_tab->cn_dev;
17665958cb6Saoyama sc->sc_tty = tp;
17765958cb6Saoyama
17865958cb6Saoyama sc->sc_si = softintr_establish(IPL_SOFTTTY, siottysoft, sc);
17902b01b5eSaoyama }
18002b01b5eSaoyama
18102b01b5eSaoyama /*-------------------- low level routine --------------------*/
18202b01b5eSaoyama
18302b01b5eSaoyama void
siottyintr(void * arg)184b6c895f4Saoyama siottyintr(void *arg)
18502b01b5eSaoyama {
18602b01b5eSaoyama struct siotty_softc *sc;
18702b01b5eSaoyama struct sioreg *sio;
18865958cb6Saoyama u_int8_t *put, *end;
18965958cb6Saoyama u_int8_t c;
19065958cb6Saoyama u_int16_t rr;
19165958cb6Saoyama int cc;
19202b01b5eSaoyama
19365958cb6Saoyama sc = arg;
19465958cb6Saoyama end = sc->sc_rbufend;
19565958cb6Saoyama put = sc->sc_rbput;
19665958cb6Saoyama cc = sc->sc_rbavail;
19765958cb6Saoyama
19802b01b5eSaoyama sio = sc->sc_ctl;
19902b01b5eSaoyama rr = getsiocsr(sio);
20002b01b5eSaoyama if (rr & RR_RXRDY) {
20102b01b5eSaoyama do {
20265958cb6Saoyama if (cc > 0) {
20365958cb6Saoyama c = sio->sio_data;
20465958cb6Saoyama put[0] = c;
20565958cb6Saoyama put[1] = rr & 0xff;
20665958cb6Saoyama put += 2;
20765958cb6Saoyama if (put >= end)
20865958cb6Saoyama put = sc->sc_rbuf;
20965958cb6Saoyama cc--;
21065958cb6Saoyama }
21165958cb6Saoyama if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY))
21202b01b5eSaoyama sio->sio_cmd = WR0_ERRRST;
21365958cb6Saoyama
21465958cb6Saoyama sc->sc_rbput = put;
21565958cb6Saoyama sc->sc_rbavail = cc;
21665958cb6Saoyama sc->sc_rx_ready = true;
21702b01b5eSaoyama } while ((rr = getsiocsr(sio)) & RR_RXRDY);
21802b01b5eSaoyama }
21902b01b5eSaoyama if (rr & RR_TXRDY) {
22002b01b5eSaoyama sio->sio_cmd = WR0_RSTPEND;
22165958cb6Saoyama if (sc->sc_tbc > 0) {
22265958cb6Saoyama sio->sio_data = *sc->sc_tba;
22365958cb6Saoyama sc->sc_tba++;
22465958cb6Saoyama sc->sc_tbc--;
22565958cb6Saoyama } else {
22665958cb6Saoyama if (sc->sc_tx_busy) {
22765958cb6Saoyama sc->sc_tx_busy = false;
22865958cb6Saoyama sc->sc_tx_done = true;
22965958cb6Saoyama }
23065958cb6Saoyama }
23165958cb6Saoyama }
23265958cb6Saoyama softintr_schedule(sc->sc_si);
23365958cb6Saoyama }
23465958cb6Saoyama
23565958cb6Saoyama void
siottysoft(void * arg)23665958cb6Saoyama siottysoft(void *arg)
23765958cb6Saoyama {
23865958cb6Saoyama struct siotty_softc *sc;
23965958cb6Saoyama struct tty *tp;
24065958cb6Saoyama
24165958cb6Saoyama sc = arg;
24265958cb6Saoyama tp = sc->sc_tty;
24365958cb6Saoyama
24465958cb6Saoyama if (sc->sc_rx_ready) {
24565958cb6Saoyama sc->sc_rx_ready = false;
24665958cb6Saoyama siotty_rxsoft(sc, tp);
24765958cb6Saoyama }
24865958cb6Saoyama if (sc->sc_tx_done) {
24965958cb6Saoyama sc->sc_tx_done = false;
25065958cb6Saoyama siotty_txsoft(sc, tp);
25165958cb6Saoyama }
25265958cb6Saoyama }
25365958cb6Saoyama
25465958cb6Saoyama void
siotty_rxsoft(struct siotty_softc * sc,struct tty * tp)25565958cb6Saoyama siotty_rxsoft(struct siotty_softc *sc, struct tty *tp)
25665958cb6Saoyama {
25765958cb6Saoyama uint8_t *get, *end;
25865958cb6Saoyama u_int cc, scc;
25965958cb6Saoyama unsigned int code;
26065958cb6Saoyama uint8_t stat;
26165958cb6Saoyama int s;
26265958cb6Saoyama
26365958cb6Saoyama end = sc->sc_rbufend;
26465958cb6Saoyama get = sc->sc_rbget;
26565958cb6Saoyama scc = cc = siotty_rbuf_size - sc->sc_rbavail;
26665958cb6Saoyama
26765958cb6Saoyama if (cc == siotty_rbuf_size) {
26865958cb6Saoyama printf("%s: rx buffer overflow\n", (sc->sc_dev).dv_xname);
26965958cb6Saoyama }
27065958cb6Saoyama
27165958cb6Saoyama while (cc > 0) {
27265958cb6Saoyama code = get[0];
27365958cb6Saoyama stat = get[1];
27465958cb6Saoyama if ((stat & RR_FRAMING) != 0)
27565958cb6Saoyama code |= TTY_FE;
27665958cb6Saoyama else if ((stat & RR_PARITY) != 0)
27765958cb6Saoyama code |= TTY_PE;
27865958cb6Saoyama
27965958cb6Saoyama (*linesw[tp->t_line].l_rint)(code, tp);
28065958cb6Saoyama get += 2;
28165958cb6Saoyama if (get >= end)
28265958cb6Saoyama get = sc->sc_rbuf;
28365958cb6Saoyama cc--;
28465958cb6Saoyama }
28565958cb6Saoyama
28665958cb6Saoyama if (cc != scc) {
28765958cb6Saoyama s = spltty();
28865958cb6Saoyama sc->sc_rbget = get;
28965958cb6Saoyama sc->sc_rbavail += scc - cc;
29065958cb6Saoyama splx(s);
29165958cb6Saoyama }
29265958cb6Saoyama }
29365958cb6Saoyama
29465958cb6Saoyama void
siotty_txsoft(struct siotty_softc * sc,struct tty * tp)29565958cb6Saoyama siotty_txsoft(struct siotty_softc *sc, struct tty *tp)
29665958cb6Saoyama {
29765958cb6Saoyama
29865958cb6Saoyama tp->t_state &= ~TS_BUSY;
29965958cb6Saoyama if ((tp->t_state & TS_FLUSH) != 0)
30065958cb6Saoyama tp->t_state &= ~TS_FLUSH;
30165958cb6Saoyama else
30265958cb6Saoyama ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
30302b01b5eSaoyama (*linesw[tp->t_line].l_start)(tp);
30402b01b5eSaoyama }
30502b01b5eSaoyama
30602b01b5eSaoyama void
siostart(struct tty * tp)30780bc78ddSaoyama siostart(struct tty *tp)
30802b01b5eSaoyama {
30902b01b5eSaoyama struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)];
31065958cb6Saoyama int s;
31165958cb6Saoyama u_int8_t *tba;
31265958cb6Saoyama int tbc;
31302b01b5eSaoyama
31402b01b5eSaoyama s = spltty();
31502b01b5eSaoyama if (tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP))
31602b01b5eSaoyama goto out;
3174cc8800eSnicm ttwakeupwr(tp);
31802b01b5eSaoyama if (tp->t_outq.c_cc == 0)
31902b01b5eSaoyama goto out;
32002b01b5eSaoyama
32102b01b5eSaoyama tp->t_state |= TS_BUSY;
32265958cb6Saoyama
32365958cb6Saoyama tba = tp->t_outq.c_cf;
32465958cb6Saoyama tbc = ndqb(&tp->t_outq, 0);
32565958cb6Saoyama
32665958cb6Saoyama sc->sc_tba = tba;
32765958cb6Saoyama sc->sc_tbc = tbc;
32865958cb6Saoyama sc->sc_tx_busy = true;
32965958cb6Saoyama
33065958cb6Saoyama sc->sc_ctl->sio_data = *sc->sc_tba;
33165958cb6Saoyama sc->sc_tba++;
33265958cb6Saoyama sc->sc_tbc--;
33302b01b5eSaoyama out:
33402b01b5eSaoyama splx(s);
33502b01b5eSaoyama }
33602b01b5eSaoyama
33702b01b5eSaoyama int
siostop(struct tty * tp,int flag)33880bc78ddSaoyama siostop(struct tty *tp, int flag)
33902b01b5eSaoyama {
34002b01b5eSaoyama int s;
34102b01b5eSaoyama
34202b01b5eSaoyama s = spltty();
34302b01b5eSaoyama if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
34402b01b5eSaoyama /*
34502b01b5eSaoyama * Device is transmitting; must stop it.
34602b01b5eSaoyama */
34702b01b5eSaoyama tp->t_state |= TS_FLUSH;
34802b01b5eSaoyama }
34902b01b5eSaoyama splx(s);
35002b01b5eSaoyama return (0);
35102b01b5eSaoyama }
35202b01b5eSaoyama
35302b01b5eSaoyama int
sioparam(struct tty * tp,struct termios * t)35480bc78ddSaoyama sioparam(struct tty *tp, struct termios *t)
35502b01b5eSaoyama {
35602b01b5eSaoyama struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)];
35702b01b5eSaoyama int wr4, s;
35802b01b5eSaoyama
35902b01b5eSaoyama if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
36002b01b5eSaoyama return EINVAL;
36102b01b5eSaoyama wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
36202b01b5eSaoyama if (wr4 < 0)
36302b01b5eSaoyama return EINVAL;
36402b01b5eSaoyama
36502b01b5eSaoyama if (sc->sc_flags & TIOCFLAG_SOFTCAR) {
36602b01b5eSaoyama t->c_cflag |= CLOCAL;
36702b01b5eSaoyama t->c_cflag &= ~HUPCL;
36802b01b5eSaoyama }
36902b01b5eSaoyama if (sc->sc_flags & TIOCFLAG_CLOCAL)
37002b01b5eSaoyama t->c_cflag |= CLOCAL;
37102b01b5eSaoyama
37202b01b5eSaoyama /*
37302b01b5eSaoyama * If there were no changes, don't do anything. This avoids dropping
37402b01b5eSaoyama * input and improves performance when all we did was frob things like
37502b01b5eSaoyama * VMIN and VTIME.
37602b01b5eSaoyama */
37702b01b5eSaoyama if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
37802b01b5eSaoyama return 0;
37902b01b5eSaoyama
38002b01b5eSaoyama tp->t_ispeed = t->c_ispeed;
38102b01b5eSaoyama tp->t_ospeed = t->c_ospeed;
38202b01b5eSaoyama tp->t_cflag = t->c_cflag;
38302b01b5eSaoyama
38402b01b5eSaoyama sc->sc_wr[WR3] &= 0x3f;
38502b01b5eSaoyama sc->sc_wr[WR5] &= 0x9f;
38602b01b5eSaoyama switch (tp->t_cflag & CSIZE) {
38702b01b5eSaoyama case CS7:
38802b01b5eSaoyama sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT;
38902b01b5eSaoyama break;
39002b01b5eSaoyama case CS8:
39102b01b5eSaoyama sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT;
39202b01b5eSaoyama break;
39302b01b5eSaoyama }
39402b01b5eSaoyama if (tp->t_cflag & PARENB) {
39502b01b5eSaoyama wr4 |= WR4_PARENAB;
39602b01b5eSaoyama if ((tp->t_cflag & PARODD) == 0)
39702b01b5eSaoyama wr4 |= WR4_EPARITY;
39802b01b5eSaoyama }
39902b01b5eSaoyama wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
40002b01b5eSaoyama sc->sc_wr[WR4] = wr4;
40102b01b5eSaoyama
40202b01b5eSaoyama s = spltty();
40302b01b5eSaoyama setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
40402b01b5eSaoyama setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
40502b01b5eSaoyama setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
40602b01b5eSaoyama splx(s);
40702b01b5eSaoyama
40802b01b5eSaoyama return 0;
40902b01b5eSaoyama }
41002b01b5eSaoyama
41102b01b5eSaoyama int
siomctl(struct siotty_softc * sc,int control,int op)41280bc78ddSaoyama siomctl(struct siotty_softc *sc, int control, int op)
41302b01b5eSaoyama {
41402b01b5eSaoyama int val, s, wr5, rr;
41502b01b5eSaoyama
41602b01b5eSaoyama val = 0;
41702b01b5eSaoyama if (control & TIOCM_BREAK)
41802b01b5eSaoyama val |= WR5_BREAK;
41902b01b5eSaoyama if (control & TIOCM_DTR)
42002b01b5eSaoyama val |= WR5_DTR;
42102b01b5eSaoyama if (control & TIOCM_RTS)
42202b01b5eSaoyama val |= WR5_RTS;
42302b01b5eSaoyama s = spltty();
42402b01b5eSaoyama wr5 = sc->sc_wr[WR5];
42502b01b5eSaoyama switch (op) {
42602b01b5eSaoyama case DMSET:
42702b01b5eSaoyama wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
428341cd9feSjsg /* FALLTHROUGH */
42902b01b5eSaoyama case DMBIS:
43002b01b5eSaoyama wr5 |= val;
43102b01b5eSaoyama break;
43202b01b5eSaoyama case DMBIC:
43302b01b5eSaoyama wr5 &= ~val;
43402b01b5eSaoyama break;
43502b01b5eSaoyama case DMGET:
43602b01b5eSaoyama val = 0;
43702b01b5eSaoyama rr = getsiocsr(sc->sc_ctl);
43802b01b5eSaoyama if (wr5 & WR5_DTR)
43902b01b5eSaoyama val |= TIOCM_DTR;
44002b01b5eSaoyama if (wr5 & WR5_RTS)
44102b01b5eSaoyama val |= TIOCM_RTS;
44202b01b5eSaoyama if (rr & RR_CTS)
44302b01b5eSaoyama val |= TIOCM_CTS;
44402b01b5eSaoyama if (rr & RR_DCD)
44502b01b5eSaoyama val |= TIOCM_CD;
44602b01b5eSaoyama goto done;
44702b01b5eSaoyama }
44802b01b5eSaoyama sc->sc_wr[WR5] = wr5;
44902b01b5eSaoyama setsioreg(sc->sc_ctl, WR5, wr5);
45002b01b5eSaoyama val = 0;
45102b01b5eSaoyama done:
45202b01b5eSaoyama splx(s);
45302b01b5eSaoyama return val;
45402b01b5eSaoyama }
45502b01b5eSaoyama
45602b01b5eSaoyama /*-------------------- cdevsw[] interface --------------------*/
45702b01b5eSaoyama
45802b01b5eSaoyama int
sioopen(dev_t dev,int flag,int mode,struct proc * p)45980bc78ddSaoyama sioopen(dev_t dev, int flag, int mode, struct proc *p)
46002b01b5eSaoyama {
46102b01b5eSaoyama struct siotty_softc *sc;
46202b01b5eSaoyama struct tty *tp;
46365958cb6Saoyama int s;
46402b01b5eSaoyama
46502b01b5eSaoyama if ((sc = siotty_cd.cd_devs[minor(dev)]) == NULL)
46602b01b5eSaoyama return ENXIO;
46765958cb6Saoyama
46865958cb6Saoyama tp = sc->sc_tty;
46965958cb6Saoyama
47065958cb6Saoyama if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE)
4713e676399Smpi && suser(p) != 0)
47202b01b5eSaoyama return EBUSY;
47302b01b5eSaoyama
47402b01b5eSaoyama if ((tp->t_state & TS_ISOPEN) == 0) {
47502b01b5eSaoyama struct termios t;
47602b01b5eSaoyama
47765958cb6Saoyama tp->t_dev = dev;
47802b01b5eSaoyama t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
47902b01b5eSaoyama t.c_cflag = TTYDEF_CFLAG;
48002b01b5eSaoyama tp->t_ospeed = 0; /* force register update */
48102b01b5eSaoyama (void)sioparam(tp, &t);
48202b01b5eSaoyama tp->t_iflag = TTYDEF_IFLAG;
48302b01b5eSaoyama tp->t_oflag = TTYDEF_OFLAG;
48402b01b5eSaoyama tp->t_lflag = TTYDEF_LFLAG;
48502b01b5eSaoyama ttychars(tp);
48602b01b5eSaoyama ttsetwater(tp);
48702b01b5eSaoyama /* raise RTS and DTR here; but, DTR lead is not wired */
48802b01b5eSaoyama /* then check DCD condition; but, DCD lead is not wired */
48902b01b5eSaoyama #if 0
49002b01b5eSaoyama if ((sc->sc_flags & TIOCFLAG_SOFTCAR)
49102b01b5eSaoyama || (tp->t_cflag & MDMBUF)
49202b01b5eSaoyama || (getsiocsr(sc->sc_ctl) & RR_DCD))
49302b01b5eSaoyama tp->t_state |= TS_CARR_ON;
49402b01b5eSaoyama else
49502b01b5eSaoyama tp->t_state &= ~TS_CARR_ON;
49665958cb6Saoyama #else
49765958cb6Saoyama tp->t_state |= TS_CARR_ON; /* assume detected all the time */
49802b01b5eSaoyama #endif
49965958cb6Saoyama s = spltty();
50065958cb6Saoyama sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
50165958cb6Saoyama sc->sc_rbavail = siotty_rbuf_size;
50265958cb6Saoyama splx(s);
50302b01b5eSaoyama }
50402b01b5eSaoyama
50579f6c33aStedu return (*linesw[tp->t_line].l_open)(dev, tp, p);
50602b01b5eSaoyama }
50702b01b5eSaoyama
50802b01b5eSaoyama int
sioclose(dev_t dev,int flag,int mode,struct proc * p)50980bc78ddSaoyama sioclose(dev_t dev, int flag, int mode, struct proc *p)
51002b01b5eSaoyama {
51102b01b5eSaoyama struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
51202b01b5eSaoyama struct tty *tp = sc->sc_tty;
51302b01b5eSaoyama int s;
51402b01b5eSaoyama
51579f6c33aStedu (*linesw[tp->t_line].l_close)(tp, flag, p);
51602b01b5eSaoyama
51702b01b5eSaoyama s = spltty();
51802b01b5eSaoyama siomctl(sc, TIOCM_BREAK, DMBIC);
51902b01b5eSaoyama #if 0 /* because unable to feed DTR signal */
52002b01b5eSaoyama if ((tp->t_cflag & HUPCL)
52102b01b5eSaoyama || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
52202b01b5eSaoyama siomctl(sc, TIOCM_DTR, DMBIC);
52302b01b5eSaoyama /* Yield CPU time to others for 1 second, then ... */
52402b01b5eSaoyama siomctl(sc, TIOCM_DTR, DMBIS);
52502b01b5eSaoyama }
52602b01b5eSaoyama #endif
52702b01b5eSaoyama splx(s);
52802b01b5eSaoyama return ttyclose(tp);
52902b01b5eSaoyama }
53002b01b5eSaoyama
53102b01b5eSaoyama int
sioread(dev_t dev,struct uio * uio,int flag)53280bc78ddSaoyama sioread(dev_t dev, struct uio *uio, int flag)
53302b01b5eSaoyama {
53402b01b5eSaoyama struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
53502b01b5eSaoyama struct tty *tp = sc->sc_tty;
53602b01b5eSaoyama
53702b01b5eSaoyama return (*linesw[tp->t_line].l_read)(tp, uio, flag);
53802b01b5eSaoyama }
53902b01b5eSaoyama
54002b01b5eSaoyama int
siowrite(dev_t dev,struct uio * uio,int flag)54180bc78ddSaoyama siowrite(dev_t dev, struct uio *uio, int flag)
54202b01b5eSaoyama {
54302b01b5eSaoyama struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
54402b01b5eSaoyama struct tty *tp = sc->sc_tty;
54502b01b5eSaoyama
54602b01b5eSaoyama return (*linesw[tp->t_line].l_write)(tp, uio, flag);
54702b01b5eSaoyama }
54802b01b5eSaoyama
54902b01b5eSaoyama int
sioioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)55080bc78ddSaoyama sioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
55102b01b5eSaoyama {
55202b01b5eSaoyama struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
55302b01b5eSaoyama struct tty *tp = sc->sc_tty;
55402b01b5eSaoyama int error;
55502b01b5eSaoyama
55602b01b5eSaoyama error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
55702b01b5eSaoyama if (error >= 0)
55802b01b5eSaoyama return error;
55902b01b5eSaoyama
56002b01b5eSaoyama error = ttioctl(tp, cmd, data, flag, p);
56102b01b5eSaoyama if (error >= 0)
56202b01b5eSaoyama return error;
56302b01b5eSaoyama
564e4c489dbSjca /* the last resort for TIOC ioctl traversing */
56502b01b5eSaoyama switch (cmd) {
56602b01b5eSaoyama case TIOCSBRK: /* Set the hardware into BREAK condition */
56702b01b5eSaoyama siomctl(sc, TIOCM_BREAK, DMBIS);
56802b01b5eSaoyama break;
56902b01b5eSaoyama case TIOCCBRK: /* Clear the hardware BREAK condition */
57002b01b5eSaoyama siomctl(sc, TIOCM_BREAK, DMBIC);
57102b01b5eSaoyama break;
57202b01b5eSaoyama case TIOCSDTR: /* Assert DTR signal */
57302b01b5eSaoyama siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
57402b01b5eSaoyama break;
57502b01b5eSaoyama case TIOCCDTR: /* Clear DTR signal */
57602b01b5eSaoyama siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
57702b01b5eSaoyama break;
57802b01b5eSaoyama case TIOCMSET: /* Set modem state replacing current one */
57902b01b5eSaoyama siomctl(sc, *(int *)data, DMSET);
58002b01b5eSaoyama break;
58102b01b5eSaoyama case TIOCMGET: /* Return current modem state */
58202b01b5eSaoyama *(int *)data = siomctl(sc, 0, DMGET);
58302b01b5eSaoyama break;
58402b01b5eSaoyama case TIOCMBIS: /* Set individual bits of modem state */
58502b01b5eSaoyama siomctl(sc, *(int *)data, DMBIS);
58602b01b5eSaoyama break;
58702b01b5eSaoyama case TIOCMBIC: /* Clear individual bits of modem state */
58802b01b5eSaoyama siomctl(sc, *(int *)data, DMBIC);
58902b01b5eSaoyama break;
59002b01b5eSaoyama case TIOCSFLAGS: /* Instruct how serial port behaves */
5913e676399Smpi error = suser(p);
5922b84db25Smiod if (error != 0)
5932b84db25Smiod return EPERM;
59402b01b5eSaoyama sc->sc_flags = *(int *)data;
59502b01b5eSaoyama break;
59602b01b5eSaoyama case TIOCGFLAGS: /* Return current serial port state */
59702b01b5eSaoyama *(int *)data = sc->sc_flags;
59802b01b5eSaoyama break;
59902b01b5eSaoyama default:
60002b01b5eSaoyama return ENOTTY;
60102b01b5eSaoyama }
60202b01b5eSaoyama return 0;
60302b01b5eSaoyama }
60402b01b5eSaoyama
60502b01b5eSaoyama /* ARSGUSED */
60602b01b5eSaoyama struct tty *
siotty(dev_t dev)60780bc78ddSaoyama siotty(dev_t dev)
60802b01b5eSaoyama {
60902b01b5eSaoyama struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
61002b01b5eSaoyama
61102b01b5eSaoyama return sc->sc_tty;
61202b01b5eSaoyama }
61302b01b5eSaoyama
61402b01b5eSaoyama /*-------------------- miscellaneous routines --------------------*/
61502b01b5eSaoyama
61602b01b5eSaoyama /* EXPORT */ void
setsioreg(struct sioreg * sio,int regno,int val)61780bc78ddSaoyama setsioreg(struct sioreg *sio, int regno, int val)
61802b01b5eSaoyama {
61902b01b5eSaoyama if (regno != 0)
62002b01b5eSaoyama sio->sio_cmd = regno; /* DELAY(); */
62102b01b5eSaoyama sio->sio_cmd = val; /* DELAY(); */
62202b01b5eSaoyama }
62302b01b5eSaoyama
62402b01b5eSaoyama /* EXPORT */ int
getsiocsr(struct sioreg * sio)62580bc78ddSaoyama getsiocsr(struct sioreg *sio)
62602b01b5eSaoyama {
62702b01b5eSaoyama int val;
62802b01b5eSaoyama
62902b01b5eSaoyama val = sio->sio_stat << 8; /* DELAY(); */
63002b01b5eSaoyama sio->sio_cmd = 1; /* DELAY(); */
63102b01b5eSaoyama val |= sio->sio_stat; /* DELAY(); */
63202b01b5eSaoyama return val;
63302b01b5eSaoyama }
63402b01b5eSaoyama
63502b01b5eSaoyama /*--------------------- console interface ----------------------*/
63602b01b5eSaoyama
63702b01b5eSaoyama void syscnattach(int);
63802b01b5eSaoyama int syscngetc(dev_t);
63902b01b5eSaoyama void syscnputc(dev_t, int);
64002b01b5eSaoyama
64102b01b5eSaoyama struct consdev syscons = {
64202b01b5eSaoyama NULL,
64302b01b5eSaoyama NULL,
64402b01b5eSaoyama syscngetc,
64502b01b5eSaoyama syscnputc,
64602b01b5eSaoyama nullcnpollc,
64702b01b5eSaoyama NULL,
64802b01b5eSaoyama NODEV,
649713cf266Sjsing CN_HIGHPRI,
65002b01b5eSaoyama };
65102b01b5eSaoyama
65202b01b5eSaoyama /* EXPORT */ void
syscnattach(int channel)65380bc78ddSaoyama syscnattach(int channel)
65402b01b5eSaoyama {
65502b01b5eSaoyama /*
65602b01b5eSaoyama * Channel A is immediately initialized with 9600N1 right after cold
65702b01b5eSaoyama * boot/reset/poweron. ROM monitor emits one line message on CH.A.
65802b01b5eSaoyama */
65902b01b5eSaoyama struct sioreg *sio;
6608aed167bSmiod sio = (struct sioreg *)OBIO_SIO + channel;
66102b01b5eSaoyama
66202b01b5eSaoyama syscons.cn_dev = makedev(12, channel);
66302b01b5eSaoyama cn_tab = &syscons;
66402b01b5eSaoyama
66502b01b5eSaoyama setsioreg(sio, WR0, WR0_CHANRST);
66602b01b5eSaoyama setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1);
66702b01b5eSaoyama setsioreg(sio, WR2B, 0);
66802b01b5eSaoyama setsioreg(sio, WR0, ch0_regs[WR0]);
66902b01b5eSaoyama setsioreg(sio, WR4, ch0_regs[WR4]);
67002b01b5eSaoyama setsioreg(sio, WR3, ch0_regs[WR3]);
67102b01b5eSaoyama setsioreg(sio, WR5, ch0_regs[WR5]);
67202b01b5eSaoyama setsioreg(sio, WR0, ch0_regs[WR0]);
67302b01b5eSaoyama }
67402b01b5eSaoyama
67502b01b5eSaoyama /* EXPORT */ int
syscngetc(dev_t dev)67680bc78ddSaoyama syscngetc(dev_t dev)
67702b01b5eSaoyama {
67802b01b5eSaoyama struct sioreg *sio;
67902b01b5eSaoyama int s, c;
68002b01b5eSaoyama
6818aed167bSmiod sio = (struct sioreg *)OBIO_SIO + ((int)dev & 0x1);
68202b01b5eSaoyama s = splhigh();
68302b01b5eSaoyama while ((getsiocsr(sio) & RR_RXRDY) == 0)
68402b01b5eSaoyama ;
68502b01b5eSaoyama c = sio->sio_data;
68602b01b5eSaoyama splx(s);
68702b01b5eSaoyama
68802b01b5eSaoyama return c;
68902b01b5eSaoyama }
69002b01b5eSaoyama
69102b01b5eSaoyama /* EXPORT */ void
syscnputc(dev_t dev,int c)69280bc78ddSaoyama syscnputc(dev_t dev, int c)
69302b01b5eSaoyama {
69402b01b5eSaoyama struct sioreg *sio;
69502b01b5eSaoyama int s;
69602b01b5eSaoyama
6978aed167bSmiod sio = (struct sioreg *)OBIO_SIO + ((int)dev & 0x1);
69802b01b5eSaoyama s = splhigh();
69902b01b5eSaoyama while ((getsiocsr(sio) & RR_TXRDY) == 0)
70002b01b5eSaoyama ;
70102b01b5eSaoyama sio->sio_cmd = WR0_RSTPEND;
70202b01b5eSaoyama sio->sio_data = c;
70302b01b5eSaoyama splx(s);
70402b01b5eSaoyama }
705