📄 zs.c
字号:
zi->zi_dev.dv_xname, (unit & 1) + 'a', i ? (o ? "i/o" : i) : o); cs->cs_consio = 1; cs->cs_brkabort = 1; return (tp);}#ifdef KGDB/* * The kgdb zs port, if any, was altered at boot time (see zs_kgdb_init). * Pick up the current speed and character size and restore the original * speed. */static voidzs_checkkgdb(int unit, struct zs_chanstate *cs, struct tty *tp){ if (kgdb_dev == makedev(ZSMAJOR, unit)) { tp->t_ispeed = tp->t_ospeed = kgdb_rate; tp->t_cflag = CS8; cs->cs_kgdb = 1; cs->cs_speed = zs_kgdb_savedspeed; (void) zsparam(tp, &tp->t_termios); }}#endif/* * Compute the current baud rate given a ZSCC channel. */static intzs_getspeed(zc) register volatile struct zschan *zc;{ register int tconst; tconst = ZS_READ(zc, 12); tconst |= ZS_READ(zc, 13) << 8; return (TCONST_TO_BPS(PCLK / 16, tconst));}/* * Do an internal open. */static voidzsiopen(struct tty *tp){ (void) zsparam(tp, &tp->t_termios); ttsetwater(tp); tp->t_state = TS_ISOPEN | TS_CARR_ON;}/* * Do an internal close. Eventually we should shut off the chip when both * ports on it are closed. */static voidzsiclose(struct tty *tp){ ttylclose(tp, 0); /* ??? */ ttyclose(tp); /* ??? */ tp->t_state = 0;}/* * Open a zs serial port. This interface may not be used to open * the keyboard and mouse ports. (XXX) */intzsopen(dev_t dev, int flags, int mode, struct proc *p){ register struct tty *tp; register struct zs_chanstate *cs; struct zsinfo *zi; int unit = minor(dev), zs = unit >> 1, error, s; if (zs >= zscd.cd_ndevs || (zi = zscd.cd_devs[zs]) == NULL || unit == ZS_KBD || unit == ZS_MOUSE) return (ENXIO); cs = &zi->zi_cs[unit & 1]; if (cs->cs_consio) return (ENXIO); /* ??? */ tp = cs->cs_ttyp; s = spltty(); if ((tp->t_state & TS_ISOPEN) == 0) { ttychars(tp); if (tp->t_ispeed == 0) { tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = cs->cs_speed; } (void) zsparam(tp, &tp->t_termios); ttsetwater(tp); } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { splx(s); return (EBUSY); } error = 0; for (;;) { /* loop, turning on the device, until carrier present */ zs_modem(cs, 1); if (cs->cs_softcar) tp->t_state |= TS_CARR_ON; if (flags & O_NONBLOCK || tp->t_cflag & CLOCAL || tp->t_state & TS_CARR_ON) break; tp->t_state |= TS_WOPEN; if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0)) break; } splx(s); if (error == 0) error = linesw[tp->t_line].l_open(dev, tp); if (error) zs_modem(cs, 0); return (error);}/* * Close a zs serial port. */intzsclose(dev_t dev, int flags, int mode, struct proc *p){ register struct zs_chanstate *cs; register struct tty *tp; struct zsinfo *zi; int unit = minor(dev), s; zi = zscd.cd_devs[unit >> 1]; cs = &zi->zi_cs[unit & 1]; tp = cs->cs_ttyp; linesw[tp->t_line].l_close(tp, flags); if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || (tp->t_state & TS_ISOPEN) == 0) { zs_modem(cs, 0); /* hold low for 1 second */ (void) tsleep((caddr_t)cs, TTIPRI, ttclos, hz); } ttyclose(tp);#ifdef KGDB /* Reset the speed if we're doing kgdb on this port */ if (cs->cs_kgdb) { tp->t_ispeed = tp->t_ospeed = kgdb_rate; (void) zsparam(tp, &tp->t_termios); }#endif return (0);}/* * Read/write zs serial port. */intzsread(dev_t dev, struct uio *uio, int flags){ register struct tty *tp = &zs_tty[minor(dev)]; return (linesw[tp->t_line].l_read(tp, uio, flags));}intzswrite(dev_t dev, struct uio *uio, int flags){ register struct tty *tp = &zs_tty[minor(dev)]; return (linesw[tp->t_line].l_write(tp, uio, flags));}/* * ZS hardware interrupt. Scan all ZS channels. NB: we know here that * channels are kept in (A,B) pairs. * * Do just a little, then get out; set a software interrupt if more * work is needed. * * We deliberately ignore the vectoring Zilog gives us, and match up * only the number of `reset interrupt under service' operations, not * the order. *//* ARGSUSED */intzshard(void *intrarg){ register struct zs_chanstate *a;#define b (a + 1) register volatile struct zschan *zc; register int rr3, intflags = 0, v, i; static int zsrint(struct zs_chanstate *, volatile struct zschan *); static int zsxint(struct zs_chanstate *, volatile struct zschan *); static int zssint(struct zs_chanstate *, volatile struct zschan *); for (a = zslist; a != NULL; a = b->cs_next) { rr3 = ZS_READ(a->cs_zc, 3); if (rr3 & (ZSRR3_IP_A_RX|ZSRR3_IP_A_TX|ZSRR3_IP_A_STAT)) { intflags |= 2; zc = a->cs_zc; i = a->cs_rbput; if (rr3 & ZSRR3_IP_A_RX && (v = zsrint(a, zc)) != 0) { a->cs_rbuf[i++ & ZLRB_RING_MASK] = v; intflags |= 1; } if (rr3 & ZSRR3_IP_A_TX && (v = zsxint(a, zc)) != 0) { a->cs_rbuf[i++ & ZLRB_RING_MASK] = v; intflags |= 1; } if (rr3 & ZSRR3_IP_A_STAT && (v = zssint(a, zc)) != 0) { a->cs_rbuf[i++ & ZLRB_RING_MASK] = v; intflags |= 1; } a->cs_rbput = i; } if (rr3 & (ZSRR3_IP_B_RX|ZSRR3_IP_B_TX|ZSRR3_IP_B_STAT)) { intflags |= 2; zc = b->cs_zc; i = b->cs_rbput; if (rr3 & ZSRR3_IP_B_RX && (v = zsrint(b, zc)) != 0) { b->cs_rbuf[i++ & ZLRB_RING_MASK] = v; intflags |= 1; } if (rr3 & ZSRR3_IP_B_TX && (v = zsxint(b, zc)) != 0) { b->cs_rbuf[i++ & ZLRB_RING_MASK] = v; intflags |= 1; } if (rr3 & ZSRR3_IP_B_STAT && (v = zssint(b, zc)) != 0) { b->cs_rbuf[i++ & ZLRB_RING_MASK] = v; intflags |= 1; } b->cs_rbput = i; } }#undef b if (intflags & 1) {#if sun4c /* XXX -- but this will go away when zshard moves to locore.s */ struct clockframe *p = intrarg; if ((p->psr & PSR_PIL) < (PIL_TTY << 8)) { zsshortcuts++; (void) spltty(); if (zshardscope) { LED_ON; LED_OFF; } return (zssoft(intrarg)); }#endif ienab_bis(IE_ZSSOFT); } return (intflags & 2);}static intzsrint(register struct zs_chanstate *cs, register volatile struct zschan *zc){ register int c = zc->zc_data; if (cs->cs_conk) { register struct conk_state *conk = &zsconk_state; /* * Check here for console abort function, so that we * can abort even when interrupts are locking up the * machine. */ if (c == KBD_RESET) { conk->conk_id = 1; /* ignore next byte */ conk->conk_l1 = 0; } else if (conk->conk_id) conk->conk_id = 0; /* stop ignoring bytes */ else if (c == KBD_L1) conk->conk_l1 = 1; /* L1 went down */ else if (c == (KBD_L1|KBD_UP)) conk->conk_l1 = 0; /* L1 went up */ else if (c == KBD_A && conk->conk_l1) { zsabort(); conk->conk_l1 = 0; /* we never see the up */ goto clearit; /* eat the A after L1-A */ } }#ifdef KGDB if (c == FRAME_START && cs->cs_kgdb && (cs->cs_ttyp->t_state & TS_ISOPEN) == 0) { zskgdb(cs->cs_unit); goto clearit; }#endif /* compose receive character and status */ c <<= 8; c |= ZS_READ(zc, 1); /* clear receive error & interrupt condition */ zc->zc_csr = ZSWR0_RESET_ERRORS; zc->zc_csr = ZSWR0_CLR_INTR; return (ZRING_MAKE(ZRING_RINT, c));clearit: zc->zc_csr = ZSWR0_RESET_ERRORS; zc->zc_csr = ZSWR0_CLR_INTR; return (0);}static intzsxint(register struct zs_chanstate *cs, register volatile struct zschan *zc){ register int i = cs->cs_tbc; if (i == 0) { zc->zc_csr = ZSWR0_RESET_TXINT; zc->zc_csr = ZSWR0_CLR_INTR; return (ZRING_MAKE(ZRING_XINT, 0)); } cs->cs_tbc = i - 1; zc->zc_data = *cs->cs_tba++; zc->zc_csr = ZSWR0_CLR_INTR; return (0);}static intzssint(register struct zs_chanstate *cs, register volatile struct zschan *zc){ register int rr0; rr0 = zc->zc_csr; zc->zc_csr = ZSWR0_RESET_STATUS; zc->zc_csr = ZSWR0_CLR_INTR; /* * The chip's hardware flow control is, as noted in zsreg.h, * busted---if the DCD line goes low the chip shuts off the * receiver (!). If we want hardware CTS flow control but do * not have it, and carrier is now on, turn HFC on; if we have * HFC now but carrier has gone low, turn it off. */ if (rr0 & ZSRR0_DCD) { if (cs->cs_ttyp->t_cflag & CCTS_OFLOW && (cs->cs_creg[3] & ZSWR3_HFC) == 0) { cs->cs_creg[3] |= ZSWR3_HFC; ZS_WRITE(zc, 3, cs->cs_creg[3]); } } else { if (cs->cs_creg[3] & ZSWR3_HFC) { cs->cs_creg[3] &= ~ZSWR3_HFC; ZS_WRITE(zc, 3, cs->cs_creg[3]); } } if ((rr0 & ZSRR0_BREAK) && cs->cs_brkabort) { zsabort(); return (0); } return (ZRING_MAKE(ZRING_SINT, rr0));}zsabort(){ printf("stopping on keyboard abort\n"); callrom();}#ifdef KGDB/* * KGDB framing character received: enter kernel debugger. This probably * should time out after a few seconds to avoid hanging on spurious input. */zskgdb(int unit){ printf("zs%d%c: kgdb interrupt\n", unit >> 1, (unit & 1) + 'a'); kgdb_connect(1);}#endif/* * Print out a ring or fifo overrun error message. */static voidzsoverrun(int unit, long *ptime, char *what){ if (*ptime != time.tv_sec) { *ptime = time.tv_sec; log(LOG_WARNING, "zs%d%c: %s overrun\n", unit >> 1, (unit & 1) + 'a', what); }}/* * ZS software interrupt. Scan all channels for deferred interrupts. */intzssoft(void *arg){ register struct zs_chanstate *cs; register volatile struct zschan *zc; register struct linesw *line; register struct tty *tp; register int get, n, c, cc, unit, s; for (cs = zslist; cs != NULL; cs = cs->cs_next) { get = cs->cs_rbget;again: n = cs->cs_rbput; /* atomic */ if (get == n) /* nothing more on this line */ continue; unit = cs->cs_unit; /* set up to handle interrupts */ zc = cs->cs_zc; tp = cs->cs_ttyp; line = &linesw[tp->t_line]; /* * Compute the number of interrupts in the receive ring. * If the count is overlarge, we lost some events, and * must advance to the first valid one. It may get * overwritten if more data are arriving, but this is * too expensive to check and gains nothing (we already * lost out; all we can do at this point is trade one * kind of loss for another). */ n -= get; if (n > ZLRB_RING_SIZE) { zsoverrun(unit, &cs->cs_rotime, "ring"); get += n - ZLRB_RING_SIZE; n = ZLRB_RING_SIZE; } while (--n >= 0) { /* race to keep ahead of incoming interrupts */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -