cy.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,542 行 · 第 1/5 页
C
2,542 行
struct com_s *com; u_int count; u_char *ioptr; u_char line_status; u_char recv_data; u_char serv_type;#ifdef PollMode u_char save_car; u_char save_rir;#endif#ifdef PollMode save_rir = cd_inb(iobase, CD1400_RIR); save_car = cd_inb(iobase, CD1400_CAR); /* enter rx service */ cd_outb(iobase, CD1400_CAR, save_rir); serv_type = cd_inb(iobase, CD1400_RIVR); com = com_addr(baseu + ((serv_type >> CD1400_xIVR_CHAN_SHIFT) & CD1400_xIVR_CHAN));#else /* ack receive service */ serv_type = cy_inb(iobase, CY8_SVCACKR); com = com_addr(baseu + + ((serv_type >> CD1400_xIVR_CHAN_SHIFT) & CD1400_xIVR_CHAN));#endif if (com->do_timestamp) /* XXX a little bloat here... */ com->timestamp = intr_timestamp; if (serv_type & CD1400_RIVR_EXCEPTION) { ++com->recv_exception; line_status = cd_inb(iobase, CD1400_RDSR); /* break/unnattached error bits or real input? */ recv_data = cd_inb(iobase, CD1400_RDSR);#ifndef SOFT_HOTCHAR if (line_status & CD1400_RDSR_SPECIAL && com->hotchar != 0) setsofttty();#endif#if 1 /* XXX "intelligent" PFO error handling would break O error handling */ if (line_status & (LSR_PE|LSR_FE|LSR_BI)) { /* Don't store PE if IGNPAR and BI if IGNBRK, this hack allows "raw" tty optimization works even if IGN* is set. */ if ( com->tp == NULL || !(com->tp->t_state & TS_ISOPEN) || (line_status & (LSR_PE|LSR_FE)) && (com->tp->t_iflag & IGNPAR) || (line_status & LSR_BI) && (com->tp->t_iflag & IGNBRK)) goto cont; if ( (line_status & (LSR_PE|LSR_FE)) && (com->tp->t_state & TS_CAN_BYPASS_L_RINT) && ((line_status & LSR_FE) || (line_status & LSR_PE) && (com->tp->t_iflag & INPCK))) recv_data = 0; }#endif /* 1 */ ++com->bytes_in;#ifdef SOFT_HOTCHAR if (com->hotchar != 0 && recv_data == com->hotchar) setsofttty();#endif ioptr = com->iptr; if (ioptr >= com->ibufend) CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); else { ++com_events; ioptr[0] = recv_data; ioptr[CE_INPUT_OFFSET] = line_status; com->iptr = ++ioptr; if (ioptr == com->ihighwater && 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 if (line_status & LSR_OE) CE_RECORD(com, CE_OVERRUN); } goto cont; } else { int ifree; count = cd_inb(iobase, CD1400_RDCR); com->bytes_in += count; ioptr = com->iptr; ifree = com->ibufend - ioptr; if (count > ifree) { count -= ifree; com_events += ifree; while (ifree-- != 0) { recv_data = cd_inb(iobase, CD1400_RDSR);#ifdef SOFT_HOTCHAR if (com->hotchar != 0 && recv_data == com->hotchar) setsofttty();#endif ioptr[0] = recv_data; ioptr[CE_INPUT_OFFSET] = 0; ++ioptr; } com->delta_error_counts [CE_INTERRUPT_BUF_OVERFLOW] += count; do { recv_data = cd_inb(iobase, CD1400_RDSR);#ifdef SOFT_HOTCHAR if (com->hotchar != 0 && recv_data == com->hotchar) setsofttty();#endif } while (--count != 0); } else { if (ioptr <= com->ihighwater && ioptr + count > com->ihighwater && 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 com_events += count; do { recv_data = cd_inb(iobase, CD1400_RDSR);#ifdef SOFT_HOTCHAR if (com->hotchar != 0 && recv_data == com->hotchar) setsofttty();#endif ioptr[0] = recv_data; ioptr[CE_INPUT_OFFSET] = 0; ++ioptr; } while (--count != 0); } com->iptr = ioptr; }cont: /* terminate service context */#ifdef PollMode cd_outb(iobase, CD1400_RIR, save_rir & ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY)); cd_outb(iobase, CD1400_CAR, save_car);#else cd_outb(iobase, CD1400_EOSRR, 0);#endif } if (status & CD1400_SVRR_MDMCH) { struct com_s *com; u_char modem_status;#ifdef PollMode u_char save_car; u_char save_mir;#else u_char vector;#endif#ifdef PollMode save_mir = cd_inb(iobase, CD1400_MIR); save_car = cd_inb(iobase, CD1400_CAR); /* enter modem service */ cd_outb(iobase, CD1400_CAR, save_mir); com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS + (save_mir & CD1400_MIR_CHAN));#else /* ack modem service */ vector = cy_inb(iobase, CY8_SVCACKM); com = com_addr(baseu + ((vector >> CD1400_xIVR_CHAN_SHIFT) & CD1400_xIVR_CHAN));#endif ++com->mdm; modem_status = cd_inb(iobase, CD1400_MSVR2); if (modem_status != com->last_modem_status) { /* * Schedule high level to handle DCD changes. Note * that we don't use the delta bits anywhere. Some * UARTs mess them up, and it's easy to remember the * previous bits and calculate the delta. */ com->last_modem_status = modem_status; if (!(com->state & CS_CHECKMSR)) { com_events += LOTS_OF_EVENTS; com->state |= CS_CHECKMSR; setsofttty(); }#ifdef SOFT_CTS_OFLOW /* handle CTS change immediately for crisp flow ctl */ if (com->state & CS_CTS_OFLOW) { if (modem_status & MSR_CTS) { com->state |= CS_ODEVREADY; 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); } else { com->state &= ~CS_ODEVREADY; if (com->intr_enable & CD1400_SRER_TXRDY) cd_outb(iobase, CD1400_SRER, com->intr_enable &= ~CD1400_SRER_TXRDY); } }#endif } /* terminate service context */#ifdef PollMode cd_outb(iobase, CD1400_MIR, save_mir & ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY)); cd_outb(iobase, CD1400_CAR, save_car);#else cd_outb(iobase, CD1400_EOSRR, 0);#endif } if (status & CD1400_SVRR_TXRDY) { struct com_s *com;#ifdef PollMode u_char save_car; u_char save_tir;#else u_char vector;#endif#ifdef PollMode save_tir = cd_inb(iobase, CD1400_TIR); save_car = cd_inb(iobase, CD1400_CAR); /* enter tx service */ cd_outb(iobase, CD1400_CAR, save_tir); com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS + (save_tir & CD1400_TIR_CHAN));#else /* ack transmit service */ vector = cy_inb(iobase, CY8_SVCACKT); com = com_addr(baseu + ((vector >> CD1400_xIVR_CHAN_SHIFT) & CD1400_xIVR_CHAN));#endif if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { u_char *ioptr; u_int ocount; ioptr = com->obufq.l_head; ocount = com->obufq.l_tail - ioptr; if (ocount > CD1400_TX_FIFO_SIZE) ocount = CD1400_TX_FIFO_SIZE; com->bytes_out += ocount; do cd_outb(iobase, CD1400_TDR, *ioptr++); while (--ocount != 0); com->obufq.l_head = ioptr; if (ioptr >= com->obufq.l_tail) { struct lbq *qp; qp = com->obufq.l_next; qp->l_queued = FALSE; qp = qp->l_next; if (qp != NULL) { com->obufq.l_head = qp->l_head; com->obufq.l_tail = qp->l_tail; com->obufq.l_next = qp; } else { /* output just completed */ com->state &= ~CS_BUSY; cd_outb(iobase, CD1400_SRER, com->intr_enable &= ~CD1400_SRER_TXRDY); } if (!(com->state & CS_ODONE)) { com_events += LOTS_OF_EVENTS; com->state |= CS_ODONE; setsofttty(); /* handle at high level ASAP */ } } } /* terminate service context */#ifdef PollMode cd_outb(iobase, CD1400_TIR, save_tir & ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY)); cd_outb(iobase, CD1400_CAR, save_car);#else cd_outb(iobase, CD1400_EOSRR, 0);#endif } } /* ensure an edge for the next interrupt */ cy_outb(cy_iobase, CY_CLEAR_INTR, 0); schedsofttty();}static voidsiointr1(com) struct com_s *com;{}intsioioctl(dev, cmd, data, flag, p) dev_t dev; int cmd; caddr_t data; int flag; struct proc *p;{ struct com_s *com; int error; cy_addr iobase; int mynor; int s; struct tty *tp;#if defined(COMPAT_43) || defined(COMPAT_SUNOS) int oldcmd; struct termios term;#endif mynor = minor(dev); com = com_addr(MINOR_TO_UNIT(mynor)); iobase = com->iobase; if (mynor & CONTROL_MASK) { struct termios *ct; switch (mynor & CONTROL_MASK) { case CONTROL_INIT_STATE: ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in; break; case CONTROL_LOCK_STATE: ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in; break; default: return (ENODEV); /* /dev/nodev */ } switch (cmd) { case TIOCSETA: error = suser(p->p_ucred, &p->p_acflag); if (error != 0) return (error); *ct = *(struct termios *)data; return (0); case TIOCGETA: *(struct termios *)data = *ct; return (0); case TIOCGETD: *(int *)data = TTYDISC; return (0); case TIOCGWINSZ: bzero(data, sizeof(struct winsize)); return (0); default: return (ENOTTY); } } tp = com->tp;#if defined(COMPAT_43) || defined(COMPAT_SUNOS) term = tp->t_termios; oldcmd = cmd; error = ttsetcompat(tp, &cmd, data, &term); if (error != 0) return (error); if (cmd != oldcmd) data = (caddr_t)&term;#endif if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { int cc; struct termios *dt = (struct termios *)data; struct termios *lt = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in; dt->c_iflag = (tp->t_iflag & lt->c_iflag) | (dt->c_iflag & ~lt->c_iflag); dt->c_oflag = (tp->t_oflag & lt->c_oflag) | (dt->c_oflag & ~lt->c_oflag); dt->c_cflag = (tp->t_cflag & lt->c_cflag) | (dt->c_cflag & ~lt->c_cflag); dt->c_lflag = (tp->t_lflag & lt->c_lflag) | (dt->c_lflag & ~lt->c_lflag); for (cc = 0; cc < NCCS; ++cc) if (lt->c_cc[cc] != 0) dt->c_cc[cc] = tp->t_cc[cc]; if (lt->c_ispeed != 0) dt->c_ispeed = tp->t_ispeed; if (lt->c_ospeed != 0) dt->c_ospeed = tp->t_ospeed; } error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error >= 0) return (error); s = spltty(); error = ttioctl(tp, cmd, data, flag); disc_optim(tp, &tp->t_termios, com); if (error >= 0) { splx(s); return (error); } cd_outb(iobase, CD1400_CAR, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN); switch (cmd) {#if 0 case TIOCSBRK: outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); break; case TIOCCBRK: outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); break;#endif /* 0 */ case TIOCSDTR: (void)commctl(com, TIOCM_DTR, DMBIS); break; case TIOCCDTR: (void)commctl(com, TIOCM_DTR, DMBIC); break; case TIOCMSET: (void)commctl(com, *(int *)data, DMSET); break; case TIOCMBIS: (void)commctl(com, *(int *)data, DMBIS); break; case TIOCMBIC: (void)commctl(com, *(int *)data, DMBIC); break; case TIOCMGET: *(int *)data = commctl(com, 0, DMGET); break; case TIOCMSDTRWAIT: /* must be root since the wait applies to following logins */ error = suser(p->p_ucred, &p->p_acflag); if (error != 0) { splx(s); return (error); } com->dtr_wait = *(int *)data * hz / 100; break; case TIOCMGDTRWAIT: *(int *)data = com->dtr_wait * 100 / hz; break; case TIOCTIMESTAMP: com->do_timestamp = TRUE; *(struct timeval *)data = com->timestamp; break; default: splx(s); return (ENOTTY); } splx(s); return (0);}voidsiopoll(){ int unit;#ifdef CyDebug ++cy_timeouts;#endif if (com_events == 0) return;repeat: for (unit = 0; unit < NSIO; ++unit) { u_char *buf; struct com_s *com; u_char *ibuf; cy_addr iobase; int incc; struct tty *tp; com = com_addr(unit); if (com == NULL) continue; tp = com->tp; if (tp == NULL) { /* * XXX forget any events related to closed devices * (actually never opened devices) so that we don't * loop. */ disable_intr(); incc = com->iptr - com->ibuf; com->iptr = com->ibuf; if (com->state & CS_CHECKMSR) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?