Annotation of sys/arch/sparc/dev/spif.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: spif.c,v 1.20 2006/06/02 20:00:54 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 26: * POSSIBILITY OF SUCH DAMAGE.
! 27: */
! 28:
! 29: /*
! 30: * Driver for the SUNW,spif: 8 serial, 1 parallel sbus board
! 31: * based heavily on Iain Hibbert's driver for the MAGMA cards
! 32: */
! 33:
! 34: #include <sys/param.h>
! 35: #include <sys/systm.h>
! 36: #include <sys/proc.h>
! 37: #include <sys/device.h>
! 38: #include <sys/kernel.h>
! 39: #include <sys/file.h>
! 40: #include <sys/errno.h>
! 41: #include <sys/ioctl.h>
! 42: #include <sys/mbuf.h>
! 43: #include <sys/socket.h>
! 44: #include <sys/syslog.h>
! 45: #include <sys/malloc.h>
! 46: #include <sys/tty.h>
! 47: #include <sys/conf.h>
! 48:
! 49: #include <machine/autoconf.h>
! 50: #include <sparc/cpu.h>
! 51: #include <sparc/sparc/cpuvar.h>
! 52: #include <sparc/dev/sbusvar.h>
! 53: #include <sparc/dev/spifreg.h>
! 54: #include <sparc/dev/spifvar.h>
! 55:
! 56: #if IPL_TTY == 1
! 57: # define IE_MSOFT IE_L1
! 58: #elif IPL_TTY == 4
! 59: # define IE_MSOFT IE_L4
! 60: #elif IPL_TTY == 6
! 61: # define IE_MSOFT IE_L6
! 62: #else
! 63: # error "no suitable software interrupt bit"
! 64: #endif
! 65:
! 66: int spifmatch(struct device *, void *, void *);
! 67: void spifattach(struct device *, struct device *, void *);
! 68:
! 69: int sttymatch(struct device *, void *, void *);
! 70: void sttyattach(struct device *, struct device *, void *);
! 71: int sttyopen(dev_t, int, int, struct proc *);
! 72: int sttyclose(dev_t, int, int, struct proc *);
! 73: int sttyread(dev_t, struct uio *, int);
! 74: int sttywrite(dev_t, struct uio *, int);
! 75: int sttyioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 76: int sttystop(struct tty *, int);
! 77:
! 78: int spifstcintr(void *);
! 79: int spifstcintr_mx(struct spif_softc *, int *);
! 80: int spifstcintr_tx(struct spif_softc *, int *);
! 81: int spifstcintr_rx(struct spif_softc *, int *);
! 82: int spifstcintr_rxexception(struct spif_softc *, int *);
! 83: int spifsoftintr(void *);
! 84:
! 85: int stty_param(struct tty *, struct termios *);
! 86: struct tty *sttytty(dev_t);
! 87: int stty_modem_control(struct stty_port *, int, int);
! 88: static __inline void stty_write_ccr(struct stcregs *, u_int8_t);
! 89: int stty_compute_baud(speed_t, int, u_int8_t *, u_int8_t *);
! 90: void stty_start(struct tty *);
! 91:
! 92: int sbppmatch(struct device *, void *, void *);
! 93: void sbppattach(struct device *, struct device *, void *);
! 94: int sbppopen(dev_t, int, int, struct proc *);
! 95: int sbppclose(dev_t, int, int, struct proc *);
! 96: int sbppread(dev_t, struct uio *, int);
! 97: int sbppwrite(dev_t, struct uio *, int);
! 98: int sbpp_rw(dev_t, struct uio *);
! 99: int spifppcintr(void *);
! 100: int sbpppoll(dev_t, int, struct proc *);
! 101: int sbppioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 102:
! 103: struct cfattach spif_ca = {
! 104: sizeof (struct spif_softc), spifmatch, spifattach
! 105: };
! 106:
! 107: struct cfdriver spif_cd = {
! 108: NULL, "spif", DV_DULL
! 109: };
! 110:
! 111: struct cfattach stty_ca = {
! 112: sizeof(struct stty_softc), sttymatch, sttyattach
! 113: };
! 114:
! 115: struct cfdriver stty_cd = {
! 116: NULL, "stty", DV_TTY
! 117: };
! 118:
! 119: struct cfattach sbpp_ca = {
! 120: sizeof(struct sbpp_softc), sbppmatch, sbppattach
! 121: };
! 122:
! 123: struct cfdriver sbpp_cd = {
! 124: NULL, "sbpp", DV_DULL
! 125: };
! 126:
! 127: int
! 128: spifmatch(parent, vcf, aux)
! 129: struct device *parent;
! 130: void *vcf, *aux;
! 131: {
! 132: struct cfdata *cf = vcf;
! 133: struct confargs *ca = aux;
! 134: register struct romaux *ra = &ca->ca_ra;
! 135:
! 136: if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
! 137: strcmp("SUNW,spif", ra->ra_name))
! 138: return (0);
! 139: return (1);
! 140: }
! 141:
! 142: void
! 143: spifattach(parent, self, aux)
! 144: struct device *parent, *self;
! 145: void *aux;
! 146: {
! 147: struct spif_softc *sc = (struct spif_softc *)self;
! 148: struct confargs *ca = aux;
! 149: int stcpri, ppcpri;
! 150:
! 151: if (ca->ca_ra.ra_nintr != 2) {
! 152: printf(": expected 2 interrupts, got %d\n",
! 153: ca->ca_ra.ra_nintr);
! 154: return;
! 155: }
! 156: stcpri = ca->ca_ra.ra_intr[SERIAL_INTR].int_pri;
! 157: ppcpri = ca->ca_ra.ra_intr[PARALLEL_INTR].int_pri;
! 158:
! 159: if (ca->ca_ra.ra_nreg != 1) {
! 160: printf(": expected %d registers, got %d\n",
! 161: 1, ca->ca_ra.ra_nreg);
! 162: return;
! 163: }
! 164: sc->sc_regs = mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len);
! 165:
! 166: sc->sc_node = ca->ca_ra.ra_node;
! 167:
! 168: sc->sc_rev = getpropint(sc->sc_node, "revlev", 0);
! 169:
! 170: sc->sc_osc = getpropint(sc->sc_node, "verosc", 0);
! 171: switch (sc->sc_osc) {
! 172: case SPIF_OSC10:
! 173: sc->sc_osc = 10000000;
! 174: break;
! 175: case SPIF_OSC9:
! 176: default:
! 177: sc->sc_osc = 9830400;
! 178: break;
! 179: }
! 180:
! 181: sc->sc_nser = 8;
! 182: sc->sc_npar = 1;
! 183:
! 184: sc->sc_rev2 = sc->sc_regs->stc.gfrcr;
! 185: sc->sc_regs->stc.gsvr = 0;
! 186:
! 187: stty_write_ccr(&sc->sc_regs->stc,
! 188: CD180_CCR_CMD_RESET | CD180_CCR_RESETALL);
! 189: while (sc->sc_regs->stc.gsvr != 0xff);
! 190: while (sc->sc_regs->stc.gfrcr != sc->sc_rev2);
! 191:
! 192: sc->sc_regs->stc.pprh = CD180_PPRH;
! 193: sc->sc_regs->stc.pprl = CD180_PPRL;
! 194: sc->sc_regs->stc.msmr = SPIF_MSMR;
! 195: sc->sc_regs->stc.tsmr = SPIF_TSMR;
! 196: sc->sc_regs->stc.rsmr = SPIF_RSMR;
! 197: sc->sc_regs->stc.gsvr = 0;
! 198: sc->sc_regs->stc.gscr1 = 0;
! 199: sc->sc_regs->stc.gscr2 = 0;
! 200: sc->sc_regs->stc.gscr3 = 0;
! 201: printf(": rev %x chiprev %x osc %sMHz stcpri %d ppcpri %d softpri %d\n",
! 202: sc->sc_rev, sc->sc_rev2, clockfreq(sc->sc_osc),
! 203: stcpri, ppcpri, IPL_TTY);
! 204:
! 205: (void)config_found(self, sttymatch, NULL);
! 206: (void)config_found(self, sbppmatch, NULL);
! 207:
! 208: sc->sc_ppcih.ih_fun = spifppcintr;
! 209: sc->sc_ppcih.ih_arg = sc;
! 210: intr_establish(ppcpri, &sc->sc_ppcih, -1, self->dv_xname);
! 211:
! 212: sc->sc_stcih.ih_fun = spifstcintr;
! 213: sc->sc_stcih.ih_arg = sc;
! 214: intr_establish(stcpri, &sc->sc_stcih, -1, self->dv_xname);
! 215:
! 216: sc->sc_softih.ih_fun = spifsoftintr;
! 217: sc->sc_softih.ih_arg = sc;
! 218: intr_establish(IPL_TTY, &sc->sc_softih, IPL_TTY, self->dv_xname);
! 219: }
! 220:
! 221: int
! 222: sttymatch(parent, vcf, aux)
! 223: struct device *parent;
! 224: void *vcf, *aux;
! 225: {
! 226: struct spif_softc *sc = (struct spif_softc *)parent;
! 227:
! 228: return (aux == sttymatch && sc->sc_ttys == NULL);
! 229: }
! 230:
! 231: void
! 232: sttyattach(parent, dev, aux)
! 233: struct device *parent, *dev;
! 234: void *aux;
! 235: {
! 236: struct spif_softc *sc = (struct spif_softc *)parent;
! 237: struct stty_softc *ssc = (struct stty_softc *)dev;
! 238: int port;
! 239:
! 240: sc->sc_ttys = ssc;
! 241:
! 242: for (port = 0; port < sc->sc_nser; port++) {
! 243: struct stty_port *sp = &ssc->sc_port[port];
! 244: struct tty *tp;
! 245:
! 246: sp->sp_dtr = 0;
! 247: sc->sc_regs->dtrlatch[port] = 1;
! 248:
! 249: tp = ttymalloc();
! 250:
! 251: tp->t_oproc = stty_start;
! 252: tp->t_param = stty_param;
! 253:
! 254: sp->sp_tty = tp;
! 255: sp->sp_sc = sc;
! 256: sp->sp_channel = port;
! 257:
! 258: sp->sp_rbuf = malloc(STTY_RBUF_SIZE, M_DEVBUF, M_NOWAIT);
! 259: if(sp->sp_rbuf == NULL)
! 260: break;
! 261:
! 262: sp->sp_rend = sp->sp_rbuf + STTY_RBUF_SIZE;
! 263: }
! 264:
! 265: ssc->sc_nports = port;
! 266:
! 267: printf(": %d tty%s\n", port, port == 1 ? "" : "s");
! 268: }
! 269:
! 270: int
! 271: sttyopen(dev, flags, mode, p)
! 272: dev_t dev;
! 273: int flags;
! 274: int mode;
! 275: struct proc *p;
! 276: {
! 277: struct spif_softc *csc;
! 278: struct stty_softc *sc;
! 279: struct stty_port *sp;
! 280: struct tty *tp;
! 281: int card = SPIF_CARD(dev);
! 282: int port = SPIF_PORT(dev);
! 283: int s;
! 284:
! 285: if (card >= stty_cd.cd_ndevs || card >= spif_cd.cd_ndevs)
! 286: return (ENXIO);
! 287:
! 288: sc = stty_cd.cd_devs[card];
! 289: csc = spif_cd.cd_devs[card];
! 290: if (sc == NULL)
! 291: return (ENXIO);
! 292:
! 293: if (port >= sc->sc_nports)
! 294: return (ENXIO);
! 295:
! 296: sp = &sc->sc_port[port];
! 297: tp = sp->sp_tty;
! 298: tp->t_dev = dev;
! 299:
! 300: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 301: SET(tp->t_state, TS_WOPEN);
! 302:
! 303: ttychars(tp);
! 304: tp->t_iflag = TTYDEF_IFLAG;
! 305: tp->t_oflag = TTYDEF_OFLAG;
! 306: tp->t_cflag = TTYDEF_CFLAG;
! 307: if (ISSET(sp->sp_openflags, TIOCFLAG_CLOCAL))
! 308: SET(tp->t_cflag, CLOCAL);
! 309: if (ISSET(sp->sp_openflags, TIOCFLAG_CRTSCTS))
! 310: SET(tp->t_cflag, CRTSCTS);
! 311: if (ISSET(sp->sp_openflags, TIOCFLAG_MDMBUF))
! 312: SET(tp->t_cflag, MDMBUF);
! 313: tp->t_lflag = TTYDEF_LFLAG;
! 314: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
! 315:
! 316: sp->sp_rput = sp->sp_rget = sp->sp_rbuf;
! 317:
! 318: s = spltty();
! 319:
! 320: csc->sc_regs->stc.car = sp->sp_channel;
! 321: stty_write_ccr(&csc->sc_regs->stc,
! 322: CD180_CCR_CMD_RESET | CD180_CCR_RESETCHAN);
! 323: csc->sc_regs->stc.car = sp->sp_channel;
! 324:
! 325: stty_param(tp, &tp->t_termios);
! 326:
! 327: ttsetwater(tp);
! 328:
! 329: csc->sc_regs->stc.srer = CD180_SRER_CD | CD180_SRER_RXD;
! 330:
! 331: if (ISSET(sp->sp_openflags, TIOCFLAG_SOFTCAR) || sp->sp_carrier)
! 332: SET(tp->t_state, TS_CARR_ON);
! 333: else
! 334: CLR(tp->t_state, TS_CARR_ON);
! 335: }
! 336: else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
! 337: return (EBUSY);
! 338: } else {
! 339: s = spltty();
! 340: }
! 341:
! 342: if (!ISSET(flags, O_NONBLOCK)) {
! 343: while (!ISSET(tp->t_cflag, CLOCAL) &&
! 344: !ISSET(tp->t_state, TS_CARR_ON)) {
! 345: int error;
! 346:
! 347: SET(tp->t_state, TS_WOPEN);
! 348: error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
! 349: "sttycd", 0);
! 350: if (error != 0) {
! 351: splx(s);
! 352: CLR(tp->t_state, TS_WOPEN);
! 353: return (error);
! 354: }
! 355: }
! 356: }
! 357:
! 358: splx(s);
! 359:
! 360: return ((*linesw[tp->t_line].l_open)(dev, tp));
! 361: }
! 362:
! 363: int
! 364: sttyclose(dev, flags, mode, p)
! 365: dev_t dev;
! 366: int flags;
! 367: int mode;
! 368: struct proc *p;
! 369: {
! 370: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 371: struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
! 372: struct spif_softc *csc = sp->sp_sc;
! 373: struct tty *tp = sp->sp_tty;
! 374: int port = SPIF_PORT(dev);
! 375: int s;
! 376:
! 377: (*linesw[tp->t_line].l_close)(tp, flags);
! 378: s = spltty();
! 379:
! 380: if (ISSET(tp->t_cflag, HUPCL) || !ISSET(tp->t_state, TS_ISOPEN)) {
! 381: stty_modem_control(sp, 0, DMSET);
! 382: csc->sc_regs->stc.car = port;
! 383: csc->sc_regs->stc.ccr =
! 384: CD180_CCR_CMD_RESET | CD180_CCR_RESETCHAN;
! 385: }
! 386:
! 387: splx(s);
! 388: ttyclose(tp);
! 389: return (0);
! 390: }
! 391:
! 392: int
! 393: sttyioctl(dev, cmd, data, flags, p)
! 394: dev_t dev;
! 395: u_long cmd;
! 396: caddr_t data;
! 397: int flags;
! 398: struct proc *p;
! 399: {
! 400: struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 401: struct stty_port *sp = &stc->sc_port[SPIF_PORT(dev)];
! 402: struct spif_softc *sc = sp->sp_sc;
! 403: struct tty *tp = sp->sp_tty;
! 404: int error;
! 405:
! 406: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, p);
! 407: if (error >= 0)
! 408: return (error);
! 409:
! 410: error = ttioctl(tp, cmd, data, flags, p);
! 411: if (error >= 0)
! 412: return (error);
! 413:
! 414: error = 0;
! 415:
! 416: switch (cmd) {
! 417: case TIOCSBRK:
! 418: SET(sp->sp_flags, STTYF_SET_BREAK);
! 419: sc->sc_regs->stc.car = sp->sp_channel;
! 420: sc->sc_regs->stc.srer |= CD180_SRER_TXD;
! 421: break;
! 422: case TIOCCBRK:
! 423: SET(sp->sp_flags, STTYF_CLR_BREAK);
! 424: sc->sc_regs->stc.car = sp->sp_channel;
! 425: sc->sc_regs->stc.srer |= CD180_SRER_TXD;
! 426: break;
! 427: case TIOCSDTR:
! 428: stty_modem_control(sp, TIOCM_DTR, DMBIS);
! 429: break;
! 430: case TIOCCDTR:
! 431: stty_modem_control(sp, TIOCM_DTR, DMBIC);
! 432: break;
! 433: case TIOCMBIS:
! 434: stty_modem_control(sp, *((int *)data), DMBIS);
! 435: break;
! 436: case TIOCMBIC:
! 437: stty_modem_control(sp, *((int *)data), DMBIC);
! 438: break;
! 439: case TIOCMGET:
! 440: *((int *)data) = stty_modem_control(sp, 0, DMGET);
! 441: break;
! 442: case TIOCMSET:
! 443: stty_modem_control(sp, *((int *)data), DMSET);
! 444: break;
! 445: case TIOCGFLAGS:
! 446: *((int *)data) = sp->sp_openflags;
! 447: break;
! 448: case TIOCSFLAGS:
! 449: if (suser(p, 0))
! 450: error = EPERM;
! 451: else
! 452: sp->sp_openflags = *((int *)data) &
! 453: (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
! 454: TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
! 455: break;
! 456: default:
! 457: error = ENOTTY;
! 458: }
! 459:
! 460: return (error);
! 461: }
! 462:
! 463: int
! 464: stty_modem_control(sp, bits, how)
! 465: struct stty_port *sp;
! 466: int bits, how;
! 467: {
! 468: struct spif_softc *csc = sp->sp_sc;
! 469: struct tty *tp = sp->sp_tty;
! 470: int s, msvr;
! 471:
! 472: s = spltty();
! 473: csc->sc_regs->stc.car = sp->sp_channel;
! 474:
! 475: switch (how) {
! 476: case DMGET:
! 477: bits = TIOCM_LE;
! 478: if (sp->sp_dtr)
! 479: bits |= TIOCM_DTR;
! 480: msvr = csc->sc_regs->stc.msvr;
! 481: if (ISSET(msvr, CD180_MSVR_DSR))
! 482: bits |= TIOCM_DSR;
! 483: if (ISSET(msvr, CD180_MSVR_CD))
! 484: bits |= TIOCM_CD;
! 485: if (ISSET(msvr, CD180_MSVR_CTS))
! 486: bits |= TIOCM_CTS;
! 487: if (ISSET(msvr, CD180_MSVR_RTS))
! 488: bits |= TIOCM_RTS;
! 489: break;
! 490: case DMSET:
! 491: if (ISSET(bits, TIOCM_DTR)) {
! 492: sp->sp_dtr = 1;
! 493: csc->sc_regs->dtrlatch[sp->sp_channel] = 0;
! 494: }
! 495: else {
! 496: sp->sp_dtr = 0;
! 497: csc->sc_regs->dtrlatch[sp->sp_channel] = 1;
! 498: }
! 499: if (ISSET(bits, TIOCM_RTS))
! 500: csc->sc_regs->stc.msvr &= ~CD180_MSVR_RTS;
! 501: else
! 502: csc->sc_regs->stc.msvr |= CD180_MSVR_RTS;
! 503: break;
! 504: case DMBIS:
! 505: if (ISSET(bits, TIOCM_DTR)) {
! 506: sp->sp_dtr = 1;
! 507: csc->sc_regs->dtrlatch[sp->sp_channel] = 0;
! 508: }
! 509: if (ISSET(bits, TIOCM_RTS) && !ISSET(tp->t_cflag, CRTSCTS))
! 510: csc->sc_regs->stc.msvr &= ~CD180_MSVR_RTS;
! 511: break;
! 512: case DMBIC:
! 513: if (ISSET(bits, TIOCM_DTR)) {
! 514: sp->sp_dtr = 0;
! 515: csc->sc_regs->dtrlatch[sp->sp_channel] = 1;
! 516: }
! 517: if (ISSET(bits, TIOCM_RTS))
! 518: csc->sc_regs->stc.msvr |= CD180_MSVR_RTS;
! 519: break;
! 520: }
! 521:
! 522: splx(s);
! 523: return (bits);
! 524: }
! 525:
! 526: int
! 527: stty_param(tp, t)
! 528: struct tty *tp;
! 529: struct termios *t;
! 530: {
! 531: struct stty_softc *st = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
! 532: struct stty_port *sp = &st->sc_port[SPIF_PORT(tp->t_dev)];
! 533: struct spif_softc *sc = sp->sp_sc;
! 534: u_int8_t rbprl, rbprh, tbprl, tbprh;
! 535: int s, opt;
! 536:
! 537: if (t->c_ospeed &&
! 538: stty_compute_baud(t->c_ospeed, sc->sc_osc, &tbprl, &tbprh))
! 539: return (EINVAL);
! 540:
! 541: if (t->c_ispeed &&
! 542: stty_compute_baud(t->c_ispeed, sc->sc_osc, &rbprl, &rbprh))
! 543: return (EINVAL);
! 544:
! 545: s = spltty();
! 546:
! 547: /* hang up line if ospeed is zero, otherwise raise DTR */
! 548: stty_modem_control(sp, TIOCM_DTR,
! 549: (t->c_ospeed == 0 ? DMBIC : DMBIS));
! 550:
! 551: sc->sc_regs->stc.car = sp->sp_channel;
! 552:
! 553: opt = 0;
! 554: if (ISSET(t->c_cflag, PARENB)) {
! 555: opt |= CD180_COR1_PARMODE_NORMAL;
! 556: opt |= (ISSET(t->c_cflag, PARODD) ?
! 557: CD180_COR1_ODDPAR :
! 558: CD180_COR1_EVENPAR);
! 559: }
! 560: else
! 561: opt |= CD180_COR1_PARMODE_NO;
! 562:
! 563: if (!ISSET(t->c_iflag, INPCK))
! 564: opt |= CD180_COR1_IGNPAR;
! 565:
! 566: if (ISSET(t->c_cflag, CSTOPB))
! 567: opt |= CD180_COR1_STOP2;
! 568:
! 569: switch (t->c_cflag & CSIZE) {
! 570: case CS5:
! 571: opt |= CD180_COR1_CS5;
! 572: break;
! 573: case CS6:
! 574: opt |= CD180_COR1_CS6;
! 575: break;
! 576: case CS7:
! 577: opt |= CD180_COR1_CS7;
! 578: break;
! 579: default:
! 580: opt |= CD180_COR1_CS8;
! 581: break;
! 582: }
! 583: sc->sc_regs->stc.cor1 = opt;
! 584: stty_write_ccr(&sc->sc_regs->stc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG1);
! 585:
! 586: opt = CD180_COR2_ETC;
! 587: if (ISSET(t->c_cflag, CRTSCTS))
! 588: opt |= CD180_COR2_CTSAE;
! 589: sc->sc_regs->stc.cor2 = opt;
! 590: stty_write_ccr(&sc->sc_regs->stc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG2);
! 591:
! 592: sc->sc_regs->stc.cor3 = STTY_RX_FIFO_THRESHOLD;
! 593: stty_write_ccr(&sc->sc_regs->stc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG3);
! 594:
! 595: sc->sc_regs->stc.schr1 = 0x11;
! 596: sc->sc_regs->stc.schr2 = 0x13;
! 597: sc->sc_regs->stc.schr3 = 0x11;
! 598: sc->sc_regs->stc.schr4 = 0x13;
! 599: sc->sc_regs->stc.rtpr = 0x12;
! 600:
! 601: sc->sc_regs->stc.mcor1 = CD180_MCOR1_CDZD | STTY_RX_DTR_THRESHOLD;
! 602: sc->sc_regs->stc.mcor2 = CD180_MCOR2_CDOD;
! 603: sc->sc_regs->stc.mcr = 0;
! 604:
! 605: if (t->c_ospeed) {
! 606: sc->sc_regs->stc.tbprh = tbprh;
! 607: sc->sc_regs->stc.tbprl = tbprl;
! 608: }
! 609:
! 610: if (t->c_ispeed) {
! 611: sc->sc_regs->stc.rbprh = rbprh;
! 612: sc->sc_regs->stc.rbprl = rbprl;
! 613: }
! 614:
! 615: stty_write_ccr(&sc->sc_regs->stc, CD180_CCR_CMD_CHAN |
! 616: CD180_CCR_CHAN_TXEN | CD180_CCR_CHAN_RXEN);
! 617:
! 618: sp->sp_carrier = sc->sc_regs->stc.msvr & CD180_MSVR_CD;
! 619:
! 620: splx(s);
! 621: return (0);
! 622: }
! 623:
! 624: int
! 625: sttyread(dev, uio, flags)
! 626: dev_t dev;
! 627: struct uio *uio;
! 628: int flags;
! 629: {
! 630: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 631: struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
! 632: struct tty *tp = sp->sp_tty;
! 633:
! 634: return ((*linesw[tp->t_line].l_read)(tp, uio, flags));
! 635: }
! 636:
! 637: int
! 638: sttywrite(dev, uio, flags)
! 639: dev_t dev;
! 640: struct uio *uio;
! 641: int flags;
! 642: {
! 643: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 644: struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
! 645: struct tty *tp = sp->sp_tty;
! 646:
! 647: return ((*linesw[tp->t_line].l_write)(tp, uio, flags));
! 648: }
! 649:
! 650: struct tty *
! 651: sttytty(dev)
! 652: dev_t dev;
! 653: {
! 654: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 655: struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
! 656:
! 657: return (sp->sp_tty);
! 658: }
! 659:
! 660: int
! 661: sttystop(tp, flags)
! 662: struct tty *tp;
! 663: int flags;
! 664: {
! 665: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
! 666: struct stty_port *sp = &sc->sc_port[SPIF_PORT(tp->t_dev)];
! 667: int s;
! 668:
! 669: s = spltty();
! 670: if (ISSET(tp->t_state, TS_BUSY)) {
! 671: if (!ISSET(tp->t_state, TS_TTSTOP))
! 672: SET(tp->t_state, TS_FLUSH);
! 673: SET(sp->sp_flags, STTYF_STOP);
! 674: }
! 675: splx(s);
! 676: return (0);
! 677: }
! 678:
! 679: void
! 680: stty_start(tp)
! 681: struct tty *tp;
! 682: {
! 683: struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
! 684: struct stty_port *sp = &stc->sc_port[SPIF_PORT(tp->t_dev)];
! 685: struct spif_softc *sc = sp->sp_sc;
! 686: int s;
! 687:
! 688: s = spltty();
! 689:
! 690: if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) {
! 691: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 692: if (ISSET(tp->t_state, TS_ASLEEP)) {
! 693: CLR(tp->t_state, TS_ASLEEP);
! 694: wakeup(&tp->t_outq);
! 695: }
! 696: selwakeup(&tp->t_wsel);
! 697: }
! 698: if (tp->t_outq.c_cc) {
! 699: sp->sp_txc = ndqb(&tp->t_outq, 0);
! 700: sp->sp_txp = tp->t_outq.c_cf;
! 701: SET(tp->t_state, TS_BUSY);
! 702: sc->sc_regs->stc.car = sp->sp_channel;
! 703: sc->sc_regs->stc.srer |= CD180_SRER_TXD;
! 704: }
! 705: }
! 706:
! 707: splx(s);
! 708: }
! 709:
! 710: int
! 711: spifstcintr_rxexception(sc, needsoftp)
! 712: struct spif_softc *sc;
! 713: int *needsoftp;
! 714: {
! 715: struct stty_port *sp;
! 716: u_int8_t channel, *ptr;
! 717:
! 718: channel = CD180_GSCR_CHANNEL(sc->sc_regs->stc.gscr1);
! 719: sp = &sc->sc_ttys->sc_port[channel];
! 720: ptr = sp->sp_rput;
! 721: *ptr++ = sc->sc_regs->stc.rcsr;
! 722: *ptr++ = sc->sc_regs->stc.rdr;
! 723: if (ptr == sp->sp_rend)
! 724: ptr = sp->sp_rbuf;
! 725: if (ptr == sp->sp_rget) {
! 726: if (ptr == sp->sp_rbuf)
! 727: ptr = sp->sp_rend;
! 728: ptr -= 2;
! 729: SET(sp->sp_flags, STTYF_RING_OVERFLOW);
! 730: }
! 731: sc->sc_regs->stc.eosrr = 0;
! 732: *needsoftp = 1;
! 733: sp->sp_rput = ptr;
! 734: return (1);
! 735: }
! 736:
! 737: int
! 738: spifstcintr_rx(sc, needsoftp)
! 739: struct spif_softc *sc;
! 740: int *needsoftp;
! 741: {
! 742: struct stty_port *sp;
! 743: u_int8_t channel, *ptr, cnt, rcsr;
! 744: int i;
! 745:
! 746: channel = CD180_GSCR_CHANNEL(sc->sc_regs->stc.gscr1);
! 747: sp = &sc->sc_ttys->sc_port[channel];
! 748: ptr = sp->sp_rput;
! 749: cnt = sc->sc_regs->stc.rdcr;
! 750: for (i = 0; i < cnt; i++) {
! 751: *ptr++ = 0;
! 752: rcsr = sc->sc_regs->stc.rcsr;
! 753: *ptr++ = sc->sc_regs->stc.rdr;
! 754: if (ptr == sp->sp_rend)
! 755: ptr = sp->sp_rbuf;
! 756: if (ptr == sp->sp_rget) {
! 757: if (ptr == sp->sp_rbuf)
! 758: ptr = sp->sp_rend;
! 759: ptr -= 2;
! 760: SET(sp->sp_flags, STTYF_RING_OVERFLOW);
! 761: break;
! 762: }
! 763: }
! 764: sc->sc_regs->stc.eosrr = 0;
! 765: if (cnt) {
! 766: *needsoftp = 1;
! 767: sp->sp_rput = ptr;
! 768: }
! 769: return (1);
! 770: }
! 771:
! 772: int
! 773: spifstcintr_tx(sc, needsoftp)
! 774: struct spif_softc *sc;
! 775: int *needsoftp;
! 776: {
! 777: struct stty_port *sp;
! 778: u_int8_t channel, ch;
! 779: int cnt = 0;
! 780:
! 781: channel = CD180_GSCR_CHANNEL(sc->sc_regs->stc.gscr1);
! 782: sp = &sc->sc_ttys->sc_port[channel];
! 783: if (!ISSET(sp->sp_flags, STTYF_STOP)) {
! 784: if (ISSET(sp->sp_flags, STTYF_SET_BREAK)) {
! 785: sc->sc_regs->stc.tdr = 0;
! 786: sc->sc_regs->stc.tdr = 0x81;
! 787: CLR(sp->sp_flags, STTYF_SET_BREAK);
! 788: cnt += 2;
! 789: }
! 790: if (ISSET(sp->sp_flags, STTYF_CLR_BREAK)) {
! 791: sc->sc_regs->stc.tdr = 0;
! 792: sc->sc_regs->stc.tdr = 0x83;
! 793: CLR(sp->sp_flags, STTYF_CLR_BREAK);
! 794: cnt += 2;
! 795: }
! 796:
! 797: while (sp->sp_txc > 0 && cnt < (CD180_TX_FIFO_SIZE-1)) {
! 798: ch = *sp->sp_txp;
! 799: sp->sp_txc--;
! 800: sp->sp_txp++;
! 801:
! 802: if (ch == 0) {
! 803: sc->sc_regs->stc.tdr = ch;
! 804: cnt++;
! 805: }
! 806: sc->sc_regs->stc.tdr = ch;
! 807: cnt++;
! 808: }
! 809: }
! 810:
! 811: if (sp->sp_txc == 0 ||
! 812: ISSET(sp->sp_flags, STTYF_STOP)) {
! 813: sc->sc_regs->stc.srer &= ~CD180_SRER_TXD;
! 814: CLR(sp->sp_flags, STTYF_STOP);
! 815: SET(sp->sp_flags, STTYF_DONE);
! 816: *needsoftp = 1;
! 817: }
! 818:
! 819: sc->sc_regs->stc.eosrr = 0;
! 820:
! 821: return (1);
! 822: }
! 823:
! 824: int
! 825: spifstcintr_mx(sc, needsoftp)
! 826: struct spif_softc *sc;
! 827: int *needsoftp;
! 828: {
! 829: struct stty_port *sp;
! 830: u_int8_t channel, mcr;
! 831:
! 832: channel = CD180_GSCR_CHANNEL(sc->sc_regs->stc.gscr1);
! 833: sp = &sc->sc_ttys->sc_port[channel];
! 834: mcr = sc->sc_regs->stc.mcr;
! 835: if (mcr & CD180_MCR_CD) {
! 836: SET(sp->sp_flags, STTYF_CDCHG);
! 837: *needsoftp = 1;
! 838: }
! 839: sc->sc_regs->stc.mcr = 0;
! 840: sc->sc_regs->stc.eosrr = 0;
! 841: return (1);
! 842: }
! 843:
! 844: int
! 845: spifstcintr(vsc)
! 846: void *vsc;
! 847: {
! 848: struct spif_softc *sc = (struct spif_softc *)vsc;
! 849: int needsoft = 0, r = 0, i;
! 850: u_int8_t ar;
! 851:
! 852: for (i = 0; i < 8; i++) {
! 853: ar = sc->sc_regs->istc.rrar & CD180_GSVR_IMASK;
! 854: if (ar == CD180_GSVR_RXGOOD)
! 855: r |= spifstcintr_rx(sc, &needsoft);
! 856: else if (ar == CD180_GSVR_RXEXCEPTION)
! 857: r |= spifstcintr_rxexception(sc, &needsoft);
! 858: }
! 859:
! 860: for (i = 0; i < 8; i++) {
! 861: ar = sc->sc_regs->istc.trar & CD180_GSVR_IMASK;
! 862: if (ar == CD180_GSVR_TXDATA)
! 863: r |= spifstcintr_tx(sc, &needsoft);
! 864: }
! 865:
! 866: for (i = 0; i < 8; i++) {
! 867: ar = sc->sc_regs->istc.mrar & CD180_GSVR_IMASK;
! 868: if (ar == CD180_GSVR_STATCHG)
! 869: r |= spifstcintr_mx(sc, &needsoft);
! 870: }
! 871:
! 872: if (needsoft) {
! 873: #if defined(SUN4M)
! 874: if (CPU_ISSUN4M)
! 875: raise(0, IPL_TTY);
! 876: else
! 877: #endif
! 878: ienab_bis(IE_MSOFT);
! 879: }
! 880: return (r);
! 881: }
! 882:
! 883: int
! 884: spifsoftintr(vsc)
! 885: void *vsc;
! 886: {
! 887: struct spif_softc *sc = (struct spif_softc *)vsc;
! 888: struct stty_softc *stc = sc->sc_ttys;
! 889: int r = 0, i, data, s, flags;
! 890: u_int8_t stat, msvr;
! 891: struct stty_port *sp;
! 892: struct tty *tp;
! 893:
! 894: if (stc != NULL) {
! 895: for (i = 0; i < stc->sc_nports; i++) {
! 896: sp = &stc->sc_port[i];
! 897: tp = sp->sp_tty;
! 898:
! 899: if (!ISSET(tp->t_state, TS_ISOPEN))
! 900: continue;
! 901:
! 902: while (sp->sp_rget != sp->sp_rput) {
! 903: stat = sp->sp_rget[0];
! 904: data = sp->sp_rget[1];
! 905: sp->sp_rget += 2;
! 906: if (sp->sp_rget == sp->sp_rend)
! 907: sp->sp_rget = sp->sp_rbuf;
! 908:
! 909: if (stat & (CD180_RCSR_BE | CD180_RCSR_FE))
! 910: data |= TTY_FE;
! 911:
! 912: if (stat & CD180_RCSR_PE)
! 913: data |= TTY_PE;
! 914:
! 915: (*linesw[tp->t_line].l_rint)(data, tp);
! 916: r = 1;
! 917: }
! 918:
! 919: s = splhigh();
! 920: flags = sp->sp_flags;
! 921: CLR(sp->sp_flags, STTYF_DONE | STTYF_CDCHG |
! 922: STTYF_RING_OVERFLOW);
! 923: splx(s);
! 924:
! 925: if (ISSET(flags, STTYF_CDCHG)) {
! 926: s = spltty();
! 927: sc->sc_regs->stc.car = i;
! 928: msvr = sc->sc_regs->stc.msvr;
! 929: splx(s);
! 930:
! 931: sp->sp_carrier = msvr & CD180_MSVR_CD;
! 932: (*linesw[tp->t_line].l_modem)(tp,
! 933: sp->sp_carrier);
! 934: r = 1;
! 935: }
! 936:
! 937: if (ISSET(flags, STTYF_RING_OVERFLOW)) {
! 938: log(LOG_WARNING, "%s-%x: ring overflow\n",
! 939: stc->sc_dev.dv_xname, i);
! 940: r = 1;
! 941: }
! 942:
! 943: if (ISSET(flags, STTYF_DONE)) {
! 944: ndflush(&tp->t_outq,
! 945: sp->sp_txp - tp->t_outq.c_cf);
! 946: CLR(tp->t_state, TS_BUSY);
! 947: (*linesw[tp->t_line].l_start)(tp);
! 948: r = 1;
! 949: }
! 950: }
! 951: }
! 952:
! 953: return (r);
! 954: }
! 955:
! 956: static __inline void
! 957: stty_write_ccr(stc, val)
! 958: struct stcregs *stc;
! 959: u_int8_t val;
! 960: {
! 961: int tries = 100000;
! 962:
! 963: while (stc->ccr && tries--);
! 964: if (tries == 0)
! 965: printf("CCR: timeout\n");
! 966: stc->ccr = val;
! 967: }
! 968:
! 969: int
! 970: stty_compute_baud(speed, clock, bprlp, bprhp)
! 971: speed_t speed;
! 972: int clock;
! 973: u_int8_t *bprlp, *bprhp;
! 974: {
! 975: u_int32_t rate;
! 976:
! 977: rate = (2 * clock) / (16 * speed);
! 978: if (rate & 1)
! 979: rate = (rate >> 1) + 1;
! 980: else
! 981: rate = rate >> 1;
! 982:
! 983: if (rate > 0xffff || rate == 0)
! 984: return (1);
! 985:
! 986: *bprlp = rate & 0xff;
! 987: *bprhp = (rate >> 8) & 0xff;
! 988: return (0);
! 989: }
! 990:
! 991: int
! 992: sbppmatch(parent, vcf, aux)
! 993: struct device *parent;
! 994: void *vcf, *aux;
! 995: {
! 996: struct spif_softc *sc = (struct spif_softc *)parent;
! 997:
! 998: return (aux == sbppmatch && sc->sc_bpps == NULL);
! 999: }
! 1000:
! 1001: void
! 1002: sbppattach(parent, dev, aux)
! 1003: struct device *parent, *dev;
! 1004: void *aux;
! 1005: {
! 1006: struct spif_softc *sc = (struct spif_softc *)parent;
! 1007: struct sbpp_softc *psc = (struct sbpp_softc *)dev;
! 1008: int port;
! 1009:
! 1010: sc->sc_bpps = psc;
! 1011:
! 1012: for (port = 0; port < sc->sc_npar; port++) {
! 1013: }
! 1014:
! 1015: psc->sc_nports = port;
! 1016: printf(": %d port%s\n", port, port == 1 ? "" : "s");
! 1017: }
! 1018:
! 1019: int
! 1020: sbppopen(dev, flags, mode, p)
! 1021: dev_t dev;
! 1022: int flags;
! 1023: int mode;
! 1024: struct proc *p;
! 1025: {
! 1026: return (ENXIO);
! 1027: }
! 1028:
! 1029: int
! 1030: sbppclose(dev, flags, mode, p)
! 1031: dev_t dev;
! 1032: int flags;
! 1033: int mode;
! 1034: struct proc *p;
! 1035: {
! 1036: return (ENXIO);
! 1037: }
! 1038:
! 1039: int
! 1040: spifppcintr(v)
! 1041: void *v;
! 1042: {
! 1043: return (0);
! 1044: }
! 1045:
! 1046: int
! 1047: sbppread(dev, uio, flags)
! 1048: dev_t dev;
! 1049: struct uio *uio;
! 1050: int flags;
! 1051: {
! 1052: return (sbpp_rw(dev, uio));
! 1053: }
! 1054:
! 1055: int
! 1056: sbppwrite(dev, uio, flags)
! 1057: dev_t dev;
! 1058: struct uio *uio;
! 1059: int flags;
! 1060: {
! 1061: return (sbpp_rw(dev, uio));
! 1062: }
! 1063:
! 1064: int
! 1065: sbpp_rw(dev, uio)
! 1066: dev_t dev;
! 1067: struct uio *uio;
! 1068: {
! 1069: return (ENXIO);
! 1070: }
! 1071:
! 1072: int
! 1073: sbpppoll(dev, events, p)
! 1074: dev_t dev;
! 1075: int events;
! 1076: struct proc *p;
! 1077: {
! 1078: return (seltrue(dev, events, p));
! 1079: }
! 1080:
! 1081: int
! 1082: sbppioctl(dev, cmd, data, flags, p)
! 1083: dev_t dev;
! 1084: u_long cmd;
! 1085: caddr_t data;
! 1086: int flags;
! 1087: struct proc *p;
! 1088: {
! 1089: int error;
! 1090:
! 1091: error = ENOTTY;
! 1092:
! 1093: return (error);
! 1094: }
CVSweb