diff options
author | Kenji Aoyama <aoyama@cvs.openbsd.org> | 2017-06-10 12:23:01 +0000 |
---|---|---|
committer | Kenji Aoyama <aoyama@cvs.openbsd.org> | 2017-06-10 12:23:01 +0000 |
commit | 851bdfbfe6eb4b1a4f65da13d668c077c520f40b (patch) | |
tree | 8bafe46311eb9ff70509ea72f83261c4e77b8a76 | |
parent | 1a3f207c329b2ffd60a99ac8deeec30ce77e630d (diff) |
Use software interrupt to process TX/RX data between sio and tty(4)
layer.
This is a straightforwad port of current NetBSD/luna68k implementation
by Izumi Tsutsui. Tested on both LUNA-88K and LUNA-88K2.
-rw-r--r-- | sys/arch/luna88k/dev/lunaws.c | 112 | ||||
-rw-r--r-- | sys/arch/luna88k/dev/siotty.c | 256 |
2 files changed, 254 insertions, 114 deletions
diff --git a/sys/arch/luna88k/dev/lunaws.c b/sys/arch/luna88k/dev/lunaws.c index 12a05350d51..7ce87cde7d6 100644 --- a/sys/arch/luna88k/dev/lunaws.c +++ b/sys/arch/luna88k/dev/lunaws.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lunaws.c,v 1.13 2017/06/04 13:48:13 aoyama Exp $ */ +/* $OpenBSD: lunaws.c,v 1.14 2017/06/10 12:23:00 aoyama Exp $ */ /* $NetBSD: lunaws.c,v 1.6 2002/03/17 19:40:42 atatat Exp $ */ /*- @@ -51,6 +51,10 @@ #include <luna88k/dev/sioreg.h> #include <luna88k/dev/siovar.h> +#define OMKBD_RXQ_LEN 64 +#define OMKBD_RXQ_LEN_MASK (OMKBD_RXQ_LEN - 1) +#define OMKBD_NEXTRXQ(x) (((x) + 1) & OMKBD_RXQ_LEN_MASK) + static const u_int8_t ch1_regs[6] = { WR0_RSTINT, /* Reset E/S Interrupt */ WR1_RXALLS, /* Rx per char, No Tx */ @@ -61,16 +65,19 @@ static const u_int8_t ch1_regs[6] = { }; struct ws_softc { - struct device sc_dv; + struct device sc_dev; struct sioreg *sc_ctl; u_int8_t sc_wr[6]; struct device *sc_wskbddev; + u_int8_t sc_rxq[OMKBD_RXQ_LEN]; + u_int sc_rxqhead; + u_int sc_rxqtail; #if NWSMOUSE > 0 struct device *sc_wsmousedev; int sc_msreport; - int buttons, dx, dy; + int sc_msbuttons, sc_msdx, sc_msdy; #endif - + void *sc_si; #ifdef WSDISPLAY_COMPAT_RAWKBD int sc_rawkbd; #endif @@ -97,7 +104,7 @@ const struct wskbd_accessops omkbd_accessops = { omkbd_ioctl, }; -void ws_cnattach(void); +void ws_cnattach(void); void ws_cngetc(void *, u_int *, int *); void ws_cnpollc(void *, int); const struct wskbd_consops ws_consops = { @@ -119,6 +126,7 @@ const struct wsmouse_accessops omms_accessops = { #endif void wsintr(void *); +void wssoftintr(void *); int wsmatch(struct device *, void *, void *); void wsattach(struct device *, struct device *, void *); @@ -161,7 +169,7 @@ wsattach(struct device *parent, struct device *self, void *aux) memcpy(sc->sc_wr, ch1_regs, sizeof(ch1_regs)); siosc->sc_intrhand[channel].ih_func = wsintr; siosc->sc_intrhand[channel].ih_arg = sc; - + setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]); setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]); @@ -171,6 +179,11 @@ wsattach(struct device *parent, struct device *self, void *aux) syscnputc((dev_t)1, 0x20); /* keep quiet mouse */ + sc->sc_rxqhead = 0; + sc->sc_rxqtail = 0; + + sc->sc_si = softintr_establish(IPL_SOFTTTY, wssoftintr, sc); + printf("\n"); a.console = (args->hwflags == 1); @@ -233,43 +246,10 @@ wsintr(void *arg) sio->sio_cmd = WR0_ERRRST; continue; } -#if NWSMOUSE > 0 - /* - * if (code >= 0x80 && code <= 0x87), then - * it's the first byte of 3 byte long mouse report - * code[0] & 07 -> LMR button condition - * code[1], [2] -> x,y delta - * otherwise, key press or release event. - */ - if (sc->sc_msreport == 0) { - if (code < 0x80 || code > 0x87) { - omkbd_input(sc, code); - continue; - } - code = (code & 07) ^ 07; - /* LMR->RML: wsevent counts 0 for leftmost */ - sc->buttons = (code & 02); - if (code & 01) - sc->buttons |= 04; - if (code & 04) - sc->buttons |= 01; - sc->sc_msreport = 1; - } - else if (sc->sc_msreport == 1) { - sc->dx = (signed char)code; - sc->sc_msreport = 2; - } - else if (sc->sc_msreport == 2) { - sc->dy = (signed char)code; - if (sc->sc_wsmousedev != NULL) - WSMOUSE_INPUT(sc->sc_wsmousedev, - sc->buttons, sc->dx, sc->dy, 0, 0); - sc->sc_msreport = 0; - } -#else - omkbd_input(sc, code); -#endif + sc->sc_rxq[sc->sc_rxqtail] = code; + sc->sc_rxqtail = OMKBD_NEXTRXQ(sc->sc_rxqtail); } while ((rr = getsiocsr(sio)) & RR_RXRDY); + softintr_schedule(sc->sc_si); } if (rr & RR_TXRDY) sio->sio_cmd = WR0_RSTPEND; @@ -277,6 +257,51 @@ wsintr(void *arg) } void +wssoftintr(void *arg) +{ + struct ws_softc *sc = arg; + uint8_t code; + + while (sc->sc_rxqhead != sc->sc_rxqtail) { + code = sc->sc_rxq[sc->sc_rxqhead]; + sc->sc_rxqhead = OMKBD_NEXTRXQ(sc->sc_rxqhead); +#if NWSMOUSE > 0 + /* + * if (code >= 0x80 && code <= 0x87), then + * it's the first byte of 3 byte long mouse report + * code[0] & 07 -> LMR button condition + * code[1], [2] -> x,y delta + * otherwise, key press or release event. + */ + if (sc->sc_msreport == 0) { + if (code < 0x80 || code > 0x87) { + omkbd_input(sc, code); + continue; + } + code = (code & 07) ^ 07; + /* LMR->RML: wsevent counts 0 for leftmost */ + sc->sc_msbuttons = (code & 02); + if ((code & 01) != 0) + sc->sc_msbuttons |= 04; + if ((code & 04) != 0) + sc->sc_msbuttons |= 01; + sc->sc_msreport = 1; + } else if (sc->sc_msreport == 1) { + sc->sc_msdx = (int8_t)code; + sc->sc_msreport = 2; + } else if (sc->sc_msreport == 2) { + sc->sc_msdy = (int8_t)code; + WSMOUSE_INPUT(sc->sc_wsmousedev, + sc->sc_msbuttons, sc->sc_msdx, sc->sc_msdy, 0, 0); + sc->sc_msreport = 0; + } +#else + omkbd_input(sc, code); +#endif + } +} + +void omkbd_input(void *v, int data) { struct ws_softc *sc = v; @@ -401,9 +426,6 @@ omms_enable(void *v) int omms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) { -#if 0 - struct ws_softc *sc = v; -#endif switch (cmd) { case WSMOUSEIO_GTYPE: diff --git a/sys/arch/luna88k/dev/siotty.c b/sys/arch/luna88k/dev/siotty.c index 2f36280c4e6..597705d9d15 100644 --- a/sys/arch/luna88k/dev/siotty.c +++ b/sys/arch/luna88k/dev/siotty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: siotty.c,v 1.19 2017/06/04 13:48:13 aoyama Exp $ */ +/* $OpenBSD: siotty.c,v 1.20 2017/06/10 12:23:00 aoyama Exp $ */ /* $NetBSD: siotty.c,v 1.9 2002/03/17 19:40:43 atatat Exp $ */ /*- @@ -35,6 +35,7 @@ #include <sys/device.h> #include <sys/conf.h> #include <sys/ioctl.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <sys/tty.h> #include <sys/uio.h> @@ -51,7 +52,7 @@ static const u_int8_t ch0_regs[6] = { WR0_RSTINT, /* reset E/S interrupt */ - WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */ + WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */ 0, /* */ WR3_RX8BIT | WR3_RXENBL, /* Rx */ WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */ @@ -71,12 +72,34 @@ struct siotty_softc { struct sioreg *sc_ctl; u_int sc_flags; u_int8_t sc_wr[6]; + void *sc_si; /* software interrupt handler */ + u_int sc_hwflags; +#define SIOTTY_HW_CONSOLE 0x0001 + + u_int8_t *sc_rbuf; + u_int8_t *sc_rbufend; + u_int8_t * volatile sc_rbget; + u_int8_t * volatile sc_rbput; + volatile u_int sc_rbavail; + + u_int8_t *sc_tba; + u_int sc_tbc; + + bool sc_rx_ready; + bool sc_tx_busy; + bool sc_tx_done; }; +#define SIOTTY_RING_SIZE 2048 +u_int siotty_rbuf_size = SIOTTY_RING_SIZE; + cdev_decl(sio); void siostart(struct tty *); int sioparam(struct tty *, struct termios *); void siottyintr(void *); +void siottysoft(void *); +void siotty_rxsoft(struct siotty_softc *, struct tty *); +void siotty_txsoft(struct siotty_softc *, struct tty *); int siomctl(struct siotty_softc *, int, int); int siotty_match(struct device *, void *, void *); @@ -107,18 +130,20 @@ siotty_attach(struct device *parent, struct device *self, void *aux) struct siotty_softc *sc = (void *)self; struct sio_attach_args *args = aux; int channel; + struct tty *tp; channel = args->channel; sc->sc_ctl = &siosc->sc_ctl[channel]; memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs)); siosc->sc_intrhand[channel].ih_func = siottyintr; siosc->sc_intrhand[channel].ih_arg = sc; + if (args->hwflags == 1) + sc->sc_hwflags |= SIOTTY_HW_CONSOLE; - if (args->hwflags == 1) { + if (sc->sc_hwflags & SIOTTY_HW_CONSOLE) { printf(" (console)"); sc->sc_flags = TIOCFLAG_SOFTCAR; - } - else { + } else { setsioreg(sc->sc_ctl, WR0, WR0_CHANRST); setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1); setsioreg(sc->sc_ctl, WR2B, 0); @@ -131,6 +156,26 @@ siotty_attach(struct device *parent, struct device *self, void *aux) setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */ printf("\n"); + + sc->sc_rbuf = malloc(siotty_rbuf_size * 2, M_DEVBUF, M_NOWAIT); + if (sc->sc_rbuf == NULL) { + printf("%s: unable to allocate ring buffer\n", + (sc->sc_dev).dv_xname); + return; + } + sc->sc_rbufend = sc->sc_rbuf + (siotty_rbuf_size * 2); + sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; + sc->sc_rbavail = siotty_rbuf_size; + + tp = ttymalloc(0); + tp->t_oproc = siostart; + tp->t_param = sioparam; + tp->t_hwiflow = NULL /* XXX siohwiflow XXX */; + if (sc->sc_hwflags & SIOTTY_HW_CONSOLE) + tp->t_dev = cn_tab->cn_dev; + sc->sc_tty = tp; + + sc->sc_si = softintr_establish(IPL_SOFTTTY, siottysoft, sc); } /*-------------------- low level routine --------------------*/ @@ -140,50 +185,131 @@ siottyintr(void *arg) { struct siotty_softc *sc; struct sioreg *sio; - struct tty *tp; - unsigned int code; - int rr; + u_int8_t *put, *end; + u_int8_t c; + u_int16_t rr; + int cc; + + sc = arg; + end = sc->sc_rbufend; + put = sc->sc_rbput; + cc = sc->sc_rbavail; - sc = (struct siotty_softc *)arg; - tp = sc->sc_tty; sio = sc->sc_ctl; rr = getsiocsr(sio); if (rr & RR_RXRDY) { do { - code = sio->sio_data; - if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) { - sio->sio_cmd = WR0_ERRRST; - if (sio->sio_stat & RR_FRAMING) - code |= TTY_FE; - else if (sio->sio_stat & RR_PARITY) - code |= TTY_PE; + if (cc > 0) { + c = sio->sio_data; + put[0] = c; + put[1] = rr & 0xff; + put += 2; + if (put >= end) + put = sc->sc_rbuf; + cc--; } - if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) - continue; -#if 0 && defined(DDB) /* ?!?! fails to resume ?!?! */ - if ((rr & RR_BREAK) && tp->t_dev == cn_tab->cn_dev) { - if (db_console) - db_enter(); - return; - } -#endif - (*linesw[tp->t_line].l_rint)(code, tp); + if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) + sio->sio_cmd = WR0_ERRRST; + + sc->sc_rbput = put; + sc->sc_rbavail = cc; + sc->sc_rx_ready = true; } while ((rr = getsiocsr(sio)) & RR_RXRDY); } if (rr & RR_TXRDY) { sio->sio_cmd = WR0_RSTPEND; - if (tp != NULL) { - tp->t_state &= ~(TS_BUSY|TS_FLUSH); - (*linesw[tp->t_line].l_start)(tp); + if (sc->sc_tbc > 0) { + sio->sio_data = *sc->sc_tba; + sc->sc_tba++; + sc->sc_tbc--; + } else { + if (sc->sc_tx_busy) { + sc->sc_tx_busy = false; + sc->sc_tx_done = true; + } } } + softintr_schedule(sc->sc_si); +} + +void +siottysoft(void *arg) +{ + struct siotty_softc *sc; + struct tty *tp; + + sc = arg; + tp = sc->sc_tty; + + if (sc->sc_rx_ready) { + sc->sc_rx_ready = false; + siotty_rxsoft(sc, tp); + } + if (sc->sc_tx_done) { + sc->sc_tx_done = false; + siotty_txsoft(sc, tp); + } +} + +void +siotty_rxsoft(struct siotty_softc *sc, struct tty *tp) +{ + uint8_t *get, *end; + u_int cc, scc; + unsigned int code; + uint8_t stat; + int s; + + end = sc->sc_rbufend; + get = sc->sc_rbget; + scc = cc = siotty_rbuf_size - sc->sc_rbavail; + + if (cc == siotty_rbuf_size) { + printf("%s: rx buffer overflow\n", (sc->sc_dev).dv_xname); + } + + while (cc > 0) { + code = get[0]; + stat = get[1]; + if ((stat & RR_FRAMING) != 0) + code |= TTY_FE; + else if ((stat & RR_PARITY) != 0) + code |= TTY_PE; + + (*linesw[tp->t_line].l_rint)(code, tp); + get += 2; + if (get >= end) + get = sc->sc_rbuf; + cc--; + } + + if (cc != scc) { + s = spltty(); + sc->sc_rbget = get; + sc->sc_rbavail += scc - cc; + splx(s); + } +} + +void +siotty_txsoft(struct siotty_softc *sc, struct tty *tp) +{ + + tp->t_state &= ~TS_BUSY; + if ((tp->t_state & TS_FLUSH) != 0) + tp->t_state &= ~TS_FLUSH; + else + ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf)); + (*linesw[tp->t_line].l_start)(tp); } void siostart(struct tty *tp) { struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)]; - int s, c; + int s; + u_int8_t *tba; + int tbc; s = spltty(); if (tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP)) @@ -193,11 +319,17 @@ siostart(struct tty *tp) goto out; tp->t_state |= TS_BUSY; - while (getsiocsr(sc->sc_ctl) & RR_TXRDY) { - if ((c = getc(&tp->t_outq)) == -1) - break; - sc->sc_ctl->sio_data = c; - } + + tba = tp->t_outq.c_cf; + tbc = ndqb(&tp->t_outq, 0); + + sc->sc_tba = tba; + sc->sc_tbc = tbc; + sc->sc_tx_busy = true; + + sc->sc_ctl->sio_data = *sc->sc_tba; + sc->sc_tba++; + sc->sc_tbc--; out: splx(s); } @@ -207,14 +339,14 @@ siostop(struct tty *tp, int flag) { int s; - s = spltty(); - if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) { - /* - * Device is transmitting; must stop it. - */ + s = spltty(); + if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) { + /* + * Device is transmitting; must stop it. + */ tp->t_state |= TS_FLUSH; - } - splx(s); + } + splx(s); return (0); } @@ -329,23 +461,21 @@ sioopen(dev_t dev, int flag, int mode, struct proc *p) struct siotty_softc *sc; struct tty *tp; int error; + int s; if ((sc = siotty_cd.cd_devs[minor(dev)]) == NULL) return ENXIO; - if ((tp = sc->sc_tty) == NULL) { - tp = sc->sc_tty = ttymalloc(0); - } - else if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) + + tp = sc->sc_tty; + + if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) && suser(p, 0) != 0) return EBUSY; - tp->t_oproc = siostart; - tp->t_param = sioparam; - tp->t_hwiflow = NULL /* XXX siohwiflow XXX */; - tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { struct termios t; + tp->t_dev = dev; t.c_ispeed = t.c_ospeed = TTYDEF_SPEED; t.c_cflag = TTYDEF_CFLAG; tp->t_ospeed = 0; /* force register update */ @@ -357,7 +487,6 @@ sioopen(dev_t dev, int flag, int mode, struct proc *p) ttsetwater(tp); /* raise RTS and DTR here; but, DTR lead is not wired */ /* then check DCD condition; but, DCD lead is not wired */ - tp->t_state |= TS_CARR_ON; /* assume detected all the time */ #if 0 if ((sc->sc_flags & TIOCFLAG_SOFTCAR) || (tp->t_cflag & MDMBUF) @@ -365,7 +494,13 @@ sioopen(dev_t dev, int flag, int mode, struct proc *p) tp->t_state |= TS_CARR_ON; else tp->t_state &= ~TS_CARR_ON; +#else + tp->t_state |= TS_CARR_ON; /* assume detected all the time */ #endif + s = spltty(); + sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; + sc->sc_rbavail = siotty_rbuf_size; + splx(s); } error = ttyopen(dev, tp, p); @@ -415,21 +550,6 @@ siowrite(dev_t dev, struct uio *uio, int flag) return (*linesw[tp->t_line].l_write)(tp, uio, flag); } -#if 0 -int -sioselect(dev, events, p) - dev_t dev; - int events; - struct proc *p; -{ - struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)]; - struct tty *tp = sc->sc_tty; - - return ((*linesw[tp->t_line].l_select)(tp, events, p)); - -} -#endif - int sioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { @@ -546,7 +666,6 @@ syscnattach(int channel) syscons.cn_dev = makedev(12, channel); cn_tab = &syscons; -#if 0 setsioreg(sio, WR0, WR0_CHANRST); setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1); setsioreg(sio, WR2B, 0); @@ -555,7 +674,6 @@ syscnattach(int channel) setsioreg(sio, WR3, ch0_regs[WR3]); setsioreg(sio, WR5, ch0_regs[WR5]); setsioreg(sio, WR0, ch0_regs[WR0]); -#endif } /* EXPORT */ int |