Annotation of sys/dev/pci/cz.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cz.c,v 1.9 2003/10/03 16:44:51 miod Exp $ */
! 2: /* $NetBSD: cz.c,v 1.15 2001/01/20 19:10:36 thorpej Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2000 Zembu Labs, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * Authors: Jason R. Thorpe <thorpej@zembu.com>
! 9: * Bill Studenmund <wrstuden@zembu.com>
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by Zembu Labs, Inc.
! 22: * 4. Neither the name of Zembu Labs nor the names of its employees may
! 23: * be used to endorse or promote products derived from this software
! 24: * without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
! 27: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
! 28: * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
! 29: * CLAIMED. IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
! 30: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 31: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 32: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 33: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 35: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 36: */
! 37:
! 38: /*
! 39: * Cyclades-Z series multi-port serial adapter driver for NetBSD.
! 40: *
! 41: * Some notes:
! 42: *
! 43: * - The Cyclades-Z has fully automatic hardware (and software!)
! 44: * flow control. We only utilize RTS/CTS flow control here,
! 45: * and it is implemented in a very simplistic manner. This
! 46: * may be an area of future work.
! 47: *
! 48: * - The PLX can map the either the board's RAM or host RAM
! 49: * into the MIPS's memory window. This would enable us to
! 50: * use less expensive (for us) memory reads/writes to host
! 51: * RAM, rather than time-consuming reads/writes to PCI
! 52: * memory space. However, the PLX can only map a 0-128M
! 53: * window, so we would have to ensure that the DMA address
! 54: * of the host RAM fits there. This is kind of a pain,
! 55: * so we just don't bother right now.
! 56: *
! 57: * - In a perfect world, we would use the autoconfiguration
! 58: * mechanism to attach the TTYs that we find. However,
! 59: * that leads to somewhat icky looking autoconfiguration
! 60: * messages (one for every TTY, up to 64 per board!). So
! 61: * we don't do it that way, but assign minors as if there
! 62: * were the max of 64 ports per board.
! 63: *
! 64: * - We don't bother with PPS support here. There are so many
! 65: * ports, each with a large amount of buffer space, that the
! 66: * normal mode of operation is to poll the boards regularly
! 67: * (generally, every 20ms or so). This makes this driver
! 68: * unsuitable for PPS, as the latency will be generally too
! 69: * high.
! 70: */
! 71: /*
! 72: * This driver inspired by the FreeBSD driver written by Brian J. McGovern
! 73: * for FreeBSD 3.2.
! 74: */
! 75:
! 76: #include <sys/param.h>
! 77: #include <sys/systm.h>
! 78: #include <sys/proc.h>
! 79: #include <sys/device.h>
! 80: #include <sys/malloc.h>
! 81: #include <sys/tty.h>
! 82: #include <sys/conf.h>
! 83: #include <sys/time.h>
! 84: #include <sys/kernel.h>
! 85: #include <sys/fcntl.h>
! 86: #include <sys/syslog.h>
! 87:
! 88: #include <dev/pci/pcireg.h>
! 89: #include <dev/pci/pcivar.h>
! 90: #include <dev/pci/pcidevs.h>
! 91: #include <dev/pci/czreg.h>
! 92:
! 93: #include <dev/pci/plx9060reg.h>
! 94: #include <dev/pci/plx9060var.h>
! 95:
! 96: #include <dev/microcode/cyclades/cyzfirm.h>
! 97:
! 98: #define CZ_DRIVER_VERSION 0x20000411
! 99:
! 100: #define CZ_POLL_MS 20
! 101:
! 102: /* These are the interrupts we always use. */
! 103: #define CZ_INTERRUPTS \
! 104: (C_IN_MDSR | C_IN_MRI | C_IN_MRTS | C_IN_MCTS | C_IN_TXBEMPTY | \
! 105: C_IN_TXFEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | C_IN_RXNNDT | \
! 106: C_IN_MDCD | C_IN_PR_ERROR | C_IN_FR_ERROR | C_IN_OVR_ERROR | \
! 107: C_IN_RXOFL | C_IN_IOCTLW | C_IN_RXBRK)
! 108:
! 109: /*
! 110: * cztty_softc:
! 111: *
! 112: * Per-channel (TTY) state.
! 113: */
! 114: struct cztty_softc {
! 115: struct cz_softc *sc_parent;
! 116: struct tty *sc_tty;
! 117:
! 118: struct timeout sc_diag_to;
! 119:
! 120: int sc_channel; /* Also used to flag unattached chan */
! 121: #define CZTTY_CHANNEL_DEAD -1
! 122:
! 123: bus_space_tag_t sc_chan_st; /* channel space tag */
! 124: bus_space_handle_t sc_chan_sh; /* channel space handle */
! 125: bus_space_handle_t sc_buf_sh; /* buffer space handle */
! 126:
! 127: u_int sc_overflows,
! 128: sc_parity_errors,
! 129: sc_framing_errors,
! 130: sc_errors;
! 131:
! 132: int sc_swflags;
! 133:
! 134: u_int32_t sc_rs_control_dtr,
! 135: sc_chanctl_hw_flow,
! 136: sc_chanctl_comm_baud,
! 137: sc_chanctl_rs_control,
! 138: sc_chanctl_comm_data_l,
! 139: sc_chanctl_comm_parity;
! 140: };
! 141:
! 142: /*
! 143: * cz_softc:
! 144: *
! 145: * Per-board state.
! 146: */
! 147: struct cz_softc {
! 148: struct device cz_dev; /* generic device info */
! 149: struct plx9060_config cz_plx; /* PLX 9060 config info */
! 150: bus_space_tag_t cz_win_st; /* window space tag */
! 151: bus_space_handle_t cz_win_sh; /* window space handle */
! 152: struct timeout cz_timeout; /* timeout for polling-mode */
! 153:
! 154: void *cz_ih; /* interrupt handle */
! 155:
! 156: u_int32_t cz_mailbox0; /* our MAILBOX0 value */
! 157: int cz_nchannels; /* number of channels */
! 158: int cz_nopenchan; /* number of open channels */
! 159: struct cztty_softc *cz_ports; /* our array of ports */
! 160:
! 161: bus_addr_t cz_fwctl; /* offset of firmware control */
! 162: };
! 163:
! 164: int cz_match(struct device *, void *, void *);
! 165: void cz_attach(struct device *, struct device *, void *);
! 166: int cz_wait_pci_doorbell(struct cz_softc *, char *);
! 167:
! 168: struct cfattach cz_ca = {
! 169: sizeof(struct cz_softc), cz_match, cz_attach
! 170: };
! 171:
! 172: void cz_reset_board(struct cz_softc *);
! 173: int cz_load_firmware(struct cz_softc *);
! 174:
! 175: int cz_intr(void *);
! 176: void cz_poll(void *);
! 177: int cztty_transmit(struct cztty_softc *, struct tty *);
! 178: int cztty_receive(struct cztty_softc *, struct tty *);
! 179:
! 180: struct cztty_softc * cztty_getttysoftc(dev_t dev);
! 181: int cztty_findmajor(void);
! 182: int cztty_major;
! 183: int cztty_attached_ttys;
! 184: int cz_timeout_ticks;
! 185:
! 186: cdev_decl(cztty);
! 187:
! 188: void czttystart(struct tty *tp);
! 189: int czttyparam(struct tty *tp, struct termios *t);
! 190: void cztty_shutdown(struct cztty_softc *sc);
! 191: void cztty_modem(struct cztty_softc *sc, int onoff);
! 192: void cztty_break(struct cztty_softc *sc, int onoff);
! 193: void tiocm_to_cztty(struct cztty_softc *sc, u_long how, int ttybits);
! 194: int cztty_to_tiocm(struct cztty_softc *sc);
! 195: void cztty_diag(void *arg);
! 196:
! 197: struct cfdriver cz_cd = {
! 198: 0, "cz", DV_TTY
! 199: };
! 200:
! 201: /*
! 202: * Macros to read and write the PLX.
! 203: */
! 204: #define CZ_PLX_READ(cz, reg) \
! 205: bus_space_read_4((cz)->cz_plx.plx_st, (cz)->cz_plx.plx_sh, (reg))
! 206: #define CZ_PLX_WRITE(cz, reg, val) \
! 207: bus_space_write_4((cz)->cz_plx.plx_st, (cz)->cz_plx.plx_sh, \
! 208: (reg), (val))
! 209:
! 210: /*
! 211: * Macros to read and write the FPGA. We must already be in the FPGA
! 212: * window for this.
! 213: */
! 214: #define CZ_FPGA_READ(cz, reg) \
! 215: bus_space_read_4((cz)->cz_win_st, (cz)->cz_win_sh, (reg))
! 216: #define CZ_FPGA_WRITE(cz, reg, val) \
! 217: bus_space_write_4((cz)->cz_win_st, (cz)->cz_win_sh, (reg), (val))
! 218:
! 219: /*
! 220: * Macros to read and write the firmware control structures in board RAM.
! 221: */
! 222: #define CZ_FWCTL_READ(cz, off) \
! 223: bus_space_read_4((cz)->cz_win_st, (cz)->cz_win_sh, \
! 224: (cz)->cz_fwctl + (off))
! 225:
! 226: #define CZ_FWCTL_WRITE(cz, off, val) \
! 227: bus_space_write_4((cz)->cz_win_st, (cz)->cz_win_sh, \
! 228: (cz)->cz_fwctl + (off), (val))
! 229:
! 230: /*
! 231: * Convenience macros for cztty routines. PLX window MUST be to RAM.
! 232: */
! 233: #define CZTTY_CHAN_READ(sc, off) \
! 234: bus_space_read_4((sc)->sc_chan_st, (sc)->sc_chan_sh, (off))
! 235:
! 236: #define CZTTY_CHAN_WRITE(sc, off, val) \
! 237: bus_space_write_4((sc)->sc_chan_st, (sc)->sc_chan_sh, \
! 238: (off), (val))
! 239:
! 240: #define CZTTY_BUF_READ(sc, off) \
! 241: bus_space_read_4((sc)->sc_chan_st, (sc)->sc_buf_sh, (off))
! 242:
! 243: #define CZTTY_BUF_WRITE(sc, off, val) \
! 244: bus_space_write_4((sc)->sc_chan_st, (sc)->sc_buf_sh, \
! 245: (off), (val))
! 246:
! 247: /*
! 248: * Convenience macros.
! 249: */
! 250: #define CZ_WIN_RAM(cz) \
! 251: do { \
! 252: CZ_PLX_WRITE((cz), PLX_LAS0BA, LOCAL_ADDR0_RAM); \
! 253: delay(100); \
! 254: } while (0)
! 255:
! 256: #define CZ_WIN_FPGA(cz) \
! 257: do { \
! 258: CZ_PLX_WRITE((cz), PLX_LAS0BA, LOCAL_ADDR0_FPGA); \
! 259: delay(100); \
! 260: } while (0)
! 261:
! 262: /*****************************************************************************
! 263: * Cyclades-Z controller code starts here...
! 264: *****************************************************************************/
! 265:
! 266: /*
! 267: * cz_match:
! 268: *
! 269: * Determine if the given PCI device is a Cyclades-Z board.
! 270: */
! 271: int
! 272: cz_match(parent, match, aux)
! 273: struct device *parent;
! 274: void *match, *aux;
! 275: {
! 276: struct pci_attach_args *pa = aux;
! 277:
! 278: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CYCLADES &&
! 279: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CYCLADES_CYCLOMZ_2)
! 280: return (1);
! 281: return (0);
! 282: }
! 283:
! 284: /*
! 285: * cz_attach:
! 286: *
! 287: * A Cyclades-Z board was found; attach it.
! 288: */
! 289: void
! 290: cz_attach(parent, self, aux)
! 291: struct device *parent, *self;
! 292: void *aux;
! 293: {
! 294: struct cz_softc *cz = (void *) self;
! 295: struct pci_attach_args *pa = aux;
! 296: pci_chipset_tag_t pc = pa->pa_pc;
! 297: pci_intr_handle_t ih;
! 298: const char *intrstr = NULL;
! 299: struct cztty_softc *sc;
! 300: struct tty *tp;
! 301: int i;
! 302:
! 303: cz->cz_plx.plx_pc = pa->pa_pc;
! 304: cz->cz_plx.plx_tag = pa->pa_tag;
! 305:
! 306: if (pci_mapreg_map(pa, PLX_PCI_RUNTIME_MEMADDR,
! 307: PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
! 308: &cz->cz_plx.plx_st, &cz->cz_plx.plx_sh, NULL, NULL, 0) != 0) {
! 309: printf(": unable to map PLX registers\n");
! 310: return;
! 311: }
! 312: if (pci_mapreg_map(pa, PLX_PCI_LOCAL_ADDR0,
! 313: PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
! 314: &cz->cz_win_st, &cz->cz_win_sh, NULL, NULL, 0) != 0) {
! 315: printf(": unable to map device window\n");
! 316: return;
! 317: }
! 318:
! 319: cz->cz_mailbox0 = CZ_PLX_READ(cz, PLX_MAILBOX0);
! 320: cz->cz_nopenchan = 0;
! 321:
! 322: /*
! 323: * Make sure that the board is completely stopped.
! 324: */
! 325: CZ_WIN_FPGA(cz);
! 326: CZ_FPGA_WRITE(cz, FPGA_CPU_STOP, 0);
! 327:
! 328: /*
! 329: * Load the board's firmware.
! 330: */
! 331: if (cz_load_firmware(cz) != 0)
! 332: return;
! 333:
! 334: /*
! 335: * Now that we're ready to roll, map and establish the interrupt
! 336: * handler.
! 337: */
! 338: if (pci_intr_map(pa, &ih) != 0) {
! 339: /*
! 340: * The common case is for Cyclades-Z boards to run
! 341: * in polling mode, and thus not have an interrupt
! 342: * mapped for them. Don't bother reporting that
! 343: * the interrupt is not mappable, since this isn't
! 344: * really an error.
! 345: */
! 346: cz->cz_ih = NULL;
! 347: goto polling_mode;
! 348: } else {
! 349: intrstr = pci_intr_string(pa->pa_pc, ih);
! 350: cz->cz_ih = pci_intr_establish(pc, ih, IPL_TTY,
! 351: cz_intr, cz, cz->cz_dev.dv_xname);
! 352: }
! 353: if (cz->cz_ih == NULL) {
! 354: printf(": unable to establish interrupt");
! 355: if (intrstr != NULL)
! 356: printf(" at %s", intrstr);
! 357: printf("\n");
! 358: /* We will fall-back on polling mode. */
! 359: } else
! 360: printf(": %s\n", intrstr);
! 361:
! 362: polling_mode:
! 363: if (cz->cz_ih == NULL) {
! 364: timeout_set(&cz->cz_timeout, cz_poll, cz);
! 365: if (cz_timeout_ticks == 0)
! 366: cz_timeout_ticks = max(1, hz * CZ_POLL_MS / 1000);
! 367: printf("%s: polling mode, %d ms interval (%d tick%s)\n",
! 368: cz->cz_dev.dv_xname, CZ_POLL_MS, cz_timeout_ticks,
! 369: cz_timeout_ticks == 1 ? "" : "s");
! 370: }
! 371:
! 372: if (cztty_major == 0)
! 373: cztty_major = cztty_findmajor();
! 374: /*
! 375: * Allocate sufficient pointers for the children and
! 376: * attach them. Set all ports to a reasonable initial
! 377: * configuration while we're at it:
! 378: *
! 379: * disabled
! 380: * 8N1
! 381: * default baud rate
! 382: * hardware flow control.
! 383: */
! 384: CZ_WIN_RAM(cz);
! 385:
! 386: if (cz->cz_nchannels == 0) {
! 387: /* No channels? No more work to do! */
! 388: return;
! 389: }
! 390:
! 391: cz->cz_ports = malloc(sizeof(struct cztty_softc) * cz->cz_nchannels,
! 392: M_DEVBUF, M_WAITOK);
! 393: cztty_attached_ttys += cz->cz_nchannels;
! 394: memset(cz->cz_ports, 0,
! 395: sizeof(struct cztty_softc) * cz->cz_nchannels);
! 396:
! 397: for (i = 0; i < cz->cz_nchannels; i++) {
! 398: sc = &cz->cz_ports[i];
! 399:
! 400: sc->sc_channel = i;
! 401: sc->sc_chan_st = cz->cz_win_st;
! 402: sc->sc_parent = cz;
! 403:
! 404: if (bus_space_subregion(cz->cz_win_st, cz->cz_win_sh,
! 405: cz->cz_fwctl + ZFIRM_CHNCTL_OFF(i, 0),
! 406: ZFIRM_CHNCTL_SIZE, &sc->sc_chan_sh)) {
! 407: printf("%s: unable to subregion channel %d control\n",
! 408: cz->cz_dev.dv_xname, i);
! 409: sc->sc_channel = CZTTY_CHANNEL_DEAD;
! 410: continue;
! 411: }
! 412: if (bus_space_subregion(cz->cz_win_st, cz->cz_win_sh,
! 413: cz->cz_fwctl + ZFIRM_BUFCTL_OFF(i, 0),
! 414: ZFIRM_BUFCTL_SIZE, &sc->sc_buf_sh)) {
! 415: printf("%s: unable to subregion channel %d buffer\n",
! 416: cz->cz_dev.dv_xname, i);
! 417: sc->sc_channel = CZTTY_CHANNEL_DEAD;
! 418: continue;
! 419: }
! 420:
! 421: timeout_set(&sc->sc_diag_to, cztty_diag, sc);
! 422:
! 423: tp = ttymalloc();
! 424: tp->t_dev = makedev(cztty_major,
! 425: (cz->cz_dev.dv_unit * ZFIRM_MAX_CHANNELS) + i);
! 426: tp->t_oproc = czttystart;
! 427: tp->t_param = czttyparam;
! 428:
! 429: sc->sc_tty = tp;
! 430:
! 431: CZTTY_CHAN_WRITE(sc, CHNCTL_OP_MODE, C_CH_DISABLE);
! 432: CZTTY_CHAN_WRITE(sc, CHNCTL_INTR_ENABLE, CZ_INTERRUPTS);
! 433: CZTTY_CHAN_WRITE(sc, CHNCTL_SW_FLOW, 0);
! 434: CZTTY_CHAN_WRITE(sc, CHNCTL_FLOW_XON, 0x11);
! 435: CZTTY_CHAN_WRITE(sc, CHNCTL_FLOW_XOFF, 0x13);
! 436: CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_BAUD, TTYDEF_SPEED);
! 437: CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_PARITY, C_PR_NONE);
! 438: CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_DATA_L, C_DL_CS8 | C_DL_1STOP);
! 439: CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_FLAGS, 0);
! 440: CZTTY_CHAN_WRITE(sc, CHNCTL_HW_FLOW, C_RS_CTS | C_RS_RTS);
! 441: CZTTY_CHAN_WRITE(sc, CHNCTL_RS_CONTROL, 0);
! 442: }
! 443: }
! 444:
! 445: /*
! 446: * cz_reset_board:
! 447: *
! 448: * Reset the board via the PLX.
! 449: */
! 450: void
! 451: cz_reset_board(struct cz_softc *cz)
! 452: {
! 453: u_int32_t reg;
! 454:
! 455: reg = CZ_PLX_READ(cz, PLX_CONTROL);
! 456: CZ_PLX_WRITE(cz, PLX_CONTROL, reg | CONTROL_SWR);
! 457: delay(1000);
! 458:
! 459: CZ_PLX_WRITE(cz, PLX_CONTROL, reg);
! 460: delay(1000);
! 461:
! 462: /* Now reload the PLX from its EEPROM. */
! 463: reg = CZ_PLX_READ(cz, PLX_CONTROL);
! 464: CZ_PLX_WRITE(cz, PLX_CONTROL, reg | CONTROL_RELOADCFG);
! 465: delay(1000);
! 466: CZ_PLX_WRITE(cz, PLX_CONTROL, reg);
! 467: }
! 468:
! 469: /*
! 470: * cz_load_firmware:
! 471: *
! 472: * Load the ZFIRM firmware into the board's RAM and start it
! 473: * running.
! 474: */
! 475: int
! 476: cz_load_firmware(struct cz_softc *cz)
! 477: {
! 478: struct zfirm_header *zfh;
! 479: struct zfirm_config *zfc;
! 480: struct zfirm_block *zfb, *zblocks;
! 481: const u_int8_t *cp;
! 482: const char *board;
! 483: u_int32_t fid;
! 484: int i, j, nconfigs, nblocks, nbytes;
! 485:
! 486: zfh = (struct zfirm_header *) cycladesz_firmware;
! 487:
! 488: /* Find the config header. */
! 489: if (letoh32(zfh->zfh_configoff) & (sizeof(u_int32_t) - 1)) {
! 490: printf("%s: bad ZFIRM config offset: 0x%x\n",
! 491: cz->cz_dev.dv_xname, letoh32(zfh->zfh_configoff));
! 492: return (EIO);
! 493: }
! 494: zfc = (struct zfirm_config *)(cycladesz_firmware +
! 495: letoh32(zfh->zfh_configoff));
! 496: nconfigs = letoh32(zfh->zfh_nconfig);
! 497:
! 498: /* Locate the correct configuration for our board. */
! 499: for (i = 0; i < nconfigs; i++, zfc++) {
! 500: if (letoh32(zfc->zfc_mailbox) == cz->cz_mailbox0 &&
! 501: letoh32(zfc->zfc_function) == ZFC_FUNCTION_NORMAL)
! 502: break;
! 503: }
! 504: if (i == nconfigs) {
! 505: printf("%s: unable to locate config header\n",
! 506: cz->cz_dev.dv_xname);
! 507: return (EIO);
! 508: }
! 509:
! 510: nblocks = letoh32(zfc->zfc_nblocks);
! 511: zblocks = (struct zfirm_block *)(cycladesz_firmware +
! 512: letoh32(zfh->zfh_blockoff));
! 513:
! 514: /*
! 515: * 8Zo ver. 1 doesn't have an FPGA. Load it on all others if
! 516: * necessary.
! 517: */
! 518: if (cz->cz_mailbox0 != MAILBOX0_8Zo_V1
! 519: #if 0
! 520: && ((CZ_PLX_READ(cz, PLX_CONTROL) & CONTROL_FPGA_LOADED) == 0)
! 521: #endif
! 522: ) {
! 523: #ifdef CZ_DEBUG
! 524: printf("%s: Loading FPGA...", cz->cz_dev.dv_xname);
! 525: #endif
! 526: CZ_WIN_FPGA(cz);
! 527: for (i = 0; i < nblocks; i++) {
! 528: /* zfb = zblocks + letoh32(zfc->zfc_blocklist[i]) ?? */
! 529: zfb = &zblocks[letoh32(zfc->zfc_blocklist[i])];
! 530: if (letoh32(zfb->zfb_type) == ZFB_TYPE_FPGA) {
! 531: nbytes = letoh32(zfb->zfb_size);
! 532: cp = &cycladesz_firmware[
! 533: letoh32(zfb->zfb_fileoff)];
! 534: for (j = 0; j < nbytes; j++, cp++) {
! 535: bus_space_write_1(cz->cz_win_st,
! 536: cz->cz_win_sh, 0, *cp);
! 537: /* FPGA needs 30-100us to settle. */
! 538: delay(10);
! 539: }
! 540: }
! 541: }
! 542: #ifdef CZ_DEBUG
! 543: printf("done\n");
! 544: #endif
! 545: }
! 546:
! 547: /* Now load the firmware. */
! 548: CZ_WIN_RAM(cz);
! 549:
! 550: for (i = 0; i < nblocks; i++) {
! 551: /* zfb = zblocks + letoh32(zfc->zfc_blocklist[i]) ?? */
! 552: zfb = &zblocks[letoh32(zfc->zfc_blocklist[i])];
! 553: if (letoh32(zfb->zfb_type) == ZFB_TYPE_FIRMWARE) {
! 554: const u_int32_t *lp;
! 555: u_int32_t ro = letoh32(zfb->zfb_ramoff);
! 556: nbytes = letoh32(zfb->zfb_size);
! 557: lp = (const u_int32_t *)
! 558: &cycladesz_firmware[letoh32(zfb->zfb_fileoff)];
! 559: for (j = 0; j < nbytes; j += 4, lp++) {
! 560: bus_space_write_4(cz->cz_win_st, cz->cz_win_sh,
! 561: ro + j, letoh32(*lp));
! 562: delay(10);
! 563: }
! 564: }
! 565: }
! 566:
! 567: /* Now restart the MIPS. */
! 568: CZ_WIN_FPGA(cz);
! 569: CZ_FPGA_WRITE(cz, FPGA_CPU_START, 0);
! 570:
! 571: /* Wait for the MIPS to start, then report the results. */
! 572: CZ_WIN_RAM(cz);
! 573:
! 574: #ifdef CZ_DEBUG
! 575: printf("%s: waiting for MIPS to start", cz->cz_dev.dv_xname);
! 576: #endif
! 577: for (i = 0; i < 100; i++) {
! 578: fid = bus_space_read_4(cz->cz_win_st, cz->cz_win_sh,
! 579: ZFIRM_SIG_OFF);
! 580: if (fid == ZFIRM_SIG) {
! 581: /* MIPS has booted. */
! 582: break;
! 583: } else if (fid == ZFIRM_HLT) {
! 584: /*
! 585: * The MIPS has halted, usually due to a power
! 586: * shortage on the expansion module.
! 587: */
! 588: printf("%s: MIPS halted; possible power supply "
! 589: "problem\n", cz->cz_dev.dv_xname);
! 590: return (EIO);
! 591: } else {
! 592: #ifdef CZ_DEBUG
! 593: if ((i % 8) == 0)
! 594: printf(".");
! 595: #endif
! 596: delay(250000);
! 597: }
! 598: }
! 599: #ifdef CZ_DEBUG
! 600: printf("\n");
! 601: #endif
! 602: if (i == 100) {
! 603: CZ_WIN_FPGA(cz);
! 604: printf("%s: MIPS failed to start; wanted 0x%08x got 0x%08x\n",
! 605: cz->cz_dev.dv_xname, ZFIRM_SIG, fid);
! 606: printf("%s: FPGA ID 0x%08x, FPGA version 0x%08x\n",
! 607: cz->cz_dev.dv_xname, CZ_FPGA_READ(cz, FPGA_ID),
! 608: CZ_FPGA_READ(cz, FPGA_VERSION));
! 609: return (EIO);
! 610: }
! 611:
! 612: /*
! 613: * Locate the firmware control structures.
! 614: */
! 615: cz->cz_fwctl = bus_space_read_4(cz->cz_win_st, cz->cz_win_sh,
! 616: ZFIRM_CTRLADDR_OFF);
! 617: #ifdef CZ_DEBUG
! 618: printf("%s: FWCTL structure at offset 0x%08lx\n",
! 619: cz->cz_dev.dv_xname, cz->cz_fwctl);
! 620: #endif
! 621:
! 622: CZ_FWCTL_WRITE(cz, BRDCTL_C_OS, C_OS_BSD);
! 623: CZ_FWCTL_WRITE(cz, BRDCTL_DRVERSION, CZ_DRIVER_VERSION);
! 624:
! 625: cz->cz_nchannels = CZ_FWCTL_READ(cz, BRDCTL_NCHANNEL);
! 626:
! 627: switch (cz->cz_mailbox0) {
! 628: case MAILBOX0_8Zo_V1:
! 629: board = "Cyclades-8Zo ver. 1";
! 630: break;
! 631:
! 632: case MAILBOX0_8Zo_V2:
! 633: board = "Cyclades-8Zo ver. 2";
! 634: break;
! 635:
! 636: case MAILBOX0_Ze_V1:
! 637: board = "Cyclades-Ze";
! 638: break;
! 639:
! 640: default:
! 641: board = "unknown Cyclades Z-series";
! 642: break;
! 643: }
! 644:
! 645: fid = CZ_FWCTL_READ(cz, BRDCTL_FWVERSION);
! 646: printf("%s: %s, ", cz->cz_dev.dv_xname, board);
! 647: if (cz->cz_nchannels == 0)
! 648: printf("no channels attached, ");
! 649: else
! 650: printf("%d channels (ttyCZ%04d..ttyCZ%04d), ",
! 651: cz->cz_nchannels, cztty_attached_ttys,
! 652: cztty_attached_ttys + (cz->cz_nchannels - 1));
! 653: printf("firmware %x.%x.%x\n",
! 654: (fid >> 8) & 0xf, (fid >> 4) & 0xf, fid & 0xf);
! 655:
! 656: return (0);
! 657: }
! 658:
! 659: /*
! 660: * cz_poll:
! 661: *
! 662: * This card doesn't do interrupts, so scan it for activity every CZ_POLL_MS
! 663: * ms.
! 664: */
! 665: void
! 666: cz_poll(void *arg)
! 667: {
! 668: int s = spltty();
! 669: struct cz_softc *cz = arg;
! 670:
! 671: cz_intr(cz);
! 672: timeout_add(&cz->cz_timeout, cz_timeout_ticks);
! 673:
! 674: splx(s);
! 675: }
! 676:
! 677: /*
! 678: * cz_intr:
! 679: *
! 680: * Interrupt service routine.
! 681: *
! 682: * We either are receiving an interrupt directly from the board, or we are
! 683: * in polling mode and it's time to poll.
! 684: */
! 685: int
! 686: cz_intr(void *arg)
! 687: {
! 688: int rval = 0;
! 689: u_int command, channel, param;
! 690: struct cz_softc *cz = arg;
! 691: struct cztty_softc *sc;
! 692: struct tty *tp;
! 693:
! 694: while ((command = (CZ_PLX_READ(cz, PLX_LOCAL_PCI_DOORBELL) & 0xff))) {
! 695: rval = 1;
! 696: channel = CZ_FWCTL_READ(cz, BRDCTL_FWCMD_CHANNEL);
! 697: param = CZ_FWCTL_READ(cz, BRDCTL_FWCMD_PARAM);
! 698:
! 699: /* now clear this interrupt, posslibly enabling another */
! 700: CZ_PLX_WRITE(cz, PLX_LOCAL_PCI_DOORBELL, command);
! 701:
! 702: if (cz->cz_ports == NULL) {
! 703: #ifdef CZ_DEBUG
! 704: printf("%s: interrupt on channel %d, but no channels\n",
! 705: cz->cz_dev.dv_xname, channel);
! 706: #endif
! 707: continue;
! 708: }
! 709:
! 710: sc = &cz->cz_ports[channel];
! 711:
! 712: if (sc->sc_channel == CZTTY_CHANNEL_DEAD)
! 713: break;
! 714:
! 715: tp = sc->sc_tty;
! 716:
! 717: switch (command) {
! 718: case C_CM_TXFEMPTY: /* transmit cases */
! 719: case C_CM_TXBEMPTY:
! 720: case C_CM_TXLOWWM:
! 721: case C_CM_INTBACK:
! 722: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 723: #ifdef CZ_DEBUG
! 724: printf("%s: tx intr on closed channel %d\n",
! 725: cz->cz_dev.dv_xname, channel);
! 726: #endif
! 727: break;
! 728: }
! 729:
! 730: if (cztty_transmit(sc, tp)) {
! 731: /*
! 732: * Do wakeup stuff here.
! 733: */
! 734: ttwakeup(tp);
! 735: wakeup(tp);
! 736: }
! 737: break;
! 738:
! 739: case C_CM_RXNNDT: /* receive cases */
! 740: case C_CM_RXHIWM:
! 741: case C_CM_INTBACK2: /* from restart ?? */
! 742: #if 0
! 743: case C_CM_ICHAR:
! 744: #endif
! 745: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 746: CZTTY_BUF_WRITE(sc, BUFCTL_RX_GET,
! 747: CZTTY_BUF_READ(sc, BUFCTL_RX_PUT));
! 748: break;
! 749: }
! 750:
! 751: if (cztty_receive(sc, tp)) {
! 752: /*
! 753: * Do wakeup stuff here.
! 754: */
! 755: ttwakeup(tp);
! 756: wakeup(tp);
! 757: }
! 758: break;
! 759:
! 760: case C_CM_MDCD:
! 761: if (!ISSET(tp->t_state, TS_ISOPEN))
! 762: break;
! 763:
! 764: (void) (*linesw[tp->t_line].l_modem)(tp,
! 765: ISSET(C_RS_DCD, CZTTY_CHAN_READ(sc,
! 766: CHNCTL_RS_STATUS)));
! 767: break;
! 768:
! 769: case C_CM_MDSR:
! 770: case C_CM_MRI:
! 771: case C_CM_MCTS:
! 772: case C_CM_MRTS:
! 773: break;
! 774:
! 775: case C_CM_IOCTLW:
! 776: break;
! 777:
! 778: case C_CM_PR_ERROR:
! 779: sc->sc_parity_errors++;
! 780: goto error_common;
! 781:
! 782: case C_CM_FR_ERROR:
! 783: sc->sc_framing_errors++;
! 784: goto error_common;
! 785:
! 786: case C_CM_OVR_ERROR:
! 787: sc->sc_overflows++;
! 788: error_common:
! 789: if (sc->sc_errors++ == 0)
! 790: timeout_add(&sc->sc_diag_to, 60 * hz);
! 791: break;
! 792:
! 793: case C_CM_RXBRK:
! 794: if (!ISSET(tp->t_state, TS_ISOPEN))
! 795: break;
! 796:
! 797: /*
! 798: * A break is a \000 character with TTY_FE error
! 799: * flags set. So TTY_FE by itself works.
! 800: */
! 801: (*linesw[tp->t_line].l_rint)(TTY_FE, tp);
! 802: ttwakeup(tp);
! 803: wakeup(tp);
! 804: break;
! 805:
! 806: default:
! 807: #ifdef CZ_DEBUG
! 808: printf("%s: channel %d: Unknown interrupt 0x%x\n",
! 809: cz->cz_dev.dv_xname, sc->sc_channel, command);
! 810: #endif
! 811: break;
! 812: }
! 813: }
! 814:
! 815: return (rval);
! 816: }
! 817:
! 818: /*
! 819: * cz_wait_pci_doorbell:
! 820: *
! 821: * Wait for the pci doorbell to be clear - wait for pending
! 822: * activity to drain.
! 823: */
! 824: int
! 825: cz_wait_pci_doorbell(struct cz_softc *cz, char *wstring)
! 826: {
! 827: int error;
! 828:
! 829: while (CZ_PLX_READ(cz, PLX_PCI_LOCAL_DOORBELL)) {
! 830: error = tsleep(cz, TTIPRI | PCATCH, wstring, max(1, hz/100));
! 831: if ((error != 0) && (error != EWOULDBLOCK))
! 832: return (error);
! 833: }
! 834: return (0);
! 835: }
! 836:
! 837: /*****************************************************************************
! 838: * Cyclades-Z TTY code starts here...
! 839: *****************************************************************************/
! 840:
! 841: #define CZTTYDIALOUT_MASK 0x80
! 842:
! 843: #define CZTTY_DIALOUT(dev) (minor((dev)) & CZTTYDIALOUT_MASK)
! 844: #define CZTTY_CZ(sc) ((sc)->sc_parent)
! 845:
! 846: #define CZTTY_SOFTC(dev) cztty_getttysoftc(dev)
! 847:
! 848: struct cztty_softc *
! 849: cztty_getttysoftc(dev_t dev)
! 850: {
! 851: int i, j, k, u = minor(dev) & ~CZTTYDIALOUT_MASK;
! 852: struct cz_softc *cz;
! 853:
! 854: for (i = 0, j = 0; i < cz_cd.cd_ndevs; i++) {
! 855: k = j;
! 856: cz = (struct cz_softc *)device_lookup(&cz_cd, i);
! 857: if (cz == NULL)
! 858: continue;
! 859: if (cz->cz_ports == NULL)
! 860: continue;
! 861: j += cz->cz_nchannels;
! 862: if (j > u)
! 863: break;
! 864: }
! 865:
! 866: if (i >= cz_cd.cd_ndevs)
! 867: return (NULL);
! 868: else
! 869: return (&cz->cz_ports[u - k]);
! 870: }
! 871:
! 872: int
! 873: cztty_findmajor(void)
! 874: {
! 875: int maj;
! 876:
! 877: for (maj = 0; maj < nchrdev; maj++) {
! 878: if (cdevsw[maj].d_open == czttyopen)
! 879: break;
! 880: }
! 881:
! 882: return (maj == nchrdev) ? 0 : maj;
! 883: }
! 884:
! 885: /*
! 886: * czttytty:
! 887: *
! 888: * Return a pointer to our tty.
! 889: */
! 890: struct tty *
! 891: czttytty(dev_t dev)
! 892: {
! 893: struct cztty_softc *sc = CZTTY_SOFTC(dev);
! 894:
! 895: #ifdef DIAGNOSTIC
! 896: if (sc == NULL)
! 897: panic("czttytty");
! 898: #endif
! 899:
! 900: return (sc->sc_tty);
! 901: }
! 902:
! 903: /*
! 904: * cztty_shutdown:
! 905: *
! 906: * Shut down a port.
! 907: */
! 908: void
! 909: cztty_shutdown(struct cztty_softc *sc)
! 910: {
! 911: struct cz_softc *cz = CZTTY_CZ(sc);
! 912: struct tty *tp = sc->sc_tty;
! 913: int s;
! 914:
! 915: s = spltty();
! 916:
! 917: /* Clear any break condition set with TIOCSBRK. */
! 918: cztty_break(sc, 0);
! 919:
! 920: /*
! 921: * Hang up if necessary. Wait a bit, so the other side has time to
! 922: * notice even if we immediately open the port again.
! 923: */
! 924: if (ISSET(tp->t_cflag, HUPCL)) {
! 925: cztty_modem(sc, 0);
! 926: (void) tsleep(tp, TTIPRI, ttclos, hz);
! 927: }
! 928:
! 929: /* Disable the channel. */
! 930: cz_wait_pci_doorbell(cz, "czdis");
! 931: CZTTY_CHAN_WRITE(sc, CHNCTL_OP_MODE, C_CH_DISABLE);
! 932: CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel);
! 933: CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTL);
! 934:
! 935: if ((--cz->cz_nopenchan == 0) && (cz->cz_ih == NULL)) {
! 936: #ifdef CZ_DEBUG
! 937: printf("%s: Disabling polling\n", cz->cz_dev.dv_xname);
! 938: #endif
! 939: timeout_del(&cz->cz_timeout);
! 940: }
! 941:
! 942: splx(s);
! 943: }
! 944:
! 945: /*
! 946: * czttyopen:
! 947: *
! 948: * Open a Cyclades-Z serial port.
! 949: */
! 950: int
! 951: czttyopen(dev_t dev, int flags, int mode, struct proc *p)
! 952: {
! 953: struct cztty_softc *sc = CZTTY_SOFTC(dev);
! 954: struct cz_softc *cz;
! 955: struct tty *tp;
! 956: int s, error;
! 957:
! 958: if (sc == NULL)
! 959: return (ENXIO);
! 960:
! 961: if (sc->sc_channel == CZTTY_CHANNEL_DEAD)
! 962: return (ENXIO);
! 963:
! 964: cz = CZTTY_CZ(sc);
! 965: tp = sc->sc_tty;
! 966:
! 967: if (ISSET(tp->t_state, TS_ISOPEN) &&
! 968: ISSET(tp->t_state, TS_XCLUDE) &&
! 969: p->p_ucred->cr_uid != 0)
! 970: return (EBUSY);
! 971:
! 972: s = spltty();
! 973:
! 974: /*
! 975: * Do the following iff this is a first open.
! 976: */
! 977: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 978: struct termios t;
! 979:
! 980: tp->t_dev = dev;
! 981:
! 982: /* If we're turning things on, enable interrupts */
! 983: if ((cz->cz_nopenchan++ == 0) && (cz->cz_ih == NULL)) {
! 984: #ifdef CZ_DEBUG
! 985: printf("%s: Enabling polling.\n",
! 986: cz->cz_dev.dv_xname);
! 987: #endif
! 988: timeout_add(&cz->cz_timeout, cz_timeout_ticks);
! 989: }
! 990:
! 991: /*
! 992: * Enable the channel. Don't actually ring the
! 993: * doorbell here; czttyparam() will do it for us.
! 994: */
! 995: cz_wait_pci_doorbell(cz, "czopen");
! 996:
! 997: CZTTY_CHAN_WRITE(sc, CHNCTL_OP_MODE, C_CH_ENABLE);
! 998:
! 999: /*
! 1000: * Initialize the termios status to the defaults. Add in the
! 1001: * sticky bits from TIOCSFLAGS.
! 1002: */
! 1003: t.c_ispeed = 0;
! 1004: t.c_ospeed = TTYDEF_SPEED;
! 1005: t.c_cflag = TTYDEF_CFLAG;
! 1006: if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
! 1007: SET(t.c_cflag, CLOCAL);
! 1008: if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
! 1009: SET(t.c_cflag, CRTSCTS);
! 1010:
! 1011: /*
! 1012: * Reset the input and output rings. Do this before
! 1013: * we call czttyparam(), as that function enables
! 1014: * the channel.
! 1015: */
! 1016: CZTTY_BUF_WRITE(sc, BUFCTL_RX_GET,
! 1017: CZTTY_BUF_READ(sc, BUFCTL_RX_PUT));
! 1018: CZTTY_BUF_WRITE(sc, BUFCTL_TX_PUT,
! 1019: CZTTY_BUF_READ(sc, BUFCTL_TX_GET));
! 1020:
! 1021: /* Make sure czttyparam() will see changes. */
! 1022: tp->t_ospeed = 0;
! 1023: (void) czttyparam(tp, &t);
! 1024: tp->t_iflag = TTYDEF_IFLAG;
! 1025: tp->t_oflag = TTYDEF_OFLAG;
! 1026: tp->t_lflag = TTYDEF_LFLAG;
! 1027: ttychars(tp);
! 1028: ttsetwater(tp);
! 1029:
! 1030: /*
! 1031: * Turn on DTR. We must always do this, even if carrier is not
! 1032: * present, because otherwise we'd have to use TIOCSDTR
! 1033: * immediately after setting CLOCAL, which applications do not
! 1034: * expect. We always assert DTR while the device is open
! 1035: * unless explicitly requested to deassert it.
! 1036: */
! 1037: cztty_modem(sc, 1);
! 1038: }
! 1039:
! 1040: splx(s);
! 1041:
! 1042: error = ttyopen(CZTTY_DIALOUT(dev), tp);
! 1043: if (error)
! 1044: goto bad;
! 1045:
! 1046: error = (*linesw[tp->t_line].l_open)(dev, tp);
! 1047: if (error)
! 1048: goto bad;
! 1049:
! 1050: return (0);
! 1051:
! 1052: bad:
! 1053: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 1054: /*
! 1055: * We failed to open the device, and nobody else had it opened.
! 1056: * Clean up the state as appropriate.
! 1057: */
! 1058: cztty_shutdown(sc);
! 1059: }
! 1060:
! 1061: return (error);
! 1062: }
! 1063:
! 1064: /*
! 1065: * czttyclose:
! 1066: *
! 1067: * Close a Cyclades-Z serial port.
! 1068: */
! 1069: int
! 1070: czttyclose(dev_t dev, int flags, int mode, struct proc *p)
! 1071: {
! 1072: struct cztty_softc *sc = CZTTY_SOFTC(dev);
! 1073: struct tty *tp = sc->sc_tty;
! 1074:
! 1075: /* XXX This is for cons.c. */
! 1076: if (!ISSET(tp->t_state, TS_ISOPEN))
! 1077: return (0);
! 1078:
! 1079: (*linesw[tp->t_line].l_close)(tp, flags);
! 1080: ttyclose(tp);
! 1081:
! 1082: if (!ISSET(tp->t_state, TS_ISOPEN)) {
! 1083: /*
! 1084: * Although we got a last close, the device may still be in
! 1085: * use; e.g. if this was the dialout node, and there are still
! 1086: * processes waiting for carrier on the non-dialout node.
! 1087: */
! 1088: cztty_shutdown(sc);
! 1089: }
! 1090:
! 1091: return (0);
! 1092: }
! 1093:
! 1094: /*
! 1095: * czttyread:
! 1096: *
! 1097: * Read from a Cyclades-Z serial port.
! 1098: */
! 1099: int
! 1100: czttyread(dev_t dev, struct uio *uio, int flags)
! 1101: {
! 1102: struct cztty_softc *sc = CZTTY_SOFTC(dev);
! 1103: struct tty *tp = sc->sc_tty;
! 1104:
! 1105: return ((*linesw[tp->t_line].l_read)(tp, uio, flags));
! 1106: }
! 1107:
! 1108: /*
! 1109: * czttywrite:
! 1110: *
! 1111: * Write to a Cyclades-Z serial port.
! 1112: */
! 1113: int
! 1114: czttywrite(dev_t dev, struct uio *uio, int flags)
! 1115: {
! 1116: struct cztty_softc *sc = CZTTY_SOFTC(dev);
! 1117: struct tty *tp = sc->sc_tty;
! 1118:
! 1119: return ((*linesw[tp->t_line].l_write)(tp, uio, flags));
! 1120: }
! 1121:
! 1122: #if 0
! 1123: /*
! 1124: * czttypoll:
! 1125: *
! 1126: * Poll a Cyclades-Z serial port.
! 1127: */
! 1128: int
! 1129: czttypoll(dev_t dev, int events, struct proc p)
! 1130: {
! 1131: struct cztty_softc *sc = CZTTY_SOFTC(dev);
! 1132: struct tty *tp = sc->sc_tty;
! 1133:
! 1134: return ((*linesw[tp->t_line].l_poll)(tp, events, p));
! 1135: }
! 1136: #endif
! 1137:
! 1138: /*
! 1139: * czttyioctl:
! 1140: *
! 1141: * Perform a control operation on a Cyclades-Z serial port.
! 1142: */
! 1143: int
! 1144: czttyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 1145: {
! 1146: struct cztty_softc *sc = CZTTY_SOFTC(dev);
! 1147: struct tty *tp = sc->sc_tty;
! 1148: int s, error;
! 1149:
! 1150: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 1151: if (error >= 0)
! 1152: return (error);
! 1153:
! 1154: error = ttioctl(tp, cmd, data, flag, p);
! 1155: if (error >= 0)
! 1156: return (error);
! 1157:
! 1158: error = 0;
! 1159:
! 1160: s = spltty();
! 1161:
! 1162: switch (cmd) {
! 1163: case TIOCSBRK:
! 1164: cztty_break(sc, 1);
! 1165: break;
! 1166:
! 1167: case TIOCCBRK:
! 1168: cztty_break(sc, 0);
! 1169: break;
! 1170:
! 1171: case TIOCGFLAGS:
! 1172: *(int *)data = sc->sc_swflags;
! 1173: break;
! 1174:
! 1175: case TIOCSFLAGS:
! 1176: error = suser(p, 0);
! 1177: if (error)
! 1178: break;
! 1179: sc->sc_swflags = *(int *)data;
! 1180: break;
! 1181:
! 1182: case TIOCSDTR:
! 1183: cztty_modem(sc, 1);
! 1184: break;
! 1185:
! 1186: case TIOCCDTR:
! 1187: cztty_modem(sc, 0);
! 1188: break;
! 1189:
! 1190: case TIOCMSET:
! 1191: case TIOCMBIS:
! 1192: case TIOCMBIC:
! 1193: tiocm_to_cztty(sc, cmd, *(int *)data);
! 1194: break;
! 1195:
! 1196: case TIOCMGET:
! 1197: *(int *)data = cztty_to_tiocm(sc);
! 1198: break;
! 1199:
! 1200: default:
! 1201: error = ENOTTY;
! 1202: break;
! 1203: }
! 1204:
! 1205: splx(s);
! 1206:
! 1207: return (error);
! 1208: }
! 1209:
! 1210: /*
! 1211: * cztty_break:
! 1212: *
! 1213: * Set or clear BREAK on a port.
! 1214: */
! 1215: void
! 1216: cztty_break(struct cztty_softc *sc, int onoff)
! 1217: {
! 1218: struct cz_softc *cz = CZTTY_CZ(sc);
! 1219:
! 1220: cz_wait_pci_doorbell(cz, "czbreak");
! 1221:
! 1222: CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel);
! 1223: CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL,
! 1224: onoff ? C_CM_SET_BREAK : C_CM_CLR_BREAK);
! 1225: }
! 1226:
! 1227: /*
! 1228: * cztty_modem:
! 1229: *
! 1230: * Set or clear DTR on a port.
! 1231: */
! 1232: void
! 1233: cztty_modem(struct cztty_softc *sc, int onoff)
! 1234: {
! 1235: struct cz_softc *cz = CZTTY_CZ(sc);
! 1236:
! 1237: if (sc->sc_rs_control_dtr == 0)
! 1238: return;
! 1239:
! 1240: cz_wait_pci_doorbell(cz, "czmod");
! 1241:
! 1242: if (onoff)
! 1243: sc->sc_chanctl_rs_control |= sc->sc_rs_control_dtr;
! 1244: else
! 1245: sc->sc_chanctl_rs_control &= ~sc->sc_rs_control_dtr;
! 1246: CZTTY_CHAN_WRITE(sc, CHNCTL_RS_CONTROL, sc->sc_chanctl_rs_control);
! 1247:
! 1248: CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel);
! 1249: CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTLM);
! 1250: }
! 1251:
! 1252: /*
! 1253: * tiocm_to_cztty:
! 1254: *
! 1255: * Process TIOCM* ioctls.
! 1256: */
! 1257: void
! 1258: tiocm_to_cztty(struct cztty_softc *sc, u_long how, int ttybits)
! 1259: {
! 1260: struct cz_softc *cz = CZTTY_CZ(sc);
! 1261: u_int32_t czttybits;
! 1262:
! 1263: czttybits = 0;
! 1264: if (ISSET(ttybits, TIOCM_DTR))
! 1265: SET(czttybits, C_RS_DTR);
! 1266: if (ISSET(ttybits, TIOCM_RTS))
! 1267: SET(czttybits, C_RS_RTS);
! 1268:
! 1269: cz_wait_pci_doorbell(cz, "cztiocm");
! 1270:
! 1271: switch (how) {
! 1272: case TIOCMBIC:
! 1273: CLR(sc->sc_chanctl_rs_control, czttybits);
! 1274: break;
! 1275:
! 1276: case TIOCMBIS:
! 1277: SET(sc->sc_chanctl_rs_control, czttybits);
! 1278: break;
! 1279:
! 1280: case TIOCMSET:
! 1281: CLR(sc->sc_chanctl_rs_control, C_RS_DTR | C_RS_RTS);
! 1282: SET(sc->sc_chanctl_rs_control, czttybits);
! 1283: break;
! 1284: }
! 1285:
! 1286: CZTTY_CHAN_WRITE(sc, CHNCTL_RS_CONTROL, sc->sc_chanctl_rs_control);
! 1287:
! 1288: CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel);
! 1289: CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTLM);
! 1290: }
! 1291:
! 1292: /*
! 1293: * cztty_to_tiocm:
! 1294: *
! 1295: * Process the TIOCMGET ioctl.
! 1296: */
! 1297: int
! 1298: cztty_to_tiocm(struct cztty_softc *sc)
! 1299: {
! 1300: struct cz_softc *cz = CZTTY_CZ(sc);
! 1301: u_int32_t rs_status, op_mode;
! 1302: int ttybits = 0;
! 1303:
! 1304: cz_wait_pci_doorbell(cz, "cztty");
! 1305:
! 1306: rs_status = CZTTY_CHAN_READ(sc, CHNCTL_RS_STATUS);
! 1307: op_mode = CZTTY_CHAN_READ(sc, CHNCTL_OP_MODE);
! 1308:
! 1309: if (ISSET(rs_status, C_RS_RTS))
! 1310: SET(ttybits, TIOCM_RTS);
! 1311: if (ISSET(rs_status, C_RS_CTS))
! 1312: SET(ttybits, TIOCM_CTS);
! 1313: if (ISSET(rs_status, C_RS_DCD))
! 1314: SET(ttybits, TIOCM_CAR);
! 1315: if (ISSET(rs_status, C_RS_DTR))
! 1316: SET(ttybits, TIOCM_DTR);
! 1317: if (ISSET(rs_status, C_RS_RI))
! 1318: SET(ttybits, TIOCM_RNG);
! 1319: if (ISSET(rs_status, C_RS_DSR))
! 1320: SET(ttybits, TIOCM_DSR);
! 1321:
! 1322: if (ISSET(op_mode, C_CH_ENABLE))
! 1323: SET(ttybits, TIOCM_LE);
! 1324:
! 1325: return (ttybits);
! 1326: }
! 1327:
! 1328: /*
! 1329: * czttyparam:
! 1330: *
! 1331: * Set Cyclades-Z serial port parameters from termios.
! 1332: *
! 1333: * XXX Should just copy the whole termios after making
! 1334: * XXX sure all the changes could be done.
! 1335: */
! 1336: int
! 1337: czttyparam(struct tty *tp, struct termios *t)
! 1338: {
! 1339: struct cztty_softc *sc = CZTTY_SOFTC(tp->t_dev);
! 1340: struct cz_softc *cz = CZTTY_CZ(sc);
! 1341: u_int32_t rs_status;
! 1342: int ospeed, cflag;
! 1343:
! 1344: ospeed = t->c_ospeed;
! 1345: cflag = t->c_cflag;
! 1346:
! 1347: /* Check requested parameters. */
! 1348: if (ospeed < 0)
! 1349: return (EINVAL);
! 1350: if (t->c_ispeed && t->c_ispeed != ospeed)
! 1351: return (EINVAL);
! 1352:
! 1353: if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
! 1354: SET(cflag, CLOCAL);
! 1355: CLR(cflag, HUPCL);
! 1356: }
! 1357:
! 1358: /*
! 1359: * If there were no changes, don't do anything. This avoids dropping
! 1360: * input and improves performance when all we did was frob things like
! 1361: * VMIN and VTIME.
! 1362: */
! 1363: if (tp->t_ospeed == ospeed &&
! 1364: tp->t_cflag == cflag)
! 1365: return (0);
! 1366:
! 1367: /* Data bits. */
! 1368: sc->sc_chanctl_comm_data_l = 0;
! 1369: switch (t->c_cflag & CSIZE) {
! 1370: case CS5:
! 1371: sc->sc_chanctl_comm_data_l |= C_DL_CS5;
! 1372: break;
! 1373:
! 1374: case CS6:
! 1375: sc->sc_chanctl_comm_data_l |= C_DL_CS6;
! 1376: break;
! 1377:
! 1378: case CS7:
! 1379: sc->sc_chanctl_comm_data_l |= C_DL_CS7;
! 1380: break;
! 1381:
! 1382: case CS8:
! 1383: sc->sc_chanctl_comm_data_l |= C_DL_CS8;
! 1384: break;
! 1385: }
! 1386:
! 1387: /* Stop bits. */
! 1388: if (t->c_cflag & CSTOPB) {
! 1389: if ((sc->sc_chanctl_comm_data_l & C_DL_CS) == C_DL_CS5)
! 1390: sc->sc_chanctl_comm_data_l |= C_DL_15STOP;
! 1391: else
! 1392: sc->sc_chanctl_comm_data_l |= C_DL_2STOP;
! 1393: } else
! 1394: sc->sc_chanctl_comm_data_l |= C_DL_1STOP;
! 1395:
! 1396: /* Parity. */
! 1397: if (t->c_cflag & PARENB) {
! 1398: if (t->c_cflag & PARODD)
! 1399: sc->sc_chanctl_comm_parity = C_PR_ODD;
! 1400: else
! 1401: sc->sc_chanctl_comm_parity = C_PR_EVEN;
! 1402: } else
! 1403: sc->sc_chanctl_comm_parity = C_PR_NONE;
! 1404:
! 1405: /*
! 1406: * Initialize flow control pins depending on the current flow control
! 1407: * mode.
! 1408: */
! 1409: if (ISSET(t->c_cflag, CRTSCTS)) {
! 1410: sc->sc_rs_control_dtr = C_RS_DTR;
! 1411: sc->sc_chanctl_hw_flow = C_RS_CTS | C_RS_RTS;
! 1412: } else if (ISSET(t->c_cflag, MDMBUF)) {
! 1413: sc->sc_rs_control_dtr = 0;
! 1414: sc->sc_chanctl_hw_flow = C_RS_DCD | C_RS_DTR;
! 1415: } else {
! 1416: /*
! 1417: * If no flow control, then always set RTS. This will make
! 1418: * the other side happy if it mistakenly thinks we're doing
! 1419: * RTS/CTS flow control.
! 1420: */
! 1421: sc->sc_rs_control_dtr = C_RS_DTR | C_RS_RTS;
! 1422: sc->sc_chanctl_hw_flow = 0;
! 1423: if (ISSET(sc->sc_chanctl_rs_control, C_RS_DTR))
! 1424: SET(sc->sc_chanctl_rs_control, C_RS_RTS);
! 1425: else
! 1426: CLR(sc->sc_chanctl_rs_control, C_RS_RTS);
! 1427: }
! 1428:
! 1429: /* Baud rate. */
! 1430: sc->sc_chanctl_comm_baud = ospeed;
! 1431:
! 1432: /* Copy to tty. */
! 1433: tp->t_ispeed = 0;
! 1434: tp->t_ospeed = t->c_ospeed;
! 1435: tp->t_cflag = t->c_cflag;
! 1436:
! 1437: /*
! 1438: * Now load the channel control structure.
! 1439: */
! 1440:
! 1441: cz_wait_pci_doorbell(cz, "czparam");
! 1442:
! 1443: CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_BAUD, sc->sc_chanctl_comm_baud);
! 1444: CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_DATA_L, sc->sc_chanctl_comm_data_l);
! 1445: CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_PARITY, sc->sc_chanctl_comm_parity);
! 1446: CZTTY_CHAN_WRITE(sc, CHNCTL_HW_FLOW, sc->sc_chanctl_hw_flow);
! 1447: CZTTY_CHAN_WRITE(sc, CHNCTL_RS_CONTROL, sc->sc_chanctl_rs_control);
! 1448:
! 1449: CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel);
! 1450: CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTLW);
! 1451:
! 1452: cz_wait_pci_doorbell(cz, "czparam");
! 1453:
! 1454: CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel);
! 1455: CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTLM);
! 1456:
! 1457: cz_wait_pci_doorbell(cz, "czparam");
! 1458:
! 1459: /*
! 1460: * Update the tty layer's idea of the carrier bit, in case we changed
! 1461: * CLOCAL. We don't hang up here; we only do that by explicit
! 1462: * request.
! 1463: */
! 1464: rs_status = CZTTY_CHAN_READ(sc, CHNCTL_RS_STATUS);
! 1465: (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(rs_status, C_RS_DCD));
! 1466:
! 1467: return (0);
! 1468: }
! 1469:
! 1470: /*
! 1471: * czttystart:
! 1472: *
! 1473: * Start or restart transmission.
! 1474: */
! 1475: void
! 1476: czttystart(struct tty *tp)
! 1477: {
! 1478: struct cztty_softc *sc = CZTTY_SOFTC(tp->t_dev);
! 1479: int s;
! 1480:
! 1481: s = spltty();
! 1482: if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
! 1483: goto out;
! 1484:
! 1485: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 1486: if (ISSET(tp->t_state, TS_ASLEEP)) {
! 1487: CLR(tp->t_state, TS_ASLEEP);
! 1488: wakeup(&tp->t_outq);
! 1489: }
! 1490: selwakeup(&tp->t_wsel);
! 1491: if (tp->t_outq.c_cc == 0)
! 1492: goto out;
! 1493: }
! 1494:
! 1495: cztty_transmit(sc, tp);
! 1496: out:
! 1497: splx(s);
! 1498: }
! 1499:
! 1500: /*
! 1501: * czttystop:
! 1502: *
! 1503: * Stop output, e.g., for ^S or output flush.
! 1504: */
! 1505: int
! 1506: czttystop(struct tty *tp, int flag)
! 1507: {
! 1508:
! 1509: /*
! 1510: * XXX We don't do anything here, yet. Mostly, I don't know
! 1511: * XXX exactly how this should be implemented on this device.
! 1512: * XXX We've given a big chunk of data to the MIPS already,
! 1513: * XXX and I don't know how we request the MIPS to stop sending
! 1514: * XXX the data. So, punt for now. --thorpej
! 1515: */
! 1516: return (0);
! 1517: }
! 1518:
! 1519: /*
! 1520: * cztty_diag:
! 1521: *
! 1522: * Issue a scheduled diagnostic message.
! 1523: */
! 1524: void
! 1525: cztty_diag(void *arg)
! 1526: {
! 1527: struct cztty_softc *sc = arg;
! 1528: struct cz_softc *cz = CZTTY_CZ(sc);
! 1529: u_int overflows, parity_errors, framing_errors;
! 1530: int s;
! 1531:
! 1532: s = spltty();
! 1533:
! 1534: overflows = sc->sc_overflows;
! 1535: sc->sc_overflows = 0;
! 1536:
! 1537: parity_errors = sc->sc_parity_errors;
! 1538: sc->sc_parity_errors = 0;
! 1539:
! 1540: framing_errors = sc->sc_framing_errors;
! 1541: sc->sc_framing_errors = 0;
! 1542:
! 1543: sc->sc_errors = 0;
! 1544:
! 1545: splx(s);
! 1546:
! 1547: log(LOG_WARNING,
! 1548: "%s: channel %d: %u overflow%s, %u parity, %u framing error%s\n",
! 1549: cz->cz_dev.dv_xname, sc->sc_channel,
! 1550: overflows, overflows == 1 ? "" : "s",
! 1551: parity_errors,
! 1552: framing_errors, framing_errors == 1 ? "" : "s");
! 1553: }
! 1554:
! 1555: /*
! 1556: * tx and rx ring buffer size macros:
! 1557: *
! 1558: * The transmitter and receiver both use ring buffers. For each one, there
! 1559: * is a get (consumer) and a put (producer) offset. The get value is the
! 1560: * next byte to be read from the ring, and the put is the next one to be
! 1561: * put into the ring. get == put means the ring is empty.
! 1562: *
! 1563: * For each ring, the firmware controls one of (get, put) and this driver
! 1564: * controls the other. For transmission, this driver updates put to point
! 1565: * past the valid data, and the firmware moves get as bytes are sent. Likewise
! 1566: * for receive, the driver controls put, and this driver controls get.
! 1567: */
! 1568: #define TX_MOVEABLE(g, p, s) (((g) > (p)) ? ((g) - (p) - 1) : ((s) - (p)))
! 1569: #define RX_MOVEABLE(g, p, s) (((g) > (p)) ? ((s) - (g)) : ((p) - (g)))
! 1570:
! 1571: /*
! 1572: * cztty_transmit()
! 1573: *
! 1574: * Look at the tty for this port and start sending.
! 1575: */
! 1576: int
! 1577: cztty_transmit(struct cztty_softc *sc, struct tty *tp)
! 1578: {
! 1579: struct cz_softc *cz = CZTTY_CZ(sc);
! 1580: u_int move, get, put, size, address;
! 1581: #ifdef HOSTRAMCODE
! 1582: int error, done = 0;
! 1583: #else
! 1584: int done = 0;
! 1585: #endif
! 1586:
! 1587: size = CZTTY_BUF_READ(sc, BUFCTL_TX_BUFSIZE);
! 1588: get = CZTTY_BUF_READ(sc, BUFCTL_TX_GET);
! 1589: put = CZTTY_BUF_READ(sc, BUFCTL_TX_PUT);
! 1590: address = CZTTY_BUF_READ(sc, BUFCTL_TX_BUFADDR);
! 1591:
! 1592: while ((tp->t_outq.c_cc > 0) && ((move = TX_MOVEABLE(get, put, size)))){
! 1593: #ifdef HOSTRAMCODE
! 1594: if (0) {
! 1595: move = min(tp->t_outq.c_cc, move);
! 1596: error = q_to_b(&tp->t_outq, 0, move);
! 1597: if (error != move) {
! 1598: printf("%s: channel %d: error moving to "
! 1599: "transmit buf\n", cz->cz_dev.dv_xname,
! 1600: sc->sc_channel);
! 1601: move = error;
! 1602: }
! 1603: } else {
! 1604: #endif
! 1605: move = min(ndqb(&tp->t_outq, 0), move);
! 1606: bus_space_write_region_1(cz->cz_win_st, cz->cz_win_sh,
! 1607: address + put, tp->t_outq.c_cf, move);
! 1608: ndflush(&tp->t_outq, move);
! 1609: #ifdef HOSTRAMCODE
! 1610: }
! 1611: #endif
! 1612:
! 1613: put = ((put + move) % size);
! 1614: done = 1;
! 1615: }
! 1616: if (done) {
! 1617: CZTTY_BUF_WRITE(sc, BUFCTL_TX_PUT, put);
! 1618: }
! 1619: return (done);
! 1620: }
! 1621:
! 1622: int
! 1623: cztty_receive(struct cztty_softc *sc, struct tty *tp)
! 1624: {
! 1625: struct cz_softc *cz = CZTTY_CZ(sc);
! 1626: u_int get, put, size, address;
! 1627: int done = 0, ch;
! 1628:
! 1629: size = CZTTY_BUF_READ(sc, BUFCTL_RX_BUFSIZE);
! 1630: get = CZTTY_BUF_READ(sc, BUFCTL_RX_GET);
! 1631: put = CZTTY_BUF_READ(sc, BUFCTL_RX_PUT);
! 1632: address = CZTTY_BUF_READ(sc, BUFCTL_RX_BUFADDR);
! 1633:
! 1634: while ((get != put) && ((tp->t_canq.c_cc + tp->t_rawq.c_cc) < tp->t_hiwat)) {
! 1635: #ifdef HOSTRAMCODE
! 1636: if (hostram)
! 1637: ch = ((char *)fifoaddr)[get];
! 1638: } else {
! 1639: #endif
! 1640: ch = bus_space_read_1(cz->cz_win_st, cz->cz_win_sh,
! 1641: address + get);
! 1642: #ifdef HOSTRAMCODE
! 1643: }
! 1644: #endif
! 1645: (*linesw[tp->t_line].l_rint)(ch, tp);
! 1646: get = (get + 1) % size;
! 1647: done = 1;
! 1648: }
! 1649: if (done) {
! 1650: CZTTY_BUF_WRITE(sc, BUFCTL_RX_GET, get);
! 1651: }
! 1652: return (done);
! 1653: }
CVSweb