Annotation of sys/dev/ic/cy.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cy.c,v 1.25 2005/11/21 18:16:39 millert Exp $ */
! 2: /*
! 3: * Copyright (c) 1996 Timo Rossi.
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: * 3. Neither the name of the author nor the names of contributors
! 15: * may be used to endorse or promote products derived from this software
! 16: * without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 28: * SUCH DAMAGE.
! 29: */
! 30:
! 31: /*
! 32: * cy.c
! 33: *
! 34: * Driver for Cyclades Cyclom-8/16/32 multiport serial cards
! 35: * (currently not tested with Cyclom-32 cards)
! 36: *
! 37: * Timo Rossi, 1996
! 38: *
! 39: * Supports both ISA and PCI Cyclom cards
! 40: *
! 41: * Uses CD1400 automatic CTS flow control, and
! 42: * if CY_HW_RTS is defined, uses CD1400 automatic input flow control.
! 43: * This requires a special cable that exchanges the RTS and DTR lines.
! 44: *
! 45: * Lots of debug output can be enabled by defining CY_DEBUG
! 46: * Some debugging counters (number of receive/transmit interrupts etc.)
! 47: * can be enabled by defining CY_DEBUG1
! 48: *
! 49: * This version uses the bus_space/io_??() stuff
! 50: *
! 51: */
! 52:
! 53: /* NCY is the number of Cyclom cards in the machine */
! 54: #include "cy.h"
! 55: #if NCY > 0
! 56:
! 57: #include <sys/types.h>
! 58: #include <sys/param.h>
! 59: #include <sys/ioctl.h>
! 60: #include <sys/syslog.h>
! 61: #include <sys/fcntl.h>
! 62: #include <sys/tty.h>
! 63: #include <sys/proc.h>
! 64: #include <sys/conf.h>
! 65: #include <sys/user.h>
! 66: #include <sys/selinfo.h>
! 67: #include <sys/device.h>
! 68: #include <sys/malloc.h>
! 69: #include <sys/systm.h>
! 70:
! 71: #include <machine/bus.h>
! 72: #include <machine/intr.h>
! 73:
! 74: #if NCY_ISA > 0
! 75: #include <dev/isa/isavar.h>
! 76: #include <dev/isa/isareg.h>
! 77: #endif /* NCY_ISA > 0 */
! 78: #if NCY_PCI > 0
! 79: #include <dev/pci/pcivar.h>
! 80: #include <dev/pci/pcireg.h>
! 81: #include <dev/pci/pcidevs.h>
! 82: #endif /* NCY_PCI > 0 */
! 83:
! 84: #include <dev/ic/cd1400reg.h>
! 85: #include <dev/ic/cyreg.h>
! 86:
! 87:
! 88: int cy_intr(void *);
! 89: int cyparam(struct tty *, struct termios *);
! 90: void cystart(struct tty *);
! 91: void cy_poll(void *);
! 92: int cy_modem_control(struct cy_port *, int, int);
! 93: void cy_enable_transmitter(struct cy_port *);
! 94: void cd1400_channel_cmd(struct cy_port *, int);
! 95: int cy_speed(speed_t, int *, int *, int);
! 96:
! 97: struct cfdriver cy_cd = {
! 98: NULL, "cy", DV_TTY
! 99: };
! 100:
! 101: /*
! 102: * Common probe routine
! 103: *
! 104: * returns the number of chips found.
! 105: */
! 106: int
! 107: cy_probe_common(bus_space_tag_t memt, bus_space_handle_t memh, int bustype)
! 108: {
! 109: int cy_chip, chip_offs;
! 110: u_char firmware_ver;
! 111: int nchips;
! 112:
! 113: /* Cyclom card hardware reset */
! 114: bus_space_write_1(memt, memh, CY16_RESET<<bustype, 0);
! 115: DELAY(500); /* wait for reset to complete */
! 116: bus_space_write_1(memt, memh, CY_CLEAR_INTR<<bustype, 0);
! 117:
! 118: #ifdef CY_DEBUG
! 119: printf("cy: card reset done\n");
! 120: #endif
! 121:
! 122: nchips = 0;
! 123:
! 124: for (cy_chip = 0, chip_offs = 0;
! 125: cy_chip < CY_MAX_CD1400s;
! 126: cy_chip++, chip_offs += (CY_CD1400_MEMSPACING << bustype)) {
! 127: int i;
! 128:
! 129: /* the last 4 cd1400s are 'interleaved'
! 130: with the first 4 on 32-port boards */
! 131: if (cy_chip == 4)
! 132: chip_offs -= (CY32_ADDR_FIX << bustype);
! 133:
! 134: #ifdef CY_DEBUG
! 135: printf("cy: probe chip %d offset 0x%lx ... ",
! 136: cy_chip, chip_offs);
! 137: #endif
! 138:
! 139: /* wait until the chip is ready for command */
! 140: DELAY(1000);
! 141: if (bus_space_read_1(memt, memh, chip_offs +
! 142: ((CD1400_CCR << 1) << bustype)) != 0) {
! 143: #ifdef CY_DEBUG
! 144: printf("not ready for command\n");
! 145: #endif
! 146: break;
! 147: }
! 148:
! 149: /* clear the firmware version reg. */
! 150: bus_space_write_1(memt, memh, chip_offs +
! 151: ((CD1400_GFRCR << 1) << bustype), 0);
! 152:
! 153: /*
! 154: * On Cyclom-16 references to non-existent chip 4
! 155: * actually access chip 0 (address line 9 not decoded).
! 156: * Here we check if the clearing of chip 4 GFRCR actually
! 157: * cleared chip 0 GFRCR. In that case we have a 16 port card.
! 158: */
! 159: if (cy_chip == 4 &&
! 160: bus_space_read_1(memt, memh, chip_offs +
! 161: ((CD1400_GFRCR << 1) << bustype)) == 0)
! 162: break;
! 163:
! 164: /* reset the chip */
! 165: bus_space_write_1(memt, memh, chip_offs +
! 166: ((CD1400_CCR << 1) << bustype),
! 167: CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
! 168:
! 169: /* wait for the chip to initialize itself */
! 170: for (i = 0; i < 200; i++) {
! 171: DELAY(50);
! 172: firmware_ver = bus_space_read_1(memt, memh, chip_offs +
! 173: ((CD1400_GFRCR << 1) << bustype));
! 174: if ((firmware_ver & 0xf0) == 0x40) /* found a CD1400 */
! 175: break;
! 176: }
! 177: #ifdef CY_DEBUG
! 178: printf("firmware version 0x%x\n", firmware_ver);
! 179: #endif
! 180:
! 181: if ((firmware_ver & 0xf0) != 0x40)
! 182: break;
! 183:
! 184: /* firmware version OK, CD1400 found */
! 185: nchips++;
! 186: }
! 187:
! 188: if (nchips == 0) {
! 189: #ifdef CY_DEBUG
! 190: printf("no CD1400s found\n");
! 191: #endif
! 192: return (0);
! 193: }
! 194:
! 195: #ifdef CY_DEBUG
! 196: printf("found %d CD1400s\n", nchips);
! 197: #endif
! 198:
! 199: return (nchips);
! 200: }
! 201:
! 202: void
! 203: cy_attach(parent, self)
! 204: struct device *parent, *self;
! 205: {
! 206: int card, port, cy_chip, num_chips, cdu, chip_offs, cy_clock;
! 207: struct cy_softc *sc = (void *)self;
! 208:
! 209: card = sc->sc_dev.dv_unit;
! 210: num_chips = sc->sc_nr_cd1400s;
! 211: if (num_chips == 0)
! 212: return;
! 213:
! 214: timeout_set(&sc->sc_poll_to, cy_poll, sc);
! 215: bzero(sc->sc_ports, sizeof(sc->sc_ports));
! 216: sc->sc_nports = num_chips * CD1400_NO_OF_CHANNELS;
! 217:
! 218: port = 0;
! 219: for (cy_chip = 0, chip_offs = 0;
! 220: cy_chip < num_chips;
! 221: cy_chip++, chip_offs += (CY_CD1400_MEMSPACING<<sc->sc_bustype)) {
! 222: if (cy_chip == 4)
! 223: chip_offs -= (CY32_ADDR_FIX<<sc->sc_bustype);
! 224:
! 225: #ifdef CY_DEBUG
! 226: printf("attach CD1400 #%d offset 0x%x\n", cy_chip, chip_offs);
! 227: #endif
! 228: sc->sc_cd1400_offs[cy_chip] = chip_offs;
! 229:
! 230: /* configure port 0 as serial port
! 231: (should already be after reset) */
! 232: cd_write_reg_sc(sc, cy_chip, CD1400_GCR, 0);
! 233:
! 234: /* Set cy_clock depending on firmware version */
! 235: if (cd_read_reg_sc(sc, cy_chip, CD1400_GFRCR) <= 0x46)
! 236: cy_clock = CY_CLOCK;
! 237: else
! 238: cy_clock = CY_CLOCK_60;
! 239:
! 240: /* set up a receive timeout period (1ms) */
! 241: cd_write_reg_sc(sc, cy_chip, CD1400_PPR,
! 242: (cy_clock / CD1400_PPR_PRESCALER / 1000) + 1);
! 243:
! 244: for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; cdu++) {
! 245: sc->sc_ports[port].cy_port_num = port;
! 246: sc->sc_ports[port].cy_memt = sc->sc_memt;
! 247: sc->sc_ports[port].cy_memh = sc->sc_memh;
! 248: sc->sc_ports[port].cy_chip_offs = chip_offs;
! 249: sc->sc_ports[port].cy_bustype = sc->sc_bustype;
! 250: sc->sc_ports[port].cy_clock = cy_clock;
! 251:
! 252: /* should we initialize anything else here? */
! 253: port++;
! 254: } /* for(each port on one CD1400...) */
! 255:
! 256: } /* for(each CD1400 on a card... ) */
! 257:
! 258: printf(": %d ports\n", port);
! 259:
! 260: /* ensure an edge for the next interrupt */
! 261: bus_space_write_1(sc->sc_memt, sc->sc_memh,
! 262: CY_CLEAR_INTR<<sc->sc_bustype, 0);
! 263: }
! 264:
! 265: /*
! 266: * open routine. returns zero if successful, else error code
! 267: */
! 268: int cyopen(dev_t, int, int, struct proc *);
! 269: int cyclose(dev_t, int, int, struct proc *);
! 270: int cyread(dev_t, struct uio *, int);
! 271: int cywrite(dev_t, struct uio *, int);
! 272: struct tty *cytty(dev_t);
! 273: int cyioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 274: int cystop(struct tty *, int flag);
! 275:
! 276: int
! 277: cyopen(dev, flag, mode, p)
! 278: dev_t dev;
! 279: int flag, mode;
! 280: struct proc *p;
! 281: {
! 282: int card = CY_CARD(dev);
! 283: int port = CY_PORT(dev);
! 284: struct cy_softc *sc;
! 285: struct cy_port *cy;
! 286: struct tty *tp;
! 287: int s, error;
! 288:
! 289: if (card >= cy_cd.cd_ndevs ||
! 290: (sc = cy_cd.cd_devs[card]) == NULL) {
! 291: return (ENXIO);
! 292: }
! 293:
! 294: #ifdef CY_DEBUG
! 295: printf("%s open port %d flag 0x%x mode 0x%x\n", sc->sc_dev.dv_xname,
! 296: port, flag, mode);
! 297: #endif
! 298:
! 299: cy = &sc->sc_ports[port];
! 300:
! 301: s = spltty();
! 302: if (cy->cy_tty == NULL) {
! 303: cy->cy_tty = ttymalloc();
! 304: }
! 305: splx(s);
! 306:
! 307: tp = cy->cy_tty;
! 308: tp->t_oproc = cystart;
! 309: tp->t_param = cyparam;
! 310: tp->t_dev = dev;
! 311:
! 312: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 313: SET(tp->t_state, TS_WOPEN);
! 314: ttychars(tp);
! 315: tp->t_iflag = TTYDEF_IFLAG;
! 316: tp->t_oflag = TTYDEF_OFLAG;
! 317: tp->t_cflag = TTYDEF_CFLAG;
! 318: if (ISSET(cy->cy_openflags, TIOCFLAG_CLOCAL))
! 319: SET(tp->t_cflag, CLOCAL);
! 320: if (ISSET(cy->cy_openflags, TIOCFLAG_CRTSCTS))
! 321: SET(tp->t_cflag, CRTSCTS);
! 322: if (ISSET(cy->cy_openflags, TIOCFLAG_MDMBUF))
! 323: SET(tp->t_cflag, MDMBUF);
! 324: tp->t_lflag = TTYDEF_LFLAG;
! 325: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
! 326:
! 327: s = spltty();
! 328:
! 329: /*
! 330: * Allocate input ring buffer if we don't already have one
! 331: */
! 332: if (cy->cy_ibuf == NULL) {
! 333: cy->cy_ibuf = malloc(IBUF_SIZE, M_DEVBUF, M_NOWAIT);
! 334: if (cy->cy_ibuf == NULL) {
! 335: printf("%s: (port %d) can't allocate input buffer\n",
! 336: sc->sc_dev.dv_xname, port);
! 337: splx(s);
! 338: return (ENOMEM);
! 339: }
! 340: cy->cy_ibuf_end = cy->cy_ibuf + IBUF_SIZE;
! 341: }
! 342:
! 343: /* mark the ring buffer as empty */
! 344: cy->cy_ibuf_rd_ptr = cy->cy_ibuf_wr_ptr = cy->cy_ibuf;
! 345:
! 346: /* select CD1400 channel */
! 347: cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN);
! 348: /* reset the channel */
! 349: cd1400_channel_cmd(cy, CD1400_CCR_CMDRESET);
! 350: /* encode unit (port) number in LIVR */
! 351: /* there is just enough space for 5 bits (32 ports) */
! 352: cd_write_reg(cy, CD1400_LIVR, port << 3);
! 353:
! 354: cy->cy_channel_control = 0;
! 355:
! 356: if (!timeout_pending(&sc->sc_poll_to))
! 357: timeout_add(&sc->sc_poll_to, 1);
! 358:
! 359: /* this sets parameters and raises DTR */
! 360: cyparam(tp, &tp->t_termios);
! 361:
! 362: ttsetwater(tp);
! 363:
! 364: /* raise RTS too */
! 365: cy_modem_control(cy, TIOCM_RTS, DMBIS);
! 366:
! 367: cy->cy_carrier_stat = cd_read_reg(cy, CD1400_MSVR2);
! 368:
! 369: /* enable receiver and modem change interrupts */
! 370: cd_write_reg(cy, CD1400_SRER,
! 371: CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
! 372:
! 373: if (CY_DIALOUT(dev) ||
! 374: ISSET(cy->cy_openflags, TIOCFLAG_SOFTCAR) ||
! 375: ISSET(tp->t_cflag, MDMBUF) ||
! 376: ISSET(cy->cy_carrier_stat, CD1400_MSVR2_CD))
! 377: SET(tp->t_state, TS_CARR_ON);
! 378: else
! 379: CLR(tp->t_state, TS_CARR_ON);
! 380: } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
! 381: return (EBUSY);
! 382: } else {
! 383: s = spltty();
! 384: }
! 385:
! 386: /* wait for carrier if necessary */
! 387: if (!ISSET(flag, O_NONBLOCK)) {
! 388: while (!ISSET(tp->t_cflag, CLOCAL) &&
! 389: !ISSET(tp->t_state, TS_CARR_ON)) {
! 390: SET(tp->t_state, TS_WOPEN);
! 391: error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
! 392: "cydcd", 0);
! 393: if (error != 0) {
! 394: splx(s);
! 395: CLR(tp->t_state, TS_WOPEN);
! 396: return (error);
! 397: }
! 398: }
! 399: }
! 400:
! 401: splx(s);
! 402:
! 403: return (*linesw[tp->t_line].l_open)(dev, tp);
! 404: }
! 405:
! 406: /*
! 407: * close routine. returns zero if successful, else error code
! 408: */
! 409: int
! 410: cyclose(dev, flag, mode, p)
! 411: dev_t dev;
! 412: int flag, mode;
! 413: struct proc *p;
! 414: {
! 415: int card = CY_CARD(dev);
! 416: int port = CY_PORT(dev);
! 417: struct cy_softc *sc = cy_cd.cd_devs[card];
! 418: struct cy_port *cy = &sc->sc_ports[port];
! 419: struct tty *tp = cy->cy_tty;
! 420: int s;
! 421:
! 422: #ifdef CY_DEBUG
! 423: printf("%s close port %d, flag 0x%x, mode 0x%x\n", sc->sc_dev.dv_xname,
! 424: port, flag, mode);
! 425: #endif
! 426:
! 427: (*linesw[tp->t_line].l_close)(tp, flag);
! 428: s = spltty();
! 429:
! 430: if (ISSET(tp->t_cflag, HUPCL) &&
! 431: !ISSET(cy->cy_openflags, TIOCFLAG_SOFTCAR)) {
! 432: /* drop DTR and RTS
! 433: (should we wait for output buffer to become empty first?) */
! 434: cy_modem_control(cy, 0, DMSET);
! 435: }
! 436:
! 437: /*
! 438: * XXX should we disable modem change and
! 439: * receive interrupts here or somewhere ?
! 440: */
! 441: CLR(tp->t_state, TS_BUSY | TS_FLUSH);
! 442:
! 443: splx(s);
! 444: ttyclose(tp);
! 445:
! 446: return (0);
! 447: }
! 448:
! 449: /*
! 450: * Read routine
! 451: */
! 452: int
! 453: cyread(dev, uio, flag)
! 454: dev_t dev;
! 455: struct uio *uio;
! 456: int flag;
! 457: {
! 458: int card = CY_CARD(dev);
! 459: int port = CY_PORT(dev);
! 460: struct cy_softc *sc = cy_cd.cd_devs[card];
! 461: struct cy_port *cy = &sc->sc_ports[port];
! 462: struct tty *tp = cy->cy_tty;
! 463:
! 464: #ifdef CY_DEBUG
! 465: printf("%s read port %d uio 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
! 466: port, uio, flag);
! 467: #endif
! 468:
! 469: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
! 470: }
! 471:
! 472: /*
! 473: * Write routine
! 474: */
! 475: int
! 476: cywrite(dev, uio, flag)
! 477: dev_t dev;
! 478: struct uio *uio;
! 479: int flag;
! 480: {
! 481: int card = CY_CARD(dev);
! 482: int port = CY_PORT(dev);
! 483: struct cy_softc *sc = cy_cd.cd_devs[card];
! 484: struct cy_port *cy = &sc->sc_ports[port];
! 485: struct tty *tp = cy->cy_tty;
! 486:
! 487: #ifdef CY_DEBUG
! 488: printf("%s write port %d uio 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
! 489: port, uio, flag);
! 490: #endif
! 491:
! 492: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
! 493: }
! 494:
! 495: /*
! 496: * return tty pointer
! 497: */
! 498: struct tty *
! 499: cytty(dev)
! 500: dev_t dev;
! 501: {
! 502: int card = CY_CARD(dev);
! 503: int port = CY_PORT(dev);
! 504: struct cy_softc *sc = cy_cd.cd_devs[card];
! 505: struct cy_port *cy = &sc->sc_ports[port];
! 506: struct tty *tp = cy->cy_tty;
! 507:
! 508: return (tp);
! 509: }
! 510:
! 511: /*
! 512: * ioctl routine
! 513: */
! 514: int
! 515: cyioctl(dev, cmd, data, flag, p)
! 516: dev_t dev;
! 517: u_long cmd;
! 518: caddr_t data;
! 519: int flag;
! 520: struct proc *p;
! 521: {
! 522: int card = CY_CARD(dev);
! 523: int port = CY_PORT(dev);
! 524: struct cy_softc *sc = cy_cd.cd_devs[card];
! 525: struct cy_port *cy = &sc->sc_ports[port];
! 526: struct tty *tp = cy->cy_tty;
! 527: int error;
! 528:
! 529: #ifdef CY_DEBUG
! 530: printf("%s port %d ioctl cmd 0x%x data 0x%x flag 0x%x\n",
! 531: sc->sc_dev.dv_xname, port, cmd, data, flag);
! 532: #endif
! 533:
! 534: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 535: if (error >= 0)
! 536: return (error);
! 537:
! 538: error = ttioctl(tp, cmd, data, flag, p);
! 539: if (error >= 0)
! 540: return (error);
! 541:
! 542: /* XXX should not allow dropping DTR when dialin? */
! 543:
! 544: switch (cmd) {
! 545: case TIOCSBRK: /* start break */
! 546: SET(cy->cy_flags, CYF_START_BREAK);
! 547: cy_enable_transmitter(cy);
! 548: break;
! 549:
! 550: case TIOCCBRK: /* stop break */
! 551: SET(cy->cy_flags, CYF_END_BREAK);
! 552: cy_enable_transmitter(cy);
! 553: break;
! 554:
! 555: case TIOCSDTR: /* DTR on */
! 556: cy_modem_control(cy, TIOCM_DTR, DMBIS);
! 557: break;
! 558:
! 559: case TIOCCDTR: /* DTR off */
! 560: cy_modem_control(cy, TIOCM_DTR, DMBIC);
! 561: break;
! 562:
! 563: case TIOCMSET: /* set new modem control line values */
! 564: cy_modem_control(cy, *((int *)data), DMSET);
! 565: break;
! 566:
! 567: case TIOCMBIS: /* turn modem control bits on */
! 568: cy_modem_control(cy, *((int *)data), DMBIS);
! 569: break;
! 570:
! 571: case TIOCMBIC: /* turn modem control bits off */
! 572: cy_modem_control(cy, *((int *)data), DMBIC);
! 573: break;
! 574:
! 575: case TIOCMGET: /* get modem control/status line state */
! 576: *((int *)data) = cy_modem_control(cy, 0, DMGET);
! 577: break;
! 578:
! 579: case TIOCGFLAGS:
! 580: *((int *)data) = cy->cy_openflags |
! 581: (CY_DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0);
! 582: break;
! 583:
! 584: case TIOCSFLAGS:
! 585: error = suser(p, 0);
! 586: if (error != 0)
! 587: return (EPERM);
! 588:
! 589: cy->cy_openflags = *((int *)data) &
! 590: (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
! 591: TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
! 592: break;
! 593:
! 594: default:
! 595: return (ENOTTY);
! 596: }
! 597:
! 598: return (0);
! 599: }
! 600:
! 601: /*
! 602: * start output
! 603: */
! 604: void
! 605: cystart(tp)
! 606: struct tty *tp;
! 607: {
! 608: int card = CY_CARD(tp->t_dev);
! 609: int port = CY_PORT(tp->t_dev);
! 610: struct cy_softc *sc = cy_cd.cd_devs[card];
! 611: struct cy_port *cy = &sc->sc_ports[port];
! 612: int s;
! 613:
! 614: #ifdef CY_DEBUG
! 615: printf("%s port %d start, tty 0x%x\n", sc->sc_dev.dv_xname, port, tp);
! 616: #endif
! 617:
! 618: s = spltty();
! 619:
! 620: #ifdef CY_DEBUG1
! 621: cy->cy_start_count++;
! 622: #endif
! 623:
! 624: if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) {
! 625: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 626: if (ISSET(tp->t_state, TS_ASLEEP)) {
! 627: CLR(tp->t_state, TS_ASLEEP);
! 628: wakeup(&tp->t_outq);
! 629: }
! 630:
! 631: selwakeup(&tp->t_wsel);
! 632:
! 633: if (tp->t_outq.c_cc == 0)
! 634: goto out;
! 635: }
! 636:
! 637: SET(tp->t_state, TS_BUSY);
! 638: cy_enable_transmitter(cy);
! 639: }
! 640: out:
! 641:
! 642: splx(s);
! 643: }
! 644:
! 645: /*
! 646: * stop output
! 647: */
! 648: int
! 649: cystop(tp, flag)
! 650: struct tty *tp;
! 651: int flag;
! 652: {
! 653: int card = CY_CARD(tp->t_dev);
! 654: int port = CY_PORT(tp->t_dev);
! 655: struct cy_softc *sc = cy_cd.cd_devs[card];
! 656: struct cy_port *cy = &sc->sc_ports[port];
! 657: int s;
! 658:
! 659: #ifdef CY_DEBUG
! 660: printf("%s port %d stop tty 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
! 661: port, tp, flag);
! 662: #endif
! 663:
! 664: s = spltty();
! 665:
! 666: if (ISSET(tp->t_state, TS_BUSY)) {
! 667: if (!ISSET(tp->t_state, TS_TTSTOP))
! 668: SET(tp->t_state, TS_FLUSH);
! 669:
! 670: /*
! 671: * the transmit interrupt routine will disable transmit when it
! 672: * notices that CYF_STOP has been set.
! 673: */
! 674: SET(cy->cy_flags, CYF_STOP);
! 675: }
! 676: splx(s);
! 677: return (0);
! 678: }
! 679:
! 680: /*
! 681: * parameter setting routine.
! 682: * returns 0 if successful, else returns error code
! 683: */
! 684: int
! 685: cyparam(tp, t)
! 686: struct tty *tp;
! 687: struct termios *t;
! 688: {
! 689: int card = CY_CARD(tp->t_dev);
! 690: int port = CY_PORT(tp->t_dev);
! 691: struct cy_softc *sc = cy_cd.cd_devs[card];
! 692: struct cy_port *cy = &sc->sc_ports[port];
! 693: int ibpr, obpr, i_clk_opt, o_clk_opt;
! 694: int s, opt;
! 695:
! 696: #ifdef CY_DEBUG
! 697: printf("%s port %d param tty 0x%x termios 0x%x\n", sc->sc_dev.dv_xname,
! 698: port, tp, t);
! 699: printf("ispeed %d ospeed %d\n", t->c_ispeed, t->c_ospeed);
! 700: #endif
! 701:
! 702: if (t->c_ospeed != 0 &&
! 703: cy_speed(t->c_ospeed, &o_clk_opt, &obpr, cy->cy_clock) < 0)
! 704: return (EINVAL);
! 705:
! 706: if (t->c_ispeed != 0 &&
! 707: cy_speed(t->c_ispeed, &i_clk_opt, &ibpr, cy->cy_clock) < 0)
! 708: return (EINVAL);
! 709:
! 710: s = spltty();
! 711:
! 712: /* hang up the line is ospeed is zero, else turn DTR on */
! 713: cy_modem_control(cy, TIOCM_DTR, (t->c_ospeed == 0 ? DMBIC : DMBIS));
! 714:
! 715: /* channel was selected by the above call to cy_modem_control() */
! 716: /* cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN); */
! 717:
! 718: /* set transmit speed */
! 719: if (t->c_ospeed != 0) {
! 720: cd_write_reg(cy, CD1400_TCOR, o_clk_opt);
! 721: cd_write_reg(cy, CD1400_TBPR, obpr);
! 722: }
! 723: /* set receive speed */
! 724: if (t->c_ispeed != 0) {
! 725: cd_write_reg(cy, CD1400_RCOR, i_clk_opt);
! 726: cd_write_reg(cy, CD1400_RBPR, ibpr);
! 727: }
! 728:
! 729: opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
! 730: | (ISSET(t->c_cflag, CREAD) ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
! 731:
! 732: if (opt != cy->cy_channel_control) {
! 733: cy->cy_channel_control = opt;
! 734: cd1400_channel_cmd(cy, opt);
! 735: }
! 736:
! 737: /* compute COR1 contents */
! 738: opt = 0;
! 739: if (ISSET(t->c_cflag, PARENB)) {
! 740: if (ISSET(t->c_cflag, PARODD))
! 741: opt |= CD1400_COR1_PARODD;
! 742: opt |= CD1400_COR1_PARNORMAL;
! 743: }
! 744:
! 745: if (!ISSET(t->c_iflag, INPCK))
! 746: opt |= CD1400_COR1_NOINPCK; /* no parity checking */
! 747:
! 748: if (ISSET(t->c_cflag, CSTOPB))
! 749: opt |= CD1400_COR1_STOP2;
! 750:
! 751: switch (t->c_cflag & CSIZE) {
! 752: case CS5:
! 753: opt |= CD1400_COR1_CS5;
! 754: break;
! 755:
! 756: case CS6:
! 757: opt |= CD1400_COR1_CS6;
! 758: break;
! 759:
! 760: case CS7:
! 761: opt |= CD1400_COR1_CS7;
! 762: break;
! 763:
! 764: default:
! 765: opt |= CD1400_COR1_CS8;
! 766: break;
! 767: }
! 768:
! 769: cd_write_reg(cy, CD1400_COR1, opt);
! 770:
! 771: #ifdef CY_DEBUG
! 772: printf("cor1 = 0x%x...", opt);
! 773: #endif
! 774:
! 775: /*
! 776: * use the CD1400 automatic CTS flow control if CRTSCTS is set
! 777: *
! 778: * CD1400_COR2_ETC is used because breaks are generated with
! 779: * embedded transmit commands
! 780: */
! 781: cd_write_reg(cy, CD1400_COR2,
! 782: CD1400_COR2_ETC |
! 783: (ISSET(t->c_cflag, CRTSCTS) ? CD1400_COR2_CCTS_OFLOW : 0));
! 784:
! 785: cd_write_reg(cy, CD1400_COR3, RX_FIFO_THRESHOLD);
! 786:
! 787: cd1400_channel_cmd(cy,
! 788: CD1400_CCR_CMDCORCHG |
! 789: CD1400_CCR_COR1 | CD1400_CCR_COR2 | CD1400_CCR_COR3);
! 790:
! 791: cd_write_reg(cy, CD1400_COR4, CD1400_COR4_PFO_EXCEPTION);
! 792: cd_write_reg(cy, CD1400_COR5, 0);
! 793:
! 794: /*
! 795: * set modem change option registers to generate interrupts
! 796: * on carrier detect changes.
! 797: *
! 798: * if hardware RTS handshaking is used (CY_HW_RTS, DTR and RTS lines
! 799: * exchanged), also set the handshaking threshold.
! 800: */
! 801: #ifdef CY_HW_RTS
! 802: cd_write_reg(cy, CD1400_MCOR1, CD1400_MCOR1_CDzd |
! 803: (ISSET(t->c_cflag, CRTSCTS) ? RX_DTR_THRESHOLD : 0));
! 804: #else
! 805: cd_write_reg(cy, CD1400_MCOR1, CD1400_MCOR1_CDzd);
! 806: #endif /* CY_HW_RTS */
! 807:
! 808: cd_write_reg(cy, CD1400_MCOR2, CD1400_MCOR2_CDod);
! 809:
! 810: /*
! 811: * set receive timeout to approx. 2ms
! 812: * could use more complex logic here...
! 813: * (but is it actually needed or even useful?)
! 814: */
! 815: cd_write_reg(cy, CD1400_RTPR, 2);
! 816:
! 817: /*
! 818: * should do anything else here?
! 819: * XXX check MDMBUF handshaking like in com.c?
! 820: */
! 821:
! 822: splx(s);
! 823: return (0);
! 824: }
! 825:
! 826: /*
! 827: * set/get modem line status
! 828: *
! 829: * bits can be: TIOCM_DTR, TIOCM_RTS, TIOCM_CTS, TIOCM_CD, TIOCM_RI, TIOCM_DSR
! 830: *
! 831: * RTS and DTR are exchanged if CY_HW_RTS is set
! 832: *
! 833: */
! 834: int
! 835: cy_modem_control(cy, bits, howto)
! 836: struct cy_port *cy;
! 837: int bits;
! 838: int howto;
! 839: {
! 840: int s, msvr;
! 841:
! 842: s = spltty();
! 843:
! 844: /* select channel */
! 845: cd_write_reg(cy, CD1400_CAR, cy->cy_port_num & CD1400_CAR_CHAN);
! 846:
! 847: /* does not manipulate RTS if it is used for flow control */
! 848: switch (howto) {
! 849: case DMGET:
! 850: bits = 0;
! 851: if (cy->cy_channel_control & CD1400_CCR_RCVEN)
! 852: bits |= TIOCM_LE;
! 853: msvr = cd_read_reg(cy, CD1400_MSVR2);
! 854: #ifdef CY_HW_RTS
! 855: if (cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS)
! 856: bits |= TIOCM_DTR;
! 857: if (msvr & CD1400_MSVR2_DTR)
! 858: bits |= TIOCM_RTS;
! 859: #else
! 860: if (cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS)
! 861: bits |= TIOCM_RTS;
! 862: if (msvr & CD1400_MSVR2_DTR)
! 863: bits |= TIOCM_DTR;
! 864: #endif /* CY_HW_RTS */
! 865: if (msvr & CD1400_MSVR2_CTS)
! 866: bits |= TIOCM_CTS;
! 867: if (msvr & CD1400_MSVR2_CD)
! 868: bits |= TIOCM_CD;
! 869: if (msvr & CD1400_MSVR2_DSR) /* not connected on some
! 870: Cyclom cards? */
! 871: bits |= TIOCM_DSR;
! 872: if (msvr & CD1400_MSVR2_RI) /* not connected on
! 873: Cyclom-8Y cards? */
! 874: bits |= TIOCM_RI;
! 875: splx(s);
! 876: return (bits);
! 877:
! 878: case DMSET: /* replace old values with new ones */
! 879: #ifdef CY_HW_RTS
! 880: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS))
! 881: cd_write_reg(cy, CD1400_MSVR2,
! 882: ((bits & TIOCM_RTS) ? CD1400_MSVR2_DTR : 0));
! 883: cd_write_reg(cy, CD1400_MSVR1,
! 884: ((bits & TIOCM_DTR) ? CD1400_MSVR1_RTS : 0));
! 885: #else
! 886: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS))
! 887: cd_write_reg(cy, CD1400_MSVR1,
! 888: ((bits & TIOCM_RTS) ? CD1400_MSVR1_RTS : 0));
! 889: cd_write_reg(cy, CD1400_MSVR2,
! 890: ((bits & TIOCM_DTR) ? CD1400_MSVR2_DTR : 0));
! 891: #endif /* CY_HW_RTS */
! 892: break;
! 893:
! 894: case DMBIS: /* set bits */
! 895: #ifdef CY_HW_RTS
! 896: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
! 897: (bits & TIOCM_RTS) != 0)
! 898: cd_write_reg(cy, CD1400_MSVR2, CD1400_MSVR2_DTR);
! 899: if (bits & TIOCM_DTR)
! 900: cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS);
! 901: #else
! 902: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
! 903: (bits & TIOCM_RTS) != 0)
! 904: cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS);
! 905: if (bits & TIOCM_DTR)
! 906: cd_write_reg(cy, CD1400_MSVR2, CD1400_MSVR2_DTR);
! 907: #endif /* CY_HW_RTS */
! 908: break;
! 909:
! 910: case DMBIC: /* clear bits */
! 911: #ifdef CY_HW_RTS
! 912: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
! 913: (bits & TIOCM_RTS))
! 914: cd_write_reg(cy, CD1400_MSVR2, 0);
! 915: if (bits & TIOCM_DTR)
! 916: cd_write_reg(cy, CD1400_MSVR1, 0);
! 917: #else
! 918: if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
! 919: (bits & TIOCM_RTS))
! 920: cd_write_reg(cy, CD1400_MSVR1, 0);
! 921: if (bits & TIOCM_DTR)
! 922: cd_write_reg(cy, CD1400_MSVR2, 0);
! 923: #endif /* CY_HW_RTS */
! 924: break;
! 925: }
! 926: splx(s);
! 927: return (0);
! 928: }
! 929:
! 930: /*
! 931: * Upper-level handler loop (called from timer interrupt?)
! 932: * This routine is common for multiple cards
! 933: */
! 934: void
! 935: cy_poll(void *arg)
! 936: {
! 937: int port;
! 938: struct cy_softc *sc = arg;
! 939: struct cy_port *cy;
! 940: struct tty *tp;
! 941: static int counter = 0;
! 942: #ifdef CY_DEBUG1
! 943: int did_something;
! 944: #endif
! 945:
! 946: int s;
! 947:
! 948: s = spltty();
! 949:
! 950: if (sc->sc_events == 0 && ++counter < 200) {
! 951: splx(s);
! 952: goto out;
! 953: }
! 954:
! 955: sc->sc_events = 0;
! 956: splx(s);
! 957:
! 958: #ifdef CY_DEBUG1
! 959: sc->sc_poll_count1++;
! 960: did_something = 0;
! 961: #endif
! 962:
! 963: for (port = 0; port < sc->sc_nports; port++) {
! 964: cy = &sc->sc_ports[port];
! 965: if ((tp = cy->cy_tty) == NULL || cy->cy_ibuf == NULL ||
! 966: !ISSET(tp->t_state, TS_ISOPEN | TS_WOPEN))
! 967: continue;
! 968:
! 969: /*
! 970: * handle received data
! 971: */
! 972: while (cy->cy_ibuf_rd_ptr != cy->cy_ibuf_wr_ptr) {
! 973: u_char line_stat;
! 974: int chr;
! 975:
! 976: line_stat = cy->cy_ibuf_rd_ptr[0];
! 977: chr = cy->cy_ibuf_rd_ptr[1];
! 978:
! 979: if (line_stat &
! 980: (CD1400_RDSR_BREAK|CD1400_RDSR_FE))
! 981: chr |= TTY_FE;
! 982: if (line_stat & CD1400_RDSR_PE)
! 983: chr |= TTY_PE;
! 984:
! 985: /*
! 986: * on an overrun error the data is treated as
! 987: * good just as it should be.
! 988: */
! 989:
! 990: #ifdef CY_DEBUG
! 991: printf("%s port %d ttyinput 0x%x\n",
! 992: sc->sc_dev.dv_xname, port, chr);
! 993: #endif
! 994:
! 995: (*linesw[tp->t_line].l_rint)(chr, tp);
! 996:
! 997: s = spltty(); /* really necessary? */
! 998: if ((cy->cy_ibuf_rd_ptr += 2) ==
! 999: cy->cy_ibuf_end)
! 1000: cy->cy_ibuf_rd_ptr = cy->cy_ibuf;
! 1001: splx(s);
! 1002:
! 1003: #ifdef CY_DEBUG1
! 1004: did_something = 1;
! 1005: #endif
! 1006: }
! 1007:
! 1008: #ifndef CY_HW_RTS
! 1009: /*
! 1010: * If we don't have any received data in ibuf and
! 1011: * CRTSCTS is on and RTS is turned off, it is time
! 1012: * to turn RTS back on
! 1013: */
! 1014: if (ISSET(tp->t_cflag, CRTSCTS)) {
! 1015: /* we can't use cy_modem_control() here as it
! 1016: doesn't change RTS if RTSCTS is on */
! 1017: cd_write_reg(cy, CD1400_CAR,
! 1018: port & CD1400_CAR_CHAN);
! 1019:
! 1020: if ((cd_read_reg(cy,
! 1021: CD1400_MSVR1) & CD1400_MSVR1_RTS) == 0) {
! 1022: cd_write_reg(cy, CD1400_MSVR1,
! 1023: CD1400_MSVR1_RTS);
! 1024: #ifdef CY_DEBUG1
! 1025: did_something = 1;
! 1026: #endif
! 1027: }
! 1028: }
! 1029: #endif /* CY_HW_RTS */
! 1030:
! 1031: /*
! 1032: * handle carrier changes
! 1033: */
! 1034: s = spltty();
! 1035: if (ISSET(cy->cy_flags, CYF_CARRIER_CHANGED)) {
! 1036: int carrier;
! 1037:
! 1038: CLR(cy->cy_flags, CYF_CARRIER_CHANGED);
! 1039: splx(s);
! 1040:
! 1041: carrier = ((cy->cy_carrier_stat &
! 1042: CD1400_MSVR2_CD) != 0);
! 1043:
! 1044: #ifdef CY_DEBUG
! 1045: printf("%s: cy_poll: carrier change "
! 1046: "(port %d, carrier %d)\n",
! 1047: sc->sc_dev.dv_xname, port, carrier);
! 1048: #endif
! 1049: if (CY_DIALIN(tp->t_dev) &&
! 1050: !(*linesw[tp->t_line].l_modem)(tp, carrier))
! 1051: cy_modem_control(cy, TIOCM_DTR, DMBIC);
! 1052:
! 1053: #ifdef CY_DEBUG1
! 1054: did_something = 1;
! 1055: #endif
! 1056: } else {
! 1057: splx(s);
! 1058: }
! 1059:
! 1060: s = spltty();
! 1061: if (ISSET(cy->cy_flags, CYF_START)) {
! 1062: CLR(cy->cy_flags, CYF_START);
! 1063: splx(s);
! 1064:
! 1065: (*linesw[tp->t_line].l_start)(tp);
! 1066:
! 1067: #ifdef CY_DEBUG1
! 1068: did_something = 1;
! 1069: #endif
! 1070: } else {
! 1071: splx(s);
! 1072: }
! 1073:
! 1074: /* could move this to even upper level... */
! 1075: if (cy->cy_fifo_overruns) {
! 1076: cy->cy_fifo_overruns = 0;
! 1077: /* doesn't report overrun count,
! 1078: but shouldn't really matter */
! 1079: log(LOG_WARNING, "%s: port %d fifo overrun\n",
! 1080: sc->sc_dev.dv_xname, port);
! 1081: }
! 1082: if (cy->cy_ibuf_overruns) {
! 1083: cy->cy_ibuf_overruns = 0;
! 1084: log(LOG_WARNING, "%s: port %d ibuf overrun\n",
! 1085: sc->sc_dev.dv_xname, port);
! 1086: }
! 1087: } /* for(port...) */
! 1088: #ifdef CY_DEBUG1
! 1089: if (did_something && counter >= 200)
! 1090: sc->sc_poll_count2++;
! 1091: #endif
! 1092:
! 1093: counter = 0;
! 1094:
! 1095: out:
! 1096: timeout_add(&sc->sc_poll_to, 1);
! 1097: }
! 1098:
! 1099: /*
! 1100: * hardware interrupt routine
! 1101: */
! 1102: int
! 1103: cy_intr(arg)
! 1104: void *arg;
! 1105: {
! 1106: struct cy_softc *sc = arg;
! 1107: struct cy_port *cy;
! 1108: int cy_chip, stat;
! 1109: int int_serviced = -1;
! 1110:
! 1111: /*
! 1112: * Check interrupt status of each CD1400 chip on this card
! 1113: * (multiple cards cannot share the same interrupt)
! 1114: */
! 1115: for (cy_chip = 0; cy_chip < sc->sc_nr_cd1400s; cy_chip++) {
! 1116:
! 1117: stat = cd_read_reg_sc(sc, cy_chip, CD1400_SVRR);
! 1118: if (stat == 0)
! 1119: continue;
! 1120:
! 1121: if (ISSET(stat, CD1400_SVRR_RXRDY)) {
! 1122: u_char save_car, save_rir, serv_type;
! 1123: u_char line_stat, recv_data, n_chars;
! 1124: u_char *buf_p;
! 1125:
! 1126: save_rir = cd_read_reg_sc(sc, cy_chip, CD1400_RIR);
! 1127: save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
! 1128: /* enter rx service */
! 1129: cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_rir);
! 1130:
! 1131: serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_RIVR);
! 1132: cy = &sc->sc_ports[serv_type >> 3];
! 1133:
! 1134: #ifdef CY_DEBUG1
! 1135: cy->cy_rx_int_count++;
! 1136: #endif
! 1137:
! 1138: buf_p = cy->cy_ibuf_wr_ptr;
! 1139:
! 1140: if (ISSET(serv_type, CD1400_RIVR_EXCEPTION)) {
! 1141: line_stat = cd_read_reg(cy, CD1400_RDSR);
! 1142: recv_data = cd_read_reg(cy, CD1400_RDSR);
! 1143:
! 1144: if (cy->cy_tty == NULL ||
! 1145: !ISSET(cy->cy_tty->t_state, TS_ISOPEN))
! 1146: goto end_rx_serv;
! 1147:
! 1148: #ifdef CY_DEBUG
! 1149: printf("%s port %d recv exception, "
! 1150: "line_stat 0x%x, char 0x%x\n",
! 1151: sc->sc_dev.dv_xname, cy->cy_port_num,
! 1152: line_stat, recv_data);
! 1153: #endif
! 1154: if (ISSET(line_stat, CD1400_RDSR_OE))
! 1155: cy->cy_fifo_overruns++;
! 1156:
! 1157: *buf_p++ = line_stat;
! 1158: *buf_p++ = recv_data;
! 1159: if (buf_p == cy->cy_ibuf_end)
! 1160: buf_p = cy->cy_ibuf;
! 1161:
! 1162: if (buf_p == cy->cy_ibuf_rd_ptr) {
! 1163: if (buf_p == cy->cy_ibuf)
! 1164: buf_p = cy->cy_ibuf_end;
! 1165: buf_p -= 2;
! 1166: cy->cy_ibuf_overruns++;
! 1167: }
! 1168: sc->sc_events = 1;
! 1169: } else { /* no exception, received data OK */
! 1170: n_chars = cd_read_reg(cy, CD1400_RDCR);
! 1171:
! 1172: /* If no tty or not open, discard data */
! 1173: if (cy->cy_tty == NULL ||
! 1174: !ISSET(cy->cy_tty->t_state, TS_ISOPEN)) {
! 1175: while (n_chars--)
! 1176: cd_read_reg(cy, CD1400_RDSR);
! 1177: goto end_rx_serv;
! 1178: }
! 1179:
! 1180: #ifdef CY_DEBUG
! 1181: printf("%s port %d receive ok %d chars\n",
! 1182: sc->sc_dev.dv_xname, cy->cy_port_num,
! 1183: n_chars);
! 1184: #endif
! 1185: while (n_chars--) {
! 1186: *buf_p++ = 0; /* status: OK */
! 1187: *buf_p++ = cd_read_reg(cy,
! 1188: CD1400_RDSR); /* data byte */
! 1189: if (buf_p == cy->cy_ibuf_end)
! 1190: buf_p = cy->cy_ibuf;
! 1191: if (buf_p == cy->cy_ibuf_rd_ptr) {
! 1192: if (buf_p == cy->cy_ibuf)
! 1193: buf_p = cy->cy_ibuf_end;
! 1194: buf_p -= 2;
! 1195: cy->cy_ibuf_overruns++;
! 1196: break;
! 1197: }
! 1198: }
! 1199: sc->sc_events = 1;
! 1200: }
! 1201:
! 1202: cy->cy_ibuf_wr_ptr = buf_p;
! 1203:
! 1204: #ifndef CY_HW_RTS
! 1205: /* RTS handshaking for incoming data */
! 1206: if (ISSET(cy->cy_tty->t_cflag, CRTSCTS)) {
! 1207: int bf;
! 1208:
! 1209: bf = buf_p - cy->cy_ibuf_rd_ptr;
! 1210: if (bf < 0)
! 1211: bf += IBUF_SIZE;
! 1212:
! 1213: if (bf > (IBUF_SIZE/2)) /* turn RTS off */
! 1214: cd_write_reg(cy, CD1400_MSVR1, 0);
! 1215: }
! 1216: #endif /* CY_HW_RTS */
! 1217:
! 1218: end_rx_serv:
! 1219: /* terminate service context */
! 1220: cd_write_reg(cy, CD1400_RIR, save_rir & 0x3f);
! 1221: cd_write_reg(cy, CD1400_CAR, save_car);
! 1222: int_serviced = 1;
! 1223: } /* if(rx_service...) */
! 1224:
! 1225: if (ISSET(stat, CD1400_SVRR_MDMCH)) {
! 1226: u_char save_car, save_mir, serv_type, modem_stat;
! 1227:
! 1228: save_mir = cd_read_reg_sc(sc, cy_chip, CD1400_MIR);
! 1229: save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
! 1230: /* enter modem service */
! 1231: cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_mir);
! 1232:
! 1233: serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_MIVR);
! 1234: cy = &sc->sc_ports[serv_type >> 3];
! 1235:
! 1236: #ifdef CY_DEBUG1
! 1237: cy->cy_modem_int_count++;
! 1238: #endif
! 1239:
! 1240: modem_stat = cd_read_reg(cy, CD1400_MSVR2);
! 1241:
! 1242: #ifdef CY_DEBUG
! 1243: printf("%s port %d modem line change, new stat 0x%x\n",
! 1244: sc->sc_dev.dv_xname, cy->cy_port_num, modem_stat);
! 1245: #endif
! 1246: if (ISSET((cy->cy_carrier_stat ^ modem_stat),
! 1247: CD1400_MSVR2_CD)) {
! 1248: SET(cy->cy_flags, CYF_CARRIER_CHANGED);
! 1249: sc->sc_events = 1;
! 1250: }
! 1251:
! 1252: cy->cy_carrier_stat = modem_stat;
! 1253:
! 1254: /* terminate service context */
! 1255: cd_write_reg(cy, CD1400_MIR, save_mir & 0x3f);
! 1256: cd_write_reg(cy, CD1400_CAR, save_car);
! 1257: int_serviced = 1;
! 1258: } /* if(modem_service...) */
! 1259:
! 1260: if (ISSET(stat, CD1400_SVRR_TXRDY)) {
! 1261: u_char save_car, save_tir, serv_type, count, ch;
! 1262: struct tty *tp;
! 1263:
! 1264: save_tir = cd_read_reg_sc(sc, cy_chip, CD1400_TIR);
! 1265: save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
! 1266: /* enter tx service */
! 1267: cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_tir);
! 1268:
! 1269: serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_TIVR);
! 1270: cy = &sc->sc_ports[serv_type >> 3];
! 1271:
! 1272: #ifdef CY_DEBUG1
! 1273: cy->cy_tx_int_count++;
! 1274: #endif
! 1275: #ifdef CY_DEBUG
! 1276: printf("%s port %d tx service\n", sc->sc_dev.dv_xname,
! 1277: cy->cy_port_num);
! 1278: #endif
! 1279:
! 1280: /* stop transmitting if no tty or CYF_STOP set */
! 1281: tp = cy->cy_tty;
! 1282: if (tp == NULL || ISSET(cy->cy_flags, CYF_STOP))
! 1283: goto txdone;
! 1284:
! 1285: count = 0;
! 1286: if (ISSET(cy->cy_flags, CYF_SEND_NUL)) {
! 1287: cd_write_reg(cy, CD1400_TDR, 0);
! 1288: cd_write_reg(cy, CD1400_TDR, 0);
! 1289: count += 2;
! 1290: CLR(cy->cy_flags, CYF_SEND_NUL);
! 1291: }
! 1292:
! 1293: if (tp->t_outq.c_cc > 0) {
! 1294: SET(tp->t_state, TS_BUSY);
! 1295: while (tp->t_outq.c_cc > 0 &&
! 1296: count < CD1400_TX_FIFO_SIZE) {
! 1297: ch = getc(&tp->t_outq);
! 1298: /* remember to double NUL characters
! 1299: because embedded transmit commands
! 1300: are enabled */
! 1301: if (ch == 0) {
! 1302: if (count >=
! 1303: CD1400_TX_FIFO_SIZE-2) {
! 1304: SET(cy->cy_flags,
! 1305: CYF_SEND_NUL);
! 1306: break;
! 1307: }
! 1308:
! 1309: cd_write_reg(cy, CD1400_TDR, ch);
! 1310: count++;
! 1311: }
! 1312:
! 1313: cd_write_reg(cy, CD1400_TDR, ch);
! 1314: count++;
! 1315: }
! 1316: } else {
! 1317: /* no data to send -- check if we should
! 1318: start/stop a break */
! 1319: /* XXX does this cause too much delay before
! 1320: breaks? */
! 1321: if (ISSET(cy->cy_flags, CYF_START_BREAK)) {
! 1322: cd_write_reg(cy, CD1400_TDR, 0);
! 1323: cd_write_reg(cy, CD1400_TDR, 0x81);
! 1324: CLR(cy->cy_flags, CYF_START_BREAK);
! 1325: }
! 1326: if (ISSET(cy->cy_flags, CYF_END_BREAK)) {
! 1327: cd_write_reg(cy, CD1400_TDR, 0);
! 1328: cd_write_reg(cy, CD1400_TDR, 0x83);
! 1329: CLR(cy->cy_flags, CYF_END_BREAK);
! 1330: }
! 1331: }
! 1332:
! 1333: if (tp->t_outq.c_cc == 0) {
! 1334: txdone:
! 1335: /*
! 1336: * No data to send or requested to stop.
! 1337: * Disable transmit interrupt
! 1338: */
! 1339: cd_write_reg(cy, CD1400_SRER,
! 1340: cd_read_reg(cy, CD1400_SRER)
! 1341: & ~CD1400_SRER_TXRDY);
! 1342: CLR(cy->cy_flags, CYF_STOP);
! 1343: CLR(tp->t_state, TS_BUSY);
! 1344: }
! 1345:
! 1346: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 1347: SET(cy->cy_flags, CYF_START);
! 1348: sc->sc_events = 1;
! 1349: }
! 1350:
! 1351: /* terminate service context */
! 1352: cd_write_reg(cy, CD1400_TIR, save_tir & 0x3f);
! 1353: cd_write_reg(cy, CD1400_CAR, save_car);
! 1354: int_serviced = 1;
! 1355: } /* if(tx_service...) */
! 1356: } /* for(...all CD1400s on a card) */
! 1357:
! 1358: /* ensure an edge for next interrupt */
! 1359: bus_space_write_1(sc->sc_memt, sc->sc_memh,
! 1360: CY_CLEAR_INTR<<sc->sc_bustype, 0);
! 1361: return (int_serviced);
! 1362: }
! 1363:
! 1364: /*
! 1365: * subroutine to enable CD1400 transmitter
! 1366: */
! 1367: void
! 1368: cy_enable_transmitter(cy)
! 1369: struct cy_port *cy;
! 1370: {
! 1371: int s;
! 1372: s = spltty();
! 1373: cd_write_reg(cy, CD1400_CAR, cy->cy_port_num & CD1400_CAR_CHAN);
! 1374: cd_write_reg(cy, CD1400_SRER, cd_read_reg(cy, CD1400_SRER)
! 1375: | CD1400_SRER_TXRDY);
! 1376: splx(s);
! 1377: }
! 1378:
! 1379: /*
! 1380: * Execute a CD1400 channel command
! 1381: */
! 1382: void
! 1383: cd1400_channel_cmd(cy, cmd)
! 1384: struct cy_port *cy;
! 1385: int cmd;
! 1386: {
! 1387: u_int waitcnt = 5 * 8 * 1024; /* approx 5 ms */
! 1388:
! 1389: #ifdef CY_DEBUG
! 1390: printf("c1400_channel_cmd cy 0x%x command 0x%x\n", cy, cmd);
! 1391: #endif
! 1392:
! 1393: /* wait until cd1400 is ready to process a new command */
! 1394: while (cd_read_reg(cy, CD1400_CCR) != 0 && waitcnt-- > 0)
! 1395: ;
! 1396:
! 1397: if (waitcnt == 0)
! 1398: log(LOG_ERR, "cy: channel command timeout\n");
! 1399:
! 1400: cd_write_reg(cy, CD1400_CCR, cmd);
! 1401: }
! 1402:
! 1403: /*
! 1404: * Compute clock option register and baud rate register values
! 1405: * for a given speed. Return 0 on success, -1 on failure.
! 1406: *
! 1407: * The error between requested and actual speed seems
! 1408: * to be well within allowed limits (less than 3%)
! 1409: * with every speed value between 50 and 150000 bps.
! 1410: */
! 1411: int
! 1412: cy_speed(speed_t speed, int *cor, int *bpr, int cy_clock)
! 1413: {
! 1414: int c, co, br;
! 1415:
! 1416: if (speed < 50 || speed > 150000)
! 1417: return (-1);
! 1418:
! 1419: for (c = 0, co = 8; co <= 2048; co <<= 2, c++) {
! 1420: br = (cy_clock + (co * speed) / 2) / (co * speed);
! 1421: if (br < 0x100) {
! 1422: *bpr = br;
! 1423: *cor = c;
! 1424: return (0);
! 1425: }
! 1426: }
! 1427:
! 1428: return (-1);
! 1429: }
! 1430:
! 1431: #endif /* NCY > 0 */
CVSweb