2 * Cronyx-Sigma adapter driver for FreeBSD.
3 * Supports PPP/HDLC protocol in synchronous mode,
4 * and asyncronous channels with full modem control.
6 * Copyright (C) 1994 Cronyx Ltd.
7 * Author: Serge Vakulenko, <vak@zebub.msk.su>
9 * This software is distributed with NO WARRANTIES, not even the implied
10 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Authors grant any other persons or organisations permission to use
13 * or modify this software as long as this message is kept with the software,
14 * all derivative works or modified versions.
16 * Version 1.9, Wed Oct 4 18:58:15 MSK 1995
18 * $FreeBSD: src/sys/i386/isa/cx.c,v 1.45.2.1 2001/02/26 04:23:09 jlemon Exp $
19 * $DragonFly: src/sys/dev/netif/cx/cx.c,v 1.15 2005/06/13 21:53:24 joerg Exp $
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/kernel.h>
29 #include <sys/fcntl.h>
33 #include <sys/socket.h>
34 #include <sys/thread2.h>
37 #if defined(__DragonFly__) || defined(__FreeBSD__)
38 # if defined(__FreeBSD__) && __FreeBSD__ < 2
39 # include <machine/pio.h>
40 # define RB_GETC(q) getc(q)
44 # include <sys/ttystats.h>
45 # include <machine/inline.h>
46 # define tsleep(tp,pri,msg,x) ((tp)->t_state |= TS_WOPEN,\
47 ttysleep (tp, (caddr_t)&tp->t_rawq, pri, msg, x))
49 #if defined(__DragonFly__) || !defined (__FreeBSD__) || __FreeBSD__ >= 2
51 # define RB_LEN(q) ((q).c_cc)
52 # define RB_GETC(q) getc(&q)
53 #ifndef TSA_CARR_ON /* FreeBSD 2.x before not long after 2.0.5 */
54 # define TSA_CARR_ON(tp) tp
55 # define TSA_OLOWAT(q) ((caddr_t)&(q)->t_out)
59 #include <machine/cronyx.h>
62 /* XXX imported from if_cx.c. */
63 void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
66 void cxmint (cx_chan_t *c);
67 int cxrinta (cx_chan_t *c);
68 void cxtinta (cx_chan_t *c);
70 extern struct callout cxtimeout_ch;
73 # define print(s) printf s
75 # define print(s) {/*void*/}
78 #define DMABUFSZ (6*256) /* buffer size */
79 #define BYTE *(unsigned char*)&
80 #define UNIT(u) (minor(u) & 077)
83 extern cx_board_t cxboard [NCX]; /* adapter state structures */
84 extern cx_chan_t *cxchan [NCX*NCHAN]; /* unit to channel struct pointer */
85 #if defined(__DragonFly__) || __FreeBSD__ >= 2
86 static struct tty cx_tty [NCX*NCHAN]; /* tty data */
88 static d_open_t cxopen;
89 static d_close_t cxclose;
90 static d_ioctl_t cxioctl;
93 /* Don't make this static, since if_cx.c uses it. */
94 struct cdevsw cx_cdevsw = {
97 /* flags */ D_TTY | D_KQFILTER,
104 /* write */ ttywrite,
108 /* strategy */ nostrategy,
111 /* kqfilter */ ttykqfilter
114 struct tty *cx_tty [NCX*NCHAN]; /* tty data */
117 static void cxoproc (struct tty *tp);
118 static void cxstop (struct tty *tp, int flag);
119 static int cxparam (struct tty *tp, struct termios *t);
121 int cxopen (dev_t dev, int flag, int mode, struct thread *td)
123 int unit = UNIT (dev);
124 cx_chan_t *c = cxchan[unit];
129 if (unit == UNIT_CTL) {
130 print (("cx: cxopen /dev/cronyx\n"));
133 if (unit >= NCX*NCHAN || !c || c->type==T_NONE)
135 port = c->chip->port;
136 print (("cx%d.%d: cxopen unit=%d\n", c->board->num, c->num, unit));
137 if (c->mode != M_ASYNC)
140 #if defined(__DragonFly__) || defined(__FreeBSD__)
141 #if defined(__DragonFly__) || __FreeBSD__ >= 2
142 c->ttyp = &cx_tty[unit];
144 c->ttyp = cx_tty[unit] = ttymalloc (cx_tty[unit]);
147 MALLOC (cx_tty[unit], struct tty*, sizeof (struct tty), M_DEVBUF, M_WAITOK);
148 bzero (cx_tty[unit], sizeof (*cx_tty[unit]));
149 c->ttyp = cx_tty[unit];
151 c->ttyp->t_oproc = cxoproc;
152 c->ttyp->t_stop = cxstop;
153 c->ttyp->t_param = cxparam;
155 dev->si_tty = c->ttyp;
158 MALLOC (c->ttydev, struct ttydevice_tmp*,
159 sizeof (struct ttydevice_tmp), M_DEVBUF, M_WAITOK);
160 bzero (c->ttydev, sizeof (*c->ttydev));
161 strcpy (c->ttydev->tty_name, "cx");
162 c->ttydev->tty_unit = unit;
163 c->ttydev->tty_base = unit;
164 c->ttydev->tty_count = 1;
165 c->ttydev->tty_ttys = c->ttyp;
166 tty_attach (c->ttydev);
171 if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) &&
174 if (! (tp->t_state & TS_ISOPEN)) {
176 if (tp->t_ispeed == 0) {
178 tp->t_termios = deftermios;
183 tp->t_cflag = CREAD | CS8 | HUPCL;
184 tp->t_ispeed = c->rxbaud;
185 tp->t_ospeed = c->txbaud;
188 cxparam (tp, &tp->t_termios);
193 if (! (tp->t_state & TS_ISOPEN)) {
195 * Compute optimal receiver buffer length.
196 * The best choice is rxbaud/400.
197 * Make it even, to avoid byte-wide DMA transfers.
198 * --------------------------
199 * Baud rate Buffer length
200 * --------------------------
208 * --------------------------
210 int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
213 else if (rbsz > DMABUFSZ)
216 /* Initialize channel, enable receiver. */
217 cx_cmd (port, CCR_INITCH | CCR_ENRX);
218 cx_cmd (port, CCR_INITCH | CCR_ENRX);
220 /* Start receiver. */
221 outw (ARBCNT(port), rbsz);
222 outw (BRBCNT(port), rbsz);
223 outw (ARBSTS(port), BSTS_OWN24);
224 outw (BRBSTS(port), BSTS_OWN24);
226 /* Enable interrupts. */
227 outb (IER(port), IER_RXD | IER_RET | IER_TXD | IER_MDM);
233 (*linesw[tp->t_line].l_modem)(tp, 1);
234 if (! (flag & O_NONBLOCK)) {
235 /* Lock the channel against cxconfig while we are
236 * waiting for carrier. */
238 while (!(tp->t_cflag & CLOCAL) && !(tp->t_state & TS_CARR_ON))
239 if ((error = tsleep (TSA_CARR_ON(tp), PCATCH,
242 c->sopt.lock = 0; /* Unlock the channel. */
244 print (("cx%d.%d: cxopen done csr=%b\n", c->board->num, c->num,
245 inb(CSR(c->chip->port)), CSRA_BITS));
249 #if defined(__DragonFly__) || __FreeBSD__ >= 2
250 error = (*linesw[tp->t_line].l_open) (dev, tp);
252 error = (*linesw[tp->t_line].l_open) (dev, tp, 0);
257 int cxclose (dev_t dev, int flag, int mode, struct thread *td)
259 int unit = UNIT (dev);
260 cx_chan_t *c = cxchan[unit];
263 if (unit == UNIT_CTL)
266 (*linesw[tp->t_line].l_close) (tp, flag);
269 * Transmitter continues sending the queued data. */
272 outb (CAR(c->chip->port), c->num & 3);
273 outb (IER(c->chip->port), IER_TXD | IER_MDM);
274 cx_cmd (c->chip->port, CCR_DISRX);
276 /* Clear DTR and RTS. */
277 if ((tp->t_cflag & HUPCL) || ! (tp->t_state & TS_ISOPEN)) {
282 /* Stop sending break. */
283 if (c->brk == BRK_SEND) {
285 if (! (tp->t_state & TS_BUSY))
293 int cxioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
295 int unit = UNIT (dev);
301 struct ifnet *master;
303 if (unit == UNIT_CTL) {
304 /* Process an ioctl request on /dev/cronyx */
305 cx_options_t *o = (cx_options_t*) data;
307 if (o->board >= NCX || o->channel >= NCHAN)
309 c = &cxboard[o->board].chan[o->channel];
310 if (c->type == T_NONE)
317 print (("cx%d.%d: CXIOCSETMODE\n", o->board, o->channel));
318 if (c->type == T_NONE)
320 if (c->type == T_ASYNC && o->mode != M_ASYNC)
322 if (o->mode == M_ASYNC)
329 /* Somebody is waiting for carrier? */
332 /* /dev/ttyXX is already opened by someone? */
333 if (c->mode == M_ASYNC && c->ttyp &&
334 (c->ttyp->t_state & TS_ISOPEN))
336 /* Network interface is up? */
337 if (c->mode != M_ASYNC && (c->ifp->if_flags & IFF_UP))
340 /* Find the master interface. */
341 master = *o->master ? ifunit (o->master) : c->ifp;
344 m = cxchan[master->if_dunit];
346 /* Leave the previous master queue. */
347 if (c->master != c->ifp) {
348 cx_chan_t *p = cxchan[c->master->if_dunit];
350 for (; p; p=p->slaveq)
352 p->slaveq = c->slaveq;
355 /* Set up new master. */
359 /* Join the new master queue. */
360 if (c->master != c->ifp) {
361 c->slaveq = m->slaveq;
366 c->rxbaud = o->rxbaud;
367 c->txbaud = o->txbaud;
374 case 0: c->board->if0type = o->iftype; break;
375 case 8: c->board->if8type = o->iftype; break;
378 cxswitch (c, o->sopt);
380 outb (IER(c->chip->port), 0);
385 st = (cx_stat_t*) data;
386 st->rintr = c->stat->rintr;
387 st->tintr = c->stat->tintr;
388 st->mintr = c->stat->mintr;
389 st->ibytes = c->stat->ibytes;
390 st->ipkts = c->stat->ipkts;
391 st->ierrs = c->stat->ierrs;
392 st->obytes = c->stat->obytes;
393 st->opkts = c->stat->opkts;
394 st->oerrs = c->stat->oerrs;
398 print (("cx%d.%d: CXIOCGETMODE\n", o->board, o->channel));
401 o->rxbaud = c->rxbaud;
402 o->txbaud = c->txbaud;
410 case 0: o->iftype = c->board->if0type; break;
411 case 8: o->iftype = c->board->if8type; break;
413 if (c->master != c->ifp)
414 strlcpy(o->master, c->master->if_xname, sizeof(o->master));
426 #if defined(__DragonFly__) || __FreeBSD__ >= 2
427 error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag, td);
429 error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag);
431 if (error != ENOIOCTL)
433 error = ttioctl (tp, cmd, data, flag);
434 if (error != ENOIOCTL)
443 case TIOCSBRK: /* Start sending line break */
445 if (! (tp->t_state & TS_BUSY))
448 case TIOCCBRK: /* Stop sending line break */
450 if (! (tp->t_state & TS_BUSY))
453 case TIOCSDTR: /* Set DTR */
456 case TIOCCDTR: /* Clear DTR */
459 case TIOCMSET: /* Set DTR/RTS */
460 cx_chan_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
461 cx_chan_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
463 case TIOCMBIS: /* Add DTR/RTS */
464 if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 1);
465 if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 1);
467 case TIOCMBIC: /* Clear DTR/RTS */
468 if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 0);
469 if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 0);
471 case TIOCMGET: /* Get modem status */
472 msv = inb (MSVR(c->chip->port));
473 *(int*)data = TIOCM_LE; /* always enabled while open */
474 if (msv & MSV_DSR) *(int*)data |= TIOCM_DSR;
475 if (msv & MSV_CTS) *(int*)data |= TIOCM_CTS;
476 if (msv & MSV_CD) *(int*)data |= TIOCM_CD;
477 if (c->dtr) *(int*)data |= TIOCM_DTR;
478 if (c->rts) *(int*)data |= TIOCM_RTS;
487 * Fill transmitter buffer with data.
490 cxout (cx_chan_t *c, char b)
492 unsigned char *buf, *p, sym;
493 unsigned short port = c->chip->port, len = 0, cnt_port, sts_port;
494 struct tty *tp = c->ttyp;
499 /* Choose the buffer. */
502 cnt_port = ATBCNT(port);
503 sts_port = ATBSTS(port);
506 cnt_port = BTBCNT(port);
507 sts_port = BTBSTS(port);
511 if (inb (sts_port) & BSTS_OWN24) {
512 tp->t_state |= TS_BUSY;
518 *buf++ = 0; /* extended transmit command */
519 *buf++ = 0x81; /* send break */
520 *buf++ = 0; /* extended transmit command */
521 *buf++ = 0x82; /* insert delay */
522 *buf++ = 250; /* 1/4 of second */
523 *buf++ = 0; /* extended transmit command */
524 *buf++ = 0x82; /* insert delay */
525 *buf++ = 250; /* + 1/4 of second */
530 *buf++ = 0; /* extended transmit command */
531 *buf++ = 0x83; /* stop break */
537 if (tp->t_iflag & IXOFF)
538 while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) {
539 sym = RB_GETC (tp->t_out);
540 /* Send XON/XOFF out of band. */
541 if (sym == tp->t_cc[VSTOP]) {
542 outb (STCR(port), STC_SNDSPC|STC_SSPC_2);
545 if (sym == tp->t_cc[VSTART]) {
546 outb (STCR(port), STC_SNDSPC|STC_SSPC_1);
549 /* Duplicate NULLs in ETC mode. */
555 while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) {
556 sym = RB_GETC (tp->t_out);
557 /* Duplicate NULLs in ETC mode. */
566 /* Start transmitter. */
568 outw (cnt_port, len);
569 outb (sts_port, BSTS_INTR | BSTS_OWN24);
570 c->stat->obytes += len;
571 tp->t_state |= TS_BUSY;
572 print (("cx%d.%d: out %d bytes to %c\n",
573 c->board->num, c->num, len, b));
577 void cxoproc (struct tty *tp)
579 int unit = UNIT (tp->t_dev);
580 cx_chan_t *c = cxchan[unit];
581 unsigned short port = c->chip->port;
585 /* Set current channel number */
586 outb (CAR(port), c->num & 3);
588 if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) {
589 /* Start transmitter. */
590 if (! (inb (CSR(port)) & CSRA_TXEN))
591 cx_cmd (port, CCR_ENTX);
593 /* Determine the buffer order. */
594 if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
602 #ifndef TS_ASLEEP /* FreeBSD some time after 2.0.5 */
605 if (RB_LEN (tp->t_out) <= tp->t_lowat) {
606 if (tp->t_state & TS_ASLEEP) {
607 tp->t_state &= ~TS_ASLEEP;
608 wakeup(TSA_OLOWAT(tp));
610 selwakeup(&tp->t_wsel);
617 cxparam (struct tty *tp, struct termios *t)
619 int unit = UNIT (tp->t_dev);
620 cx_chan_t *c = cxchan[unit];
621 unsigned short port = c->chip->port;
623 cx_cor1_async_t cor1;
625 if (t->c_ospeed == 0) {
626 /* Clear DTR and RTS. */
631 print (("cx%d.%d: cxparam (hangup)\n", c->board->num, c->num));
634 print (("cx%d.%d: cxparam\n", c->board->num, c->num));
636 /* Check requested parameters. */
637 if (t->c_ospeed < 300 || t->c_ospeed > 256*1024)
639 if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024))
643 /* CLOCAL flag set -- wakeup everybody who waits for CD. */
644 /* FreeBSD does this themselves. */
645 if (! (tp->t_cflag & CLOCAL) && (t->c_cflag & CLOCAL))
646 wakeup ((caddr_t) &tp->t_rawq);
648 /* And copy them to tty and channel structures. */
649 c->rxbaud = tp->t_ispeed = t->c_ispeed;
650 c->txbaud = tp->t_ospeed = t->c_ospeed;
651 tp->t_cflag = t->c_cflag;
653 /* Set character length and parity mode. */
655 switch (t->c_cflag & CSIZE) {
657 case CS8: cor1.charlen = 7; break;
658 case CS7: cor1.charlen = 6; break;
659 case CS6: cor1.charlen = 5; break;
660 case CS5: cor1.charlen = 4; break;
662 if (t->c_cflag & PARENB) {
663 cor1.parmode = PARM_NORMAL;
665 cor1.parity = (t->c_cflag & PARODD) ? PAR_ODD : PAR_EVEN;
667 cor1.parmode = PARM_NOPAR;
671 /* Enable/disable hardware CTS. */
672 c->aopt.cor2.ctsae = (t->c_cflag & CRTSCTS) ? 1 : 0;
673 /* Handle DSR as CTS. */
674 c->aopt.cor2.dsrae = (t->c_cflag & CRTSCTS) ? 1 : 0;
675 /* Enable extended transmit command mode.
676 * Unfortunately, there is no other method for sending break. */
677 c->aopt.cor2.etc = 1;
678 /* Enable/disable hardware XON/XOFF. */
679 c->aopt.cor2.ixon = (t->c_iflag & IXON) ? 1 : 0;
680 c->aopt.cor2.ixany = (t->c_iflag & IXANY) ? 1 : 0;
682 /* Set the number of stop bits. */
683 if (t->c_cflag & CSTOPB)
684 c->aopt.cor3.stopb = STOPB_2;
686 c->aopt.cor3.stopb = STOPB_1;
687 /* Disable/enable passing XON/XOFF chars to the host. */
688 c->aopt.cor3.scde = (t->c_iflag & IXON) ? 1 : 0;
689 c->aopt.cor3.flowct = (t->c_iflag & IXON) ? FLOWCC_NOTPASS : FLOWCC_PASS;
691 c->aopt.schr1 = t->c_cc[VSTART]; /* XON */
692 c->aopt.schr2 = t->c_cc[VSTOP]; /* XOFF */
694 /* Set current channel number. */
696 outb (CAR(port), c->num & 3);
698 /* Set up receiver clock values. */
699 cx_clock (c->chip->oscfreq, c->rxbaud, &clock, &period);
700 c->opt.rcor.clk = clock;
701 outb (RCOR(port), BYTE c->opt.rcor);
702 outb (RBPR(port), period);
704 /* Set up transmitter clock values. */
705 cx_clock (c->chip->oscfreq, c->txbaud, &clock, &period);
706 c->opt.tcor.clk = clock;
707 c->opt.tcor.ext1x = 0;
708 outb (TCOR(port), BYTE c->opt.tcor);
709 outb (TBPR(port), period);
711 outb (COR2(port), BYTE c->aopt.cor2);
712 outb (COR3(port), BYTE c->aopt.cor3);
713 outb (SCHR1(port), c->aopt.schr1);
714 outb (SCHR2(port), c->aopt.schr2);
716 if (BYTE c->aopt.cor1 != BYTE cor1) {
717 BYTE c->aopt.cor1 = BYTE cor1;
718 outb (COR1(port), BYTE c->aopt.cor1);
719 /* Any change to COR1 require reinitialization. */
720 /* Unfortunately, it may cause transmitter glitches... */
721 cx_cmd (port, CCR_INITCH);
729 * Stop output on a line
731 void cxstop (struct tty *tp, int flag)
733 cx_chan_t *c = cxchan[UNIT(tp->t_dev)];
734 unsigned short port = c->chip->port;
738 if (tp->t_state & TS_BUSY) {
739 print (("cx%d.%d: cxstop\n", c->board->num, c->num));
741 /* Set current channel number */
742 outb (CAR(port), c->num & 3);
744 /* Stop transmitter */
745 cx_cmd (port, CCR_DISTX);
752 * Handle receive interrupts, including receive errors and
753 * receive timeout interrupt.
755 int cxrinta (cx_chan_t *c)
757 unsigned short port = c->chip->port;
758 unsigned short len = 0, risr = inw (RISR(port)), reoir = 0;
759 struct tty *tp = c->ttyp;
761 /* Compute optimal receiver buffer length. */
762 int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
765 else if (rbsz > DMABUFSZ)
768 if (risr & RISA_TIMEOUT) {
769 unsigned long rcbadr = (unsigned short) inw (RCBADRL(port)) |
770 (long) inw (RCBADRU(port)) << 16;
771 unsigned char *buf = 0;
772 unsigned short cnt_port = 0, sts_port = 0;
773 if (rcbadr >= c->brphys && rcbadr < c->brphys+DMABUFSZ) {
775 len = rcbadr - c->brphys;
776 cnt_port = BRBCNT(port);
777 sts_port = BRBSTS(port);
778 } else if (rcbadr >= c->arphys && rcbadr < c->arphys+DMABUFSZ) {
780 len = rcbadr - c->arphys;
781 cnt_port = ARBCNT(port);
782 sts_port = ARBSTS(port);
784 printf ("cx%d.%d: timeout: invalid buffer address\n",
785 c->board->num, c->num);
788 print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n",
789 c->board->num, c->num, len, risr, RISA_BITS,
790 inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
791 c->stat->ibytes += len;
792 if (tp && (tp->t_state & TS_ISOPEN)) {
794 int (*rint)(int, struct tty *) =
795 linesw[tp->t_line].l_rint;
797 for (i=0; i<len; ++i)
798 (*rint) (buf[i], tp);
801 /* Restart receiver. */
802 outw (cnt_port, rbsz);
803 outb (sts_port, BSTS_OWN24);
805 return (REOI_TERMBUFF);
808 print (("cx%d.%d: async receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
809 c->board->num, c->num, risr, RISA_BITS,
810 inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
812 if (risr & RIS_BUSERR) {
813 printf ("cx%d.%d: receive bus error\n", c->board->num, c->num);
816 if (risr & (RIS_OVERRUN | RISA_PARERR | RISA_FRERR | RISA_BREAK)) {
819 if (risr & RISA_PARERR)
821 if (risr & RISA_FRERR)
824 if (risr & RIS_OVERRUN)
828 if (risr & RISA_BREAK)
831 print (("cx%d.%d: receive error %x\n", c->board->num, c->num, err));
832 if (tp && (tp->t_state & TS_ISOPEN))
833 (*linesw[tp->t_line].l_rint) (err, tp);
837 /* Discard exception characters. */
838 if ((risr & RISA_SCMASK) && tp && (tp->t_iflag & IXON))
839 reoir |= REOI_DISCEXC;
841 /* Handle received data. */
842 if ((risr & RIS_EOBUF) && tp && (tp->t_state & TS_ISOPEN)) {
843 int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint;
847 len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
849 print (("cx%d.%d: async: %d bytes received\n",
850 c->board->num, c->num, len));
851 c->stat->ibytes += len;
853 buf = (risr & RIS_BB) ? c->brbuf : c->arbuf;
854 for (i=0; i<len; ++i)
855 (*rint) (buf[i], tp);
858 /* Restart receiver. */
859 if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
860 outw (ARBCNT(port), rbsz);
861 outb (ARBSTS(port), BSTS_OWN24);
863 if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
864 outw (BRBCNT(port), rbsz);
865 outb (BRBSTS(port), BSTS_OWN24);
871 * Handle transmit interrupt.
873 void cxtinta (cx_chan_t *c)
875 struct tty *tp = c->ttyp;
876 unsigned short port = c->chip->port;
877 unsigned char tisr = inb (TISR(port));
879 print (("cx%d.%d: async transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
880 c->board->num, c->num, tisr, TIS_BITS,
881 inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS));
883 if (tisr & TIS_BUSERR) {
884 printf ("cx%d.%d: transmit bus error\n",
885 c->board->num, c->num);
887 } else if (tisr & TIS_UNDERRUN) {
888 printf ("cx%d.%d: transmit underrun error\n",
889 c->board->num, c->num);
893 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
895 (*linesw[tp->t_line].l_start) (tp);
902 * Handle modem interrupt.
904 void cxmint (cx_chan_t *c)
906 unsigned short port = c->chip->port;
907 unsigned char misr = inb (MISR(port));
908 unsigned char msvr = inb (MSVR(port));
909 struct tty *tp = c->ttyp;
911 if (c->mode != M_ASYNC) {
912 printf ("cx%d.%d: unexpected modem interrupt, misr=%b, msvr=%b\n",
913 c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS);
916 print (("cx%d.%d: modem interrupt, misr=%b, msvr=%b\n",
917 c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS));
919 /* Ignore DSR events. */
920 /* Ignore RTC/CTS events, handled by hardware. */
921 /* Handle carrier detect/loss. */
922 if (tp && (misr & MIS_CCD))
923 (*linesw[tp->t_line].l_modem) (tp, (msvr & MSV_CD) != 0);
927 * Recover after lost transmit interrupts.
936 for (b = cxboard; b < cxboard + NCX; ++b) {
937 for (c = b->chan; c < b->chan + NCHAN; ++c) {
939 if (c->type == T_NONE || c->mode != M_ASYNC || !tp)
942 if (tp->t_state & TS_BUSY) {
943 tp->t_state &= ~TS_BUSY;
945 (*linesw[tp->t_line].l_start) (tp);
952 callout_reset (&cxtimeout_ch, hz * 5, cxtimeout, NULL);
956 #if defined(__DragonFly__) || (defined(__FreeBSD__) && (__FreeBSD__ > 1 ))
960 cx_drvinit(void *unused)
964 SYSINIT(cxdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cx_drvinit,NULL)