1 1.10 msaitoh /* $NetBSD: dz_ebus.c,v 1.10 2019/12/27 06:52:43 msaitoh Exp $ */ 2 1.1 pooka 3 1.1 pooka /*- 4 1.1 pooka * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 1.1 pooka * All rights reserved. 6 1.1 pooka * 7 1.1 pooka * This code was written by Alessandro Forin and Neil Pittman 8 1.1 pooka * at Microsoft Research and contributed to The NetBSD Foundation 9 1.1 pooka * by Microsoft Corporation. 10 1.1 pooka * 11 1.1 pooka * Redistribution and use in source and binary forms, with or without 12 1.1 pooka * modification, are permitted provided that the following conditions 13 1.1 pooka * are met: 14 1.1 pooka * 1. Redistributions of source code must retain the above copyright 15 1.1 pooka * notice, this list of conditions and the following disclaimer. 16 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 pooka * notice, this list of conditions and the following disclaimer in the 18 1.1 pooka * documentation and/or other materials provided with the distribution. 19 1.1 pooka * 20 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 pooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 pooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 pooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 pooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 pooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 pooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 pooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 pooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 pooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 pooka * POSSIBILITY OF SUCH DAMAGE. 31 1.1 pooka */ 32 1.1 pooka 33 1.1 pooka #include <sys/cdefs.h> 34 1.10 msaitoh __KERNEL_RCSID(0, "$NetBSD: dz_ebus.c,v 1.10 2019/12/27 06:52:43 msaitoh Exp $"); 35 1.1 pooka 36 1.1 pooka #include "opt_ddb.h" 37 1.1 pooka 38 1.1 pooka #include <sys/param.h> 39 1.1 pooka #include <sys/systm.h> 40 1.1 pooka #include <sys/callout.h> 41 1.1 pooka #include <sys/ioctl.h> 42 1.1 pooka #include <sys/tty.h> 43 1.1 pooka #include <sys/proc.h> 44 1.1 pooka #include <sys/buf.h> 45 1.1 pooka #include <sys/conf.h> 46 1.1 pooka #include <sys/file.h> 47 1.1 pooka #include <sys/uio.h> 48 1.1 pooka #include <sys/kernel.h> 49 1.1 pooka #include <sys/syslog.h> 50 1.1 pooka #include <sys/device.h> 51 1.1 pooka #include <sys/kauth.h> 52 1.1 pooka 53 1.1 pooka #include <machine/bus.h> 54 1.1 pooka #include <machine/emipsreg.h> 55 1.1 pooka 56 1.1 pooka #include <dev/cons.h> 57 1.1 pooka 58 1.1 pooka 59 1.1 pooka #include <emips/ebus/ebusvar.h> 60 1.1 pooka #include <emips/emips/cons.h> 61 1.3 tsutsui #if 0 62 1.3 tsutsui #include <emips/emips/machdep.h> 63 1.3 tsutsui #endif 64 1.1 pooka 65 1.1 pooka #include "ioconf.h" /* for dz_cd */ 66 1.1 pooka 67 1.3 tsutsui #define DZ_C2I(c) ((c) << 3) /* convert controller # to index */ 68 1.3 tsutsui #define DZ_I2C(c) ((c) >> 3) /* convert minor to controller # */ 69 1.3 tsutsui #define DZ_PORT(u) ((u) & 07) /* extract the port # */ 70 1.1 pooka 71 1.1 pooka struct dz_softc { 72 1.4 tsutsui device_t sc_dev; /* Autoconf blaha */ 73 1.10 msaitoh struct evcnt sc_rintrcnt; /* receive interrupt counts */ 74 1.1 pooka struct evcnt sc_tintrcnt; /* transmit interrupt counts */ 75 1.1 pooka struct _Usart *sc_dr; /* reg pointers */ 76 1.1 pooka bus_space_tag_t sc_iot; 77 1.1 pooka bus_space_handle_t sc_ioh; 78 1.1 pooka int sc_consline; /* console line, or -1 */ 79 1.1 pooka int sc_rxint; /* Receive interrupt count XXX */ 80 1.1 pooka u_char sc_brk; /* Break asserted on some lines */ 81 1.1 pooka u_char sc_dsr; /* DSR set bits if no mdm ctrl */ 82 1.1 pooka struct dz_linestate { 83 1.1 pooka struct dz_softc *dz_sc; /* backpointer to softc */ 84 1.1 pooka int dz_line; /* channel number */ 85 1.3 tsutsui struct tty *dz_tty; /* what we work on */ 86 1.1 pooka } sc_dz; 87 1.1 pooka }; 88 1.1 pooka 89 1.1 pooka void dzrint(struct dz_softc *, uint32_t); 90 1.1 pooka void dzxint(struct dz_softc *, uint32_t); 91 1.1 pooka 92 1.1 pooka #ifndef TIOCM_BRK 93 1.1 pooka #define TIOCM_BRK 0100000 /* no equivalent */ 94 1.1 pooka 95 1.1 pooka static void dzstart(struct tty *); 96 1.1 pooka static int dzparam(struct tty *, struct termios *); 97 1.1 pooka static unsigned dzmctl(struct dz_softc *sc, int line, 98 1.1 pooka int bits, /* one of the TIOCM_xx */ 99 1.1 pooka int how); /* one of the DMSET/BIS.. */ 100 1.1 pooka 101 1.1 pooka #include <dev/dec/dzkbdvar.h> 102 1.1 pooka #endif 103 1.1 pooka 104 1.1 pooka dev_type_open(dzopen); 105 1.1 pooka dev_type_close(dzclose); 106 1.1 pooka dev_type_read(dzread); 107 1.1 pooka dev_type_write(dzwrite); 108 1.1 pooka dev_type_ioctl(dzioctl); 109 1.1 pooka dev_type_stop(dzstop); 110 1.1 pooka dev_type_tty(dztty); 111 1.1 pooka dev_type_poll(dzpoll); 112 1.1 pooka 113 1.1 pooka const struct cdevsw dz_cdevsw = { 114 1.7 dholland .d_open = dzopen, 115 1.7 dholland .d_close = dzclose, 116 1.7 dholland .d_read = dzread, 117 1.7 dholland .d_write = dzwrite, 118 1.7 dholland .d_ioctl = dzioctl, 119 1.7 dholland .d_stop = dzstop, 120 1.7 dholland .d_tty = dztty, 121 1.7 dholland .d_poll = dzpoll, 122 1.7 dholland .d_mmap = nommap, 123 1.7 dholland .d_kqfilter = ttykqfilter, 124 1.8 dholland .d_discard = nodiscard, 125 1.7 dholland .d_flag = D_TTY 126 1.1 pooka }; 127 1.1 pooka 128 1.1 pooka int 129 1.1 pooka dzopen(dev_t dev, int flag, int mode, struct lwp *l) 130 1.1 pooka { 131 1.1 pooka struct tty *tp; 132 1.1 pooka int unit, line; 133 1.3 tsutsui struct dz_softc *sc; 134 1.1 pooka int s, error = 0; 135 1.1 pooka 136 1.1 pooka unit = DZ_I2C(minor(dev)); 137 1.4 tsutsui sc = device_lookup_private(&dz_cd, unit); 138 1.4 tsutsui if (sc == NULL) 139 1.4 tsutsui return ENXIO; 140 1.4 tsutsui 141 1.1 pooka line = DZ_PORT(minor(dev)); 142 1.5 tsutsui if (line > 0) /* FIXME for more than one line */ 143 1.1 pooka return ENXIO; 144 1.1 pooka 145 1.1 pooka tp = sc->sc_dz.dz_tty; 146 1.1 pooka if (tp == NULL) 147 1.3 tsutsui return ENODEV; 148 1.3 tsutsui tp->t_oproc = dzstart; 149 1.3 tsutsui tp->t_param = dzparam; 150 1.3 tsutsui tp->t_dev = dev; 151 1.1 pooka 152 1.1 pooka if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 153 1.1 pooka return (EBUSY); 154 1.1 pooka 155 1.1 pooka if ((tp->t_state & TS_ISOPEN) == 0) { 156 1.1 pooka ttychars(tp); 157 1.1 pooka if (tp->t_ispeed == 0) { 158 1.1 pooka tp->t_iflag = TTYDEF_IFLAG; 159 1.1 pooka tp->t_oflag = TTYDEF_OFLAG; 160 1.1 pooka tp->t_cflag = TTYDEF_CFLAG; 161 1.1 pooka tp->t_lflag = TTYDEF_LFLAG; 162 1.1 pooka tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 163 1.1 pooka } 164 1.3 tsutsui (void)dzparam(tp, &tp->t_termios); 165 1.1 pooka ttsetwater(tp); 166 1.1 pooka } 167 1.3 tsutsui /* we have no modem control but..*/ 168 1.1 pooka if (dzmctl(sc, line, TIOCM_DTR, DMBIS) & TIOCM_CD) 169 1.3 tsutsui tp->t_state |= TS_CARR_ON; 170 1.9 mrg s = spltty(); 171 1.9 mrg while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) && 172 1.9 mrg !(tp->t_state & TS_CARR_ON)) { 173 1.9 mrg tp->t_wopen++; 174 1.9 mrg error = ttysleep(tp, &tp->t_rawcv, true, 0); 175 1.9 mrg tp->t_wopen--; 176 1.9 mrg if (error) 177 1.9 mrg break; 178 1.9 mrg } 179 1.3 tsutsui (void)splx(s); 180 1.1 pooka if (error) 181 1.3 tsutsui return error; 182 1.3 tsutsui return (*tp->t_linesw->l_open)(dev, tp); 183 1.1 pooka } 184 1.3 tsutsui 185 1.1 pooka int 186 1.1 pooka dzclose(dev_t dev, int flag, int mode, struct lwp *l) 187 1.1 pooka { 188 1.3 tsutsui struct dz_softc *sc; 189 1.1 pooka struct tty *tp; 190 1.1 pooka int unit, line; 191 1.1 pooka 192 1.1 pooka unit = DZ_I2C(minor(dev)); 193 1.4 tsutsui sc = device_lookup_private(&dz_cd, unit); 194 1.1 pooka line = DZ_PORT(minor(dev)); 195 1.1 pooka 196 1.1 pooka tp = sc->sc_dz.dz_tty; 197 1.1 pooka 198 1.1 pooka (*tp->t_linesw->l_close)(tp, flag); 199 1.1 pooka 200 1.1 pooka /* Make sure a BREAK state is not left enabled. */ 201 1.3 tsutsui (void)dzmctl(sc, line, TIOCM_BRK, DMBIC); 202 1.1 pooka 203 1.1 pooka /* Do a hangup if so required. */ 204 1.1 pooka if ((tp->t_cflag & HUPCL) || tp->t_wopen || !(tp->t_state & TS_ISOPEN)) 205 1.5 tsutsui (void)dzmctl(sc, line, 0, DMSET); 206 1.1 pooka 207 1.3 tsutsui return ttyclose(tp); 208 1.1 pooka } 209 1.3 tsutsui 210 1.1 pooka int 211 1.1 pooka dzread(dev_t dev, struct uio *uio, int flag) 212 1.1 pooka { 213 1.1 pooka struct tty *tp; 214 1.3 tsutsui struct dz_softc *sc; 215 1.1 pooka 216 1.4 tsutsui sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev))); 217 1.1 pooka 218 1.1 pooka tp = sc->sc_dz.dz_tty; 219 1.3 tsutsui return (*tp->t_linesw->l_read)(tp, uio, flag); 220 1.1 pooka } 221 1.1 pooka 222 1.1 pooka int 223 1.1 pooka dzwrite(dev_t dev, struct uio *uio, int flag) 224 1.1 pooka { 225 1.1 pooka struct tty *tp; 226 1.3 tsutsui struct dz_softc *sc; 227 1.1 pooka 228 1.4 tsutsui sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev))); 229 1.1 pooka 230 1.1 pooka tp = sc->sc_dz.dz_tty; 231 1.3 tsutsui return (*tp->t_linesw->l_write)(tp, uio, flag); 232 1.1 pooka } 233 1.1 pooka 234 1.1 pooka /*ARGSUSED*/ 235 1.1 pooka int 236 1.1 pooka dzioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 237 1.1 pooka { 238 1.1 pooka struct dz_softc *sc; 239 1.1 pooka struct tty *tp; 240 1.1 pooka int unit, line; 241 1.1 pooka int error; 242 1.1 pooka 243 1.1 pooka unit = DZ_I2C(minor(dev)); 244 1.1 pooka line = 0; 245 1.4 tsutsui sc = device_lookup_private(&dz_cd, unit); 246 1.1 pooka tp = sc->sc_dz.dz_tty; 247 1.1 pooka 248 1.1 pooka error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 249 1.1 pooka if (error >= 0) 250 1.3 tsutsui return error; 251 1.1 pooka 252 1.1 pooka error = ttioctl(tp, cmd, data, flag, l); 253 1.1 pooka if (error >= 0) 254 1.3 tsutsui return error; 255 1.1 pooka 256 1.1 pooka switch (cmd) { 257 1.1 pooka 258 1.1 pooka case TIOCSBRK: 259 1.3 tsutsui (void)dzmctl(sc, line, TIOCM_BRK, DMBIS); 260 1.1 pooka break; 261 1.1 pooka 262 1.1 pooka case TIOCCBRK: 263 1.3 tsutsui (void)dzmctl(sc, line, TIOCM_BRK, DMBIC); 264 1.1 pooka break; 265 1.1 pooka 266 1.1 pooka case TIOCSDTR: 267 1.3 tsutsui (void)dzmctl(sc, line, TIOCM_DTR, DMBIS); 268 1.1 pooka break; 269 1.1 pooka 270 1.1 pooka case TIOCCDTR: 271 1.3 tsutsui (void)dzmctl(sc, line, TIOCM_DTR, DMBIC); 272 1.1 pooka break; 273 1.1 pooka 274 1.1 pooka case TIOCMSET: 275 1.3 tsutsui (void)dzmctl(sc, line, *(int *)data, DMSET); 276 1.1 pooka break; 277 1.1 pooka 278 1.1 pooka case TIOCMBIS: 279 1.3 tsutsui (void)dzmctl(sc, line, *(int *)data, DMBIS); 280 1.1 pooka break; 281 1.1 pooka 282 1.1 pooka case TIOCMBIC: 283 1.3 tsutsui (void)dzmctl(sc, line, *(int *)data, DMBIC); 284 1.1 pooka break; 285 1.1 pooka 286 1.1 pooka case TIOCMGET: 287 1.3 tsutsui *(int *)data = dzmctl(sc, line, 0, DMGET) & ~TIOCM_BRK; 288 1.1 pooka break; 289 1.1 pooka 290 1.1 pooka default: 291 1.3 tsutsui return EPASSTHROUGH; 292 1.1 pooka } 293 1.3 tsutsui return 0; 294 1.1 pooka } 295 1.1 pooka 296 1.1 pooka /*ARGSUSED*/ 297 1.1 pooka void 298 1.1 pooka dzstop(struct tty *tp, int flag) 299 1.1 pooka { 300 1.3 tsutsui 301 1.1 pooka if (tp->t_state & TS_BUSY) 302 1.1 pooka if (!(tp->t_state & TS_TTSTOP)) 303 1.1 pooka tp->t_state |= TS_FLUSH; 304 1.1 pooka } 305 1.1 pooka 306 1.1 pooka struct tty * 307 1.1 pooka dztty(dev_t dev) 308 1.1 pooka { 309 1.4 tsutsui struct dz_softc *sc; 310 1.4 tsutsui struct tty *tp; 311 1.4 tsutsui 312 1.4 tsutsui sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev))); 313 1.4 tsutsui tp = sc->sc_dz.dz_tty; 314 1.1 pooka 315 1.3 tsutsui return tp; 316 1.1 pooka } 317 1.1 pooka 318 1.1 pooka int 319 1.3 tsutsui dzpoll(dev_t dev, int events, struct lwp *l) 320 1.1 pooka { 321 1.3 tsutsui struct dz_softc *sc; 322 1.1 pooka struct tty *tp; 323 1.1 pooka 324 1.4 tsutsui sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev))); 325 1.1 pooka 326 1.1 pooka tp = sc->sc_dz.dz_tty; 327 1.3 tsutsui return (*tp->t_linesw->l_poll)(tp, events, l); 328 1.1 pooka } 329 1.1 pooka 330 1.1 pooka void 331 1.1 pooka dzstart(struct tty *tp) 332 1.1 pooka { 333 1.1 pooka struct dz_softc *sc; 334 1.1 pooka struct clist *cl; 335 1.1 pooka int unit, s; 336 1.1 pooka 337 1.1 pooka unit = DZ_I2C(minor(tp->t_dev)); 338 1.4 tsutsui sc = device_lookup_private(&dz_cd, unit); 339 1.1 pooka 340 1.1 pooka s = spltty(); 341 1.1 pooka if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) { 342 1.1 pooka splx(s); 343 1.1 pooka return; 344 1.1 pooka } 345 1.1 pooka cl = &tp->t_outq; 346 1.1 pooka ttypull(tp); 347 1.1 pooka if (cl->c_cc == 0) { 348 1.1 pooka splx(s); 349 1.1 pooka return; 350 1.1 pooka } 351 1.1 pooka 352 1.1 pooka tp->t_state |= TS_BUSY; 353 1.1 pooka 354 1.3 tsutsui /* was idle, get it started */ 355 1.1 pooka dzxint(sc,USI_TXRDY); 356 1.1 pooka splx(s); 357 1.1 pooka } 358 1.1 pooka 359 1.1 pooka static int rclk = 25000000; /* BUGBUGBUGBUG */ 360 1.1 pooka 361 1.1 pooka static int 362 1.1 pooka dzdivisor(int baudrate) 363 1.1 pooka { 364 1.1 pooka int act_baud, divisor, error; 365 1.1 pooka 366 1.1 pooka if (baudrate <= 0) 367 1.3 tsutsui return 0; 368 1.1 pooka 369 1.3 tsutsui divisor = (rclk / 8) / (baudrate); 370 1.3 tsutsui divisor = (divisor / 2) + (divisor & 1); 371 1.1 pooka 372 1.1 pooka if (divisor <= 0) 373 1.3 tsutsui return -1; 374 1.1 pooka act_baud = rclk / (divisor * 16); 375 1.1 pooka 376 1.1 pooka /* 10 times error in percent: */ 377 1.1 pooka error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1; 378 1.1 pooka 379 1.1 pooka /* 3.0% maximum error tolerance: */ 380 1.1 pooka if (error < -30 || error > 30) 381 1.3 tsutsui return -1; 382 1.1 pooka 383 1.3 tsutsui return divisor; 384 1.1 pooka } 385 1.1 pooka 386 1.1 pooka static int 387 1.1 pooka dzparam(struct tty *tp, struct termios *t) 388 1.1 pooka { 389 1.1 pooka struct dz_softc *sc; 390 1.1 pooka int cflag = t->c_cflag; 391 1.1 pooka int unit, line; 392 1.1 pooka int speed; 393 1.1 pooka unsigned lpr; 394 1.1 pooka int s; 395 1.1 pooka struct _Usart *dzr; 396 1.1 pooka 397 1.1 pooka unit = DZ_I2C(minor(tp->t_dev)); 398 1.1 pooka line = DZ_PORT(minor(tp->t_dev)); 399 1.4 tsutsui sc = device_lookup_private(&dz_cd, unit); 400 1.1 pooka 401 1.1 pooka /* check requested parameters */ 402 1.3 tsutsui if (t->c_ispeed != t->c_ospeed) 403 1.3 tsutsui return EINVAL; 404 1.3 tsutsui speed = dzdivisor(t->c_ispeed); 405 1.3 tsutsui if (speed < 0) 406 1.3 tsutsui return EINVAL; 407 1.3 tsutsui 408 1.3 tsutsui tp->t_ispeed = t->c_ispeed; 409 1.3 tsutsui tp->t_ospeed = t->c_ospeed; 410 1.3 tsutsui tp->t_cflag = cflag; 411 1.3 tsutsui 412 1.3 tsutsui { 413 1.3 tsutsui /* XXX */ 414 1.3 tsutsui static int didit = 0; 415 1.3 tsutsui if (!didit && t->c_ispeed != 38400) 416 1.3 tsutsui printf("dzparam: c_ispeed %d ignored, keeping 38400\n", 417 1.3 tsutsui t->c_ispeed); 418 1.3 tsutsui didit = 1; 419 1.3 tsutsui } 420 1.3 tsutsui speed = dzdivisor(38400); 421 1.1 pooka 422 1.1 pooka if (speed == 0) { 423 1.3 tsutsui (void)dzmctl(sc, line, 0, DMSET); /* hang up line */ 424 1.3 tsutsui return 0; 425 1.1 pooka } 426 1.1 pooka 427 1.3 tsutsui switch (cflag & CSIZE) { 428 1.3 tsutsui case CS5: 429 1.1 pooka lpr = USC_BPC_5; 430 1.1 pooka break; 431 1.3 tsutsui case CS6: 432 1.1 pooka lpr = USC_BPC_6; 433 1.1 pooka break; 434 1.3 tsutsui case CS7: 435 1.1 pooka lpr = USC_BPC_7; 436 1.1 pooka break; 437 1.3 tsutsui default: 438 1.1 pooka lpr = USC_BPC_8; 439 1.1 pooka break; 440 1.1 pooka } 441 1.1 pooka if (cflag & CSTOPB) 442 1.1 pooka lpr |= USC_2STOP; 443 1.1 pooka 444 1.1 pooka if (cflag & PARENB) { 445 1.3 tsutsui if (cflag & PARODD) 446 1.3 tsutsui lpr |= USC_ODD; 447 1.3 tsutsui else 448 1.3 tsutsui lpr |= USC_EVEN; 449 1.3 tsutsui } else 450 1.3 tsutsui lpr |= USC_NONE; 451 1.1 pooka 452 1.1 pooka s = spltty(); 453 1.1 pooka 454 1.1 pooka dzr = sc->sc_dr; 455 1.1 pooka 456 1.3 tsutsui dzr->Baud = speed; 457 1.3 tsutsui dzr->Control = USC_CLKDIV_4 | USC_TXEN | USC_RXEN | lpr; 458 1.1 pooka #define USI_INTRS (USI_RXRDY|USI_RXBRK|USI_OVRE|USI_FRAME|USI_PARE) 459 1.3 tsutsui dzr->IntrEnable = USI_INTRS; 460 1.1 pooka 461 1.3 tsutsui (void)splx(s); 462 1.3 tsutsui return 0; 463 1.1 pooka } 464 1.1 pooka 465 1.1 pooka static unsigned 466 1.1 pooka dzmctl(struct dz_softc *sc, int line, int bits, int how) 467 1.1 pooka { 468 1.3 tsutsui unsigned int mbits; 469 1.1 pooka int s; 470 1.1 pooka struct _Usart *dzr; 471 1.1 pooka 472 1.1 pooka mbits = 0; 473 1.1 pooka 474 1.1 pooka s = spltty(); 475 1.1 pooka 476 1.1 pooka dzr = sc->sc_dr; 477 1.1 pooka 478 1.3 tsutsui /* we have no modem control bits (CD,RI,DTR,DSR,..) */ 479 1.3 tsutsui mbits |= TIOCM_CD; 480 1.3 tsutsui mbits |= TIOCM_DTR; 481 1.1 pooka 482 1.1 pooka if (dzr->ChannelStatus & USI_RXBRK) 483 1.1 pooka mbits |= TIOCM_BRK; 484 1.1 pooka 485 1.3 tsutsui switch (how) { 486 1.3 tsutsui case DMSET: 487 1.1 pooka mbits = bits; 488 1.1 pooka break; 489 1.1 pooka 490 1.3 tsutsui case DMBIS: 491 1.1 pooka mbits |= bits; 492 1.1 pooka break; 493 1.1 pooka 494 1.3 tsutsui case DMBIC: 495 1.1 pooka mbits &= ~bits; 496 1.1 pooka break; 497 1.1 pooka 498 1.3 tsutsui case DMGET: 499 1.3 tsutsui (void)splx(s); 500 1.3 tsutsui return mbits; 501 1.1 pooka } 502 1.1 pooka 503 1.3 tsutsui /* BUGBUG work in progress */ 504 1.1 pooka if (mbits & TIOCM_BRK) { 505 1.1 pooka sc->sc_brk |= (1 << line); 506 1.3 tsutsui dzr->Control |= USC_STTBRK; 507 1.1 pooka } else { 508 1.1 pooka sc->sc_brk &= ~(1 << line); 509 1.3 tsutsui dzr->Control |= USC_STPBRK; 510 1.1 pooka } 511 1.1 pooka 512 1.3 tsutsui (void)splx(s); 513 1.3 tsutsui return mbits; 514 1.1 pooka } 515 1.1 pooka 516 1.1 pooka 517 1.1 pooka #if defined(DDB) 518 1.1 pooka int dz_ddb = 0; 519 1.1 pooka #endif 520 1.1 pooka 521 1.1 pooka /* Receiver Interrupt */ 522 1.1 pooka 523 1.1 pooka void 524 1.1 pooka dzrint(struct dz_softc *sc, uint32_t csr) 525 1.1 pooka { 526 1.1 pooka struct tty *tp; 527 1.6 christos int cc; 528 1.1 pooka struct _Usart *dzr; 529 1.1 pooka 530 1.1 pooka sc->sc_rxint++; 531 1.1 pooka dzr = sc->sc_dr; 532 1.1 pooka 533 1.3 tsutsui cc = dzr->RxData; 534 1.3 tsutsui tp = sc->sc_dz.dz_tty; 535 1.3 tsutsui 536 1.3 tsutsui /* clear errors before we print or bail out */ 537 1.3 tsutsui if (csr & (USI_OVRE|USI_FRAME|USI_PARE)) 538 1.3 tsutsui dzr->Control = USC_RSTSTA; 539 1.3 tsutsui 540 1.3 tsutsui if (!(tp->t_state & TS_ISOPEN)) { 541 1.3 tsutsui wakeup(&tp->t_rawq); 542 1.3 tsutsui return; 543 1.3 tsutsui } 544 1.3 tsutsui 545 1.3 tsutsui if (csr & USI_OVRE) { 546 1.3 tsutsui log(LOG_WARNING, "%s: silo overflow, line %d\n", 547 1.4 tsutsui device_xname(sc->sc_dev), 0); 548 1.3 tsutsui } 549 1.1 pooka 550 1.3 tsutsui if (csr & USI_FRAME) 551 1.3 tsutsui cc |= TTY_FE; 552 1.3 tsutsui if (csr & USI_PARE) 553 1.3 tsutsui cc |= TTY_PE; 554 1.1 pooka 555 1.1 pooka #if defined(DDB) 556 1.3 tsutsui /* ^P drops into DDB */ 557 1.3 tsutsui if (dz_ddb && (cc == 0x10)) 558 1.3 tsutsui Debugger(); 559 1.1 pooka #endif 560 1.3 tsutsui (*tp->t_linesw->l_rint)(cc, tp); 561 1.1 pooka } 562 1.1 pooka 563 1.1 pooka /* Transmitter Interrupt */ 564 1.1 pooka 565 1.1 pooka void 566 1.1 pooka dzxint(struct dz_softc *sc, uint32_t csr) 567 1.1 pooka { 568 1.1 pooka struct tty *tp; 569 1.1 pooka struct clist *cl; 570 1.1 pooka int ch; 571 1.1 pooka struct _Usart *dzr; 572 1.1 pooka 573 1.1 pooka dzr = sc->sc_dr; 574 1.1 pooka 575 1.3 tsutsui tp = sc->sc_dz.dz_tty; 576 1.3 tsutsui cl = &tp->t_outq; 577 1.3 tsutsui tp->t_state &= ~TS_BUSY; 578 1.3 tsutsui 579 1.3 tsutsui /* Just send out a char if we have one */ 580 1.3 tsutsui if (cl->c_cc) { 581 1.3 tsutsui tp->t_state |= TS_BUSY; 582 1.3 tsutsui ch = getc(cl); 583 1.3 tsutsui dzr->TxData = ch; 584 1.3 tsutsui dzr->IntrEnable = USI_TXRDY; 585 1.3 tsutsui return; 586 1.3 tsutsui } 587 1.3 tsutsui 588 1.3 tsutsui /* Nothing to send; turn off intr */ 589 1.3 tsutsui dzr->IntrDisable = USI_TXRDY; 590 1.3 tsutsui 591 1.3 tsutsui if (tp->t_state & TS_FLUSH) 592 1.3 tsutsui tp->t_state &= ~TS_FLUSH; 593 1.3 tsutsui else 594 1.3 tsutsui ndflush(&tp->t_outq, cl->c_cc); 595 1.3 tsutsui 596 1.3 tsutsui (*tp->t_linesw->l_start)(tp); 597 1.3 tsutsui } 598 1.3 tsutsui 599 1.3 tsutsui /* 600 1.3 tsutsui * Machdep part of the driver 601 1.3 tsutsui */ 602 1.3 tsutsui int dz_ebus_match(device_t, cfdata_t, void *); 603 1.3 tsutsui void dz_ebus_attach(device_t, device_t, void *); 604 1.1 pooka int dz_ebus_intr(void *, void *); 605 1.1 pooka 606 1.1 pooka void dz_ebus_cnsetup(paddr_t); 607 1.3 tsutsui void dz_ebus_cninit(struct consdev *); 608 1.1 pooka int dz_ebus_cngetc(dev_t); 609 1.1 pooka void dz_ebus_cnputc(dev_t, int); 610 1.1 pooka void dz_ebus_cnpollc(dev_t, int); 611 1.1 pooka 612 1.1 pooka static int dz_ebus_getmajor(void); 613 1.1 pooka 614 1.4 tsutsui CFATTACH_DECL_NEW(dz_ebus, sizeof(struct dz_softc), 615 1.1 pooka dz_ebus_match, dz_ebus_attach, NULL, NULL); 616 1.1 pooka 617 1.1 pooka struct consdev dz_ebus_consdev = { 618 1.1 pooka NULL, dz_ebus_cninit, dz_ebus_cngetc, dz_ebus_cnputc, 619 1.1 pooka dz_ebus_cnpollc, NULL, NULL, NULL, NODEV, CN_NORMAL, 620 1.1 pooka }; 621 1.1 pooka 622 1.3 tsutsui /* 623 1.3 tsutsui * Points to the console regs. Special mapping until VM is turned on. 624 1.1 pooka */ 625 1.1 pooka struct _Usart *dzcn; 626 1.1 pooka 627 1.1 pooka int 628 1.3 tsutsui dz_ebus_match(device_t parent, cfdata_t cf, void *aux) 629 1.1 pooka { 630 1.1 pooka struct ebus_attach_args *iba; 631 1.3 tsutsui struct _Usart *us; 632 1.1 pooka 633 1.1 pooka iba = aux; 634 1.1 pooka 635 1.1 pooka if (strcmp(iba->ia_name, "dz") != 0) 636 1.3 tsutsui return 0; 637 1.1 pooka 638 1.3 tsutsui us = (struct _Usart *)iba->ia_vaddr; 639 1.3 tsutsui if ((us == NULL) || 640 1.3 tsutsui (us->Tag != PMTTAG_USART)) 641 1.3 tsutsui return 0; 642 1.1 pooka 643 1.3 tsutsui return 1; 644 1.1 pooka } 645 1.1 pooka 646 1.1 pooka void 647 1.3 tsutsui dz_ebus_attach(device_t parent, device_t self, void *aux) 648 1.1 pooka { 649 1.1 pooka struct ebus_attach_args *iba; 650 1.1 pooka struct dz_softc *sc; 651 1.1 pooka 652 1.4 tsutsui sc = device_private(self); 653 1.1 pooka iba = aux; 654 1.1 pooka 655 1.4 tsutsui sc->sc_dev = self; 656 1.1 pooka sc->sc_dr = (struct _Usart *)iba->ia_vaddr; 657 1.1 pooka #if DEBUG 658 1.3 tsutsui printf(" virt=%p ", (void *)sc->sc_dr); 659 1.1 pooka #endif 660 1.1 pooka 661 1.1 pooka printf(": neilsart 1 line"); 662 1.1 pooka ebus_intr_establish(parent, (void *)iba->ia_cookie, IPL_TTY, 663 1.1 pooka dz_ebus_intr, sc); 664 1.1 pooka 665 1.1 pooka sc->sc_rxint = sc->sc_brk = 0; 666 1.1 pooka sc->sc_consline = 0; 667 1.1 pooka 668 1.1 pooka /* Initialize our softc structure. Should be done in open? */ 669 1.1 pooka 670 1.2 rmind sc->sc_dz.dz_sc = sc; 671 1.2 rmind sc->sc_dz.dz_line = 0; 672 1.2 rmind sc->sc_dz.dz_tty = tty_alloc(); 673 1.1 pooka 674 1.1 pooka evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, NULL, 675 1.4 tsutsui device_xname(self), "rintr"); 676 1.1 pooka evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, NULL, 677 1.4 tsutsui device_xname(self), "tintr"); 678 1.1 pooka 679 1.3 tsutsui /* Initialize hw regs */ 680 1.1 pooka #if 0 681 1.1 pooka DZ_WRITE_WORD(dr_csr, DZ_CSR_MSE | DZ_CSR_RXIE | DZ_CSR_TXIE); 682 1.1 pooka DZ_WRITE_BYTE(dr_dtr, 0); 683 1.1 pooka DZ_WRITE_BYTE(dr_break, 0); 684 1.1 pooka #endif 685 1.1 pooka 686 1.3 tsutsui /* Switch the console to virtual mode */ 687 1.3 tsutsui dzcn = sc->sc_dr; 688 1.3 tsutsui /* And test it */ 689 1.1 pooka printf("\n"); 690 1.1 pooka } 691 1.1 pooka 692 1.1 pooka static int 693 1.1 pooka dz_ebus_getmajor(void) 694 1.1 pooka { 695 1.1 pooka extern const struct cdevsw dz_cdevsw; 696 1.1 pooka static int cache = -1; 697 1.1 pooka 698 1.1 pooka if (cache != -1) 699 1.3 tsutsui return cache; 700 1.1 pooka 701 1.3 tsutsui return cache = cdevsw_lookup_major(&dz_cdevsw); 702 1.1 pooka } 703 1.1 pooka 704 1.1 pooka int 705 1.1 pooka dz_ebus_intr(void *cookie, void *f) 706 1.1 pooka { 707 1.1 pooka struct dz_softc *sc; 708 1.1 pooka struct _Usart *dzr; 709 1.1 pooka uint32_t csr; 710 1.1 pooka 711 1.1 pooka sc = cookie; 712 1.1 pooka dzr = sc->sc_dr; 713 1.1 pooka 714 1.1 pooka #define USI_INTERRUPTS (USI_INTRS|USI_TXRDY) 715 1.1 pooka 716 1.3 tsutsui for (; ((csr = (dzr->ChannelStatus & dzr->IntrMask)) & 717 1.3 tsutsui USI_INTERRUPTS) != 0;) { 718 1.1 pooka if ((csr & USI_INTRS) != 0) 719 1.1 pooka dzrint(sc, csr); 720 1.1 pooka if ((csr & USI_TXRDY) != 0) 721 1.1 pooka dzxint(sc, csr); 722 1.1 pooka } 723 1.1 pooka 724 1.3 tsutsui return 0; 725 1.1 pooka } 726 1.1 pooka 727 1.1 pooka void 728 1.1 pooka dz_ebus_cnsetup(paddr_t addr) 729 1.1 pooka { 730 1.1 pooka 731 1.1 pooka dzcn = (struct _Usart *)addr; 732 1.1 pooka 733 1.1 pooka #if 0 734 1.3 tsutsui /* 735 1.3 tsutsui * Initialize enough to xmit/recv via polling. 736 1.3 tsutsui * Bootloader might or might not have done it. 737 1.3 tsutsui */ 738 1.3 tsutsui dzcn->Control = 739 1.3 tsutsui USC_RXEN | 740 1.3 tsutsui USC_TXEN | 741 1.3 tsutsui USC_BPC_8 | 742 1.3 tsutsui USC_NONE | 743 1.3 tsutsui USC_1STOP | 744 1.3 tsutsui USC_CLKDIV_4; 745 1.3 tsutsui dzcn->Baud = 0x29; /* 38400 */ 746 1.1 pooka #endif 747 1.1 pooka 748 1.1 pooka /* 749 1.1 pooka * Point the console at us 750 1.1 pooka */ 751 1.1 pooka cn_tab = &dz_ebus_consdev; 752 1.1 pooka cn_tab->cn_pri = CN_NORMAL;/*CN_REMOTE?*/ 753 1.1 pooka cn_tab->cn_dev = makedev(dz_ebus_getmajor(), 0); 754 1.1 pooka } 755 1.1 pooka 756 1.3 tsutsui void 757 1.3 tsutsui dz_ebus_cninit(struct consdev *cn) 758 1.1 pooka { 759 1.1 pooka } 760 1.1 pooka 761 1.1 pooka int 762 1.1 pooka dz_ebus_cngetc(dev_t dev) 763 1.1 pooka { 764 1.1 pooka int c, s; 765 1.1 pooka 766 1.1 pooka c = 0; 767 1.1 pooka s = spltty(); 768 1.1 pooka 769 1.3 tsutsui while ((dzcn->ChannelStatus & USI_RXRDY) == 0) 770 1.3 tsutsui DELAY(10); 771 1.3 tsutsui c = dzcn->RxData; 772 1.1 pooka 773 1.1 pooka splx(s); 774 1.1 pooka if (c == 13) /* map cr->ln */ 775 1.1 pooka c = 10; 776 1.3 tsutsui return c; 777 1.1 pooka } 778 1.1 pooka 779 1.1 pooka int dzflipped = 0; 780 1.1 pooka void 781 1.1 pooka dz_ebus_cnputc(dev_t dev, int ch) 782 1.1 pooka { 783 1.1 pooka int timeout, s; 784 1.1 pooka 785 1.1 pooka /* Don't hang the machine! */ 786 1.1 pooka timeout = 1 << 15; 787 1.1 pooka 788 1.1 pooka s = spltty(); 789 1.1 pooka 790 1.1 pooka #if 1 791 1.3 tsutsui /* Keep wired to hunt for a bug */ 792 1.3 tsutsui if (dzcn && (dzcn != (struct _Usart *)0xfff90000)) { 793 1.3 tsutsui dzcn = (struct _Usart *)0xfff90000; 794 1.3 tsutsui dzflipped++; 795 1.3 tsutsui } 796 1.1 pooka #endif 797 1.1 pooka 798 1.1 pooka /* Wait until ready */ 799 1.1 pooka while ((dzcn->ChannelStatus & USI_TXRDY) == 0) 800 1.1 pooka if (--timeout < 0) 801 1.1 pooka break; 802 1.1 pooka 803 1.1 pooka /* Put the character */ 804 1.1 pooka dzcn->TxData = ch; 805 1.1 pooka 806 1.1 pooka splx(s); 807 1.1 pooka } 808 1.1 pooka 809 1.3 tsutsui /* 810 1.3 tsutsui * Called before/after going into poll mode 811 1.1 pooka */ 812 1.3 tsutsui void 813 1.1 pooka dz_ebus_cnpollc(dev_t dev, int on) 814 1.1 pooka { 815 1.1 pooka } 816