cy.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,542 行 · 第 1/5 页
C
2,542 行
/* * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it * appropriately in comparam() if RTS-flow is being changed. * Check for races. */ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)#if 0 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);#else cd_outb(iobase, CD1400_MSVR1, com->mcr_image |= MCR_RTS);#endif } enable_intr(); if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { splx(s); return; } if (tp->t_outq.c_cc != 0) { struct lbq *qp; struct lbq *next; if (!com->obufs[0].l_queued) {#ifdef CyDebug started = TRUE;#endif com->obufs[0].l_tail = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1, sizeof com->obuf1); com->obufs[0].l_next = NULL; com->obufs[0].l_queued = TRUE; disable_intr(); if (com->state & CS_BUSY) { qp = com->obufq.l_next; while ((next = qp->l_next) != NULL) qp = next; qp->l_next = &com->obufs[0]; } else { com->obufq.l_head = com->obufs[0].l_head; com->obufq.l_tail = com->obufs[0].l_tail; com->obufq.l_next = &com->obufs[0]; com->state |= CS_BUSY; if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) cd_outb(iobase, CD1400_SRER, com->intr_enable |= CD1400_SRER_TXRDY); } enable_intr(); } if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {#ifdef CyDebug started = TRUE;#endif com->obufs[1].l_tail = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2, sizeof com->obuf2); com->obufs[1].l_next = NULL; com->obufs[1].l_queued = TRUE; disable_intr(); if (com->state & CS_BUSY) { qp = com->obufq.l_next; while ((next = qp->l_next) != NULL) qp = next; qp->l_next = &com->obufs[1]; } else { com->obufq.l_head = com->obufs[1].l_head; com->obufq.l_tail = com->obufs[1].l_tail; com->obufq.l_next = &com->obufs[1]; com->state |= CS_BUSY; if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) cd_outb(iobase, CD1400_SRER, com->intr_enable |= CD1400_SRER_TXRDY); } enable_intr(); } tp->t_state |= TS_BUSY; }#ifdef CyDebug if (started) ++com->start_real;#endif#if 0 disable_intr(); if (com->state >= (CS_BUSY | CS_TTGO)) { siointr1(com); /* fake interrupt to start output */ enable_intr();#endif ttwwakeup(tp); splx(s);}voidsiostop(tp, rw) struct tty *tp; int rw;{ struct com_s *com; com = com_addr(DEV_TO_UNIT(tp->t_dev)); disable_intr(); if (rw & FWRITE) { com->obufs[0].l_queued = FALSE; com->obufs[1].l_queued = FALSE; if (com->state & CS_ODONE) com_events -= LOTS_OF_EVENTS; com->state &= ~(CS_ODONE | CS_BUSY); com->tp->t_state &= ~TS_BUSY; } if (rw & FREAD) { com_events -= (com->iptr - com->ibuf); com->iptr = com->ibuf; } enable_intr(); comstart(tp); /* XXX should clear h/w fifos too. */}struct tty *siodevtotty(dev) dev_t dev;{ int mynor; int unit; mynor = minor(dev); if (mynor & CONTROL_MASK) return (NULL); unit = MINOR_TO_UNIT(mynor); if ((u_int) unit >= NSIO) return (NULL); return (&sio_tty[unit]);}static intcommctl(com, bits, how) struct com_s *com; int bits; int how;{ cy_addr iobase; int mcr; int msr; if (how == DMGET) { if (com->channel_control & CD1400_CCR_RCVEN) bits |= TIOCM_LE; mcr = com->mcr_image; if (mcr & MCR_DTR) bits |= TIOCM_DTR; if (mcr & MCR_RTS) /* XXX wired on for Cyclom-8Ys */ bits |= TIOCM_RTS; msr = com->prev_modem_status; if (msr & MSR_CTS) bits |= TIOCM_CTS; if (msr & MSR_DCD) bits |= TIOCM_CD; if (msr & MSR_DSR) bits |= TIOCM_DSR; if (msr & MSR_RI) /* XXX not connected except for Cyclom-16Y? */ bits |= TIOCM_RI; return (bits); } iobase = com->iobase; mcr = 0; if (bits & TIOCM_DTR) mcr |= MCR_DTR; if (bits & TIOCM_RTS) mcr |= MCR_RTS; disable_intr(); switch (how) { case DMSET: com->mcr_image = mcr; cd_outb(iobase, CD1400_MSVR1, mcr); cd_outb(iobase, CD1400_MSVR2, mcr); break; case DMBIS: com->mcr_image = mcr = com->mcr_image | mcr; cd_outb(iobase, CD1400_MSVR1, mcr); cd_outb(iobase, CD1400_MSVR2, mcr); break; case DMBIC: com->mcr_image = mcr = com->mcr_image & ~mcr; cd_outb(iobase, CD1400_MSVR1, mcr); cd_outb(iobase, CD1400_MSVR2, mcr); break; } enable_intr(); return (0);}static voidsiosettimeout(){ struct com_s *com; bool_t someopen; int unit; /* * Set our timeout period to 1 second if no polled devices are open. * Otherwise set it to max(1/200, 1/hz). * Enable timeouts iff some device is open. */ untimeout(comwakeup, (void *)NULL); sio_timeout = hz; someopen = FALSE; for (unit = 0; unit < NSIO; ++unit) { com = com_addr(unit); if (com != NULL && com->tp != NULL && com->tp->t_state & TS_ISOPEN) { someopen = TRUE;#if 0 if (com->poll || com->poll_output) { sio_timeout = hz > 200 ? hz / 200 : 1; break; }#endif } } if (someopen) { sio_timeouts_until_log = hz / sio_timeout; timeout(comwakeup, (void *)NULL, sio_timeout); } else { /* Flush error messages, if any. */ sio_timeouts_until_log = 1; comwakeup((void *)NULL); untimeout(comwakeup, (void *)NULL); }}static voidcomwakeup(chan) void *chan;{ struct com_s *com; int unit; timeout(comwakeup, (void *)NULL, sio_timeout);#if 0 /* * Recover from lost output interrupts. * Poll any lines that don't use interrupts. */ for (unit = 0; unit < NSIO; ++unit) { com = com_addr(unit); if (com != NULL && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) { disable_intr(); siointr1(com); enable_intr(); } }#endif /* * Check for and log errors, but not too often. */ if (--sio_timeouts_until_log > 0) return; sio_timeouts_until_log = hz / sio_timeout; for (unit = 0; unit < NSIO; ++unit) { int errnum; com = com_addr(unit); if (com == NULL) continue; for (errnum = 0; errnum < CE_NTYPES; ++errnum) { u_int delta; u_long total; disable_intr(); delta = com->delta_error_counts[errnum]; com->delta_error_counts[errnum] = 0; enable_intr(); if (delta == 0) continue; total = com->error_counts[errnum] += delta; log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n", unit, delta, error_desc[errnum], delta == 1 ? "" : "s", total);#if 0 /* * XXX if we resurrect this then we should move * the dropping of the ftl to somewhere with less * latency. */ if (errnum == CE_OVERRUN && com->hasfifo && com->ftl > FIFO_TRIGGER_1) { static u_char ftl_in_bytes[] = { 1, 4, 8, 14, }; com->ftl_init = FIFO_TRIGGER_8;#define FIFO_TRIGGER_DELTA FIFO_TRIGGER_4 com->ftl_max = com->ftl -= FIFO_TRIGGER_DELTA; outb(com->iobase + com_fifo, FIFO_ENABLE | com->ftl); log(LOG_DEBUG, "sio%d: reduced fifo trigger level to %d\n", unit, ftl_in_bytes[com->ftl / FIFO_TRIGGER_DELTA]); }#endif } }}static voiddisc_optim(tp, t, com) struct tty *tp; struct termios *t; struct com_s *com;{#ifndef SOFT_HOTCHAR cy_addr iobase; u_char opt;#endif /* * XXX can skip a lot more cases if Smarts. Maybe * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. */ if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) && (!(t->c_iflag & PARMRK) || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) && linesw[tp->t_line].l_rint == ttyinput) tp->t_state |= TS_CAN_BYPASS_L_RINT; else tp->t_state &= ~TS_CAN_BYPASS_L_RINT; /* * Prepare to reduce input latency for packet * discplines with a end of packet character. */ if (tp->t_line == SLIPDISC) com->hotchar = 0xc0; else if (tp->t_line == PPPDISC) com->hotchar = 0x7e; else com->hotchar = 0;#ifndef SOFT_HOTCHAR iobase = com->iobase; cd_outb(iobase, CD1400_CAR, com->unit & CD1400_CAR_CHAN); opt = com->cor[2] & ~CD1400_COR3_SCD34; if (com->hotchar != 0) { cd_outb(iobase, CD1400_SCHR3, com->hotchar); cd_outb(iobase, CD1400_SCHR4, com->hotchar); opt |= CD1400_COR3_SCD34; } if (opt != com->cor[2]) { cd_outb(iobase, CD1400_COR3, com->cor[2] = opt); cd1400_channel_cmd(com->iobase, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3); }#endif}#ifdef Smarts/* standard line discipline input routine */intcyinput(c, tp) int c; struct tty *tp;{ /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK * bits, as they are done by the CD1400. Hardly worth the effort, * given that high-throughput sessions are raw anyhow. */}#endif /* Smarts */static intcomspeed(speed, prescaler_io) speed_t speed; int *prescaler_io;{ int actual; int error; int divider; int prescaler; int prescaler_unit; if (speed == 0) return (0); if (speed < 0 || speed > 150000) return (-1); /* determine which prescaler to use */ for (prescaler_unit = 4, prescaler = 2048; prescaler_unit; prescaler_unit--, prescaler >>= 2) { if (CY_CLOCK / prescaler / speed > 63) break; } divider = (CY_CLOCK / prescaler * 2 / speed + 1) / 2; /* round off */ if (divider > 255) divider = 255; actual = CY_CLOCK/prescaler/divider; error = ((actual - speed) * 2000 / speed + 1) / 2; /* percentage */ /* 3.0% max error tolerance */ if (error < -30 || error > 30) return (-1);#if 0 printf("prescaler = %d (%d)\n", prescaler, prescaler_unit); printf("divider = %d (%x)\n", divider, divider); printf("actual = %d\n", actual); printf("error = %d\n", error);#endif *prescaler_io = prescaler_unit; return (divider);}static voidcd1400_channel_cmd(iobase, cmd) cy_addr iobase; int cmd;{ /* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed, as the card is probed every round? Replaced delaycount with 8k. Either delaycount has to be implemented in FreeBSD or more sensible way of doing these should be implemented. DELAY isn't enough here. */ u_int maxwait = 5 * 8 * 1024; /* approx. 5 ms */ /* wait for processing of previous command to complete */ while (cd_inb(iobase, CD1400_CCR) && maxwait--) ; if (!maxwait) log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n", 5 * 8 * 1024); cd_outb(iobase, CD1400_CCR, cmd);}#ifdef CyDebug/* useful in ddb */voidcystatus(unit) int unit;{ struct com_s *com; cy_addr iobase; u_int ocount; struct tty *tp; com = com_addr(unit); printf("info for channel %d\n", unit); printf("------------------\n"); printf("total cyclom service probes:\t%d\n", cy_svrr_probes); printf("calls to upper layer:\t\t%d\n", cy_timeouts); if (com == NULL) return; iobase = com->iobase; printf("\n"); printf("cd1400 base address:\\tt%p\n", iobase); cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN); printf("saved channel_control:\t\t0x%02x\n", com->channel_control); printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n", com->cor[0], com->cor[1], com->cor[2]); printf("service request enable reg:\t0x%02x (0x%02x cached)\n", cd_inb(iobase, CD1400_SRER), com->intr_enable); printf("service request register:\t0x%02x\n", cd_inb(iobase, CD1400_SVRR)); printf("modem status:\t\t\t0x%02x (0x%02x cached)\n", cd_inb(iobase, CD1400_MSVR2), com->prev_modem_status); printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n", cd_inb(iobase, CD1400_RIR), cd_inb(iobase, CD1400_TIR), cd_inb(iobase, CD1400_MIR)); printf("\n"); printf("com state:\t\t\t0x%02x\n", com->state); printf("calls to comstart():\t\t%d (%d useful)\n", com->start_count, com->start_real); printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf); ocount = 0; if (com->obufs[0].l_queued) ocount += com->obufs[0].l_tail - com->obufs[0].l_head; if (com->obufs[1].l_queued) ocount += com->obufs[1].l_tail - com->obufs[1].l_head; printf("tx buffer chars:\t\t%u\n", ocount); printf("received chars:\t\t\t%d\n", com->bytes_in); printf("received exceptions:\t\t%d\n", com->recv_exception); printf("modem signal deltas:\t\t%d\n", com->mdm); printf("transmitted chars:\t\t%d\n", com->bytes_out); printf("\n"); tp = com->tp; if (tp != NULL) { printf("tty state:\t\t\t0x%08x\n", tp->t_state); printf("upper layer queue lengths:\t%d raw, %d canon, %d output\n", tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc); } else printf("tty state:\t\t\tclosed\n");}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?