cy.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,542 行 · 第 1/5 页
C
2,542 行
incc += LOTS_OF_EVENTS; com->state &= ~CS_CHECKMSR; } com_events -= incc; enable_intr(); if (incc != 0) log(LOG_DEBUG, "sio%d: %d events for device with no tp\n", unit, incc); continue; } /* switch the role of the low-level input buffers */ if (com->iptr == (ibuf = com->ibuf)) { buf = NULL; /* not used, but compiler can't tell */ incc = 0; } else { buf = ibuf; disable_intr(); incc = com->iptr - buf; com_events -= incc; if (ibuf == com->ibuf1) ibuf = com->ibuf2; else ibuf = com->ibuf1; com->ibufend = ibuf + RS_IBUFSIZE; com->ihighwater = ibuf + RS_IHIGHWATER; com->iptr = ibuf; /* * There is now room for another low-level buffer full * of input, so enable RTS if it is now disabled and * there is room in the high-level buffer. */ /* * XXX this used not to look at CS_RTS_IFLOW. The * change is to allow full control of MCR_RTS via * ioctls after turning CS_RTS_IFLOW off. Check * for races. We shouldn't allow the ioctls while * CS_RTS_IFLOW is on. */ if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) && !(tp->t_state & TS_TBLOCK))#if 0 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);#else iobase = com->iobase, cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN), cd_outb(iobase, CD1400_MSVR1, com->mcr_image |= MCR_RTS);#endif enable_intr(); com->ibuf = ibuf; } if (com->state & CS_CHECKMSR) { u_char delta_modem_status; disable_intr(); delta_modem_status = com->last_modem_status ^ com->prev_modem_status; com->prev_modem_status = com->last_modem_status; com_events -= LOTS_OF_EVENTS; com->state &= ~CS_CHECKMSR; enable_intr(); if (delta_modem_status & MSR_DCD) (*linesw[tp->t_line].l_modem) (tp, com->prev_modem_status & MSR_DCD); } if (com->state & CS_ODONE) { disable_intr(); com_events -= LOTS_OF_EVENTS; com->state &= ~CS_ODONE; if (!(com->state & CS_BUSY)) com->tp->t_state &= ~TS_BUSY; enable_intr(); (*linesw[tp->t_line].l_start)(tp); } if (incc <= 0 || !(tp->t_state & TS_ISOPEN)) continue; /* * Avoid the grotesquely inefficient lineswitch routine * (ttyinput) in "raw" mode. It usually takes about 450 * instructions (that's without canonical processing or echo!). * slinput is reasonably fast (usually 40 instructions plus * call overhead). */ if (tp->t_state & TS_CAN_BYPASS_L_RINT) { if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER && (com->state & CS_RTS_IFLOW || tp->t_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK)) ttyblock(tp); tk_nin += incc; tk_rawcc += incc; tp->t_rawcc += incc; com->delta_error_counts[CE_TTY_BUF_OVERFLOW] += b_to_q((char *)buf, incc, &tp->t_rawq); ttwakeup(tp); if (tp->t_state & TS_TTSTOP && (tp->t_iflag & IXANY || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { tp->t_state &= ~TS_TTSTOP; tp->t_lflag &= ~FLUSHO; comstart(tp); } } else { do { u_char line_status; int recv_data; line_status = (u_char) buf[CE_INPUT_OFFSET]; recv_data = (u_char) *buf++; if (line_status & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { if (line_status & LSR_BI) recv_data |= TTY_BI; if (line_status & LSR_FE) recv_data |= TTY_FE; if (line_status & LSR_OE) recv_data |= TTY_OE; if (line_status & LSR_PE) recv_data |= TTY_PE; } (*linesw[tp->t_line].l_rint)(recv_data, tp); } while (--incc > 0); } if (com_events == 0) break; } if (com_events >= LOTS_OF_EVENTS) goto repeat;}static intcomparam(tp, t) struct tty *tp; struct termios *t;{ int bits; int cflag; struct com_s *com; u_char cor_change; int idivisor; int iflag; cy_addr iobase; int iprescaler; int itimeout; int odivisor; int oprescaler; u_char opt; int s; int unit; /* do historical conversions */ if (t->c_ispeed == 0) t->c_ispeed = t->c_ospeed; /* check requested parameters */ idivisor = comspeed(t->c_ispeed, &iprescaler); if (idivisor < 0) return (EINVAL); odivisor = comspeed(t->c_ospeed, &oprescaler); if (odivisor < 0) return (EINVAL); /* parameters are OK, convert them to the com struct and the device */ unit = DEV_TO_UNIT(tp->t_dev); com = com_addr(unit); iobase = com->iobase; s = spltty(); cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN); if (odivisor == 0) (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */ else (void)commctl(com, TIOCM_DTR, DMBIS); if (idivisor != 0) { cd_outb(iobase, CD1400_RBPR, idivisor); cd_outb(iobase, CD1400_RCOR, iprescaler); } if (odivisor != 0) { cd_outb(iobase, CD1400_TBPR, odivisor); cd_outb(iobase, CD1400_TCOR, oprescaler); } /* * channel control * receiver enable * transmitter enable (always set) */ cflag = t->c_cflag; opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS); if (opt != com->channel_control) { com->channel_control = opt; cd1400_channel_cmd(iobase, opt); }#ifdef Smarts /* set special chars */ /* XXX if one is _POSIX_VDISABLE, can't use some others */ if (t->c_cc[VSTOP] != _POSIX_VDISABLE) cd_outb(iobase, CD1400_SCHR1, t->c_cc[VSTOP]); if (t->c_cc[VSTART] != _POSIX_VDISABLE) cd_outb(iobase, CD1400_SCHR2, t->c_cc[VSTART]); if (t->c_cc[VINTR] != _POSIX_VDISABLE) cd_outb(iobase, CD1400_SCHR3, t->c_cc[VINTR]); if (t->c_cc[VSUSP] != _POSIX_VDISABLE) cd_outb(iobase, CD1400_SCHR4, t->c_cc[VSUSP]);#endif /* * set channel option register 1 - * parity mode * stop bits * char length */ opt = 0; /* parity */ if (cflag & PARENB) { if (cflag & PARODD) opt |= CD1400_COR1_PARODD; opt |= CD1400_COR1_PARNORMAL; } iflag = t->c_iflag; if (!(iflag & INPCK)) opt |= CD1400_COR1_NOINPCK; bits = 1 + 1; /* stop bits */ if (cflag & CSTOPB) { ++bits; opt |= CD1400_COR1_STOP2; } /* char length */ switch (cflag & CSIZE) { case CS5: bits += 5; opt |= CD1400_COR1_CS5; break; case CS6: bits += 6; opt |= CD1400_COR1_CS6; break; case CS7: bits += 7; opt |= CD1400_COR1_CS7; break; default: bits += 8; opt |= CD1400_COR1_CS8; break; } cor_change = 0; if (opt != com->cor[0]) { cor_change |= CD1400_CCR_COR1; cd_outb(iobase, CD1400_COR1, com->cor[0] = opt); } /* * Set receive time-out period, normally to max(one char time, 5 ms). */ if (t->c_ispeed == 0) itimeout = cd_inb(iobase, CD1400_RTPR); else { itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;#ifdef SOFT_HOTCHAR#define MIN_RTP 1#else#define MIN_RTP 5#endif if (itimeout < MIN_RTP) itimeout = MIN_RTP; } if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0 && t->c_cc[VTIME] * 10 > itimeout) itimeout = t->c_cc[VTIME] * 10; if (itimeout > 255) itimeout = 255; cd_outb(iobase, CD1400_RTPR, itimeout); /* * set channel option register 2 - * flow control */ opt = 0;#ifdef Smarts if (iflag & IXANY) opt |= CD1400_COR2_IXANY; if (iflag & IXOFF) opt |= CD1400_COR2_IXOFF;#endif#ifndef SOFT_CTS_OFLOW if (cflag & CCTS_OFLOW) opt |= CD1400_COR2_CCTS_OFLOW;#endif if (opt != com->cor[1]) { cor_change |= CD1400_CCR_COR2; cd_outb(iobase, CD1400_COR2, com->cor[1] = opt); } /* * set channel option register 3 - * receiver FIFO interrupt threshold * flow control */ opt = RxFifoThreshold;#ifdef Smarts if (t->c_lflag & ICANON) opt |= CD1400_COR3_SCD34; /* detect INTR & SUSP chars */ if (iflag & IXOFF) /* detect and transparently handle START and STOP chars */ opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12;#endif if (opt != com->cor[2]) { cor_change |= CD1400_CCR_COR3; cd_outb(iobase, CD1400_COR3, com->cor[2] = opt); } /* notify the CD1400 if COR1-3 have changed */ if (cor_change) cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change); /* * set channel option register 4 - * CR/NL processing * break processing * received exception processing */ opt = 0; if (iflag & IGNCR) opt |= CD1400_COR4_IGNCR;#ifdef Smarts /* * we need a new ttyinput() for this, as we don't want to * have ICRNL && INLCR being done in both layers, or to have * synchronisation problems */ if (iflag & ICRNL) opt |= CD1400_COR4_ICRNL; if (iflag & INLCR) opt |= CD1400_COR4_INLCR;#endif if (iflag & IGNBRK) opt |= CD1400_COR4_IGNBRK; if (!(iflag & BRKINT)) opt |= CD1400_COR4_NOBRKINT;#if 0 /* XXX using this "intelligence" breaks reporting of overruns. */ if (iflag & IGNPAR) opt |= CD1400_COR4_PFO_DISCARD; else { if (iflag & PARMRK) opt |= CD1400_COR4_PFO_ESC; else opt |= CD1400_COR4_PFO_NUL; }#else opt |= CD1400_COR4_PFO_EXCEPTION;#endif cd_outb(iobase, CD1400_COR4, opt); /* * set channel option register 5 - */ opt = 0; if (iflag & ISTRIP) opt |= CD1400_COR5_ISTRIP; if (t->c_iflag & IEXTEN) /* enable LNEXT (e.g. ctrl-v quoting) handling */ opt |= CD1400_COR5_LNEXT;#ifdef Smarts if (t->c_oflag & ONLCR) opt |= CD1400_COR5_ONLCR; if (t->c_oflag & OCRNL) opt |= CD1400_COR5_OCRNL;#endif cd_outb(iobase, CD1400_COR5, opt); /* * XXX we probably alway want to track carrier changes, so that * TS_CARR_ON gives the true carrier. If we don't track them, * then we should set TS_CARR_ON when CLOCAL drops. */ /* * set modem change option register 1 * generate modem interrupts on which 1 -> 0 input transitions * also controls auto-DTR output flow-control, which we don't use */ opt = cflag & CLOCAL ? 0 : CD1400_MCOR1_CDzd;#ifdef SOFT_CTS_OFLOW if (cflag & CCTS_OFLOW) opt |= CD1400_MCOR1_CTSzd;#endif cd_outb(iobase, CD1400_MCOR1, opt); /* * set modem change option register 2 * generate modem interrupts on specific 0 -> 1 input transitions */ opt = cflag & CLOCAL ? 0 : CD1400_MCOR2_CDod;#ifdef SOFT_CTS_OFLOW if (cflag & CCTS_OFLOW) opt |= CD1400_MCOR2_CTSod;#endif cd_outb(iobase, CD1400_MCOR2, opt); /* * XXX should have done this long ago, but there is too much state * to change all atomically. */ disable_intr(); com->state &= ~CS_TTGO; if (!(tp->t_state & TS_TTSTOP)) com->state |= CS_TTGO; if (cflag & CRTS_IFLOW) com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */ else com->state &= ~CS_RTS_IFLOW; /* * Set up state to handle output flow control. * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? * Now has 10+ msec latency, while CTS flow has 50- usec latency. */ com->state |= CS_ODEVREADY;#ifdef SOFT_CTS_OFLOW com->state &= ~CS_CTS_OFLOW; if (cflag & CCTS_OFLOW) { com->state |= CS_CTS_OFLOW; if (!(com->last_modem_status & MSR_CTS)) com->state &= ~CS_ODEVREADY; }#endif /* XXX shouldn't call functions while intrs are disabled. */ disc_optim(tp, t, com);#if 0 /* * Recover from fiddling with CS_TTGO. We used to call siointr1() * unconditionally, but that defeated the careful discarding of * stale input in sioopen(). */ if (com->state >= (CS_BUSY | CS_TTGO)) siointr1(com);#endif if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { if (!(com->intr_enable & CD1400_SRER_TXRDY)) cd_outb(iobase, CD1400_SRER, com->intr_enable |= CD1400_SRER_TXRDY); } else { if (com->intr_enable & CD1400_SRER_TXRDY) cd_outb(iobase, CD1400_SRER, com->intr_enable &= ~CD1400_SRER_TXRDY); } enable_intr(); splx(s); return (0);}static voidcomstart(tp) struct tty *tp;{ struct com_s *com; cy_addr iobase; int s;#ifdef CyDebug bool_t started;#endif int unit; unit = DEV_TO_UNIT(tp->t_dev); com = com_addr(unit); iobase = com->iobase; s = spltty();#ifdef CyDebug ++com->start_count; started = FALSE;#endif disable_intr(); cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN); if (tp->t_state & TS_TTSTOP) { com->state &= ~CS_TTGO; if (com->intr_enable & CD1400_SRER_TXRDY) cd_outb(iobase, CD1400_SRER, com->intr_enable &= ~CD1400_SRER_TXRDY); } else { com->state |= CS_TTGO; if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY) && !(com->intr_enable & CD1400_SRER_TXRDY)) cd_outb(iobase, CD1400_SRER, com->intr_enable |= CD1400_SRER_TXRDY); } if (tp->t_state & TS_TBLOCK) { if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)#if 0 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);#else cd_outb(iobase, CD1400_MSVR1, com->mcr_image &= ~MCR_RTS);#endif } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?