📄 cx.c
字号:
unsigned short port = c->chip->port, len = 0, cnt_port, sts_port; struct tty *tp = c->ttyp; int i; if (! tp) return; /* Choose the buffer. */ if (b == 'A') { buf = c->atbuf; cnt_port = ATBCNT(port); sts_port = ATBSTS(port); } else { buf = c->btbuf; cnt_port = BTBCNT(port); sts_port = BTBSTS(port); } /* Is it busy? */ if (inb (sts_port) & BSTS_OWN24) { tp->t_state |= TS_BUSY; return; } switch (c->brk) { case BRK_SEND: *buf++ = 0; /* extended transmit command */ *buf++ = 0x81; /* send break */ *buf++ = 0; /* extended transmit command */ *buf++ = 0x82; /* insert delay */ *buf++ = 250; /* 1/4 of second */ *buf++ = 0; /* extended transmit command */ *buf++ = 0x82; /* insert delay */ *buf++ = 250; /* + 1/4 of second */ len = 8; c->brk = BRK_IDLE; break; case BRK_STOP: *buf++ = 0; /* extended transmit command */ *buf++ = 0x83; /* stop break */ len = 2; c->brk = BRK_IDLE; break; case BRK_IDLE: p = buf; if (tp->t_iflag & IXOFF) while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) { sym = RB_GETC (tp->t_out); /* Send XON/XOFF out of band. */ if (sym == tp->t_cc[VSTOP]) { outb (STCR(port), STC_SNDSPC|STC_SSPC_2); continue; } if (sym == tp->t_cc[VSTART]) { outb (STCR(port), STC_SNDSPC|STC_SSPC_1); continue; } /* Duplicate NULLs in ETC mode. */ if (! sym) *p++ = 0; *p++ = sym; } else while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) { sym = RB_GETC (tp->t_out); /* Duplicate NULLs in ETC mode. */ if (! sym) *p++ = 0; *p++ = sym; } len = p - buf; break; } /* Start transmitter. */ if (len) { outw (cnt_port, len); outb (sts_port, BSTS_INTR | BSTS_OWN24); c->stat->obytes += len; tp->t_state |= TS_BUSY; print (("cx%d.%d: out %d bytes to %c\n", c->board->num, c->num, len, b)); }}void cxoproc (struct tty *tp){ int unit = UNIT (tp->t_dev); cx_chan_t *c = cxchan[unit]; unsigned short port = c->chip->port; int s = spltty (); /* Set current channel number */ outb (CAR(port), c->num & 3); if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) { /* Start transmitter. */ if (! (inb (CSR(port)) & CSRA_TXEN)) cx_cmd (port, CCR_ENTX); /* Determine the buffer order. */ if (inb (DMABSTS(port)) & DMABSTS_NTBUF) { cxout (c, 'B'); cxout (c, 'A'); } else { cxout (c, 'A'); cxout (c, 'B'); } }#if defined (__FreeBSD__) && __FreeBSD__ < 2 if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel) ttwwakeup (tp);#else /* FreeBSD 2.x and BSDI */#ifndef TS_ASLEEP /* FreeBSD some time after 2.0.5 */ ttwwakeup(tp);#else if (RB_LEN (tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup(TSA_OLOWAT(tp)); } selwakeup(&tp->t_wsel); }#endif#endif splx (s);}int cxparam (struct tty *tp, struct termios *t){ int unit = UNIT (tp->t_dev); cx_chan_t *c = cxchan[unit]; unsigned short port = c->chip->port; int clock, period, s; cx_cor1_async_t cor1; if (t->c_ospeed == 0) { /* Clear DTR and RTS. */ s = spltty (); cx_chan_dtr (c, 0); cx_chan_rts (c, 0); splx (s); print (("cx%d.%d: cxparam (hangup)\n", c->board->num, c->num)); return (0); } print (("cx%d.%d: cxparam\n", c->board->num, c->num)); /* Check requested parameters. */ if (t->c_ospeed < 300 || t->c_ospeed > 256*1024) return(EINVAL); if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024)) return(EINVAL);#ifdef __bsdi__ /* CLOCAL flag set -- wakeup everybody who waits for CD. */ /* FreeBSD does this themselves. */ if (! (tp->t_cflag & CLOCAL) && (t->c_cflag & CLOCAL)) wakeup ((caddr_t) &tp->t_rawq);#endif /* And copy them to tty and channel structures. */ c->rxbaud = tp->t_ispeed = t->c_ispeed; c->txbaud = tp->t_ospeed = t->c_ospeed; tp->t_cflag = t->c_cflag; /* Set character length and parity mode. */ BYTE cor1 = 0; switch (t->c_cflag & CSIZE) { default: case CS8: cor1.charlen = 7; break; case CS7: cor1.charlen = 6; break; case CS6: cor1.charlen = 5; break; case CS5: cor1.charlen = 4; break; } if (t->c_cflag & PARENB) { cor1.parmode = PARM_NORMAL; cor1.ignpar = 0; cor1.parity = (t->c_cflag & PARODD) ? PAR_ODD : PAR_EVEN; } else { cor1.parmode = PARM_NOPAR; cor1.ignpar = 1; } /* Enable/disable hardware CTS. */ c->aopt.cor2.ctsae = (t->c_cflag & CRTSCTS) ? 1 : 0; /* Handle DSR as CTS. */ c->aopt.cor2.dsrae = (t->c_cflag & CRTSCTS) ? 1 : 0; /* Enable extended transmit command mode. * Unfortunately, there is no other method for sending break. */ c->aopt.cor2.etc = 1; /* Enable/disable hardware XON/XOFF. */ c->aopt.cor2.ixon = (t->c_iflag & IXON) ? 1 : 0; c->aopt.cor2.ixany = (t->c_iflag & IXANY) ? 1 : 0; /* Set the number of stop bits. */ if (t->c_cflag & CSTOPB) c->aopt.cor3.stopb = STOPB_2; else c->aopt.cor3.stopb = STOPB_1; /* Disable/enable passing XON/XOFF chars to the host. */ c->aopt.cor3.scde = (t->c_iflag & IXON) ? 1 : 0; c->aopt.cor3.flowct = (t->c_iflag & IXON) ? FLOWCC_NOTPASS : FLOWCC_PASS; c->aopt.schr1 = t->c_cc[VSTART]; /* XON */ c->aopt.schr2 = t->c_cc[VSTOP]; /* XOFF */ /* Set current channel number. */ s = spltty (); outb (CAR(port), c->num & 3); /* Set up receiver clock values. */ cx_clock (c->chip->oscfreq, c->rxbaud, &clock, &period); c->opt.rcor.clk = clock; outb (RCOR(port), BYTE c->opt.rcor); outb (RBPR(port), period); /* Set up transmitter clock values. */ cx_clock (c->chip->oscfreq, c->txbaud, &clock, &period); c->opt.tcor.clk = clock; c->opt.tcor.ext1x = 0; outb (TCOR(port), BYTE c->opt.tcor); outb (TBPR(port), period); outb (COR2(port), BYTE c->aopt.cor2); outb (COR3(port), BYTE c->aopt.cor3); outb (SCHR1(port), c->aopt.schr1); outb (SCHR2(port), c->aopt.schr2); if (BYTE c->aopt.cor1 != BYTE cor1) { BYTE c->aopt.cor1 = BYTE cor1; outb (COR1(port), BYTE c->aopt.cor1); /* Any change to COR1 require reinitialization. */ /* Unfortunately, it may cause transmitter glitches... */ cx_cmd (port, CCR_INITCH); } splx (s); return (0);}struct tty *cxdevtotty (dev_t dev){ int unit = UNIT(dev); if (unit == UNIT_CTL || unit >= NCX*NCHAN) return (0); return (cxchan[unit]->ttyp);}int cxselect (dev_t dev, int flag, struct proc *p){ int unit = UNIT (dev); if (unit == UNIT_CTL || unit >= NCX*NCHAN) return (0);#if defined (__FreeBSD__) && __FreeBSD__ < 2 return (ttselect (dev, flag, p));#else /* FreeBSD 2.x and BSDI */ return (ttyselect (cxchan[unit]->ttyp, flag, p));#endif}/* * Stop output on a line */void cxstop (struct tty *tp, int flag){ cx_chan_t *c = cxchan[UNIT(tp->t_dev)]; unsigned short port = c->chip->port; int s = spltty (); if (tp->t_state & TS_BUSY) { print (("cx%d.%d: cxstop\n", c->board->num, c->num)); /* Set current channel number */ outb (CAR(port), c->num & 3); /* Stop transmitter */ cx_cmd (port, CCR_DISTX); } splx (s);}/* * Handle receive interrupts, including receive errors and * receive timeout interrupt. */int cxrinta (cx_chan_t *c){ unsigned short port = c->chip->port; unsigned short len = 0, risr = inw (RISR(port)), reoir = 0; struct tty *tp = c->ttyp; /* Compute optimal receiver buffer length. */ int rbsz = (c->rxbaud + 800 - 1) / 800 * 2; if (rbsz < 4) rbsz = 4; else if (rbsz > DMABUFSZ) rbsz = DMABUFSZ; if (risr & RISA_TIMEOUT) { unsigned long rcbadr = (unsigned short) inw (RCBADRL(port)) | (long) inw (RCBADRU(port)) << 16; unsigned char *buf = 0; unsigned short cnt_port = 0, sts_port = 0; if (rcbadr >= c->brphys && rcbadr < c->brphys+DMABUFSZ) { buf = c->brbuf; len = rcbadr - c->brphys; cnt_port = BRBCNT(port); sts_port = BRBSTS(port); } else if (rcbadr >= c->arphys && rcbadr < c->arphys+DMABUFSZ) { buf = c->arbuf; len = rcbadr - c->arphys; cnt_port = ARBCNT(port); sts_port = ARBSTS(port); } else printf ("cx%d.%d: timeout: invalid buffer address\n", c->board->num, c->num); if (len) { print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n", c->board->num, c->num, len, risr, RISA_BITS, inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); c->stat->ibytes += len; if (tp && (tp->t_state & TS_ISOPEN)) { int i; void (*rint)() = (void(*)()) linesw[tp->t_line].l_rint; for (i=0; i<len; ++i) (*rint) (buf[i], tp); } /* Restart receiver. */ outw (cnt_port, rbsz); outb (sts_port, BSTS_OWN24); } return (REOI_TERMBUFF); } print (("cx%d.%d: async receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n", c->board->num, c->num, risr, RISA_BITS, inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); if (risr & RIS_BUSERR) { printf ("cx%d.%d: receive bus error\n", c->board->num, c->num); ++c->stat->ierrs; } if (risr & (RIS_OVERRUN | RISA_PARERR | RISA_FRERR | RISA_BREAK)) { int err = 0; if (risr & RISA_PARERR) err |= TTY_PE; if (risr & RISA_FRERR) err |= TTY_FE;#ifdef TTY_OE if (risr & RIS_OVERRUN) err |= TTY_OE;#endif#ifdef TTY_BI if (risr & RISA_BREAK) err |= TTY_BI;#endif print (("cx%d.%d: receive error %x\n", c->board->num, c->num, err)); if (tp && (tp->t_state & TS_ISOPEN)) (*linesw[tp->t_line].l_rint) (err, tp); ++c->stat->ierrs; } /* Discard exception characters. */ if ((risr & RISA_SCMASK) && (tp->t_iflag & IXON)) reoir |= REOI_DISCEXC; /* Handle received data. */ if ((risr & RIS_EOBUF) && tp && (tp->t_state & TS_ISOPEN)) { void (*rint)() = (void(*)()) linesw[tp->t_line].l_rint; unsigned char *buf; int i; len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port)); print (("cx%d.%d: async: %d bytes received\n", c->board->num, c->num, len)); c->stat->ibytes += len; buf = (risr & RIS_BB) ? c->brbuf : c->arbuf; for (i=0; i<len; ++i) (*rint) (buf[i], tp); } /* Restart receiver. */ if (! (inb (ARBSTS(port)) & BSTS_OWN24)) { outw (ARBCNT(port), rbsz); outb (ARBSTS(port), BSTS_OWN24); } if (! (inb (BRBSTS(port)) & BSTS_OWN24)) { outw (BRBCNT(port), rbsz); outb (BRBSTS(port), BSTS_OWN24); } return (reoir);}/* * Handle transmit interrupt. */void cxtinta (cx_chan_t *c){ struct tty *tp = c->ttyp; unsigned short port = c->chip->port; unsigned char tisr = inb (TISR(port)); print (("cx%d.%d: async transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n", c->board->num, c->num, tisr, TIS_BITS, inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS)); if (tisr & TIS_BUSERR) { printf ("cx%d.%d: transmit bus error\n", c->board->num, c->num); ++c->stat->oerrs; } else if (tisr & TIS_UNDERRUN) { printf ("cx%d.%d: transmit underrun error\n", c->board->num, c->num); ++c->stat->oerrs; } if (tp) { tp->t_state &= ~(TS_BUSY | TS_FLUSH); if (tp->t_line) (*linesw[tp->t_line].l_start) (tp); else cxoproc (tp); }}/* * Handle modem interrupt. */void cxmint (cx_chan_t *c){ unsigned short port = c->chip->port; unsigned char misr = inb (MISR(port)); unsigned char msvr = inb (MSVR(port)); struct tty *tp = c->ttyp; if (c->mode != M_ASYNC) { printf ("cx%d.%d: unexpected modem interrupt, misr=%b, msvr=%b\n", c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS); return; } print (("cx%d.%d: modem interrupt, misr=%b, msvr=%b\n", c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS)); /* Ignore DSR events. */ /* Ignore RTC/CTS events, handled by hardware. */ /* Handle carrier detect/loss. */ if (tp && (misr & MIS_CCD)) (*linesw[tp->t_line].l_modem) (tp, (msvr & MSV_CD) != 0);}/* * Recover after lost transmit interrupts. */void cxtimeout (caddr_t a){ cx_board_t *b; cx_chan_t *c; struct tty *tp; int s; for (b=cxboard; b<cxboard+NCX; ++b) for (c=b->chan; c<b->chan+NCHAN; ++c) { tp = c->ttyp; if (c->type==T_NONE || c->mode!=M_ASYNC || !tp) continue; s = spltty (); if (tp->t_state & TS_BUSY) { tp->t_state &= ~TS_BUSY; if (tp->t_line) (*linesw[tp->t_line].l_start) (tp); else cxoproc (tp); } splx (s); } timeout ((timeout_func_t) cxtimeout, 0, hz*5);}#endif /* NCX */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -