1272343Sngie/* $OpenBSD: mvuart.c,v 1.4 2021/10/24 17:52:26 mpi Exp $ */ 2272343Sngie/* 3272343Sngie * Copyright (c) 2005 Dale Rahn <drahn@motorola.com> 4272343Sngie * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se> 5272343Sngie * 6272343Sngie * Permission to use, copy, modify, and distribute this software for any 7272343Sngie * purpose with or without fee is hereby granted, provided that the above 8272343Sngie * copyright notice and this permission notice appear in all copies. 9272343Sngie * 10272343Sngie * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11272343Sngie * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12272343Sngie * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13272343Sngie * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14272343Sngie * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15272343Sngie * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16272343Sngie * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17272343Sngie */ 18272343Sngie 19272343Sngie#include <sys/param.h> 20272343Sngie#include <sys/ioctl.h> 21272343Sngie#include <sys/proc.h> 22272343Sngie#include <sys/tty.h> 23272343Sngie#include <sys/systm.h> 24272343Sngie#include <sys/device.h> 25272343Sngie#include <sys/conf.h> 26272343Sngie#include <sys/fcntl.h> 27272343Sngie 28272343Sngie#include <machine/bus.h> 29272343Sngie#include <machine/fdt.h> 30272343Sngie 31272343Sngie#include <dev/cons.h> 32272343Sngie 33272343Sngie#include <dev/ofw/openfirm.h> 34272343Sngie#include <dev/ofw/ofw_clock.h> 35272343Sngie#include <dev/ofw/ofw_pinctrl.h> 36272343Sngie#include <dev/ofw/fdt.h> 37272343Sngie 38272343Sngie#define MVUART_RBR 0x00 39272343Sngie#define MVUART_TSH 0x04 40272343Sngie#define MVUART_CTRL 0x08 41272343Sngie#define MVUART_CTRL_RX_RDY_INT (1 << 4) 42272343Sngie#define MVUART_CTRL_TX_RDY_INT (1 << 5) 43272343Sngie#define MVUART_STAT 0x0c 44272343Sngie#define MVUART_STAT_STD_OVR_ERR (1 << 0) 45272343Sngie#define MVUART_STAT_STD_PAR_ERR (1 << 1) 46272343Sngie#define MVUART_STAT_STD_FRM_ERR (1 << 2) 47272343Sngie#define MVUART_STAT_STD_BRK_DET (1 << 3) 48272343Sngie#define MVUART_STAT_STD_ERROR_MASK (0xf << 0) 49272343Sngie#define MVUART_STAT_STD_RX_RDY (1 << 4) 50272343Sngie#define MVUART_STAT_STD_TX_RDY (1 << 5) 51272343Sngie#define MVUART_STAT_STD_TX_EMPTY (1 << 6) 52272343Sngie#define MVUART_STAT_STD_TX_FIFO_FULL (1 << 11) 53272343Sngie#define MVUART_STAT_STD_TX_FIFO_EMPTY (1 << 13) 54272343Sngie#define MVUART_BAUD_RATE_DIV 0x10 55272343Sngie#define MVUART_BAUD_RATE_DIV_MASK 0x3ff 56272343Sngie 57272343Sngie#define DEVUNIT(x) (minor(x) & 0x7f) 58272343Sngie#define DEVCUA(x) (minor(x) & 0x80) 59272343Sngie 60272343Sngie#define HREAD4(sc, reg) \ 61272343Sngie (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 62272343Sngie#define HWRITE4(sc, reg, val) \ 63272343Sngie bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 64272343Sngie#define HSET4(sc, reg, bits) \ 65272343Sngie HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 66272343Sngie#define HCLR4(sc, reg, bits) \ 67272343Sngie HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 68272343Sngie 69272343Sngiestruct mvuart_softc { 70272343Sngie struct device sc_dev; 71272343Sngie bus_space_tag_t sc_iot; 72272343Sngie bus_space_handle_t sc_ioh; 73272343Sngie int sc_node; 74272343Sngie struct soft_intrhand *sc_si; 75272343Sngie void *sc_ih; 76272343Sngie struct tty *sc_tty; 77272343Sngie int sc_floods; 78272343Sngie int sc_errors; 79272343Sngie int sc_halt; 80272343Sngie uint8_t sc_hwflags; 81272343Sngie#define COM_HW_NOIEN 0x01 82272343Sngie#define COM_HW_FIFO 0x02 83272343Sngie#define COM_HW_SIR 0x20 84272343Sngie#define COM_HW_CONSOLE 0x40 85272343Sngie uint8_t sc_cua; 86272343Sngie uint16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend; 87272343Sngie#define MVUART_IBUFSIZE 128 88272343Sngie#define MVUART_IHIGHWATER 100 89272343Sngie uint16_t sc_ibufs[2][MVUART_IBUFSIZE]; 90272343Sngie}; 91272343Sngie 92272343Sngieint mvuart_match(struct device *, void *, void *); 93272343Sngievoid mvuart_attach(struct device *, struct device *, void *); 94272343Sngie 95272343Sngievoid mvuartcnprobe(struct consdev *cp); 96272343Sngievoid mvuartcninit(struct consdev *cp); 97272343Sngieint mvuartcnattach(bus_space_tag_t, bus_addr_t, int, tcflag_t); 98272343Sngieint mvuartcngetc(dev_t dev); 99272343Sngievoid mvuartcnputc(dev_t dev, int c); 100272343Sngievoid mvuartcnpollc(dev_t dev, int on); 101272343Sngieint mvuart_param(struct tty *, struct termios *); 102272343Sngievoid mvuart_start(struct tty *); 103272343Sngievoid mvuart_softint(void *arg); 104272343Sngie 105272343Sngiestruct mvuart_softc *mvuart_sc(dev_t dev); 106272343Sngie 107272343Sngieint mvuart_intr(void *); 108272343Sngieint mvuart_intr_rx(struct mvuart_softc *); 109272343Sngieint mvuart_intr_tx(struct mvuart_softc *); 110272343Sngie 111272343Sngie/* XXX - we imitate 'com' serial ports and take over their entry points */ 112272343Sngie/* XXX: These belong elsewhere */ 113272343Sngiecdev_decl(com); 114272343Sngiecdev_decl(mvuart); 115272343Sngie 116272343Sngiestruct cfdriver mvuart_cd = { 117272343Sngie NULL, "mvuart", DV_TTY 118272343Sngie}; 119272343Sngie 120272343Sngieconst struct cfattach mvuart_ca = { 121272343Sngie sizeof(struct mvuart_softc), mvuart_match, mvuart_attach 122272343Sngie}; 123272343Sngie 124272343Sngiebus_space_tag_t mvuartconsiot; 125272343Sngiebus_space_handle_t mvuartconsioh; 126272343Sngiebus_addr_t mvuartconsaddr; 127272343Sngie 128272343Sngiestruct cdevsw mvuartdev = 129272343Sngie cdev_tty_init(3/*XXX NMVUART */, mvuart); /* 12: serial port */ 130272343Sngie 131272343Sngievoid 132272343Sngiemvuart_init_cons(void) 133272343Sngie{ 134272343Sngie struct fdt_reg reg; 135272343Sngie void *node; 136272343Sngie 137272343Sngie if ((node = fdt_find_cons("marvell,armada-3700-uart")) == NULL) 138272343Sngie return; 139272343Sngie 140272343Sngie if (fdt_get_reg(node, 0, ®)) 141272343Sngie return; 142272343Sngie 143272343Sngie mvuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG); 144272343Sngie} 145272343Sngie 146272343Sngieint 147272343Sngiemvuart_match(struct device *parent, void *match, void *aux) 148272343Sngie{ 149272343Sngie struct fdt_attach_args *faa = aux; 150272343Sngie 151272343Sngie return OF_is_compatible(faa->fa_node, "marvell,armada-3700-uart"); 152272343Sngie} 153272343Sngie 154272343Sngievoid 155272343Sngiemvuart_attach(struct device *parent, struct device *self, void *aux) 156272343Sngie{ 157272343Sngie struct mvuart_softc *sc = (struct mvuart_softc *)self; 158272343Sngie struct fdt_attach_args *faa = aux; 159272343Sngie int maj; 160272343Sngie 161272343Sngie if (faa->fa_nreg < 1) 162272343Sngie return; 163272343Sngie 164272343Sngie pinctrl_byname(faa->fa_node, "default"); 165272343Sngie 166272343Sngie sc->sc_node = faa->fa_node; 167272343Sngie sc->sc_iot = faa->fa_iot; 168272343Sngie if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 169272343Sngie faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 170272343Sngie panic("%s: bus_space_map failed", sc->sc_dev.dv_xname); 171272343Sngie return; 172272343Sngie } 173272343Sngie 174272343Sngie if (faa->fa_reg[0].addr == mvuartconsaddr) { 175272343Sngie /* Locate the major number. */ 176272343Sngie for (maj = 0; maj < nchrdev; maj++) 177272343Sngie if (cdevsw[maj].d_open == mvuartopen) 178272343Sngie break; 179272343Sngie cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); 180272343Sngie 181272343Sngie printf(": console"); 182272343Sngie } 183272343Sngie 184272343Sngie printf("\n"); 185272343Sngie 186272343Sngie sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY, 187272343Sngie mvuart_intr, sc, sc->sc_dev.dv_xname); 188272343Sngie if (sc->sc_ih == NULL) 189272343Sngie panic("%s: can't establish hard interrupt", 190272343Sngie sc->sc_dev.dv_xname); 191272343Sngie 192272343Sngie sc->sc_si = softintr_establish(IPL_TTY, mvuart_softint, sc); 193272343Sngie if (sc->sc_si == NULL) 194272343Sngie panic("%s: can't establish soft interrupt", 195272343Sngie sc->sc_dev.dv_xname); 196272343Sngie} 197272343Sngie 198272343Sngieint 199272343Sngiemvuart_intr(void *arg) 200272343Sngie{ 201272343Sngie struct mvuart_softc *sc = arg; 202272343Sngie uint32_t stat; 203272343Sngie int ret = 0; 204272343Sngie 205272343Sngie if (sc->sc_tty == NULL) 206272343Sngie return 0; 207272343Sngie 208272343Sngie stat = HREAD4(sc, MVUART_STAT); 209272343Sngie 210272343Sngie if ((stat & MVUART_STAT_STD_RX_RDY) != 0) 211272343Sngie ret |= mvuart_intr_rx(sc); 212272343Sngie 213272343Sngie if ((stat & MVUART_STAT_STD_TX_RDY) != 0) 214272343Sngie ret |= mvuart_intr_tx(sc); 215272343Sngie 216272343Sngie return ret; 217272343Sngie} 218272343Sngie 219272343Sngieint 220272343Sngiemvuart_intr_rx(struct mvuart_softc *sc) 221272343Sngie{ 222272343Sngie uint32_t stat; 223272343Sngie uint16_t *p, c; 224272343Sngie 225272343Sngie p = sc->sc_ibufp; 226272343Sngie 227272343Sngie stat = HREAD4(sc, MVUART_STAT); 228272343Sngie while ((stat & MVUART_STAT_STD_RX_RDY) != 0) { 229272343Sngie c = HREAD4(sc, MVUART_RBR); 230272343Sngie c |= (stat & MVUART_STAT_STD_ERROR_MASK) << 8; 231272343Sngie if (p >= sc->sc_ibufend) { 232272343Sngie sc->sc_floods++; 233272343Sngie } else { 234272343Sngie *p++ = c; 235272343Sngie } 236272343Sngie stat = HREAD4(sc, MVUART_STAT); 237272343Sngie } 238272343Sngie sc->sc_ibufp = p; 239272343Sngie 240272343Sngie softintr_schedule(sc->sc_si); 241272343Sngie return 1; 242272343Sngie} 243272343Sngie 244272343Sngieint 245272343Sngiemvuart_intr_tx(struct mvuart_softc *sc) 246272343Sngie{ 247272343Sngie struct tty *tp = sc->sc_tty; 248272343Sngie 249272343Sngie HCLR4(sc, MVUART_CTRL, MVUART_CTRL_TX_RDY_INT); 250272343Sngie if (ISSET(tp->t_state, TS_BUSY)) { 251272343Sngie CLR(tp->t_state, TS_BUSY | TS_FLUSH); 252272343Sngie if (sc->sc_halt > 0) 253272343Sngie wakeup(&tp->t_outq); 254272343Sngie (*linesw[tp->t_line].l_start)(tp); 255272343Sngie } 256272343Sngie 257272343Sngie return 1; 258272343Sngie} 259272343Sngie 260272343Sngieint 261272343Sngiemvuart_param(struct tty *tp, struct termios *t) 262272343Sngie{ 263272343Sngie struct mvuart_softc *sc = mvuart_sc(tp->t_dev); 264272343Sngie int error, ospeed = t->c_ospeed; 265272343Sngie tcflag_t oldcflag; 266272343Sngie 267272343Sngie if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 268272343Sngie return EINVAL; 269272343Sngie 270272343Sngie switch (ISSET(t->c_cflag, CSIZE)) { 271272343Sngie case CS5: 272272343Sngie case CS6: 273272343Sngie case CS7: 274272343Sngie return EINVAL; 275272343Sngie case CS8: 276272343Sngie break; 277272343Sngie } 278272343Sngie 279272343Sngie if (ospeed != 0) { 280272343Sngie while (ISSET(tp->t_state, TS_BUSY)) { 281272343Sngie ++sc->sc_halt; 282272343Sngie error = ttysleep(tp, &tp->t_outq, 283272343Sngie TTOPRI | PCATCH, "mvuartprm"); 284272343Sngie --sc->sc_halt; 285272343Sngie if (error) { 286272343Sngie mvuart_start(tp); 287272343Sngie return (error); 288272343Sngie } 289272343Sngie } 290272343Sngie } 291272343Sngie 292272343Sngie /* and copy to tty */ 293272343Sngie tp->t_ispeed = t->c_ispeed; 294272343Sngie tp->t_ospeed = t->c_ospeed; 295272343Sngie oldcflag = tp->t_cflag; 296272343Sngie tp->t_cflag = t->c_cflag; 297272343Sngie 298272343Sngie mvuart_start(tp); 299272343Sngie return 0; 300272343Sngie} 301272343Sngie 302272343Sngievoid 303272343Sngiemvuart_start(struct tty *tp) 304272343Sngie{ 305272343Sngie struct mvuart_softc *sc = mvuart_sc(tp->t_dev); 306272343Sngie uint8_t buf; 307272343Sngie int i, n, s; 308272343Sngie 309272343Sngie s = spltty(); 310272343Sngie if (ISSET(tp->t_state, TS_BUSY)) { 311272343Sngie splx(s); 312272343Sngie return; 313272343Sngie } 314272343Sngie if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP)) 315272343Sngie goto out; 316272343Sngie if (tp->t_outq.c_cc <= tp->t_lowat) { 317272343Sngie if (ISSET(tp->t_state, TS_ASLEEP)) { 318272343Sngie CLR(tp->t_state, TS_ASLEEP); 319272343Sngie wakeup(&tp->t_outq); 320272343Sngie } 321272343Sngie if (tp->t_outq.c_cc == 0) 322272343Sngie goto out; 323272343Sngie selwakeup(&tp->t_wsel); 324272343Sngie } 325272343Sngie SET(tp->t_state, TS_BUSY); 326272343Sngie 327272343Sngie for (i = 0; i < 32; i++) { 328272343Sngie n = q_to_b(&tp->t_outq, &buf, 1); 329272343Sngie if (n < 1) 330272343Sngie break; 331272343Sngie HWRITE4(sc, MVUART_TSH, buf); 332272343Sngie if (HREAD4(sc, MVUART_STAT) & MVUART_STAT_STD_TX_FIFO_FULL) 333272343Sngie break; 334272343Sngie } 335272343Sngie HSET4(sc, MVUART_CTRL, MVUART_CTRL_TX_RDY_INT); 336272343Sngie 337272343Sngieout: 338272343Sngie splx(s); 339272343Sngie} 340272343Sngie 341272343Sngievoid 342272343Sngiemvuart_softint(void *arg) 343272343Sngie{ 344272343Sngie struct mvuart_softc *sc = arg; 345272343Sngie struct tty *tp; 346272343Sngie uint16_t *ibufp; 347272343Sngie uint16_t *ibufend; 348272343Sngie int c, err, s; 349272343Sngie 350272343Sngie if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf) 351272343Sngie return; 352272343Sngie 353272343Sngie tp = sc->sc_tty; 354272343Sngie s = spltty(); 355272343Sngie 356272343Sngie ibufp = sc->sc_ibuf; 357272343Sngie ibufend = sc->sc_ibufp; 358272343Sngie 359272343Sngie if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) { 360272343Sngie splx(s); 361272343Sngie return; 362272343Sngie } 363272343Sngie 364272343Sngie sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? 365272343Sngie sc->sc_ibufs[1] : sc->sc_ibufs[0]; 366272343Sngie sc->sc_ibufhigh = sc->sc_ibuf + MVUART_IHIGHWATER; 367272343Sngie sc->sc_ibufend = sc->sc_ibuf + MVUART_IBUFSIZE; 368272343Sngie 369272343Sngie splx(s); 370272343Sngie 371272343Sngie while (ibufp < ibufend) { 372272343Sngie err = 0; 373272343Sngie c = *ibufp++; 374272343Sngie if (ISSET(c, (MVUART_STAT_STD_PAR_ERR << 8))) 375272343Sngie err |= TTY_PE; 376272343Sngie if (ISSET(c, (MVUART_STAT_STD_FRM_ERR << 8))) 377272343Sngie err |= TTY_FE; 378272343Sngie c = (c & 0xff) | err; 379272343Sngie (*linesw[tp->t_line].l_rint)(c, tp); 380272343Sngie } 381272343Sngie} 382272343Sngie 383272343Sngieint 384272343Sngiemvuartopen(dev_t dev, int flag, int mode, struct proc *p) 385272343Sngie{ 386272343Sngie struct mvuart_softc *sc; 387272343Sngie struct tty *tp; 388272343Sngie int s, error = 0; 389272343Sngie 390272343Sngie sc = mvuart_sc(dev); 391272343Sngie if (sc == NULL) 392272343Sngie return ENXIO; 393272343Sngie 394272343Sngie s = spltty(); 395272343Sngie if (sc->sc_tty == NULL) 396272343Sngie tp = sc->sc_tty = ttymalloc(0); 397272343Sngie else 398272343Sngie tp = sc->sc_tty; 399272343Sngie 400272343Sngie splx(s); 401272343Sngie 402272343Sngie tp->t_oproc = mvuart_start; 403272343Sngie tp->t_param = mvuart_param; 404272343Sngie tp->t_dev = dev; 405272343Sngie 406272343Sngie if (!ISSET(tp->t_state, TS_ISOPEN)) { 407272343Sngie SET(tp->t_state, TS_WOPEN); 408272343Sngie ttychars(tp); 409272343Sngie tp->t_iflag = TTYDEF_IFLAG; 410272343Sngie tp->t_oflag = TTYDEF_OFLAG; 411272343Sngie 412272343Sngie tp->t_cflag = TTYDEF_CFLAG; 413272343Sngie tp->t_lflag = TTYDEF_LFLAG; 414272343Sngie tp->t_ispeed = tp->t_ospeed = B115200; 415272343Sngie 416272343Sngie s = spltty(); 417272343Sngie 418272343Sngie mvuart_param(tp, &tp->t_termios); 419272343Sngie ttsetwater(tp); 420272343Sngie sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; 421272343Sngie sc->sc_ibufhigh = sc->sc_ibuf + MVUART_IHIGHWATER; 422272343Sngie sc->sc_ibufend = sc->sc_ibuf + MVUART_IBUFSIZE; 423272343Sngie 424272343Sngie /* Enable interrupts */ 425272343Sngie HSET4(sc, MVUART_CTRL, MVUART_CTRL_RX_RDY_INT); 426272343Sngie 427272343Sngie SET(tp->t_state, TS_CARR_ON); /* XXX */ 428272343Sngie } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0) 429272343Sngie return EBUSY; 430272343Sngie else 431272343Sngie s = spltty(); 432272343Sngie 433272343Sngie if (DEVCUA(dev)) { 434272343Sngie if (ISSET(tp->t_state, TS_ISOPEN)) { 435272343Sngie splx(s); 436272343Sngie return EBUSY; 437272343Sngie } 438272343Sngie sc->sc_cua = 1; 439272343Sngie } else { 440272343Sngie /* tty (not cua) device; wait for carrier if necessary */ 441272343Sngie if (ISSET(flag, O_NONBLOCK)) { 442272343Sngie if (sc->sc_cua) { 443272343Sngie /* Opening TTY non-blocking... but the CUA is busy */ 444272343Sngie splx(s); 445272343Sngie return EBUSY; 446272343Sngie } 447272343Sngie } else { 448272343Sngie while (sc->sc_cua || 449272343Sngie (!ISSET(tp->t_cflag, CLOCAL) && 450272343Sngie !ISSET(tp->t_state, TS_CARR_ON))) { 451272343Sngie SET(tp->t_state, TS_WOPEN); 452272343Sngie error = ttysleep(tp, &tp->t_rawq, 453272343Sngie TTIPRI | PCATCH, ttopen); 454272343Sngie /* 455272343Sngie * If TS_WOPEN has been reset, that means the 456272343Sngie * cua device has been closed. We don't want 457272343Sngie * to fail in that case, 458272343Sngie * so just go around again. 459272343Sngie */ 460272343Sngie if (error && ISSET(tp->t_state, TS_WOPEN)) { 461272343Sngie CLR(tp->t_state, TS_WOPEN); 462272343Sngie splx(s); 463272343Sngie return error; 464272343Sngie } 465272343Sngie } 466272343Sngie } 467272343Sngie } 468272343Sngie splx(s); 469272343Sngie return (*linesw[tp->t_line].l_open)(dev,tp,p); 470272343Sngie} 471272343Sngie 472272343Sngieint 473272343Sngiemvuartclose(dev_t dev, int flag, int mode, struct proc *p) 474272343Sngie{ 475272343Sngie struct mvuart_softc *sc = mvuart_sc(dev); 476272343Sngie struct tty *tp = sc->sc_tty; 477272343Sngie int s; 478272343Sngie 479272343Sngie if (!ISSET(tp->t_state, TS_ISOPEN)) 480272343Sngie return 0; 481272343Sngie 482272343Sngie (*linesw[tp->t_line].l_close)(tp, flag, p); 483272343Sngie s = spltty(); 484272343Sngie if (!ISSET(tp->t_state, TS_WOPEN)) { 485272343Sngie /* Disable interrupts */ 486272343Sngie HCLR4(sc, MVUART_CTRL, MVUART_CTRL_RX_RDY_INT | 487272343Sngie MVUART_CTRL_TX_RDY_INT); 488272343Sngie } 489272343Sngie CLR(tp->t_state, TS_BUSY | TS_FLUSH); 490272343Sngie sc->sc_cua = 0; 491272343Sngie splx(s); 492272343Sngie ttyclose(tp); 493272343Sngie 494272343Sngie return 0; 495272343Sngie} 496272343Sngie 497272343Sngieint 498272343Sngiemvuartread(dev_t dev, struct uio *uio, int flag) 499272343Sngie{ 500272343Sngie struct tty *tty; 501272343Sngie 502272343Sngie tty = mvuarttty(dev); 503272343Sngie if (tty == NULL) 504272343Sngie return ENODEV; 505272343Sngie 506272343Sngie return((*linesw[tty->t_line].l_read)(tty, uio, flag)); 507272343Sngie} 508272343Sngie 509272343Sngieint 510272343Sngiemvuartwrite(dev_t dev, struct uio *uio, int flag) 511272343Sngie{ 512272343Sngie struct tty *tty; 513272343Sngie 514272343Sngie tty = mvuarttty(dev); 515272343Sngie if (tty == NULL) 516272343Sngie return ENODEV; 517272343Sngie 518272343Sngie return((*linesw[tty->t_line].l_write)(tty, uio, flag)); 519272343Sngie} 520272343Sngie 521272343Sngieint 522272343Sngiemvuartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 523272343Sngie{ 524272343Sngie struct mvuart_softc *sc; 525272343Sngie struct tty *tp; 526272343Sngie int error; 527272343Sngie 528272343Sngie sc = mvuart_sc(dev); 529272343Sngie if (sc == NULL) 530272343Sngie return (ENODEV); 531272343Sngie 532272343Sngie tp = sc->sc_tty; 533272343Sngie if (tp == NULL) 534272343Sngie return (ENXIO); 535272343Sngie 536272343Sngie error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 537272343Sngie if (error >= 0) 538272343Sngie return (error); 539272343Sngie 540272343Sngie error = ttioctl(tp, cmd, data, flag, p); 541272343Sngie if (error >= 0) 542272343Sngie return (error); 543272343Sngie 544272343Sngie switch(cmd) { 545272343Sngie case TIOCSBRK: 546272343Sngie case TIOCCBRK: 547272343Sngie case TIOCSDTR: 548272343Sngie case TIOCCDTR: 549272343Sngie case TIOCMSET: 550272343Sngie case TIOCMBIS: 551272343Sngie case TIOCMBIC: 552272343Sngie case TIOCMGET: 553272343Sngie case TIOCGFLAGS: 554272343Sngie break; 555272343Sngie case TIOCSFLAGS: 556272343Sngie error = suser(p); 557272343Sngie if (error != 0) 558272343Sngie return(EPERM); 559272343Sngie break; 560272343Sngie default: 561272343Sngie return (ENOTTY); 562272343Sngie } 563272343Sngie 564 return 0; 565} 566 567int 568mvuartstop(struct tty *tp, int flag) 569{ 570 return 0; 571} 572 573struct tty * 574mvuarttty(dev_t dev) 575{ 576 struct mvuart_softc *sc; 577 sc = mvuart_sc(dev); 578 if (sc == NULL) 579 return NULL; 580 return sc->sc_tty; 581} 582 583struct mvuart_softc * 584mvuart_sc(dev_t dev) 585{ 586 int unit; 587 unit = DEVUNIT(dev); 588 if (unit >= mvuart_cd.cd_ndevs) 589 return NULL; 590 return (struct mvuart_softc *)mvuart_cd.cd_devs[unit]; 591} 592 593/* serial console */ 594void 595mvuartcnprobe(struct consdev *cp) 596{ 597} 598 599void 600mvuartcninit(struct consdev *cp) 601{ 602} 603 604int 605mvuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag) 606{ 607 static struct consdev mvuartcons = { 608 NULL, NULL, mvuartcngetc, mvuartcnputc, mvuartcnpollc, NULL, 609 NODEV, CN_MIDPRI 610 }; 611 int maj; 612 613 if (bus_space_map(iot, iobase, 0x200, 0, &mvuartconsioh)) 614 return ENOMEM; 615 616 /* Look for major of com(4) to replace. */ 617 for (maj = 0; maj < nchrdev; maj++) 618 if (cdevsw[maj].d_open == comopen) 619 break; 620 if (maj == nchrdev) 621 return ENXIO; 622 623 cn_tab = &mvuartcons; 624 cn_tab->cn_dev = makedev(maj, 0); 625 cdevsw[maj] = mvuartdev; /* KLUDGE */ 626 627 mvuartconsiot = iot; 628 mvuartconsaddr = iobase; 629 630 return 0; 631} 632 633int 634mvuartcngetc(dev_t dev) 635{ 636 int c; 637 int s; 638 s = splhigh(); 639 while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) & 640 MVUART_STAT_STD_RX_RDY) == 0) 641 ; 642 c = bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_RBR); 643 splx(s); 644 return c; 645} 646 647void 648mvuartcnputc(dev_t dev, int c) 649{ 650 int s; 651 s = splhigh(); 652 while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) & 653 MVUART_STAT_STD_TX_FIFO_FULL) != 0) 654 ; 655 bus_space_write_4(mvuartconsiot, mvuartconsioh, MVUART_TSH, (uint8_t)c); 656 while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) & 657 MVUART_STAT_STD_TX_FIFO_EMPTY) != 0) 658 ; 659 splx(s); 660} 661 662void 663mvuartcnpollc(dev_t dev, int on) 664{ 665} 666