Annotation of sys/dev/sbus/spif.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: spif.c,v 1.13 2006/03/04 13:00:55 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1999-2002 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: * Effort sponsored in part by the Defense Advanced Research Projects
! 29: * Agency (DARPA) and Air Force Research Laboratory, Air Force
! 30: * Materiel Command, USAF, under agreement number F30602-01-2-0537.
! 31: *
! 32: */
! 33:
! 34: /*
! 35: * Driver for the SUNW,spif: 8 serial, 1 parallel sbus board
! 36: * based heavily on Iain Hibbert's driver for the MAGMA cards
! 37: */
! 38:
! 39: #include <sys/param.h>
! 40: #include <sys/systm.h>
! 41: #include <sys/proc.h>
! 42: #include <sys/device.h>
! 43: #include <sys/kernel.h>
! 44: #include <sys/file.h>
! 45: #include <sys/errno.h>
! 46: #include <sys/ioctl.h>
! 47: #include <sys/mbuf.h>
! 48: #include <sys/socket.h>
! 49: #include <sys/syslog.h>
! 50: #include <sys/malloc.h>
! 51: #include <sys/tty.h>
! 52: #include <sys/conf.h>
! 53:
! 54: #include <machine/autoconf.h>
! 55: #include <dev/sbus/sbusvar.h>
! 56: #include <dev/sbus/spifreg.h>
! 57: #include <dev/sbus/spifvar.h>
! 58:
! 59: int spifmatch(struct device *, void *, void *);
! 60: void spifattach(struct device *, struct device *, void *);
! 61:
! 62: int sttymatch(struct device *, void *, void *);
! 63: void sttyattach(struct device *, struct device *, void *);
! 64: int sttyopen(dev_t, int, int, struct proc *);
! 65: int sttyclose(dev_t, int, int, struct proc *);
! 66: int sttyread(dev_t, struct uio *, int);
! 67: int sttywrite(dev_t, struct uio *, int);
! 68: int sttyioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 69: int sttystop(struct tty *, int);
! 70:
! 71: int spifstcintr(void *);
! 72: int spifstcintr_mx(struct spif_softc *, int *);
! 73: int spifstcintr_tx(struct spif_softc *, int *);
! 74: int spifstcintr_rx(struct spif_softc *, int *);
! 75: int spifstcintr_rxexception(struct spif_softc *, int *);
! 76: void spifsoftintr(void *);
! 77:
! 78: int stty_param(struct tty *, struct termios *);
! 79: struct tty *sttytty(dev_t);
! 80: int stty_modem_control(struct stty_port *, int, int);
! 81: void stty_write_ccr(struct spif_softc *, u_int8_t);
! 82: int stty_compute_baud(speed_t, int, u_int8_t *, u_int8_t *);
! 83: void stty_start(struct tty *);
! 84:
! 85: int sbppmatch(struct device *, void *, void *);
! 86: void sbppattach(struct device *, struct device *, void *);
! 87: int sbppopen(dev_t, int, int, struct proc *);
! 88: int sbppclose(dev_t, int, int, struct proc *);
! 89: int sbppread(dev_t, struct uio *, int);
! 90: int sbppwrite(dev_t, struct uio *, int);
! 91: int sbpp_rw(dev_t, struct uio *);
! 92: int spifppcintr(void *);
! 93: int sbpppoll(dev_t, int, struct proc *);
! 94: int sbppioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 95:
! 96: struct cfattach spif_ca = {
! 97: sizeof (struct spif_softc), spifmatch, spifattach
! 98: };
! 99:
! 100: struct cfdriver spif_cd = {
! 101: NULL, "spif", DV_DULL
! 102: };
! 103:
! 104: struct cfattach stty_ca = {
! 105: sizeof(struct stty_softc), sttymatch, sttyattach
! 106: };
! 107:
! 108: struct cfdriver stty_cd = {
! 109: NULL, "stty", DV_TTY
! 110: };
! 111:
! 112: struct cfattach sbpp_ca = {
! 113: sizeof(struct sbpp_softc), sbppmatch, sbppattach
! 114: };
! 115:
! 116: struct cfdriver sbpp_cd = {
! 117: NULL, "sbpp", DV_DULL
! 118: };
! 119:
! 120: /* normal STC access */
! 121: #define STC_WRITE(sc,r,v) \
! 122: bus_space_write_1((sc)->sc_bustag, (sc)->sc_stch, (r), (v))
! 123: #define STC_READ(sc,r) \
! 124: bus_space_read_1((sc)->sc_bustag, (sc)->sc_stch, (r))
! 125:
! 126: /* IACK STC access */
! 127: #define ISTC_WRITE(sc,r,v) \
! 128: bus_space_write_1((sc)->sc_bustag, (sc)->sc_istch, (r), (v))
! 129: #define ISTC_READ(sc,r) \
! 130: bus_space_read_1((sc)->sc_bustag, (sc)->sc_istch, (r))
! 131:
! 132: /* PPC access */
! 133: #define PPC_WRITE(sc,r,v) \
! 134: bus_space_write_1((sc)->sc_bustag, (sc)->sc_ppch, (r), (v))
! 135: #define PPC_READ(sc,r) \
! 136: bus_space_read_1((sc)->sc_bustag, (sc)->sc_ppch, (r))
! 137:
! 138: #define DTR_WRITE(sc,port,v) \
! 139: do { \
! 140: sc->sc_ttys->sc_port[(port)].sp_dtr = v; \
! 141: bus_space_write_1((sc)->sc_bustag, \
! 142: sc->sc_dtrh, port, (v == 0) ? 1 : 0); \
! 143: } while (0)
! 144:
! 145: #define DTR_READ(sc,port) ((sc)->sc_ttys->sc_port[(port)].sp_dtr)
! 146:
! 147: int
! 148: spifmatch(parent, vcf, aux)
! 149: struct device *parent;
! 150: void *vcf, *aux;
! 151: {
! 152: struct cfdata *cf = vcf;
! 153: struct sbus_attach_args *sa = aux;
! 154:
! 155: if (strcmp(cf->cf_driver->cd_name, sa->sa_name) &&
! 156: strcmp("SUNW,spif", sa->sa_name))
! 157: return (0);
! 158: return (1);
! 159: }
! 160:
! 161: void
! 162: spifattach(parent, self, aux)
! 163: struct device *parent, *self;
! 164: void *aux;
! 165: {
! 166: struct spif_softc *sc = (struct spif_softc *)self;
! 167: struct sbus_attach_args *sa = aux;
! 168:
! 169: if (sa->sa_nintr != 2) {
! 170: printf(": expected %d interrupts, got %d\n", 2, sa->sa_nintr);
! 171: return;
! 172: }
! 173:
! 174: if (sa->sa_nreg != 1) {
! 175: printf(": expected %d registers, got %d\n", 1, sa->sa_nreg);
! 176: return;
! 177: }
! 178:
! 179: sc->sc_bustag = sa->sa_bustag;
! 180: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
! 181: sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size,
! 182: 0, 0, &sc->sc_regh) != 0) {
! 183: printf(": can't map registers\n");
! 184: return;
! 185: }
! 186:
! 187: if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
! 188: DTR_REG_OFFSET, DTR_REG_LEN, &sc->sc_dtrh) != 0) {
! 189: printf(": can't map dtr regs\n");
! 190: goto fail_unmapregs;
! 191: }
! 192:
! 193: if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
! 194: STC_REG_OFFSET, STC_REG_LEN, &sc->sc_stch) != 0) {
! 195: printf(": can't map dtr regs\n");
! 196: goto fail_unmapregs;
! 197: }
! 198:
! 199: if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
! 200: ISTC_REG_OFFSET, ISTC_REG_LEN, &sc->sc_istch) != 0) {
! 201: printf(": can't map dtr regs\n");
! 202: goto fail_unmapregs;
! 203: }
! 204:
! 205: if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
! 206: PPC_REG_OFFSET, PPC_REG_LEN, &sc->sc_ppch) != 0) {
! 207: printf(": can't map dtr regs\n");
! 208: goto fail_unmapregs;
! 209: }
! 210:
! 211: sc->sc_ppcih = bus_intr_establish(sa->sa_bustag,
! 212: sa->sa_intr[PARALLEL_INTR].sbi_pri, IPL_TTY, 0, spifppcintr, sc,
! 213: self->dv_xname);
! 214: if (sc->sc_ppcih == NULL) {
! 215: printf(": failed to establish ppc interrupt\n");
! 216: goto fail_unmapregs;
! 217: }
! 218:
! 219: sc->sc_stcih = bus_intr_establish(sa->sa_bustag,
! 220: sa->sa_intr[SERIAL_INTR].sbi_pri, IPL_TTY, 0, spifstcintr, sc,
! 221: self->dv_xname);
! 222: if (sc->sc_stcih == NULL) {
! 223: printf(": failed to establish stc interrupt\n");
! 224: goto fail_unmapregs;
! 225: }
! 226:
! 227: sc->sc_softih = softintr_establish(IPL_TTY, spifsoftintr, sc);
! 228: if (sc->sc_softih == NULL) {
! 229: printf(": can't get soft intr\n");
! 230: goto fail_unmapregs;
! 231: }
! 232:
! 233: sc->sc_node = sa->sa_node;
! 234:
! 235: sc->sc_rev = getpropint(sc->sc_node, "revlev", 0);
! 236:
! 237: sc->sc_osc = getpropint(sc->sc_node, "verosc", 0);
! 238: switch (sc->sc_osc) {
! 239: case SPIF_OSC10:
! 240: sc->sc_osc = 10000000;
! 241: break;
! 242: case SPIF_OSC9:
! 243: default:
! 244: sc->sc_osc = 9830400;
! 245: break;
! 246: }
! 247:
! 248: sc->sc_nser = 8;
! 249: sc->sc_npar = 1;
! 250:
! 251: sc->sc_rev2 = STC_READ(sc, STC_GFRCR);
! 252: STC_WRITE(sc, STC_GSVR, 0);
! 253:
! 254: stty_write_ccr(sc, CD180_CCR_CMD_RESET | CD180_CCR_RESETALL);
! 255: while (STC_READ(sc, STC_GSVR) != 0xff);
! 256: while (STC_READ(sc, STC_GFRCR) != sc->sc_rev2);
! 257:
! 258: STC_WRITE(sc, STC_PPRH, CD180_PPRH);
! 259: STC_WRITE(sc, STC_PPRL, CD180_PPRL);
! 260: STC_WRITE(sc, STC_MSMR, SPIF_MSMR);
! 261: STC_WRITE(sc, STC_TSMR, SPIF_TSMR);
! 262: STC_WRITE(sc, STC_RSMR, SPIF_RSMR);
! 263: STC_WRITE(sc, STC_GSVR, 0);
! 264: STC_WRITE(sc, STC_GSCR1, 0);
! 265: STC_WRITE(sc, STC_GSCR2, 0);
! 266: STC_WRITE(sc, STC_GSCR3, 0);
! 267:
! 268: printf(": rev %x chiprev %x osc %sMHz\n",
! 269: sc->sc_rev, sc->sc_rev2, clockfreq(sc->sc_osc));
! 270:
! 271: (void)config_found(self, sttymatch, NULL);
! 272: (void)config_found(self, sbppmatch, NULL);
! 273:
! 274: return;
! 275:
! 276: fail_unmapregs:
! 277: bus_space_unmap(sa->sa_bustag, sc->sc_regh, sa->sa_reg[0].sbr_size);
! 278: }
! 279:
! 280: int
! 281: sttymatch(parent, vcf, aux)
! 282: struct device *parent;
! 283: void *vcf, *aux;
! 284: {
! 285: struct spif_softc *sc = (struct spif_softc *)parent;
! 286:
! 287: return (aux == sttymatch && sc->sc_ttys == NULL);
! 288: }
! 289:
! 290: void
! 291: sttyattach(parent, dev, aux)
! 292: struct device *parent, *dev;
! 293: void *aux;
! 294: {
! 295: struct spif_softc *sc = (struct spif_softc *)parent;
! 296: struct stty_softc *ssc = (struct stty_softc *)dev;
! 297: int port;
! 298:
! 299: sc->sc_ttys = ssc;
! 300:
! 301: for (port = 0; port < sc->sc_nser; port++) {
! 302: struct stty_port *sp = &ssc->sc_port[port];
! 303: struct tty *tp;
! 304:
! 305: DTR_WRITE(sc, port, 0);
! 306:
! 307: tp = ttymalloc();
! 308:
! 309: tp->t_oproc = stty_start;
! 310: tp->t_param = stty_param;
! 311:
! 312: sp->sp_tty = tp;
! 313: sp->sp_sc = sc;
! 314: sp->sp_channel = port;
! 315:
! 316: sp->sp_rbuf = malloc(STTY_RBUF_SIZE, M_DEVBUF, M_NOWAIT);
! 317: if(sp->sp_rbuf == NULL)
! 318: break;
! 319:
! 320: sp->sp_rend = sp->sp_rbuf + STTY_RBUF_SIZE;
! 321: }
! 322:
! 323: ssc->sc_nports = port;
! 324:
! 325: printf(": %d tty%s\n", port, port == 1 ? "" : "s");
! 326: }
! 327:
! 328: int
! 329: sttyopen(dev, flags, mode, p)
! 330: dev_t dev;
! 331: int flags;
! 332: int mode;
! 333: struct proc *p;
! 334: {
! 335: struct spif_softc *csc;
! 336: struct stty_softc *sc;
! 337: struct stty_port *sp;
! 338: struct tty *tp;
! 339: int card = SPIF_CARD(dev);
! 340: int port = SPIF_PORT(dev);
! 341: int s;
! 342:
! 343: if (card >= stty_cd.cd_ndevs || card >= spif_cd.cd_ndevs)
! 344: return (ENXIO);
! 345:
! 346: sc = stty_cd.cd_devs[card];
! 347: csc = spif_cd.cd_devs[card];
! 348: if (sc == NULL || csc == NULL)
! 349: return (ENXIO);
! 350:
! 351: if (port >= sc->sc_nports)
! 352: return (ENXIO);
! 353:
! 354: sp = &sc->sc_port[port];
! 355: tp = sp->sp_tty;
! 356: tp->t_dev = dev;
! 357:
! 358: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 359: SET(tp->t_state, TS_WOPEN);
! 360:
! 361: ttychars(tp);
! 362: tp->t_iflag = TTYDEF_IFLAG;
! 363: tp->t_oflag = TTYDEF_OFLAG;
! 364: tp->t_cflag = TTYDEF_CFLAG;
! 365: if (ISSET(sp->sp_openflags, TIOCFLAG_CLOCAL))
! 366: SET(tp->t_cflag, CLOCAL);
! 367: if (ISSET(sp->sp_openflags, TIOCFLAG_CRTSCTS))
! 368: SET(tp->t_cflag, CRTSCTS);
! 369: if (ISSET(sp->sp_openflags, TIOCFLAG_MDMBUF))
! 370: SET(tp->t_cflag, MDMBUF);
! 371: tp->t_lflag = TTYDEF_LFLAG;
! 372: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
! 373:
! 374: sp->sp_rput = sp->sp_rget = sp->sp_rbuf;
! 375:
! 376: s = spltty();
! 377:
! 378: STC_WRITE(csc, STC_CAR, sp->sp_channel);
! 379: stty_write_ccr(csc, CD180_CCR_CMD_RESET|CD180_CCR_RESETCHAN);
! 380: STC_WRITE(csc, STC_CAR, sp->sp_channel);
! 381:
! 382: stty_param(tp, &tp->t_termios);
! 383:
! 384: ttsetwater(tp);
! 385:
! 386: STC_WRITE(csc, STC_SRER, CD180_SRER_CD | CD180_SRER_RXD);
! 387:
! 388: if (ISSET(sp->sp_openflags, TIOCFLAG_SOFTCAR) || sp->sp_carrier)
! 389: SET(tp->t_state, TS_CARR_ON);
! 390: else
! 391: CLR(tp->t_state, TS_CARR_ON);
! 392: }
! 393: else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
! 394: return (EBUSY);
! 395: } else {
! 396: s = spltty();
! 397: }
! 398:
! 399: if (!ISSET(flags, O_NONBLOCK)) {
! 400: while (!ISSET(tp->t_cflag, CLOCAL) &&
! 401: !ISSET(tp->t_state, TS_CARR_ON)) {
! 402: int error;
! 403:
! 404: SET(tp->t_state, TS_WOPEN);
! 405: error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
! 406: "sttycd", 0);
! 407: if (error != 0) {
! 408: splx(s);
! 409: CLR(tp->t_state, TS_WOPEN);
! 410: return (error);
! 411: }
! 412: }
! 413: }
! 414:
! 415: splx(s);
! 416:
! 417: return ((*linesw[tp->t_line].l_open)(dev, tp));
! 418: }
! 419:
! 420: int
! 421: sttyclose(dev, flags, mode, p)
! 422: dev_t dev;
! 423: int flags;
! 424: int mode;
! 425: struct proc *p;
! 426: {
! 427: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 428: struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
! 429: struct spif_softc *csc = sp->sp_sc;
! 430: struct tty *tp = sp->sp_tty;
! 431: int port = SPIF_PORT(dev);
! 432: int s;
! 433:
! 434: (*linesw[tp->t_line].l_close)(tp, flags);
! 435: s = spltty();
! 436:
! 437: if (ISSET(tp->t_cflag, HUPCL) || !ISSET(tp->t_state, TS_ISOPEN)) {
! 438: stty_modem_control(sp, 0, DMSET);
! 439: STC_WRITE(csc, STC_CAR, port);
! 440: STC_WRITE(csc, STC_CCR,
! 441: CD180_CCR_CMD_RESET|CD180_CCR_RESETCHAN);
! 442: }
! 443:
! 444: splx(s);
! 445: ttyclose(tp);
! 446: return (0);
! 447: }
! 448:
! 449: int
! 450: sttyioctl(dev, cmd, data, flags, p)
! 451: dev_t dev;
! 452: u_long cmd;
! 453: caddr_t data;
! 454: int flags;
! 455: struct proc *p;
! 456: {
! 457: struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 458: struct stty_port *sp = &stc->sc_port[SPIF_PORT(dev)];
! 459: struct spif_softc *sc = sp->sp_sc;
! 460: struct tty *tp = sp->sp_tty;
! 461: int error;
! 462:
! 463: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, p);
! 464: if (error >= 0)
! 465: return (error);
! 466:
! 467: error = ttioctl(tp, cmd, data, flags, p);
! 468: if (error >= 0)
! 469: return (error);
! 470:
! 471: error = 0;
! 472:
! 473: switch (cmd) {
! 474: case TIOCSBRK:
! 475: SET(sp->sp_flags, STTYF_SET_BREAK);
! 476: STC_WRITE(sc, STC_CAR, sp->sp_channel);
! 477: STC_WRITE(sc, STC_SRER,
! 478: STC_READ(sc, STC_SRER) | CD180_SRER_TXD);
! 479: break;
! 480: case TIOCCBRK:
! 481: SET(sp->sp_flags, STTYF_CLR_BREAK);
! 482: STC_WRITE(sc, STC_CAR, sp->sp_channel);
! 483: STC_WRITE(sc, STC_SRER,
! 484: STC_READ(sc, STC_SRER) | CD180_SRER_TXD);
! 485: break;
! 486: case TIOCSDTR:
! 487: stty_modem_control(sp, TIOCM_DTR, DMBIS);
! 488: break;
! 489: case TIOCCDTR:
! 490: stty_modem_control(sp, TIOCM_DTR, DMBIC);
! 491: break;
! 492: case TIOCMBIS:
! 493: stty_modem_control(sp, *((int *)data), DMBIS);
! 494: break;
! 495: case TIOCMBIC:
! 496: stty_modem_control(sp, *((int *)data), DMBIC);
! 497: break;
! 498: case TIOCMGET:
! 499: *((int *)data) = stty_modem_control(sp, 0, DMGET);
! 500: break;
! 501: case TIOCMSET:
! 502: stty_modem_control(sp, *((int *)data), DMSET);
! 503: break;
! 504: case TIOCGFLAGS:
! 505: *((int *)data) = sp->sp_openflags;
! 506: break;
! 507: case TIOCSFLAGS:
! 508: if (suser(p, 0))
! 509: error = EPERM;
! 510: else
! 511: sp->sp_openflags = *((int *)data) &
! 512: (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
! 513: TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
! 514: break;
! 515: default:
! 516: error = ENOTTY;
! 517: }
! 518:
! 519: return (error);
! 520: }
! 521:
! 522: int
! 523: stty_modem_control(sp, bits, how)
! 524: struct stty_port *sp;
! 525: int bits, how;
! 526: {
! 527: struct spif_softc *csc = sp->sp_sc;
! 528: struct tty *tp = sp->sp_tty;
! 529: int s, msvr;
! 530:
! 531: s = spltty();
! 532: STC_WRITE(csc, STC_CAR, sp->sp_channel);
! 533:
! 534: switch (how) {
! 535: case DMGET:
! 536: bits = TIOCM_LE;
! 537: if (DTR_READ(csc, sp->sp_channel))
! 538: bits |= TIOCM_DTR;
! 539: msvr = STC_READ(csc, STC_MSVR);
! 540: if (ISSET(msvr, CD180_MSVR_DSR))
! 541: bits |= TIOCM_DSR;
! 542: if (ISSET(msvr, CD180_MSVR_CD))
! 543: bits |= TIOCM_CD;
! 544: if (ISSET(msvr, CD180_MSVR_CTS))
! 545: bits |= TIOCM_CTS;
! 546: if (ISSET(msvr, CD180_MSVR_RTS))
! 547: bits |= TIOCM_RTS;
! 548: break;
! 549: case DMSET:
! 550: DTR_WRITE(csc, sp->sp_channel, ISSET(bits, TIOCM_DTR) ? 1 : 0);
! 551: if (ISSET(bits, TIOCM_RTS))
! 552: STC_WRITE(csc, STC_MSVR,
! 553: STC_READ(csc, STC_MSVR) & (~CD180_MSVR_RTS));
! 554: else
! 555: STC_WRITE(csc, STC_MSVR,
! 556: STC_READ(csc, STC_MSVR) | CD180_MSVR_RTS);
! 557: break;
! 558: case DMBIS:
! 559: if (ISSET(bits, TIOCM_DTR))
! 560: DTR_WRITE(csc, sp->sp_channel, 1);
! 561: if (ISSET(bits, TIOCM_RTS) && !ISSET(tp->t_cflag, CRTSCTS))
! 562: STC_WRITE(csc, STC_MSVR,
! 563: STC_READ(csc, STC_MSVR) & (~CD180_MSVR_RTS));
! 564: break;
! 565: case DMBIC:
! 566: if (ISSET(bits, TIOCM_DTR))
! 567: DTR_WRITE(csc, sp->sp_channel, 0);
! 568: if (ISSET(bits, TIOCM_RTS))
! 569: STC_WRITE(csc, STC_MSVR,
! 570: STC_READ(csc, STC_MSVR) | CD180_MSVR_RTS);
! 571: break;
! 572: }
! 573:
! 574: splx(s);
! 575: return (bits);
! 576: }
! 577:
! 578: int
! 579: stty_param(tp, t)
! 580: struct tty *tp;
! 581: struct termios *t;
! 582: {
! 583: struct stty_softc *st = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
! 584: struct stty_port *sp = &st->sc_port[SPIF_PORT(tp->t_dev)];
! 585: struct spif_softc *sc = sp->sp_sc;
! 586: u_int8_t rbprl, rbprh, tbprl, tbprh;
! 587: int s, opt;
! 588:
! 589: if (t->c_ospeed &&
! 590: stty_compute_baud(t->c_ospeed, sc->sc_osc, &tbprl, &tbprh))
! 591: return (EINVAL);
! 592:
! 593: if (t->c_ispeed &&
! 594: stty_compute_baud(t->c_ispeed, sc->sc_osc, &rbprl, &rbprh))
! 595: return (EINVAL);
! 596:
! 597: s = spltty();
! 598:
! 599: /* hang up line if ospeed is zero, otherwise raise DTR */
! 600: stty_modem_control(sp, TIOCM_DTR,
! 601: (t->c_ospeed == 0 ? DMBIC : DMBIS));
! 602:
! 603: STC_WRITE(sc, STC_CAR, sp->sp_channel);
! 604:
! 605: opt = 0;
! 606: if (ISSET(t->c_cflag, PARENB)) {
! 607: opt |= CD180_COR1_PARMODE_NORMAL;
! 608: opt |= (ISSET(t->c_cflag, PARODD) ?
! 609: CD180_COR1_ODDPAR :
! 610: CD180_COR1_EVENPAR);
! 611: }
! 612: else
! 613: opt |= CD180_COR1_PARMODE_NO;
! 614:
! 615: if (!ISSET(t->c_iflag, INPCK))
! 616: opt |= CD180_COR1_IGNPAR;
! 617:
! 618: if (ISSET(t->c_cflag, CSTOPB))
! 619: opt |= CD180_COR1_STOP2;
! 620:
! 621: switch (t->c_cflag & CSIZE) {
! 622: case CS5:
! 623: opt |= CD180_COR1_CS5;
! 624: break;
! 625: case CS6:
! 626: opt |= CD180_COR1_CS6;
! 627: break;
! 628: case CS7:
! 629: opt |= CD180_COR1_CS7;
! 630: break;
! 631: default:
! 632: opt |= CD180_COR1_CS8;
! 633: break;
! 634: }
! 635: STC_WRITE(sc, STC_COR1, opt);
! 636: stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG1);
! 637:
! 638: opt = CD180_COR2_ETC;
! 639: if (ISSET(t->c_cflag, CRTSCTS))
! 640: opt |= CD180_COR2_CTSAE;
! 641: STC_WRITE(sc, STC_COR2, opt);
! 642: stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG2);
! 643:
! 644: STC_WRITE(sc, STC_COR3, STTY_RX_FIFO_THRESHOLD);
! 645: stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG3);
! 646:
! 647: STC_WRITE(sc, STC_SCHR1, 0x11);
! 648: STC_WRITE(sc, STC_SCHR2, 0x13);
! 649: STC_WRITE(sc, STC_SCHR3, 0x11);
! 650: STC_WRITE(sc, STC_SCHR4, 0x13);
! 651: STC_WRITE(sc, STC_RTPR, 0x12);
! 652:
! 653: STC_WRITE(sc, STC_MCOR1, CD180_MCOR1_CDZD | STTY_RX_DTR_THRESHOLD);
! 654: STC_WRITE(sc, STC_MCOR2, CD180_MCOR2_CDOD);
! 655: STC_WRITE(sc, STC_MCR, 0);
! 656:
! 657: if (t->c_ospeed) {
! 658: STC_WRITE(sc, STC_TBPRH, tbprh);
! 659: STC_WRITE(sc, STC_TBPRL, tbprl);
! 660: }
! 661:
! 662: if (t->c_ispeed) {
! 663: STC_WRITE(sc, STC_RBPRH, rbprh);
! 664: STC_WRITE(sc, STC_RBPRL, rbprl);
! 665: }
! 666:
! 667: stty_write_ccr(sc, CD180_CCR_CMD_CHAN |
! 668: CD180_CCR_CHAN_TXEN | CD180_CCR_CHAN_RXEN);
! 669:
! 670: sp->sp_carrier = STC_READ(sc, STC_MSVR) & CD180_MSVR_CD;
! 671:
! 672: splx(s);
! 673: return (0);
! 674: }
! 675:
! 676: int
! 677: sttyread(dev, uio, flags)
! 678: dev_t dev;
! 679: struct uio *uio;
! 680: int flags;
! 681: {
! 682: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 683: struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
! 684: struct tty *tp = sp->sp_tty;
! 685:
! 686: return ((*linesw[tp->t_line].l_read)(tp, uio, flags));
! 687: }
! 688:
! 689: int
! 690: sttywrite(dev, uio, flags)
! 691: dev_t dev;
! 692: struct uio *uio;
! 693: int flags;
! 694: {
! 695: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 696: struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
! 697: struct tty *tp = sp->sp_tty;
! 698:
! 699: return ((*linesw[tp->t_line].l_write)(tp, uio, flags));
! 700: }
! 701:
! 702: struct tty *
! 703: sttytty(dev)
! 704: dev_t dev;
! 705: {
! 706: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
! 707: struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
! 708:
! 709: return (sp->sp_tty);
! 710: }
! 711:
! 712: int
! 713: sttystop(tp, flags)
! 714: struct tty *tp;
! 715: int flags;
! 716: {
! 717: struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
! 718: struct stty_port *sp = &sc->sc_port[SPIF_PORT(tp->t_dev)];
! 719: int s;
! 720:
! 721: s = spltty();
! 722: if (ISSET(tp->t_state, TS_BUSY)) {
! 723: if (!ISSET(tp->t_state, TS_TTSTOP))
! 724: SET(tp->t_state, TS_FLUSH);
! 725: SET(sp->sp_flags, STTYF_STOP);
! 726: }
! 727: splx(s);
! 728: return (0);
! 729: }
! 730:
! 731: void
! 732: stty_start(tp)
! 733: struct tty *tp;
! 734: {
! 735: struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
! 736: struct stty_port *sp = &stc->sc_port[SPIF_PORT(tp->t_dev)];
! 737: struct spif_softc *sc = sp->sp_sc;
! 738: int s;
! 739:
! 740: s = spltty();
! 741:
! 742: if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) {
! 743: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 744: if (ISSET(tp->t_state, TS_ASLEEP)) {
! 745: CLR(tp->t_state, TS_ASLEEP);
! 746: wakeup(&tp->t_outq);
! 747: }
! 748: selwakeup(&tp->t_wsel);
! 749: }
! 750: if (tp->t_outq.c_cc) {
! 751: sp->sp_txc = ndqb(&tp->t_outq, 0);
! 752: sp->sp_txp = tp->t_outq.c_cf;
! 753: SET(tp->t_state, TS_BUSY);
! 754: STC_WRITE(sc, STC_CAR, sp->sp_channel);
! 755: STC_WRITE(sc, STC_SRER,
! 756: STC_READ(sc, STC_SRER) | CD180_SRER_TXD);
! 757: }
! 758: }
! 759:
! 760: splx(s);
! 761: }
! 762:
! 763: int
! 764: spifstcintr_rxexception(sc, needsoftp)
! 765: struct spif_softc *sc;
! 766: int *needsoftp;
! 767: {
! 768: struct stty_port *sp;
! 769: u_int8_t channel, *ptr;
! 770:
! 771: channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
! 772: sp = &sc->sc_ttys->sc_port[channel];
! 773: ptr = sp->sp_rput;
! 774: *ptr++ = STC_READ(sc, STC_RCSR);
! 775: *ptr++ = STC_READ(sc, STC_RDR);
! 776: if (ptr == sp->sp_rend)
! 777: ptr = sp->sp_rbuf;
! 778: if (ptr == sp->sp_rget) {
! 779: if (ptr == sp->sp_rbuf)
! 780: ptr = sp->sp_rend;
! 781: ptr -= 2;
! 782: SET(sp->sp_flags, STTYF_RING_OVERFLOW);
! 783: }
! 784: STC_WRITE(sc, STC_EOSRR, 0);
! 785: *needsoftp = 1;
! 786: sp->sp_rput = ptr;
! 787: return (1);
! 788: }
! 789:
! 790: int
! 791: spifstcintr_rx(sc, needsoftp)
! 792: struct spif_softc *sc;
! 793: int *needsoftp;
! 794: {
! 795: struct stty_port *sp;
! 796: u_int8_t channel, *ptr, cnt, rcsr;
! 797: int i;
! 798:
! 799: channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
! 800: sp = &sc->sc_ttys->sc_port[channel];
! 801: ptr = sp->sp_rput;
! 802: cnt = STC_READ(sc, STC_RDCR);
! 803: for (i = 0; i < cnt; i++) {
! 804: *ptr++ = 0;
! 805: rcsr = STC_READ(sc, STC_RCSR);
! 806: *ptr++ = STC_READ(sc, STC_RDR);
! 807: if (ptr == sp->sp_rend)
! 808: ptr = sp->sp_rbuf;
! 809: if (ptr == sp->sp_rget) {
! 810: if (ptr == sp->sp_rbuf)
! 811: ptr = sp->sp_rend;
! 812: ptr -= 2;
! 813: SET(sp->sp_flags, STTYF_RING_OVERFLOW);
! 814: break;
! 815: }
! 816: }
! 817: STC_WRITE(sc, STC_EOSRR, 0);
! 818: if (cnt) {
! 819: *needsoftp = 1;
! 820: sp->sp_rput = ptr;
! 821: }
! 822: return (1);
! 823: }
! 824:
! 825: int
! 826: spifstcintr_tx(sc, needsoftp)
! 827: struct spif_softc *sc;
! 828: int *needsoftp;
! 829: {
! 830: struct stty_port *sp;
! 831: u_int8_t channel, ch;
! 832: int cnt = 0;
! 833:
! 834: channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
! 835: sp = &sc->sc_ttys->sc_port[channel];
! 836: if (!ISSET(sp->sp_flags, STTYF_STOP)) {
! 837: if (ISSET(sp->sp_flags, STTYF_SET_BREAK)) {
! 838: STC_WRITE(sc, STC_TDR, 0);
! 839: STC_WRITE(sc, STC_TDR, 0x81);
! 840: CLR(sp->sp_flags, STTYF_SET_BREAK);
! 841: cnt += 2;
! 842: }
! 843: if (ISSET(sp->sp_flags, STTYF_CLR_BREAK)) {
! 844: STC_WRITE(sc, STC_TDR, 0);
! 845: STC_WRITE(sc, STC_TDR, 0x83);
! 846: CLR(sp->sp_flags, STTYF_CLR_BREAK);
! 847: cnt += 2;
! 848: }
! 849:
! 850: while (sp->sp_txc > 0 && cnt < (CD180_TX_FIFO_SIZE-1)) {
! 851: ch = *sp->sp_txp;
! 852: sp->sp_txc--;
! 853: sp->sp_txp++;
! 854:
! 855: if (ch == 0) {
! 856: STC_WRITE(sc, STC_TDR, ch);
! 857: cnt++;
! 858: }
! 859: STC_WRITE(sc, STC_TDR, ch);
! 860: cnt++;
! 861: }
! 862: }
! 863:
! 864: if (sp->sp_txc == 0 ||
! 865: ISSET(sp->sp_flags, STTYF_STOP)) {
! 866: STC_WRITE(sc, STC_SRER, STC_READ(sc, STC_SRER) &
! 867: (~CD180_SRER_TXD));
! 868: CLR(sp->sp_flags, STTYF_STOP);
! 869: SET(sp->sp_flags, STTYF_DONE);
! 870: *needsoftp = 1;
! 871: }
! 872:
! 873: STC_WRITE(sc, STC_EOSRR, 0);
! 874:
! 875: return (1);
! 876: }
! 877:
! 878: int
! 879: spifstcintr_mx(sc, needsoftp)
! 880: struct spif_softc *sc;
! 881: int *needsoftp;
! 882: {
! 883: struct stty_port *sp;
! 884: u_int8_t channel, mcr;
! 885:
! 886: channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
! 887: sp = &sc->sc_ttys->sc_port[channel];
! 888: mcr = STC_READ(sc, STC_MCR);
! 889: if (mcr & CD180_MCR_CD) {
! 890: SET(sp->sp_flags, STTYF_CDCHG);
! 891: *needsoftp = 1;
! 892: }
! 893: STC_WRITE(sc, STC_MCR, 0);
! 894: STC_WRITE(sc, STC_EOSRR, 0);
! 895: return (1);
! 896: }
! 897:
! 898: int
! 899: spifstcintr(vsc)
! 900: void *vsc;
! 901: {
! 902: struct spif_softc *sc = (struct spif_softc *)vsc;
! 903: int needsoft = 0, r = 0, i;
! 904: u_int8_t ar;
! 905:
! 906: for (i = 0; i < 8; i++) {
! 907: ar = ISTC_READ(sc, STC_RRAR) & CD180_GSVR_IMASK;
! 908: if (ar == CD180_GSVR_RXGOOD)
! 909: r |= spifstcintr_rx(sc, &needsoft);
! 910: else if (ar == CD180_GSVR_RXEXCEPTION)
! 911: r |= spifstcintr_rxexception(sc, &needsoft);
! 912: }
! 913:
! 914: for (i = 0; i < 8; i++) {
! 915: ar = ISTC_READ(sc, STC_TRAR) & CD180_GSVR_IMASK;
! 916: if (ar == CD180_GSVR_TXDATA)
! 917: r |= spifstcintr_tx(sc, &needsoft);
! 918: }
! 919:
! 920: for (i = 0; i < 8; i++) {
! 921: ar = ISTC_READ(sc, STC_MRAR) & CD180_GSVR_IMASK;
! 922: if (ar == CD180_GSVR_STATCHG)
! 923: r |= spifstcintr_mx(sc, &needsoft);
! 924: }
! 925:
! 926: if (needsoft)
! 927: softintr_schedule(sc->sc_softih);
! 928: return (r);
! 929: }
! 930:
! 931: void
! 932: spifsoftintr(vsc)
! 933: void *vsc;
! 934: {
! 935: struct spif_softc *sc = (struct spif_softc *)vsc;
! 936: struct stty_softc *stc = sc->sc_ttys;
! 937: int r = 0, i, data, s, flags;
! 938: u_int8_t stat, msvr;
! 939: struct stty_port *sp;
! 940: struct tty *tp;
! 941:
! 942: if (stc != NULL) {
! 943: for (i = 0; i < stc->sc_nports; i++) {
! 944: sp = &stc->sc_port[i];
! 945: tp = sp->sp_tty;
! 946:
! 947: if (!ISSET(tp->t_state, TS_ISOPEN))
! 948: continue;
! 949:
! 950: while (sp->sp_rget != sp->sp_rput) {
! 951: stat = sp->sp_rget[0];
! 952: data = sp->sp_rget[1];
! 953: sp->sp_rget += 2;
! 954: if (sp->sp_rget == sp->sp_rend)
! 955: sp->sp_rget = sp->sp_rbuf;
! 956:
! 957: if (stat & (CD180_RCSR_BE | CD180_RCSR_FE))
! 958: data |= TTY_FE;
! 959:
! 960: if (stat & CD180_RCSR_PE)
! 961: data |= TTY_PE;
! 962:
! 963: (*linesw[tp->t_line].l_rint)(data, tp);
! 964: r = 1;
! 965: }
! 966:
! 967: s = splhigh();
! 968: flags = sp->sp_flags;
! 969: CLR(sp->sp_flags, STTYF_DONE | STTYF_CDCHG |
! 970: STTYF_RING_OVERFLOW);
! 971: splx(s);
! 972:
! 973: if (ISSET(flags, STTYF_CDCHG)) {
! 974: s = spltty();
! 975: STC_WRITE(sc, STC_CAR, i);
! 976: msvr = STC_READ(sc, STC_MSVR);
! 977: splx(s);
! 978:
! 979: sp->sp_carrier = msvr & CD180_MSVR_CD;
! 980: (*linesw[tp->t_line].l_modem)(tp,
! 981: sp->sp_carrier);
! 982: r = 1;
! 983: }
! 984:
! 985: if (ISSET(flags, STTYF_RING_OVERFLOW)) {
! 986: log(LOG_WARNING, "%s-%x: ring overflow\n",
! 987: stc->sc_dev.dv_xname, i);
! 988: r = 1;
! 989: }
! 990:
! 991: if (ISSET(flags, STTYF_DONE)) {
! 992: ndflush(&tp->t_outq,
! 993: sp->sp_txp - tp->t_outq.c_cf);
! 994: CLR(tp->t_state, TS_BUSY);
! 995: (*linesw[tp->t_line].l_start)(tp);
! 996: r = 1;
! 997: }
! 998: }
! 999: }
! 1000: }
! 1001:
! 1002: void
! 1003: stty_write_ccr(sc, val)
! 1004: struct spif_softc *sc;
! 1005: u_int8_t val;
! 1006: {
! 1007: int tries = 100000;
! 1008:
! 1009: while (STC_READ(sc, STC_CCR) && tries--)
! 1010: /*EMPTY*/;
! 1011: if (tries == 0)
! 1012: printf("%s: ccr timeout\n", sc->sc_dev.dv_xname);
! 1013: STC_WRITE(sc, STC_CCR, val);
! 1014: }
! 1015:
! 1016: int
! 1017: stty_compute_baud(speed, clock, bprlp, bprhp)
! 1018: speed_t speed;
! 1019: int clock;
! 1020: u_int8_t *bprlp, *bprhp;
! 1021: {
! 1022: u_int32_t rate;
! 1023:
! 1024: rate = (2 * clock) / (16 * speed);
! 1025: if (rate & 1)
! 1026: rate = (rate >> 1) + 1;
! 1027: else
! 1028: rate = rate >> 1;
! 1029:
! 1030: if (rate > 0xffff || rate == 0)
! 1031: return (1);
! 1032:
! 1033: *bprlp = rate & 0xff;
! 1034: *bprhp = (rate >> 8) & 0xff;
! 1035: return (0);
! 1036: }
! 1037:
! 1038: int
! 1039: sbppmatch(parent, vcf, aux)
! 1040: struct device *parent;
! 1041: void *vcf, *aux;
! 1042: {
! 1043: struct spif_softc *sc = (struct spif_softc *)parent;
! 1044:
! 1045: return (aux == sbppmatch && sc->sc_bpps == NULL);
! 1046: }
! 1047:
! 1048: void
! 1049: sbppattach(parent, dev, aux)
! 1050: struct device *parent, *dev;
! 1051: void *aux;
! 1052: {
! 1053: struct spif_softc *sc = (struct spif_softc *)parent;
! 1054: struct sbpp_softc *psc = (struct sbpp_softc *)dev;
! 1055: int port;
! 1056:
! 1057: sc->sc_bpps = psc;
! 1058:
! 1059: for (port = 0; port < sc->sc_npar; port++) {
! 1060: }
! 1061:
! 1062: psc->sc_nports = port;
! 1063: printf(": %d port%s\n", port, port == 1 ? "" : "s");
! 1064: }
! 1065:
! 1066: int
! 1067: sbppopen(dev, flags, mode, p)
! 1068: dev_t dev;
! 1069: int flags;
! 1070: int mode;
! 1071: struct proc *p;
! 1072: {
! 1073: return (ENXIO);
! 1074: }
! 1075:
! 1076: int
! 1077: sbppclose(dev, flags, mode, p)
! 1078: dev_t dev;
! 1079: int flags;
! 1080: int mode;
! 1081: struct proc *p;
! 1082: {
! 1083: return (ENXIO);
! 1084: }
! 1085:
! 1086: int
! 1087: spifppcintr(v)
! 1088: void *v;
! 1089: {
! 1090: return (0);
! 1091: }
! 1092:
! 1093: int
! 1094: sbppread(dev, uio, flags)
! 1095: dev_t dev;
! 1096: struct uio *uio;
! 1097: int flags;
! 1098: {
! 1099: return (sbpp_rw(dev, uio));
! 1100: }
! 1101:
! 1102: int
! 1103: sbppwrite(dev, uio, flags)
! 1104: dev_t dev;
! 1105: struct uio *uio;
! 1106: int flags;
! 1107: {
! 1108: return (sbpp_rw(dev, uio));
! 1109: }
! 1110:
! 1111: int
! 1112: sbpp_rw(dev, uio)
! 1113: dev_t dev;
! 1114: struct uio *uio;
! 1115: {
! 1116: return (ENXIO);
! 1117: }
! 1118:
! 1119: int
! 1120: sbpppoll(dev, events, p)
! 1121: dev_t dev;
! 1122: int events;
! 1123: struct proc *p;
! 1124: {
! 1125: return (seltrue(dev, events, p));
! 1126: }
! 1127:
! 1128: int
! 1129: sbppioctl(dev, cmd, data, flags, p)
! 1130: dev_t dev;
! 1131: u_long cmd;
! 1132: caddr_t data;
! 1133: int flags;
! 1134: struct proc *p;
! 1135: {
! 1136: int error;
! 1137:
! 1138: error = ENOTTY;
! 1139:
! 1140: return (error);
! 1141: }
CVSweb