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.20 2006/12/22 23:26:19 swildner Exp $
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/kernel.h>
29 #include <sys/fcntl.h>
34 #include <sys/socket.h>
35 #include <sys/thread2.h>
38 #if defined(__DragonFly__) || defined(__FreeBSD__)
39 # if defined(__FreeBSD__) && __FreeBSD__ < 2
40 # include <machine/pio.h>
41 # define RB_GETC(q) getc(q)
45 # include <sys/ttystats.h>
46 # include <machine/inline.h>
47 # define tsleep(tp,pri,msg,x) ((tp)->t_state |= TS_WOPEN,\
48 ttysleep (tp, (caddr_t)&tp->t_rawq, pri, msg, x))
50 #if defined(__DragonFly__) || !defined (__FreeBSD__) || __FreeBSD__ >= 2
52 # define RB_LEN(q) ((q).c_cc)
53 # define RB_GETC(q) clist_getc(&q)
54 #ifndef TSA_CARR_ON /* FreeBSD 2.x before not long after 2.0.5 */
55 # define TSA_CARR_ON(tp) tp
56 # define TSA_OLOWAT(q) ((caddr_t)&(q)->t_out)
60 #include <machine/cronyx.h>
63 /* XXX imported from if_cx.c. */
64 void cxswitch (cx_chan_t
*c
, cx_soft_opt_t
new);
67 void cxmint (cx_chan_t
*c
);
68 int cxrinta (cx_chan_t
*c
);
69 void cxtinta (cx_chan_t
*c
);
71 extern struct callout cxtimeout_ch
;
74 # define print(s) kprintf s
76 # define print(s) {/*void*/}
79 #define DMABUFSZ (6*256) /* buffer size */
80 #define BYTE *(unsigned char*)&
81 #define UNIT(u) (minor(u) & 077)
84 extern cx_board_t cxboard
[NCX
]; /* adapter state structures */
85 extern cx_chan_t
*cxchan
[NCX
*NCHAN
]; /* unit to channel struct pointer */
86 #if defined(__DragonFly__) || __FreeBSD__ >= 2
87 static struct tty cx_tty
[NCX
*NCHAN
]; /* tty data */
89 static d_open_t cxopen
;
90 static d_close_t cxclose
;
91 static d_ioctl_t cxioctl
;
94 /* Don't make this static, since if_cx.c uses it. */
95 struct dev_ops cx_ops
= {
96 { "cx", CDEV_MAJOR
, D_TTY
| D_KQFILTER
},
103 .d_kqfilter
= ttykqfilter
106 struct tty
*cx_tty
[NCX
*NCHAN
]; /* tty data */
109 static void cxoproc (struct tty
*tp
);
110 static void cxstop (struct tty
*tp
, int flag
);
111 static int cxparam (struct tty
*tp
, struct termios
*t
);
114 cxopen (struct dev_open_args
*ap
)
116 cdev_t dev
= ap
->a_head
.a_dev
;
117 int unit
= UNIT (dev
);
118 cx_chan_t
*c
= cxchan
[unit
];
123 if (unit
== UNIT_CTL
) {
124 print (("cx: cxopen /dev/cronyx\n"));
127 if (unit
>= NCX
*NCHAN
|| !c
|| c
->type
==T_NONE
)
129 port
= c
->chip
->port
;
130 print (("cx%d.%d: cxopen unit=%d\n", c
->board
->num
, c
->num
, unit
));
131 if (c
->mode
!= M_ASYNC
)
134 #if defined(__DragonFly__) || defined(__FreeBSD__)
135 #if defined(__DragonFly__) || __FreeBSD__ >= 2
136 c
->ttyp
= &cx_tty
[unit
];
138 c
->ttyp
= cx_tty
[unit
] = ttymalloc (cx_tty
[unit
]);
141 MALLOC (cx_tty
[unit
], struct tty
*, sizeof (struct tty
), M_DEVBUF
, M_WAITOK
);
142 bzero (cx_tty
[unit
], sizeof (*cx_tty
[unit
]));
143 c
->ttyp
= cx_tty
[unit
];
145 c
->ttyp
->t_oproc
= cxoproc
;
146 c
->ttyp
->t_stop
= cxstop
;
147 c
->ttyp
->t_param
= cxparam
;
149 dev
->si_tty
= c
->ttyp
;
152 MALLOC (c
->ttydev
, struct ttydevice_tmp
*,
153 sizeof (struct ttydevice_tmp
), M_DEVBUF
, M_WAITOK
);
154 bzero (c
->ttydev
, sizeof (*c
->ttydev
));
155 strcpy (c
->ttydev
->tty_name
, "cx");
156 c
->ttydev
->tty_unit
= unit
;
157 c
->ttydev
->tty_base
= unit
;
158 c
->ttydev
->tty_count
= 1;
159 c
->ttydev
->tty_ttys
= c
->ttyp
;
160 tty_attach (c
->ttydev
);
165 if ((tp
->t_state
& TS_ISOPEN
) && (tp
->t_state
& TS_XCLUDE
) &&
166 priv_check_cred(ap
->a_cred
, PRIV_ROOT
, 0))
168 if (! (tp
->t_state
& TS_ISOPEN
)) {
170 if (tp
->t_ispeed
== 0) {
172 tp
->t_termios
= deftermios
;
177 tp
->t_cflag
= CREAD
| CS8
| HUPCL
;
178 tp
->t_ispeed
= c
->rxbaud
;
179 tp
->t_ospeed
= c
->txbaud
;
182 cxparam (tp
, &tp
->t_termios
);
187 if (! (tp
->t_state
& TS_ISOPEN
)) {
189 * Compute optimal receiver buffer length.
190 * The best choice is rxbaud/400.
191 * Make it even, to avoid byte-wide DMA transfers.
192 * --------------------------
193 * Baud rate Buffer length
194 * --------------------------
202 * --------------------------
204 int rbsz
= (c
->rxbaud
+ 800 - 1) / 800 * 2;
207 else if (rbsz
> DMABUFSZ
)
210 /* Initialize channel, enable receiver. */
211 cx_cmd (port
, CCR_INITCH
| CCR_ENRX
);
212 cx_cmd (port
, CCR_INITCH
| CCR_ENRX
);
214 /* Start receiver. */
215 outw (ARBCNT(port
), rbsz
);
216 outw (BRBCNT(port
), rbsz
);
217 outw (ARBSTS(port
), BSTS_OWN24
);
218 outw (BRBSTS(port
), BSTS_OWN24
);
220 /* Enable interrupts. */
221 outb (IER(port
), IER_RXD
| IER_RET
| IER_TXD
| IER_MDM
);
227 (*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
228 if (! (ap
->a_oflags
& O_NONBLOCK
)) {
229 /* Lock the channel against cxconfig while we are
230 * waiting for carrier. */
232 while (!(tp
->t_cflag
& CLOCAL
) && !(tp
->t_state
& TS_CARR_ON
))
233 if ((error
= tsleep (TSA_CARR_ON(tp
), PCATCH
,
236 c
->sopt
.lock
= 0; /* Unlock the channel. */
238 print (("cx%d.%d: cxopen done csr=%b\n", c
->board
->num
, c
->num
,
239 inb(CSR(c
->chip
->port
)), CSRA_BITS
));
243 #if defined(__DragonFly__) || __FreeBSD__ >= 2
244 error
= (*linesw
[tp
->t_line
].l_open
) (dev
, tp
);
246 error
= (*linesw
[tp
->t_line
].l_open
) (dev
, tp
, 0);
252 cxclose (struct dev_close_args
*ap
)
254 cdev_t dev
= ap
->a_head
.a_dev
;
255 int unit
= UNIT (dev
);
256 cx_chan_t
*c
= cxchan
[unit
];
259 if (unit
== UNIT_CTL
)
262 (*linesw
[tp
->t_line
].l_close
) (tp
, ap
->a_fflag
);
265 * Transmitter continues sending the queued data. */
268 outb (CAR(c
->chip
->port
), c
->num
& 3);
269 outb (IER(c
->chip
->port
), IER_TXD
| IER_MDM
);
270 cx_cmd (c
->chip
->port
, CCR_DISRX
);
272 /* Clear DTR and RTS. */
273 if ((tp
->t_cflag
& HUPCL
) || ! (tp
->t_state
& TS_ISOPEN
)) {
278 /* Stop sending break. */
279 if (c
->brk
== BRK_SEND
) {
281 if (! (tp
->t_state
& TS_BUSY
))
290 cxioctl (struct dev_ioctl_args
*ap
)
292 cdev_t dev
= ap
->a_head
.a_dev
;
293 caddr_t data
= ap
->a_data
;
294 int unit
= UNIT (dev
);
300 struct ifnet
*master
;
302 if (unit
== UNIT_CTL
) {
303 /* Process an ioctl request on /dev/cronyx */
304 cx_options_t
*o
= (cx_options_t
*) data
;
306 if (o
->board
>= NCX
|| o
->channel
>= NCHAN
)
308 c
= &cxboard
[o
->board
].chan
[o
->channel
];
309 if (c
->type
== T_NONE
)
316 print (("cx%d.%d: CXIOCSETMODE\n", o
->board
, o
->channel
));
317 if (c
->type
== T_NONE
)
319 if (c
->type
== T_ASYNC
&& o
->mode
!= M_ASYNC
)
321 if (o
->mode
== M_ASYNC
)
328 /* Somebody is waiting for carrier? */
331 /* /dev/ttyXX is already opened by someone? */
332 if (c
->mode
== M_ASYNC
&& c
->ttyp
&&
333 (c
->ttyp
->t_state
& TS_ISOPEN
))
335 /* Network interface is up? */
336 if (c
->mode
!= M_ASYNC
&& (c
->ifp
->if_flags
& IFF_UP
))
339 /* Find the master interface. */
340 master
= *o
->master
? ifunit (o
->master
) : c
->ifp
;
343 m
= cxchan
[master
->if_dunit
];
345 /* Leave the previous master queue. */
346 if (c
->master
!= c
->ifp
) {
347 cx_chan_t
*p
= cxchan
[c
->master
->if_dunit
];
349 for (; p
; p
=p
->slaveq
)
351 p
->slaveq
= c
->slaveq
;
354 /* Set up new master. */
358 /* Join the new master queue. */
359 if (c
->master
!= c
->ifp
) {
360 c
->slaveq
= m
->slaveq
;
365 c
->rxbaud
= o
->rxbaud
;
366 c
->txbaud
= o
->txbaud
;
373 case 0: c
->board
->if0type
= o
->iftype
; break;
374 case 8: c
->board
->if8type
= o
->iftype
; break;
377 cxswitch (c
, o
->sopt
);
379 outb (IER(c
->chip
->port
), 0);
384 st
= (cx_stat_t
*) data
;
385 st
->rintr
= c
->stat
->rintr
;
386 st
->tintr
= c
->stat
->tintr
;
387 st
->mintr
= c
->stat
->mintr
;
388 st
->ibytes
= c
->stat
->ibytes
;
389 st
->ipkts
= c
->stat
->ipkts
;
390 st
->ierrs
= c
->stat
->ierrs
;
391 st
->obytes
= c
->stat
->obytes
;
392 st
->opkts
= c
->stat
->opkts
;
393 st
->oerrs
= c
->stat
->oerrs
;
397 print (("cx%d.%d: CXIOCGETMODE\n", o
->board
, o
->channel
));
400 o
->rxbaud
= c
->rxbaud
;
401 o
->txbaud
= c
->txbaud
;
409 case 0: o
->iftype
= c
->board
->if0type
; break;
410 case 8: o
->iftype
= c
->board
->if8type
; break;
412 if (c
->master
!= c
->ifp
)
413 strlcpy(o
->master
, c
->master
->if_xname
, sizeof(o
->master
));
425 error
= (*linesw
[tp
->t_line
].l_ioctl
) (tp
, ap
->a_cmd
, data
,
426 ap
->a_fflag
, ap
->a_cred
);
427 if (error
!= ENOIOCTL
)
429 error
= ttioctl (tp
, ap
->a_cmd
, data
, ap
->a_fflag
);
430 if (error
!= ENOIOCTL
)
439 case TIOCSBRK
: /* Start sending line break */
441 if (! (tp
->t_state
& TS_BUSY
))
444 case TIOCCBRK
: /* Stop sending line break */
446 if (! (tp
->t_state
& TS_BUSY
))
449 case TIOCSDTR
: /* Set DTR */
452 case TIOCCDTR
: /* Clear DTR */
455 case TIOCMSET
: /* Set DTR/RTS */
456 cx_chan_dtr (c
, (*(int*)data
& TIOCM_DTR
) ? 1 : 0);
457 cx_chan_rts (c
, (*(int*)data
& TIOCM_RTS
) ? 1 : 0);
459 case TIOCMBIS
: /* Add DTR/RTS */
460 if (*(int*)data
& TIOCM_DTR
) cx_chan_dtr (c
, 1);
461 if (*(int*)data
& TIOCM_RTS
) cx_chan_rts (c
, 1);
463 case TIOCMBIC
: /* Clear DTR/RTS */
464 if (*(int*)data
& TIOCM_DTR
) cx_chan_dtr (c
, 0);
465 if (*(int*)data
& TIOCM_RTS
) cx_chan_rts (c
, 0);
467 case TIOCMGET
: /* Get modem status */
468 msv
= inb (MSVR(c
->chip
->port
));
469 *(int*)data
= TIOCM_LE
; /* always enabled while open */
470 if (msv
& MSV_DSR
) *(int*)data
|= TIOCM_DSR
;
471 if (msv
& MSV_CTS
) *(int*)data
|= TIOCM_CTS
;
472 if (msv
& MSV_CD
) *(int*)data
|= TIOCM_CD
;
473 if (c
->dtr
) *(int*)data
|= TIOCM_DTR
;
474 if (c
->rts
) *(int*)data
|= TIOCM_RTS
;
483 * Fill transmitter buffer with data.
486 cxout (cx_chan_t
*c
, char b
)
488 unsigned char *buf
, *p
, sym
;
489 unsigned short port
= c
->chip
->port
, len
= 0, cnt_port
, sts_port
;
490 struct tty
*tp
= c
->ttyp
;
495 /* Choose the buffer. */
498 cnt_port
= ATBCNT(port
);
499 sts_port
= ATBSTS(port
);
502 cnt_port
= BTBCNT(port
);
503 sts_port
= BTBSTS(port
);
507 if (inb (sts_port
) & BSTS_OWN24
) {
508 tp
->t_state
|= TS_BUSY
;
514 *buf
++ = 0; /* extended transmit command */
515 *buf
++ = 0x81; /* send break */
516 *buf
++ = 0; /* extended transmit command */
517 *buf
++ = 0x82; /* insert delay */
518 *buf
++ = 250; /* 1/4 of second */
519 *buf
++ = 0; /* extended transmit command */
520 *buf
++ = 0x82; /* insert delay */
521 *buf
++ = 250; /* + 1/4 of second */
526 *buf
++ = 0; /* extended transmit command */
527 *buf
++ = 0x83; /* stop break */
533 if (tp
->t_iflag
& IXOFF
)
534 while (RB_LEN (tp
->t_out
) && p
<buf
+DMABUFSZ
-1) {
535 sym
= RB_GETC (tp
->t_out
);
536 /* Send XON/XOFF out of band. */
537 if (sym
== tp
->t_cc
[VSTOP
]) {
538 outb (STCR(port
), STC_SNDSPC
|STC_SSPC_2
);
541 if (sym
== tp
->t_cc
[VSTART
]) {
542 outb (STCR(port
), STC_SNDSPC
|STC_SSPC_1
);
545 /* Duplicate NULLs in ETC mode. */
551 while (RB_LEN (tp
->t_out
) && p
<buf
+DMABUFSZ
-1) {
552 sym
= RB_GETC (tp
->t_out
);
553 /* Duplicate NULLs in ETC mode. */
562 /* Start transmitter. */
564 outw (cnt_port
, len
);
565 outb (sts_port
, BSTS_INTR
| BSTS_OWN24
);
566 c
->stat
->obytes
+= len
;
567 tp
->t_state
|= TS_BUSY
;
568 print (("cx%d.%d: out %d bytes to %c\n",
569 c
->board
->num
, c
->num
, len
, b
));
574 cxoproc (struct tty
*tp
)
576 int unit
= UNIT (tp
->t_dev
);
577 cx_chan_t
*c
= cxchan
[unit
];
578 unsigned short port
= c
->chip
->port
;
582 /* Set current channel number */
583 outb (CAR(port
), c
->num
& 3);
585 if (! (tp
->t_state
& (TS_TIMEOUT
| TS_TTSTOP
))) {
586 /* Start transmitter. */
587 if (! (inb (CSR(port
)) & CSRA_TXEN
))
588 cx_cmd (port
, CCR_ENTX
);
590 /* Determine the buffer order. */
591 if (inb (DMABSTS(port
)) & DMABSTS_NTBUF
) {
599 #ifndef TS_ASLEEP /* FreeBSD some time after 2.0.5 */
602 if (RB_LEN (tp
->t_out
) <= tp
->t_lowat
) {
603 if (tp
->t_state
& TS_ASLEEP
) {
604 tp
->t_state
&= ~TS_ASLEEP
;
605 wakeup(TSA_OLOWAT(tp
));
607 selwakeup(&tp
->t_wsel
);
614 cxparam (struct tty
*tp
, struct termios
*t
)
616 int unit
= UNIT (tp
->t_dev
);
617 cx_chan_t
*c
= cxchan
[unit
];
618 unsigned short port
= c
->chip
->port
;
620 cx_cor1_async_t cor1
;
622 if (t
->c_ospeed
== 0) {
623 /* Clear DTR and RTS. */
628 print (("cx%d.%d: cxparam (hangup)\n", c
->board
->num
, c
->num
));
631 print (("cx%d.%d: cxparam\n", c
->board
->num
, c
->num
));
633 /* Check requested parameters. */
634 if (t
->c_ospeed
< 300 || t
->c_ospeed
> 256*1024)
636 if (t
->c_ispeed
&& (t
->c_ispeed
< 300 || t
->c_ispeed
> 256*1024))
640 /* CLOCAL flag set -- wakeup everybody who waits for CD. */
641 /* FreeBSD does this themselves. */
642 if (! (tp
->t_cflag
& CLOCAL
) && (t
->c_cflag
& CLOCAL
))
643 wakeup ((caddr_t
) &tp
->t_rawq
);
645 /* And copy them to tty and channel structures. */
646 c
->rxbaud
= tp
->t_ispeed
= t
->c_ispeed
;
647 c
->txbaud
= tp
->t_ospeed
= t
->c_ospeed
;
648 tp
->t_cflag
= t
->c_cflag
;
650 /* Set character length and parity mode. */
652 switch (t
->c_cflag
& CSIZE
) {
654 case CS8
: cor1
.charlen
= 7; break;
655 case CS7
: cor1
.charlen
= 6; break;
656 case CS6
: cor1
.charlen
= 5; break;
657 case CS5
: cor1
.charlen
= 4; break;
659 if (t
->c_cflag
& PARENB
) {
660 cor1
.parmode
= PARM_NORMAL
;
662 cor1
.parity
= (t
->c_cflag
& PARODD
) ? PAR_ODD
: PAR_EVEN
;
664 cor1
.parmode
= PARM_NOPAR
;
668 /* Enable/disable hardware CTS. */
669 c
->aopt
.cor2
.ctsae
= (t
->c_cflag
& CRTSCTS
) ? 1 : 0;
670 /* Handle DSR as CTS. */
671 c
->aopt
.cor2
.dsrae
= (t
->c_cflag
& CRTSCTS
) ? 1 : 0;
672 /* Enable extended transmit command mode.
673 * Unfortunately, there is no other method for sending break. */
674 c
->aopt
.cor2
.etc
= 1;
675 /* Enable/disable hardware XON/XOFF. */
676 c
->aopt
.cor2
.ixon
= (t
->c_iflag
& IXON
) ? 1 : 0;
677 c
->aopt
.cor2
.ixany
= (t
->c_iflag
& IXANY
) ? 1 : 0;
679 /* Set the number of stop bits. */
680 if (t
->c_cflag
& CSTOPB
)
681 c
->aopt
.cor3
.stopb
= STOPB_2
;
683 c
->aopt
.cor3
.stopb
= STOPB_1
;
684 /* Disable/enable passing XON/XOFF chars to the host. */
685 c
->aopt
.cor3
.scde
= (t
->c_iflag
& IXON
) ? 1 : 0;
686 c
->aopt
.cor3
.flowct
= (t
->c_iflag
& IXON
) ? FLOWCC_NOTPASS
: FLOWCC_PASS
;
688 c
->aopt
.schr1
= t
->c_cc
[VSTART
]; /* XON */
689 c
->aopt
.schr2
= t
->c_cc
[VSTOP
]; /* XOFF */
691 /* Set current channel number. */
693 outb (CAR(port
), c
->num
& 3);
695 /* Set up receiver clock values. */
696 cx_clock (c
->chip
->oscfreq
, c
->rxbaud
, &clock
, &period
);
697 c
->opt
.rcor
.clk
= clock
;
698 outb (RCOR(port
), BYTE c
->opt
.rcor
);
699 outb (RBPR(port
), period
);
701 /* Set up transmitter clock values. */
702 cx_clock (c
->chip
->oscfreq
, c
->txbaud
, &clock
, &period
);
703 c
->opt
.tcor
.clk
= clock
;
704 c
->opt
.tcor
.ext1x
= 0;
705 outb (TCOR(port
), BYTE c
->opt
.tcor
);
706 outb (TBPR(port
), period
);
708 outb (COR2(port
), BYTE c
->aopt
.cor2
);
709 outb (COR3(port
), BYTE c
->aopt
.cor3
);
710 outb (SCHR1(port
), c
->aopt
.schr1
);
711 outb (SCHR2(port
), c
->aopt
.schr2
);
713 if (BYTE c
->aopt
.cor1
!= BYTE cor1
) {
714 BYTE c
->aopt
.cor1
= BYTE cor1
;
715 outb (COR1(port
), BYTE c
->aopt
.cor1
);
716 /* Any change to COR1 require reinitialization. */
717 /* Unfortunately, it may cause transmitter glitches... */
718 cx_cmd (port
, CCR_INITCH
);
726 * Stop output on a line
729 cxstop (struct tty
*tp
, int flag
)
733 if (tp
->t_state
& TS_BUSY
) {
734 cx_chan_t
*c
= cxchan
[UNIT(tp
->t_dev
)];
735 unsigned short port
= c
->chip
->port
;
737 print (("cx%d.%d: cxstop\n", c
->board
->num
, c
->num
));
739 /* Set current channel number */
740 outb (CAR(port
), c
->num
& 3);
742 /* Stop transmitter */
743 cx_cmd (port
, CCR_DISTX
);
750 * Handle receive interrupts, including receive errors and
751 * receive timeout interrupt.
754 cxrinta (cx_chan_t
*c
)
756 unsigned short port
= c
->chip
->port
;
757 unsigned short len
= 0, risr
= inw (RISR(port
)), reoir
= 0;
758 struct tty
*tp
= c
->ttyp
;
760 /* Compute optimal receiver buffer length. */
761 int rbsz
= (c
->rxbaud
+ 800 - 1) / 800 * 2;
764 else if (rbsz
> DMABUFSZ
)
767 if (risr
& RISA_TIMEOUT
) {
768 unsigned long rcbadr
= (unsigned short) inw (RCBADRL(port
)) |
769 (long) inw (RCBADRU(port
)) << 16;
770 unsigned char *buf
= 0;
771 unsigned short cnt_port
= 0, sts_port
= 0;
772 if (rcbadr
>= c
->brphys
&& rcbadr
< c
->brphys
+DMABUFSZ
) {
774 len
= rcbadr
- c
->brphys
;
775 cnt_port
= BRBCNT(port
);
776 sts_port
= BRBSTS(port
);
777 } else if (rcbadr
>= c
->arphys
&& rcbadr
< c
->arphys
+DMABUFSZ
) {
779 len
= rcbadr
- c
->arphys
;
780 cnt_port
= ARBCNT(port
);
781 sts_port
= ARBSTS(port
);
783 kprintf ("cx%d.%d: timeout: invalid buffer address\n",
784 c
->board
->num
, c
->num
);
787 print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n",
788 c
->board
->num
, c
->num
, len
, risr
, RISA_BITS
,
789 inb (ARBSTS(port
)), BSTS_BITS
, inb (BRBSTS(port
)), BSTS_BITS
));
790 c
->stat
->ibytes
+= len
;
791 if (tp
&& (tp
->t_state
& TS_ISOPEN
)) {
793 int (*rint
)(int, struct tty
*) =
794 linesw
[tp
->t_line
].l_rint
;
796 for (i
=0; i
<len
; ++i
)
797 (*rint
) (buf
[i
], tp
);
800 /* Restart receiver. */
801 outw (cnt_port
, rbsz
);
802 outb (sts_port
, BSTS_OWN24
);
804 return (REOI_TERMBUFF
);
807 print (("cx%d.%d: async receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
808 c
->board
->num
, c
->num
, risr
, RISA_BITS
,
809 inb (ARBSTS(port
)), BSTS_BITS
, inb (BRBSTS(port
)), BSTS_BITS
));
811 if (risr
& RIS_BUSERR
) {
812 kprintf ("cx%d.%d: receive bus error\n", c
->board
->num
, c
->num
);
815 if (risr
& (RIS_OVERRUN
| RISA_PARERR
| RISA_FRERR
| RISA_BREAK
)) {
818 if (risr
& RISA_PARERR
)
820 if (risr
& RISA_FRERR
)
823 if (risr
& RIS_OVERRUN
)
827 if (risr
& RISA_BREAK
)
830 print (("cx%d.%d: receive error %x\n", c
->board
->num
, c
->num
, err
));
831 if (tp
&& (tp
->t_state
& TS_ISOPEN
))
832 (*linesw
[tp
->t_line
].l_rint
) (err
, tp
);
836 /* Discard exception characters. */
837 if ((risr
& RISA_SCMASK
) && tp
&& (tp
->t_iflag
& IXON
))
838 reoir
|= REOI_DISCEXC
;
840 /* Handle received data. */
841 if ((risr
& RIS_EOBUF
) && tp
&& (tp
->t_state
& TS_ISOPEN
)) {
842 int (*rint
)(int, struct tty
*) = linesw
[tp
->t_line
].l_rint
;
846 len
= (risr
& RIS_BB
) ? inw(BRBCNT(port
)) : inw(ARBCNT(port
));
848 print (("cx%d.%d: async: %d bytes received\n",
849 c
->board
->num
, c
->num
, len
));
850 c
->stat
->ibytes
+= len
;
852 buf
= (risr
& RIS_BB
) ? c
->brbuf
: c
->arbuf
;
853 for (i
=0; i
<len
; ++i
)
854 (*rint
) (buf
[i
], tp
);
857 /* Restart receiver. */
858 if (! (inb (ARBSTS(port
)) & BSTS_OWN24
)) {
859 outw (ARBCNT(port
), rbsz
);
860 outb (ARBSTS(port
), BSTS_OWN24
);
862 if (! (inb (BRBSTS(port
)) & BSTS_OWN24
)) {
863 outw (BRBCNT(port
), rbsz
);
864 outb (BRBSTS(port
), BSTS_OWN24
);
870 * Handle transmit interrupt.
872 void cxtinta (cx_chan_t
*c
)
874 struct tty
*tp
= c
->ttyp
;
875 unsigned short port
= c
->chip
->port
;
876 unsigned char tisr
= inb (TISR(port
));
878 print (("cx%d.%d: async transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
879 c
->board
->num
, c
->num
, tisr
, TIS_BITS
,
880 inb (ATBSTS(port
)), BSTS_BITS
, inb (BTBSTS(port
)), BSTS_BITS
));
882 if (tisr
& TIS_BUSERR
) {
883 kprintf ("cx%d.%d: transmit bus error\n",
884 c
->board
->num
, c
->num
);
886 } else if (tisr
& TIS_UNDERRUN
) {
887 kprintf ("cx%d.%d: transmit underrun error\n",
888 c
->board
->num
, c
->num
);
892 tp
->t_state
&= ~(TS_BUSY
| TS_FLUSH
);
894 (*linesw
[tp
->t_line
].l_start
) (tp
);
901 * Handle modem interrupt.
904 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 kprintf ("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
)