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