1 1.11 andvar /* $NetBSD: clpscom.c,v 1.11 2023/09/01 08:53:52 andvar Exp $ */ 2 1.1 kiyohara /* 3 1.1 kiyohara * Copyright (c) 2013 KIYOHARA Takashi 4 1.1 kiyohara * All rights reserved. 5 1.1 kiyohara * 6 1.1 kiyohara * Redistribution and use in source and binary forms, with or without 7 1.1 kiyohara * modification, are permitted provided that the following conditions 8 1.1 kiyohara * are met: 9 1.1 kiyohara * 1. Redistributions of source code must retain the above copyright 10 1.1 kiyohara * notice, this list of conditions and the following disclaimer. 11 1.1 kiyohara * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 kiyohara * notice, this list of conditions and the following disclaimer in the 13 1.1 kiyohara * documentation and/or other materials provided with the distribution. 14 1.1 kiyohara * 15 1.1 kiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 kiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 kiyohara * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 kiyohara * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 1.1 kiyohara * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 1.1 kiyohara * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 kiyohara * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 kiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 1.1 kiyohara * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 1.1 kiyohara * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 kiyohara * POSSIBILITY OF SUCH DAMAGE. 26 1.1 kiyohara */ 27 1.1 kiyohara #include <sys/cdefs.h> 28 1.11 andvar __KERNEL_RCSID(0, "$NetBSD: clpscom.c,v 1.11 2023/09/01 08:53:52 andvar Exp $"); 29 1.1 kiyohara 30 1.1 kiyohara #include "rnd.h" 31 1.1 kiyohara 32 1.1 kiyohara #include <sys/param.h> 33 1.1 kiyohara #include <sys/bus.h> 34 1.1 kiyohara #include <sys/conf.h> 35 1.1 kiyohara #include <sys/device.h> 36 1.1 kiyohara #include <sys/errno.h> 37 1.1 kiyohara #include <sys/fcntl.h> 38 1.1 kiyohara #include <sys/intr.h> 39 1.1 kiyohara #include <sys/kauth.h> 40 1.1 kiyohara #include <sys/lwp.h> 41 1.9 thorpej #include <sys/kmem.h> 42 1.1 kiyohara #include <sys/systm.h> 43 1.1 kiyohara #include <sys/termios.h> 44 1.1 kiyohara #include <sys/tty.h> 45 1.1 kiyohara #include <sys/types.h> 46 1.1 kiyohara 47 1.10 riastrad #include <ddb/db_active.h> 48 1.10 riastrad 49 1.1 kiyohara #include <arm/clps711x/clps711xreg.h> 50 1.1 kiyohara #include <arm/clps711x/clpssocvar.h> 51 1.1 kiyohara 52 1.1 kiyohara #include <dev/cons.h> 53 1.1 kiyohara 54 1.1 kiyohara #ifdef RND_COM 55 1.6 riastrad #include <sys/rndsource.h> 56 1.1 kiyohara #endif 57 1.1 kiyohara 58 1.1 kiyohara #include "ioconf.h" 59 1.1 kiyohara #include "locators.h" 60 1.1 kiyohara 61 1.5 christos #define COMUNIT(x) TTUNIT(x) 62 1.5 christos #define COMDIALOUT(x) TTDIALOUT(x) 63 1.1 kiyohara 64 1.1 kiyohara #define CLPSCOM_RING_SIZE 2048 65 1.1 kiyohara #define UART_FIFO_SIZE 16 66 1.1 kiyohara 67 1.1 kiyohara #define CLPSCOM_READ_CON(sc) \ 68 1.1 kiyohara bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSCON) 69 1.1 kiyohara #define CLPSCOM_WRITE_CON(sc, val) \ 70 1.1 kiyohara bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSCON, (val)) 71 1.1 kiyohara #define CLPSCOM_READ_FLG(sc) \ 72 1.1 kiyohara bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSFLG) 73 1.1 kiyohara #define CLPSCOM_WRITE_FLG(sc, val) \ 74 1.1 kiyohara bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSFLG, (val)) 75 1.1 kiyohara #define CLPSCOM_READ(sc) \ 76 1.1 kiyohara bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR) 77 1.1 kiyohara #define CLPSCOM_WRITE(sc, val) \ 78 1.1 kiyohara bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR, (val)) 79 1.1 kiyohara #define CLPSCOM_WRITE_MULTI(sc, val, n) \ 80 1.1 kiyohara bus_space_write_multi_1((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR, (val), (n)) 81 1.1 kiyohara #define CLPSCOM_READ_UBRLCR(sc) \ 82 1.1 kiyohara bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UBRLCR) 83 1.1 kiyohara #define CLPSCOM_WRITE_UBRLCR(sc, val) \ 84 1.1 kiyohara bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UBRLCR, (val)) 85 1.1 kiyohara 86 1.1 kiyohara struct clpscom_softc { 87 1.1 kiyohara device_t sc_dev; 88 1.1 kiyohara bus_space_tag_t sc_iot; 89 1.1 kiyohara bus_space_handle_t sc_ioh; 90 1.1 kiyohara int sc_irq[3]; 91 1.1 kiyohara void *sc_ih[3]; 92 1.1 kiyohara #define CLPSCOM_TXINT 0 93 1.1 kiyohara #define CLPSCOM_RXINT 1 94 1.1 kiyohara #define CLPSCOM_MSINT 2 95 1.1 kiyohara 96 1.1 kiyohara void *sc_si; 97 1.1 kiyohara 98 1.1 kiyohara struct tty *sc_tty; 99 1.1 kiyohara 100 1.1 kiyohara u_char *sc_tba; 101 1.1 kiyohara u_int sc_tbc; 102 1.1 kiyohara u_char *sc_rbuf; 103 1.1 kiyohara char *volatile sc_rbget; 104 1.1 kiyohara char *volatile sc_rbput; 105 1.1 kiyohara volatile int sc_rbavail; 106 1.1 kiyohara 107 1.1 kiyohara #define CLPSCOM_MODEM_STATUS_MASK (SYSFLG_DCD | SYSFLG_DSR | SYSFLG_CTS) 108 1.1 kiyohara uint32_t sc_ms; 109 1.1 kiyohara uint32_t sc_ms_dcd; 110 1.1 kiyohara uint32_t sc_ms_cts; 111 1.1 kiyohara uint32_t sc_ms_mask; 112 1.1 kiyohara uint32_t sc_ms_delta; 113 1.1 kiyohara 114 1.1 kiyohara int sc_tx_stopped; 115 1.1 kiyohara 116 1.1 kiyohara int sc_tx_done; 117 1.1 kiyohara int sc_rx_ready; 118 1.1 kiyohara int sc_ms_changed; 119 1.1 kiyohara 120 1.1 kiyohara int sc_hwflags; 121 1.1 kiyohara #define COM_HW_CONSOLE (1 << 0) 122 1.1 kiyohara #define COM_HW_DEV_OK (1 << 1) 123 1.1 kiyohara #define COM_HW_KGDB (1 << 2) 124 1.1 kiyohara int sc_swflags; 125 1.1 kiyohara 126 1.1 kiyohara #ifdef RND_COM 127 1.11 andvar krndsource_t rnd_source; 128 1.1 kiyohara #endif 129 1.1 kiyohara }; 130 1.1 kiyohara 131 1.1 kiyohara static int clpscom_match(device_t, cfdata_t, void *); 132 1.1 kiyohara static void clpscom_attach(device_t, device_t, void *); 133 1.1 kiyohara 134 1.1 kiyohara static int clpscom_txintr(void *); 135 1.1 kiyohara static int clpscom_rxintr(void *); 136 1.1 kiyohara static int clpscom_msintr(void *); 137 1.1 kiyohara static void clpscom_soft(void *); 138 1.1 kiyohara 139 1.1 kiyohara static void clpscom_start(struct tty *); 140 1.1 kiyohara static int clpscom_param(struct tty *, struct termios *); 141 1.1 kiyohara static int clpscom_hwiflow(struct tty *, int); 142 1.1 kiyohara 143 1.1 kiyohara dev_type_open(clpscomopen); 144 1.1 kiyohara dev_type_close(clpscomclose); 145 1.1 kiyohara dev_type_read(clpscomread); 146 1.1 kiyohara dev_type_write(clpscomwrite); 147 1.1 kiyohara dev_type_ioctl(clpscomioctl); 148 1.1 kiyohara dev_type_stop(clpscomstop); 149 1.1 kiyohara dev_type_tty(clpscomtty); 150 1.1 kiyohara dev_type_poll(clpscompoll); 151 1.1 kiyohara 152 1.1 kiyohara static void clpscom_iflush(struct clpscom_softc *); 153 1.1 kiyohara static void clpscom_shutdown(struct clpscom_softc *); 154 1.1 kiyohara static void clpscom_break(struct clpscom_softc *, int); 155 1.1 kiyohara static int clpscom_to_tiocm(struct clpscom_softc *); 156 1.1 kiyohara 157 1.1 kiyohara static void clpscom_rxsoft(struct clpscom_softc *, struct tty *); 158 1.1 kiyohara static void clpscom_mssoft(struct clpscom_softc *, struct tty *); 159 1.1 kiyohara 160 1.1 kiyohara static inline uint32_t clpscom_rate2ubrlcr(int); 161 1.1 kiyohara static uint32_t clpscom_cflag2ubrlcr(tcflag_t); 162 1.1 kiyohara 163 1.1 kiyohara static int clpscom_cngetc(dev_t); 164 1.1 kiyohara static void clpscom_cnputc(dev_t, int); 165 1.1 kiyohara static void clpscom_cnpollc(dev_t, int); 166 1.1 kiyohara 167 1.1 kiyohara CFATTACH_DECL_NEW(clpscom, sizeof(struct clpscom_softc), 168 1.1 kiyohara clpscom_match, clpscom_attach, NULL, NULL); 169 1.1 kiyohara 170 1.1 kiyohara const struct cdevsw clpscom_cdevsw = { 171 1.2 dholland .d_open = clpscomopen, 172 1.2 dholland .d_close = clpscomclose, 173 1.2 dholland .d_read = clpscomread, 174 1.2 dholland .d_write = clpscomwrite, 175 1.2 dholland .d_ioctl = clpscomioctl, 176 1.2 dholland .d_stop = clpscomstop, 177 1.2 dholland .d_tty = clpscomtty, 178 1.2 dholland .d_poll = clpscompoll, 179 1.2 dholland .d_mmap = nommap, 180 1.2 dholland .d_kqfilter = ttykqfilter, 181 1.3 dholland .d_discard = nodiscard, 182 1.2 dholland .d_flag = D_TTY 183 1.1 kiyohara }; 184 1.1 kiyohara 185 1.1 kiyohara static struct cnm_state clpscom_cnm_state; 186 1.1 kiyohara static vaddr_t clpscom_cnaddr = 0; 187 1.1 kiyohara static int clpscom_cnrate; 188 1.1 kiyohara static tcflag_t clpscom_cncflag; 189 1.1 kiyohara 190 1.1 kiyohara 191 1.1 kiyohara /* ARGSUSED */ 192 1.1 kiyohara static int 193 1.1 kiyohara clpscom_match(device_t parent, cfdata_t match, void *aux) 194 1.1 kiyohara { 195 1.1 kiyohara 196 1.1 kiyohara return 1; 197 1.1 kiyohara } 198 1.1 kiyohara 199 1.1 kiyohara /* ARGSUSED */ 200 1.1 kiyohara static void 201 1.1 kiyohara clpscom_attach(device_t parent, device_t self, void *aux) 202 1.1 kiyohara { 203 1.1 kiyohara struct clpscom_softc *sc = device_private(self); 204 1.1 kiyohara struct clpssoc_attach_args *aa = aux; 205 1.1 kiyohara int i; 206 1.1 kiyohara 207 1.1 kiyohara aprint_naive("\n"); 208 1.1 kiyohara aprint_normal("\n"); 209 1.1 kiyohara 210 1.1 kiyohara sc->sc_dev = self; 211 1.1 kiyohara sc->sc_iot = aa->aa_iot; 212 1.1 kiyohara sc->sc_ioh = *aa->aa_ioh; 213 1.1 kiyohara for (i = 0; i < __arraycount(aa->aa_irq); i++) { 214 1.1 kiyohara sc->sc_irq[i] = aa->aa_irq[i]; 215 1.1 kiyohara sc->sc_ih[i] = NULL; 216 1.1 kiyohara } 217 1.1 kiyohara 218 1.1 kiyohara if (clpscom_cnaddr != 0) 219 1.1 kiyohara SET(sc->sc_hwflags, COM_HW_CONSOLE); 220 1.1 kiyohara 221 1.1 kiyohara sc->sc_tty = tty_alloc(); 222 1.1 kiyohara sc->sc_tty->t_oproc = clpscom_start; 223 1.1 kiyohara sc->sc_tty->t_param = clpscom_param; 224 1.1 kiyohara sc->sc_tty->t_hwiflow = clpscom_hwiflow; 225 1.1 kiyohara 226 1.1 kiyohara sc->sc_tbc = 0; 227 1.9 thorpej sc->sc_rbuf = kmem_alloc(CLPSCOM_RING_SIZE << 1, KM_SLEEP); 228 1.1 kiyohara sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 229 1.1 kiyohara sc->sc_rbavail = CLPSCOM_RING_SIZE; 230 1.1 kiyohara 231 1.1 kiyohara tty_attach(sc->sc_tty); 232 1.1 kiyohara 233 1.1 kiyohara if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 234 1.1 kiyohara int maj = cdevsw_lookup_major(&clpscom_cdevsw); 235 1.1 kiyohara 236 1.1 kiyohara sc->sc_tty->t_dev = makedev(maj, device_unit(sc->sc_dev)); 237 1.1 kiyohara cn_tab->cn_dev = sc->sc_tty->t_dev; 238 1.1 kiyohara 239 1.1 kiyohara aprint_normal_dev(self, "console\n"); 240 1.1 kiyohara } 241 1.1 kiyohara 242 1.1 kiyohara sc->sc_si = softint_establish(SOFTINT_SERIAL, clpscom_soft, sc); 243 1.1 kiyohara 244 1.1 kiyohara #ifdef RND_COM 245 1.1 kiyohara rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 246 1.4 tls RND_TYPE_TTY, RND_FLAG_DEFAULT); 247 1.1 kiyohara #endif 248 1.1 kiyohara 249 1.1 kiyohara SET(sc->sc_hwflags, COM_HW_DEV_OK); 250 1.1 kiyohara } 251 1.1 kiyohara 252 1.1 kiyohara static int 253 1.1 kiyohara clpscom_txintr(void *arg) 254 1.1 kiyohara { 255 1.1 kiyohara struct clpscom_softc *sc = arg; 256 1.1 kiyohara uint32_t sysflg; 257 1.1 kiyohara 258 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 259 1.1 kiyohara return 0; 260 1.1 kiyohara 261 1.1 kiyohara sysflg = CLPSCOM_READ_FLG(sc); 262 1.1 kiyohara 263 1.1 kiyohara /* 264 1.1 kiyohara * Done handling any receive interrupts. See if data can be 265 1.1 kiyohara * transmitted as well. Schedule tx done event if no data left 266 1.1 kiyohara * and tty was marked busy. 267 1.1 kiyohara */ 268 1.1 kiyohara 269 1.1 kiyohara if (!ISSET(sysflg, SYSFLG_UTXFF)) { 270 1.1 kiyohara /* Output the next chunk of the contiguous buffer, if any. */ 271 1.1 kiyohara if (sc->sc_tbc > 0) { 272 1.1 kiyohara while (sc->sc_tbc > 0 && !ISSET(sysflg, SYSFLG_UTXFF)) { 273 1.1 kiyohara CLPSCOM_WRITE(sc, *sc->sc_tba); 274 1.1 kiyohara sc->sc_tba++; 275 1.1 kiyohara sc->sc_tbc--; 276 1.1 kiyohara sysflg = CLPSCOM_READ_FLG(sc); 277 1.1 kiyohara } 278 1.1 kiyohara } else if (!ISSET(sysflg, SYSFLG_UBUSY) && 279 1.1 kiyohara sc->sc_ih[CLPSCOM_TXINT] != NULL) { 280 1.1 kiyohara intr_disestablish(sc->sc_ih[CLPSCOM_TXINT]); 281 1.1 kiyohara sc->sc_ih[CLPSCOM_TXINT] = NULL; 282 1.1 kiyohara sc->sc_tx_done = 1; 283 1.1 kiyohara } 284 1.1 kiyohara } 285 1.1 kiyohara 286 1.1 kiyohara /* Wake up the poller. */ 287 1.1 kiyohara softint_schedule(sc->sc_si); 288 1.1 kiyohara 289 1.1 kiyohara return 1; 290 1.1 kiyohara } 291 1.1 kiyohara 292 1.1 kiyohara static int 293 1.1 kiyohara clpscom_rxintr(void *arg) 294 1.1 kiyohara { 295 1.1 kiyohara struct clpscom_softc *sc = arg; 296 1.1 kiyohara int cc; 297 1.1 kiyohara uint32_t sysflg; 298 1.1 kiyohara uint16_t data; 299 1.1 kiyohara u_char *put; 300 1.1 kiyohara 301 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 302 1.1 kiyohara return 0; 303 1.1 kiyohara 304 1.1 kiyohara if (sc->sc_ih[CLPSCOM_RXINT] != NULL) { 305 1.1 kiyohara put = sc->sc_rbput; 306 1.1 kiyohara cc = sc->sc_rbavail; 307 1.1 kiyohara while (cc > 0) { 308 1.1 kiyohara sysflg = CLPSCOM_READ_FLG(sc); 309 1.1 kiyohara if (ISSET(sysflg, SYSFLG_URXFE)) 310 1.1 kiyohara break; 311 1.1 kiyohara data = CLPSCOM_READ(sc); 312 1.1 kiyohara cn_check_magic(sc->sc_tty->t_dev, data & 0xff, 313 1.1 kiyohara clpscom_cnm_state); 314 1.1 kiyohara 315 1.1 kiyohara put[0] = data & 0xff; 316 1.1 kiyohara put[1] = (data >> 8) & 0xff; 317 1.1 kiyohara put += 2; 318 1.1 kiyohara if (put >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1)) 319 1.1 kiyohara put = sc->sc_rbuf; 320 1.1 kiyohara cc--; 321 1.1 kiyohara sc->sc_rx_ready = 1; 322 1.1 kiyohara } 323 1.1 kiyohara 324 1.1 kiyohara /* 325 1.1 kiyohara * Current string of incoming characters ended because 326 1.1 kiyohara * no more data was available or we ran out of space. 327 1.1 kiyohara * Schedule a receive event if any data was received. 328 1.1 kiyohara * If we're out of space, turn off receive interrupts. 329 1.1 kiyohara */ 330 1.1 kiyohara sc->sc_rbput = put; 331 1.1 kiyohara sc->sc_rbavail = cc; 332 1.1 kiyohara 333 1.1 kiyohara /* 334 1.1 kiyohara * See if we are in danger of overflowing a buffer. If 335 1.1 kiyohara * so, use hardware flow control to ease the pressure. 336 1.1 kiyohara */ 337 1.1 kiyohara 338 1.1 kiyohara /* but clpscom cannot. X-( */ 339 1.1 kiyohara 340 1.1 kiyohara /* 341 1.1 kiyohara * If we're out of space, disable receive interrupts 342 1.1 kiyohara * until the queue has drained a bit. 343 1.1 kiyohara */ 344 1.1 kiyohara if (cc <= 0) { 345 1.1 kiyohara intr_disestablish(sc->sc_ih[CLPSCOM_RXINT]); 346 1.1 kiyohara sc->sc_ih[CLPSCOM_RXINT] = NULL; 347 1.1 kiyohara } 348 1.1 kiyohara } 349 1.1 kiyohara 350 1.1 kiyohara /* Wake up the poller. */ 351 1.1 kiyohara softint_schedule(sc->sc_si); 352 1.1 kiyohara 353 1.1 kiyohara return 1; 354 1.1 kiyohara } 355 1.1 kiyohara 356 1.1 kiyohara static int 357 1.1 kiyohara clpscom_msintr(void *arg) 358 1.1 kiyohara { 359 1.1 kiyohara struct clpscom_softc *sc = arg; 360 1.1 kiyohara uint32_t ms, delta; 361 1.1 kiyohara 362 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 363 1.1 kiyohara return 0; 364 1.1 kiyohara 365 1.1 kiyohara if (sc->sc_ih[CLPSCOM_MSINT] != NULL) { 366 1.1 kiyohara ms = CLPSCOM_READ_FLG(sc) & CLPSCOM_MODEM_STATUS_MASK; 367 1.1 kiyohara delta = ms ^ sc->sc_ms; 368 1.1 kiyohara sc->sc_ms = ms; 369 1.1 kiyohara 370 1.1 kiyohara if (ISSET(delta, sc->sc_ms_mask)) { 371 1.1 kiyohara SET(sc->sc_ms_delta, delta); 372 1.1 kiyohara 373 1.1 kiyohara /* 374 1.1 kiyohara * Stop output immediately if we lose the output 375 1.1 kiyohara * flow control signal or carrier detect. 376 1.1 kiyohara */ 377 1.1 kiyohara if (ISSET(~ms, sc->sc_ms_mask)) 378 1.1 kiyohara sc->sc_tbc = 0; 379 1.1 kiyohara sc->sc_ms_changed = 1; 380 1.1 kiyohara } 381 1.1 kiyohara } 382 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, PS711X_UMSEOI, 1); 383 1.1 kiyohara 384 1.1 kiyohara /* Wake up the poller. */ 385 1.1 kiyohara softint_schedule(sc->sc_si); 386 1.1 kiyohara 387 1.1 kiyohara return 1; 388 1.1 kiyohara } 389 1.1 kiyohara 390 1.1 kiyohara static void 391 1.1 kiyohara clpscom_soft(void *arg) 392 1.1 kiyohara { 393 1.1 kiyohara struct clpscom_softc *sc = arg; 394 1.1 kiyohara struct tty *tp = sc->sc_tty; 395 1.1 kiyohara 396 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 397 1.1 kiyohara return; 398 1.1 kiyohara 399 1.1 kiyohara if (sc->sc_rx_ready) { 400 1.1 kiyohara sc->sc_rx_ready = 0; 401 1.1 kiyohara clpscom_rxsoft(sc, tp); 402 1.1 kiyohara } 403 1.1 kiyohara if (sc->sc_tx_done) { 404 1.1 kiyohara sc->sc_tx_done = 0; 405 1.1 kiyohara CLR(tp->t_state, TS_BUSY); 406 1.1 kiyohara if (ISSET(tp->t_state, TS_FLUSH)) 407 1.1 kiyohara CLR(tp->t_state, TS_FLUSH); 408 1.1 kiyohara else 409 1.1 kiyohara ndflush(&tp->t_outq, 410 1.1 kiyohara (int)(sc->sc_tba - tp->t_outq.c_cf)); 411 1.1 kiyohara (*tp->t_linesw->l_start)(tp); 412 1.1 kiyohara } 413 1.1 kiyohara if (sc->sc_ms_changed == 1) { 414 1.1 kiyohara sc->sc_ms_changed = 0; 415 1.1 kiyohara clpscom_mssoft(sc, tp); 416 1.1 kiyohara } 417 1.1 kiyohara } 418 1.1 kiyohara 419 1.1 kiyohara static void 420 1.1 kiyohara clpscom_start(struct tty *tp) 421 1.1 kiyohara { 422 1.1 kiyohara struct clpscom_softc *sc 423 1.1 kiyohara = device_lookup_private(&clpscom_cd, COMUNIT(tp->t_dev)); 424 1.1 kiyohara int s, n; 425 1.1 kiyohara 426 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 427 1.1 kiyohara return; 428 1.1 kiyohara 429 1.1 kiyohara s = spltty(); 430 1.1 kiyohara if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 431 1.1 kiyohara goto out; 432 1.1 kiyohara if (sc->sc_tx_stopped) 433 1.1 kiyohara goto out; 434 1.1 kiyohara if (!ttypull(tp)) 435 1.1 kiyohara goto out; 436 1.1 kiyohara 437 1.1 kiyohara /* Grab the first contiguous region of buffer space. */ 438 1.1 kiyohara { 439 1.1 kiyohara u_char *tba; 440 1.1 kiyohara int tbc; 441 1.1 kiyohara 442 1.1 kiyohara tba = tp->t_outq.c_cf; 443 1.1 kiyohara tbc = ndqb(&tp->t_outq, 0); 444 1.1 kiyohara 445 1.1 kiyohara (void)splserial(); 446 1.1 kiyohara 447 1.1 kiyohara sc->sc_tba = tba; 448 1.1 kiyohara sc->sc_tbc = tbc; 449 1.1 kiyohara } 450 1.1 kiyohara 451 1.1 kiyohara SET(tp->t_state, TS_BUSY); 452 1.1 kiyohara 453 1.1 kiyohara if (sc->sc_ih[CLPSCOM_TXINT] == NULL) { 454 1.1 kiyohara sc->sc_ih[CLPSCOM_TXINT] = 455 1.1 kiyohara intr_establish(sc->sc_irq[CLPSCOM_TXINT], IPL_SERIAL, 0, 456 1.1 kiyohara clpscom_txintr, sc); 457 1.1 kiyohara if (sc->sc_ih[CLPSCOM_TXINT] == NULL) 458 1.1 kiyohara printf("%s: can't establish tx interrupt\n", 459 1.1 kiyohara device_xname(sc->sc_dev)); 460 1.1 kiyohara 461 1.1 kiyohara /* Output the first chunk of the contiguous buffer. */ 462 1.7 riastrad n = uimin(sc->sc_tbc, UART_FIFO_SIZE); 463 1.1 kiyohara CLPSCOM_WRITE_MULTI(sc, sc->sc_tba, n); 464 1.1 kiyohara sc->sc_tba += n; 465 1.1 kiyohara sc->sc_tbc -= n; 466 1.1 kiyohara } 467 1.1 kiyohara out: 468 1.1 kiyohara splx(s); 469 1.1 kiyohara return; 470 1.1 kiyohara } 471 1.1 kiyohara 472 1.1 kiyohara static int 473 1.1 kiyohara clpscom_param(struct tty *tp, struct termios *t) 474 1.1 kiyohara { 475 1.1 kiyohara struct clpscom_softc *sc = 476 1.1 kiyohara device_lookup_private(&clpscom_cd, COMUNIT(tp->t_dev)); 477 1.1 kiyohara int s; 478 1.1 kiyohara 479 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 480 1.1 kiyohara return ENXIO; 481 1.1 kiyohara if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 482 1.1 kiyohara return EINVAL; 483 1.1 kiyohara 484 1.1 kiyohara /* 485 1.1 kiyohara * For the console, always force CLOCAL and !HUPCL, so that the port 486 1.1 kiyohara * is always active. 487 1.1 kiyohara */ 488 1.1 kiyohara if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || 489 1.1 kiyohara ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 490 1.1 kiyohara SET(t->c_cflag, CLOCAL); 491 1.1 kiyohara CLR(t->c_cflag, HUPCL); 492 1.1 kiyohara } 493 1.1 kiyohara 494 1.1 kiyohara /* 495 1.1 kiyohara * If there were no changes, don't do anything. This avoids dropping 496 1.1 kiyohara * input and improves performance when all we did was frob things like 497 1.1 kiyohara * VMIN and VTIME. 498 1.1 kiyohara */ 499 1.1 kiyohara if (tp->t_ospeed == t->c_ospeed && 500 1.1 kiyohara tp->t_cflag == t->c_cflag) 501 1.1 kiyohara return 0; 502 1.1 kiyohara 503 1.1 kiyohara /* 504 1.1 kiyohara * If we're not in a mode that assumes a connection is present, then 505 1.1 kiyohara * ignore carrier changes. 506 1.1 kiyohara */ 507 1.1 kiyohara if (ISSET(t->c_cflag, CLOCAL | MDMBUF)) 508 1.1 kiyohara sc->sc_ms_dcd = 0; 509 1.1 kiyohara else 510 1.1 kiyohara sc->sc_ms_dcd = SYSFLG_DCD; 511 1.1 kiyohara /* 512 1.1 kiyohara * Set the flow control pins depending on the current flow control 513 1.1 kiyohara * mode. 514 1.1 kiyohara */ 515 1.1 kiyohara if (ISSET(t->c_cflag, CRTSCTS)) { 516 1.1 kiyohara sc->sc_ms_cts = SYSFLG_CTS; 517 1.1 kiyohara } else if (ISSET(t->c_cflag, MDMBUF)) { 518 1.1 kiyohara /* 519 1.1 kiyohara * For DTR/DCD flow control, make sure we don't toggle DTR for 520 1.1 kiyohara * carrier detection. 521 1.1 kiyohara */ 522 1.1 kiyohara sc->sc_ms_cts = SYSFLG_DCD; 523 1.1 kiyohara } else { 524 1.1 kiyohara /* 525 1.1 kiyohara * If no flow control, then always set RTS. This will make 526 1.1 kiyohara * the other side happy if it mistakenly thinks we're doing 527 1.1 kiyohara * RTS/CTS flow control. 528 1.1 kiyohara */ 529 1.1 kiyohara sc->sc_ms_cts = 0; 530 1.1 kiyohara } 531 1.1 kiyohara sc->sc_ms_mask = sc->sc_ms_cts | sc->sc_ms_dcd; 532 1.1 kiyohara 533 1.1 kiyohara s = splserial(); 534 1.1 kiyohara CLPSCOM_WRITE_UBRLCR(sc, 535 1.1 kiyohara UBRLCR_FIFOEN | 536 1.1 kiyohara clpscom_rate2ubrlcr(t->c_ospeed) | 537 1.1 kiyohara clpscom_cflag2ubrlcr(t->c_cflag)); 538 1.1 kiyohara 539 1.1 kiyohara /* And copy to tty. */ 540 1.1 kiyohara tp->t_ispeed = 0; 541 1.1 kiyohara tp->t_ospeed = t->c_ospeed; 542 1.1 kiyohara tp->t_cflag = t->c_cflag; 543 1.1 kiyohara splx(s); 544 1.1 kiyohara 545 1.1 kiyohara /* 546 1.1 kiyohara * Update the tty layer's idea of the carrier bit, in case we changed 547 1.1 kiyohara * CLOCAL or MDMBUF. We don't hang up here; we only do that by 548 1.1 kiyohara * explicit request. 549 1.1 kiyohara */ 550 1.1 kiyohara (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_ms, SYSFLG_DCD)); 551 1.1 kiyohara 552 1.1 kiyohara if (!ISSET(t->c_cflag, CHWFLOW)) 553 1.1 kiyohara if (sc->sc_tx_stopped) { 554 1.1 kiyohara sc->sc_tx_stopped = 0; 555 1.1 kiyohara clpscom_start(tp); 556 1.1 kiyohara } 557 1.1 kiyohara 558 1.1 kiyohara return 0; 559 1.1 kiyohara } 560 1.1 kiyohara 561 1.1 kiyohara static int 562 1.1 kiyohara clpscom_hwiflow(struct tty *tp, int block) 563 1.1 kiyohara { 564 1.1 kiyohara /* Nothing */ 565 1.1 kiyohara return 0; 566 1.1 kiyohara } 567 1.1 kiyohara 568 1.1 kiyohara /* ARGSUSED */ 569 1.1 kiyohara int 570 1.1 kiyohara clpscomopen(dev_t dev, int flag, int mode, struct lwp *l) 571 1.1 kiyohara { 572 1.1 kiyohara struct clpscom_softc *sc; 573 1.1 kiyohara struct tty *tp; 574 1.1 kiyohara int error, s, s2; 575 1.1 kiyohara 576 1.1 kiyohara sc = device_lookup_private(&clpscom_cd, COMUNIT(dev)); 577 1.1 kiyohara if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK)) 578 1.1 kiyohara return ENXIO; 579 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 580 1.1 kiyohara return ENXIO; 581 1.1 kiyohara 582 1.1 kiyohara #ifdef KGDB 583 1.1 kiyohara /* 584 1.1 kiyohara * If this is the kgdb port, no other use is permitted. 585 1.1 kiyohara */ 586 1.1 kiyohara if (ISSET(sc->sc_hwflags, COM_HW_KGDB)) 587 1.1 kiyohara return EBUSY; 588 1.1 kiyohara #endif 589 1.1 kiyohara 590 1.1 kiyohara tp = sc->sc_tty; 591 1.1 kiyohara 592 1.1 kiyohara if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 593 1.1 kiyohara return EBUSY; 594 1.1 kiyohara 595 1.1 kiyohara s = spltty(); 596 1.1 kiyohara 597 1.1 kiyohara /* 598 1.1 kiyohara * Do the following iff this is a first open. 599 1.1 kiyohara */ 600 1.1 kiyohara if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 601 1.1 kiyohara struct termios t; 602 1.1 kiyohara 603 1.1 kiyohara tp->t_dev = dev; 604 1.1 kiyohara 605 1.1 kiyohara /* Enable and turn on interrupt */ 606 1.1 kiyohara CLPSCOM_WRITE_CON(sc, CLPSCOM_READ_CON(sc) | SYSCON_UARTEN); 607 1.1 kiyohara 608 1.1 kiyohara /* Fetch the current modem control status, needed later. */ 609 1.1 kiyohara sc->sc_ms = CLPSCOM_READ_FLG(sc) & CLPSCOM_MODEM_STATUS_MASK; 610 1.1 kiyohara 611 1.1 kiyohara /* 612 1.1 kiyohara * Initialize the termios status to the defaults. Add in the 613 1.1 kiyohara * sticky bits from TIOCSFLAGS. 614 1.1 kiyohara */ 615 1.1 kiyohara t.c_ispeed = 0; 616 1.1 kiyohara if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 617 1.1 kiyohara t.c_ospeed = clpscom_cnrate; 618 1.1 kiyohara t.c_cflag = clpscom_cncflag; 619 1.1 kiyohara } else { 620 1.1 kiyohara t.c_ospeed = TTYDEF_SPEED; 621 1.1 kiyohara t.c_cflag = TTYDEF_CFLAG; 622 1.1 kiyohara } 623 1.1 kiyohara if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 624 1.1 kiyohara SET(t.c_cflag, CLOCAL); 625 1.1 kiyohara if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 626 1.1 kiyohara SET(t.c_cflag, CRTSCTS); 627 1.1 kiyohara if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 628 1.1 kiyohara SET(t.c_cflag, MDMBUF); 629 1.1 kiyohara /* Make sure pscom_param() we do something */ 630 1.1 kiyohara tp->t_ospeed = 0; 631 1.1 kiyohara clpscom_param(tp, &t); 632 1.1 kiyohara tp->t_iflag = TTYDEF_IFLAG; 633 1.1 kiyohara tp->t_oflag = TTYDEF_OFLAG; 634 1.1 kiyohara tp->t_lflag = TTYDEF_LFLAG; 635 1.1 kiyohara ttychars(tp); 636 1.1 kiyohara ttsetwater(tp); 637 1.1 kiyohara 638 1.1 kiyohara s2 = splserial(); 639 1.1 kiyohara 640 1.1 kiyohara /* Clear the input ring. */ 641 1.1 kiyohara sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 642 1.1 kiyohara sc->sc_rbavail = CLPSCOM_RING_SIZE; 643 1.1 kiyohara clpscom_iflush(sc); 644 1.1 kiyohara 645 1.1 kiyohara splx(s2); 646 1.1 kiyohara } 647 1.1 kiyohara 648 1.1 kiyohara splx(s); 649 1.1 kiyohara 650 1.1 kiyohara error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 651 1.1 kiyohara if (error) 652 1.1 kiyohara goto bad; 653 1.1 kiyohara 654 1.1 kiyohara error = (*tp->t_linesw->l_open)(dev, tp); 655 1.1 kiyohara if (error) 656 1.1 kiyohara goto bad; 657 1.1 kiyohara return 0; 658 1.1 kiyohara 659 1.1 kiyohara bad: 660 1.1 kiyohara if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 661 1.1 kiyohara /* 662 1.1 kiyohara * We failed to open the device, and nobody else had it opened. 663 1.1 kiyohara * Clean up the state as appropriate. 664 1.1 kiyohara */ 665 1.1 kiyohara clpscom_shutdown(sc); 666 1.1 kiyohara 667 1.1 kiyohara /* Disable UART */ 668 1.1 kiyohara if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 669 1.1 kiyohara CLPSCOM_WRITE_CON(sc, 670 1.1 kiyohara CLPSCOM_READ_CON(sc) & ~SYSCON_UARTEN); 671 1.1 kiyohara } 672 1.1 kiyohara 673 1.1 kiyohara return error; 674 1.1 kiyohara } 675 1.1 kiyohara 676 1.1 kiyohara /* ARGSUSED */ 677 1.1 kiyohara int 678 1.1 kiyohara clpscomclose(dev_t dev, int flag, int mode, struct lwp *l) 679 1.1 kiyohara { 680 1.1 kiyohara struct clpscom_softc *sc = 681 1.1 kiyohara device_lookup_private(&clpscom_cd, COMUNIT(dev)); 682 1.1 kiyohara struct tty *tp = sc->sc_tty; 683 1.1 kiyohara 684 1.1 kiyohara /* XXXX This is for cons.c. */ 685 1.1 kiyohara if (!ISSET(tp->t_state, TS_ISOPEN)) 686 1.1 kiyohara return 0; 687 1.1 kiyohara 688 1.1 kiyohara (*tp->t_linesw->l_close)(tp, flag); 689 1.1 kiyohara ttyclose(tp); 690 1.1 kiyohara 691 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 692 1.1 kiyohara return 0; 693 1.1 kiyohara 694 1.1 kiyohara if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 695 1.1 kiyohara /* 696 1.1 kiyohara * Although we got a last close, the device may still be in 697 1.1 kiyohara * use; e.g. if this was the dialout node, and there are still 698 1.1 kiyohara * processes waiting for carrier on the non-dialout node. 699 1.1 kiyohara */ 700 1.1 kiyohara clpscom_shutdown(sc); 701 1.1 kiyohara 702 1.1 kiyohara /* Disable UART */ 703 1.1 kiyohara if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 704 1.1 kiyohara CLPSCOM_WRITE_CON(sc, 705 1.1 kiyohara CLPSCOM_READ_CON(sc) & ~SYSCON_UARTEN); 706 1.1 kiyohara } 707 1.1 kiyohara 708 1.1 kiyohara return 0; 709 1.1 kiyohara } 710 1.1 kiyohara 711 1.1 kiyohara int 712 1.1 kiyohara clpscomread(dev_t dev, struct uio *uio, int flag) 713 1.1 kiyohara { 714 1.1 kiyohara struct clpscom_softc *sc = 715 1.1 kiyohara device_lookup_private(&clpscom_cd, COMUNIT(dev)); 716 1.1 kiyohara struct tty *tp = sc->sc_tty; 717 1.1 kiyohara 718 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 719 1.1 kiyohara return EIO; 720 1.1 kiyohara 721 1.1 kiyohara return (*tp->t_linesw->l_read)(tp, uio, flag); 722 1.1 kiyohara } 723 1.1 kiyohara 724 1.1 kiyohara int 725 1.1 kiyohara clpscomwrite(dev_t dev, struct uio *uio, int flag) 726 1.1 kiyohara { 727 1.1 kiyohara struct clpscom_softc *sc = 728 1.1 kiyohara device_lookup_private(&clpscom_cd, COMUNIT(dev)); 729 1.1 kiyohara struct tty *tp = sc->sc_tty; 730 1.1 kiyohara 731 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 732 1.1 kiyohara return EIO; 733 1.1 kiyohara 734 1.1 kiyohara return (*tp->t_linesw->l_write)(tp, uio, flag); 735 1.1 kiyohara } 736 1.1 kiyohara 737 1.1 kiyohara int 738 1.1 kiyohara clpscomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 739 1.1 kiyohara { 740 1.1 kiyohara struct clpscom_softc *sc = 741 1.1 kiyohara device_lookup_private(&clpscom_cd, COMUNIT(dev)); 742 1.1 kiyohara struct tty *tp = sc->sc_tty; 743 1.1 kiyohara int error, s; 744 1.1 kiyohara 745 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 746 1.1 kiyohara return EIO; 747 1.1 kiyohara 748 1.1 kiyohara error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 749 1.1 kiyohara if (error != EPASSTHROUGH) 750 1.1 kiyohara return error; 751 1.1 kiyohara 752 1.1 kiyohara error = ttioctl(tp, cmd, data, flag, l); 753 1.1 kiyohara if (error != EPASSTHROUGH) 754 1.1 kiyohara return error; 755 1.1 kiyohara 756 1.1 kiyohara switch (cmd) { 757 1.1 kiyohara case TIOCSFLAGS: 758 1.1 kiyohara error = kauth_authorize_device_tty(l->l_cred, 759 1.1 kiyohara KAUTH_DEVICE_TTY_PRIVSET, tp); 760 1.1 kiyohara break; 761 1.1 kiyohara default: 762 1.1 kiyohara break; 763 1.1 kiyohara } 764 1.1 kiyohara if (error) 765 1.1 kiyohara return error; 766 1.1 kiyohara 767 1.1 kiyohara s = splserial(); 768 1.1 kiyohara error = 0; 769 1.1 kiyohara switch (cmd) { 770 1.1 kiyohara case TIOCSBRK: 771 1.1 kiyohara clpscom_break(sc, 1); 772 1.1 kiyohara break; 773 1.1 kiyohara 774 1.1 kiyohara case TIOCCBRK: 775 1.1 kiyohara clpscom_break(sc, 0); 776 1.1 kiyohara break; 777 1.1 kiyohara 778 1.1 kiyohara case TIOCGFLAGS: 779 1.1 kiyohara *(int *)data = sc->sc_swflags; 780 1.1 kiyohara break; 781 1.1 kiyohara 782 1.1 kiyohara case TIOCSFLAGS: 783 1.1 kiyohara sc->sc_swflags = *(int *)data; 784 1.1 kiyohara break; 785 1.1 kiyohara 786 1.1 kiyohara case TIOCMGET: 787 1.1 kiyohara *(int *)data = clpscom_to_tiocm(sc); 788 1.1 kiyohara break; 789 1.1 kiyohara 790 1.1 kiyohara default: 791 1.1 kiyohara error = EPASSTHROUGH; 792 1.1 kiyohara break; 793 1.1 kiyohara } 794 1.1 kiyohara splx(s); 795 1.1 kiyohara return error; 796 1.1 kiyohara } 797 1.1 kiyohara 798 1.1 kiyohara int 799 1.1 kiyohara clpscompoll(dev_t dev, int events, struct lwp *l) 800 1.1 kiyohara { 801 1.1 kiyohara struct clpscom_softc *sc = 802 1.1 kiyohara device_lookup_private(&clpscom_cd, COMUNIT(dev)); 803 1.1 kiyohara struct tty *tp = sc->sc_tty; 804 1.1 kiyohara 805 1.1 kiyohara if (!device_is_active(sc->sc_dev)) 806 1.1 kiyohara return EIO; 807 1.1 kiyohara 808 1.1 kiyohara return (*tp->t_linesw->l_poll)(tp, events, l); 809 1.1 kiyohara } 810 1.1 kiyohara 811 1.1 kiyohara struct tty * 812 1.1 kiyohara clpscomtty(dev_t dev) 813 1.1 kiyohara { 814 1.1 kiyohara struct clpscom_softc *sc = 815 1.1 kiyohara device_lookup_private(&clpscom_cd, COMUNIT(dev)); 816 1.1 kiyohara 817 1.1 kiyohara return sc->sc_tty; 818 1.1 kiyohara } 819 1.1 kiyohara 820 1.1 kiyohara void 821 1.1 kiyohara clpscomstop(struct tty *tp, int flag) 822 1.1 kiyohara { 823 1.1 kiyohara int s; 824 1.1 kiyohara 825 1.1 kiyohara s = splserial(); 826 1.1 kiyohara if (ISSET(tp->t_state, TS_BUSY)) { 827 1.1 kiyohara /* Stop transmitting at the next chunk. */ 828 1.1 kiyohara if (!ISSET(tp->t_state, TS_TTSTOP)) 829 1.1 kiyohara SET(tp->t_state, TS_FLUSH); 830 1.1 kiyohara } 831 1.1 kiyohara splx(s); 832 1.1 kiyohara } 833 1.1 kiyohara 834 1.1 kiyohara 835 1.1 kiyohara static void 836 1.1 kiyohara clpscom_iflush(struct clpscom_softc *sc) 837 1.1 kiyohara { 838 1.1 kiyohara int timo; 839 1.1 kiyohara 840 1.1 kiyohara timo = 50000; 841 1.1 kiyohara while ((CLPSCOM_READ_FLG(sc) & SYSFLG_URXFE) == 0 842 1.1 kiyohara && timo--) 843 1.1 kiyohara CLPSCOM_READ(sc); 844 1.1 kiyohara if (timo == 0) 845 1.1 kiyohara printf("%s: iflush timeout\n", device_xname(sc->sc_dev)); 846 1.1 kiyohara } 847 1.1 kiyohara 848 1.1 kiyohara static void 849 1.1 kiyohara clpscom_shutdown(struct clpscom_softc *sc) 850 1.1 kiyohara { 851 1.1 kiyohara int s; 852 1.1 kiyohara 853 1.1 kiyohara s = splserial(); 854 1.1 kiyohara 855 1.1 kiyohara /* Turn off all interrupts */ 856 1.1 kiyohara if (sc->sc_ih[CLPSCOM_TXINT] != NULL) 857 1.1 kiyohara intr_disestablish(sc->sc_ih[CLPSCOM_TXINT]); 858 1.1 kiyohara sc->sc_ih[CLPSCOM_TXINT] = NULL; 859 1.1 kiyohara if (sc->sc_ih[CLPSCOM_RXINT] != NULL) 860 1.1 kiyohara intr_disestablish(sc->sc_ih[CLPSCOM_RXINT]); 861 1.1 kiyohara sc->sc_ih[CLPSCOM_RXINT] = NULL; 862 1.1 kiyohara if (sc->sc_ih[CLPSCOM_MSINT] != NULL) 863 1.1 kiyohara intr_disestablish(sc->sc_ih[CLPSCOM_MSINT]); 864 1.1 kiyohara sc->sc_ih[CLPSCOM_MSINT] = NULL; 865 1.1 kiyohara 866 1.1 kiyohara /* Clear any break condition set with TIOCSBRK. */ 867 1.1 kiyohara clpscom_break(sc, 0); 868 1.1 kiyohara 869 1.1 kiyohara splx(s); 870 1.1 kiyohara } 871 1.1 kiyohara 872 1.1 kiyohara static void 873 1.1 kiyohara clpscom_break(struct clpscom_softc *sc, int onoff) 874 1.1 kiyohara { 875 1.1 kiyohara int s; 876 1.1 kiyohara uint8_t ubrlcr; 877 1.1 kiyohara 878 1.1 kiyohara s = splserial(); 879 1.1 kiyohara ubrlcr = CLPSCOM_READ_UBRLCR(sc); 880 1.1 kiyohara if (onoff) 881 1.1 kiyohara SET(ubrlcr, UBRLCR_BREAK); 882 1.1 kiyohara else 883 1.1 kiyohara CLR(ubrlcr, UBRLCR_BREAK); 884 1.1 kiyohara CLPSCOM_WRITE_UBRLCR(sc, ubrlcr); 885 1.1 kiyohara splx(s); 886 1.1 kiyohara } 887 1.1 kiyohara 888 1.1 kiyohara static int 889 1.1 kiyohara clpscom_to_tiocm(struct clpscom_softc *sc) 890 1.1 kiyohara { 891 1.1 kiyohara uint32_t combits; 892 1.1 kiyohara int ttybits = 0; 893 1.1 kiyohara 894 1.1 kiyohara combits = sc->sc_ms; 895 1.1 kiyohara if (ISSET(combits, SYSFLG_DCD)) 896 1.1 kiyohara SET(ttybits, TIOCM_CD); 897 1.1 kiyohara if (ISSET(combits, SYSFLG_CTS)) 898 1.1 kiyohara SET(ttybits, TIOCM_CTS); 899 1.1 kiyohara if (ISSET(combits, SYSFLG_DSR)) 900 1.1 kiyohara SET(ttybits, TIOCM_DSR); 901 1.1 kiyohara 902 1.1 kiyohara return ttybits; 903 1.1 kiyohara } 904 1.1 kiyohara 905 1.1 kiyohara static void 906 1.1 kiyohara clpscom_rxsoft(struct clpscom_softc *sc, struct tty *tp) 907 1.1 kiyohara { 908 1.1 kiyohara int code, s; 909 1.1 kiyohara u_int cc, scc; 910 1.1 kiyohara u_char sts, *get; 911 1.1 kiyohara 912 1.1 kiyohara get = sc->sc_rbget; 913 1.1 kiyohara scc = cc = CLPSCOM_RING_SIZE - sc->sc_rbavail; 914 1.1 kiyohara while (cc) { 915 1.1 kiyohara code = get[0]; 916 1.1 kiyohara sts = get[1]; 917 1.1 kiyohara if (ISSET(sts, UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)) { 918 1.1 kiyohara if (ISSET(sts, (UARTDR_FRMERR))) 919 1.1 kiyohara SET(code, TTY_FE); 920 1.1 kiyohara if (ISSET(sts, UARTDR_PARERR)) 921 1.1 kiyohara SET(code, TTY_PE); 922 1.1 kiyohara if (ISSET(sts, UARTDR_OVERR)) 923 1.1 kiyohara ; /* XXXXX: Overrun */ 924 1.1 kiyohara } 925 1.1 kiyohara if ((*tp->t_linesw->l_rint)(code, tp) == -1) { 926 1.1 kiyohara /* 927 1.1 kiyohara * The line discipline's buffer is out of space. 928 1.1 kiyohara */ 929 1.1 kiyohara /* 930 1.1 kiyohara * We're either not using flow control, or the 931 1.1 kiyohara * line discipline didn't tell us to block for 932 1.1 kiyohara * some reason. Either way, we have no way to 933 1.1 kiyohara * know when there's more space available, so 934 1.1 kiyohara * just drop the rest of the data. 935 1.1 kiyohara */ 936 1.1 kiyohara get += cc << 1; 937 1.1 kiyohara if (get >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1)) 938 1.1 kiyohara get -= (CLPSCOM_RING_SIZE << 1); 939 1.1 kiyohara cc = 0; 940 1.1 kiyohara break; 941 1.1 kiyohara } 942 1.1 kiyohara get += 2; 943 1.1 kiyohara if (get >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1)) 944 1.1 kiyohara get = sc->sc_rbuf; 945 1.1 kiyohara cc--; 946 1.1 kiyohara } 947 1.1 kiyohara 948 1.1 kiyohara if (cc != scc) { 949 1.1 kiyohara sc->sc_rbget = get; 950 1.1 kiyohara s = splserial(); 951 1.1 kiyohara 952 1.1 kiyohara cc = sc->sc_rbavail += scc - cc; 953 1.1 kiyohara /* Buffers should be ok again, release possible block. */ 954 1.1 kiyohara if (cc >= 1) { 955 1.1 kiyohara if (sc->sc_ih[CLPSCOM_RXINT] == NULL) { 956 1.1 kiyohara sc->sc_ih[CLPSCOM_RXINT] = 957 1.1 kiyohara intr_establish(sc->sc_irq[CLPSCOM_RXINT], 958 1.1 kiyohara IPL_SERIAL, 0, clpscom_rxintr, sc); 959 1.1 kiyohara if (sc->sc_ih[CLPSCOM_RXINT] == NULL) 960 1.1 kiyohara printf("%s: can't establish" 961 1.1 kiyohara " rx interrupt\n", 962 1.1 kiyohara device_xname(sc->sc_dev)); 963 1.1 kiyohara } 964 1.1 kiyohara if (sc->sc_ih[CLPSCOM_MSINT] == NULL) { 965 1.1 kiyohara sc->sc_ih[CLPSCOM_MSINT] = 966 1.1 kiyohara intr_establish(sc->sc_irq[CLPSCOM_MSINT], 967 1.1 kiyohara IPL_SERIAL, 0, clpscom_msintr, sc); 968 1.1 kiyohara if (sc->sc_ih[CLPSCOM_MSINT] == NULL) 969 1.1 kiyohara printf("%s: can't establish" 970 1.1 kiyohara " ms interrupt\n", 971 1.1 kiyohara device_xname(sc->sc_dev)); 972 1.1 kiyohara } 973 1.1 kiyohara } 974 1.1 kiyohara splx(s); 975 1.1 kiyohara } 976 1.1 kiyohara } 977 1.1 kiyohara 978 1.1 kiyohara static void 979 1.1 kiyohara clpscom_mssoft(struct clpscom_softc *sc, struct tty *tp) 980 1.1 kiyohara { 981 1.1 kiyohara uint32_t ms, delta; 982 1.1 kiyohara 983 1.1 kiyohara ms = sc->sc_ms; 984 1.1 kiyohara delta = sc->sc_ms_delta; 985 1.1 kiyohara sc->sc_ms_delta = 0; 986 1.1 kiyohara 987 1.1 kiyohara if (ISSET(delta, sc->sc_ms_dcd)) 988 1.1 kiyohara /* 989 1.1 kiyohara * Inform the tty layer that carrier detect changed. 990 1.1 kiyohara */ 991 1.1 kiyohara (void) (*tp->t_linesw->l_modem)(tp, ISSET(ms, SYSFLG_DCD)); 992 1.1 kiyohara 993 1.1 kiyohara if (ISSET(delta, sc->sc_ms_cts)) { 994 1.1 kiyohara /* Block or unblock output according to flow control. */ 995 1.1 kiyohara if (ISSET(ms, sc->sc_ms_cts)) { 996 1.1 kiyohara sc->sc_tx_stopped = 0; 997 1.1 kiyohara (*tp->t_linesw->l_start)(tp); 998 1.1 kiyohara } else 999 1.1 kiyohara sc->sc_tx_stopped = 1; 1000 1.1 kiyohara } 1001 1.1 kiyohara } 1002 1.1 kiyohara 1003 1.1 kiyohara static inline uint32_t 1004 1.1 kiyohara clpscom_rate2ubrlcr(int rate) 1005 1.1 kiyohara { 1006 1.1 kiyohara 1007 1.1 kiyohara return 230400 / rate - 1; 1008 1.1 kiyohara } 1009 1.1 kiyohara 1010 1.1 kiyohara static uint32_t 1011 1.1 kiyohara clpscom_cflag2ubrlcr(tcflag_t cflag) 1012 1.1 kiyohara { 1013 1.1 kiyohara int32_t ubrlcr = 0; 1014 1.1 kiyohara 1015 1.1 kiyohara switch (cflag & CSIZE) { 1016 1.1 kiyohara case CS5: SET(ubrlcr, UBRLCR_WRDLEN_5B); break; 1017 1.1 kiyohara case CS6: SET(ubrlcr, UBRLCR_WRDLEN_6B); break; 1018 1.1 kiyohara case CS7: SET(ubrlcr, UBRLCR_WRDLEN_7B); break; 1019 1.1 kiyohara case CS8: SET(ubrlcr, UBRLCR_WRDLEN_8B); break; 1020 1.1 kiyohara default: SET(ubrlcr, UBRLCR_WRDLEN_8B); break; 1021 1.1 kiyohara } 1022 1.1 kiyohara if (cflag & CSTOPB) 1023 1.1 kiyohara SET(ubrlcr, UBRLCR_XSTOP); 1024 1.1 kiyohara if (cflag & PARENB) { 1025 1.1 kiyohara SET(ubrlcr, (UBRLCR_PRTEN | UBRLCR_EVENPRT)); 1026 1.1 kiyohara if (cflag & PARODD) 1027 1.1 kiyohara CLR(ubrlcr, UBRLCR_EVENPRT); 1028 1.1 kiyohara } 1029 1.1 kiyohara return ubrlcr; 1030 1.1 kiyohara } 1031 1.1 kiyohara 1032 1.1 kiyohara #define CLPSCOM_CNREAD() \ 1033 1.1 kiyohara (*(volatile uint32_t *)(clpscom_cnaddr + PS711X_UARTDR)) 1034 1.1 kiyohara #define CLPSCOM_CNWRITE(val) \ 1035 1.1 kiyohara (*(volatile uint8_t *)(clpscom_cnaddr + PS711X_UARTDR) = val) 1036 1.1 kiyohara #define CLPSCOM_CNSTATUS() \ 1037 1.1 kiyohara (*(volatile uint32_t *)(clpscom_cnaddr + PS711X_SYSFLG)) 1038 1.1 kiyohara 1039 1.1 kiyohara static struct consdev clpscomcons = { 1040 1.1 kiyohara NULL, NULL, clpscom_cngetc, clpscom_cnputc, clpscom_cnpollc, 1041 1.1 kiyohara NULL, NULL, NULL, NODEV, CN_NORMAL 1042 1.1 kiyohara }; 1043 1.1 kiyohara 1044 1.1 kiyohara int 1045 1.1 kiyohara clpscom_cnattach(vaddr_t addr, int rate, tcflag_t cflag) 1046 1.1 kiyohara { 1047 1.1 kiyohara 1048 1.1 kiyohara clpscom_cnaddr = addr; 1049 1.1 kiyohara clpscom_cnrate = rate; 1050 1.1 kiyohara clpscom_cncflag = cflag; 1051 1.1 kiyohara *(volatile uint32_t *)(clpscom_cnaddr + PS711X_SYSFLG) |= SYSCON_UARTEN; 1052 1.1 kiyohara *(volatile uint32_t *)(clpscom_cnaddr + PS711X_UBRLCR) = 1053 1.1 kiyohara UBRLCR_FIFOEN | 1054 1.1 kiyohara clpscom_cflag2ubrlcr(cflag) | 1055 1.1 kiyohara clpscom_rate2ubrlcr(rate); 1056 1.1 kiyohara 1057 1.1 kiyohara cn_tab = &clpscomcons; 1058 1.1 kiyohara cn_init_magic(&clpscom_cnm_state); 1059 1.1 kiyohara cn_set_magic("\047\001"); /* default magic is BREAK */ 1060 1.1 kiyohara 1061 1.1 kiyohara return 0; 1062 1.1 kiyohara } 1063 1.1 kiyohara 1064 1.1 kiyohara /* ARGSUSED */ 1065 1.1 kiyohara static int 1066 1.1 kiyohara clpscom_cngetc(dev_t dev) 1067 1.1 kiyohara { 1068 1.1 kiyohara int s = splserial(); 1069 1.1 kiyohara char ch; 1070 1.1 kiyohara 1071 1.1 kiyohara while (CLPSCOM_CNSTATUS() & SYSFLG_URXFE); 1072 1.1 kiyohara 1073 1.1 kiyohara ch = CLPSCOM_CNREAD(); 1074 1.1 kiyohara 1075 1.10 riastrad if (!db_active) 1076 1.10 riastrad cn_check_magic(dev, ch, clpscom_cnm_state); 1077 1.1 kiyohara 1078 1.1 kiyohara splx(s); 1079 1.1 kiyohara return ch; 1080 1.1 kiyohara } 1081 1.1 kiyohara 1082 1.1 kiyohara /* ARGSUSED */ 1083 1.1 kiyohara static void 1084 1.1 kiyohara clpscom_cnputc(dev_t dev, int c) 1085 1.1 kiyohara { 1086 1.1 kiyohara int s = splserial(); 1087 1.1 kiyohara 1088 1.1 kiyohara while (CLPSCOM_CNSTATUS() & SYSFLG_UTXFF); 1089 1.1 kiyohara 1090 1.1 kiyohara CLPSCOM_CNWRITE(c); 1091 1.1 kiyohara 1092 1.1 kiyohara /* Make sure output. */ 1093 1.1 kiyohara while (CLPSCOM_CNSTATUS() & SYSFLG_UBUSY); 1094 1.1 kiyohara 1095 1.1 kiyohara splx(s); 1096 1.1 kiyohara } 1097 1.1 kiyohara 1098 1.1 kiyohara /* ARGSUSED */ 1099 1.1 kiyohara static void 1100 1.1 kiyohara clpscom_cnpollc(dev_t dev, int on) 1101 1.1 kiyohara { 1102 1.1 kiyohara /* Nothing */ 1103 1.1 kiyohara } 1104