FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/cx.c
1 /*
2 * Cronyx-Sigma adapter driver for FreeBSD.
3 * Supports PPP/HDLC protocol in synchronous mode,
4 * and asyncronous channels with full modem control.
5 *
6 * Copyright (C) 1994 Cronyx Ltd.
7 * Author: Serge Vakulenko, <vak@zebub.msk.su>
8 *
9 * This software is distributed with NO WARRANTIES, not even the implied
10 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
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.
15 *
16 * Version 1.9, Wed Oct 4 18:58:15 MSK 1995
17 *
18 * $FreeBSD: releng/5.1/sys/i386/isa/cx.c 111821 2003-03-03 16:24:47Z phk $
19 *
20 */
21 #undef DEBUG
22
23 #include "cx.h"
24
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/kernel.h>
28 #include <sys/fcntl.h>
29 #include <sys/conf.h>
30 #include <sys/tty.h>
31 #include <sys/socket.h>
32 #include <net/if.h>
33
34 # define t_out t_outq
35 # define RB_LEN(q) ((q).c_cc)
36 # define RB_GETC(q) getc(&q)
37 #ifndef TSA_CARR_ON /* FreeBSD 2.x before not long after 2.0.5 */
38 # define TSA_CARR_ON(tp) tp
39 # define TSA_OLOWAT(q) ((caddr_t)&(q)->t_out)
40 #endif
41
42 #include <machine/cronyx.h>
43 #include <i386/isa/cxreg.h>
44
45 /* XXX imported from if_cx.c. */
46 void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
47
48 /* XXX exported. */
49 void cxmint (cx_chan_t *c);
50 int cxrinta (cx_chan_t *c);
51 void cxtinta (cx_chan_t *c);
52 timeout_t cxtimeout;
53
54 #ifdef DEBUG
55 # define print(s) printf s
56 #else
57 # define print(s) {/*void*/}
58 #endif
59
60 #define DMABUFSZ (6*256) /* buffer size */
61 #define BYTE *(unsigned char*)&
62 #define UNIT(u) (minor(u) & 077)
63 #define UNIT_CTL 077
64
65 extern cx_board_t cxboard [NCX]; /* adapter state structures */
66 extern cx_chan_t *cxchan [NCX*NCHAN]; /* unit to channel struct pointer */
67 static struct tty cx_tty [NCX*NCHAN]; /* tty data */
68
69 static d_open_t cxopen;
70 static d_close_t cxclose;
71 static d_ioctl_t cxioctl;
72
73 #define CDEV_MAJOR 42
74 /* Don't make this static, since if_cx.c uses it. */
75 struct cdevsw cx_cdevsw = {
76 .d_open = cxopen,
77 .d_close = cxclose,
78 .d_read = ttyread,
79 .d_write = ttywrite,
80 .d_ioctl = cxioctl,
81 .d_poll = ttypoll,
82 .d_name = "cx",
83 .d_maj = CDEV_MAJOR,
84 .d_flags = D_TTY,
85 .d_kqfilter = ttykqfilter,
86 };
87
88 static void cxoproc (struct tty *tp);
89 static void cxstop (struct tty *tp, int flag);
90 static int cxparam (struct tty *tp, struct termios *t);
91
92 static int
93 cxopen (dev_t dev, int flag, int mode, struct thread *td)
94 {
95 int unit = UNIT (dev);
96 cx_chan_t *c = cxchan[unit];
97 unsigned short port;
98 struct tty *tp;
99 int error = 0;
100
101 if (unit == UNIT_CTL) {
102 print (("cx: cxopen /dev/cronyx\n"));
103 return (0);
104 }
105 if (unit >= NCX*NCHAN || !c || c->type==T_NONE)
106 return (ENXIO);
107 port = c->chip->port;
108 print (("cx%d.%d: cxopen unit=%d\n", c->board->num, c->num, unit));
109 if (c->mode != M_ASYNC)
110 return (EBUSY);
111 if (! c->ttyp) {
112 c->ttyp = &cx_tty[unit];
113 c->ttyp->t_oproc = cxoproc;
114 c->ttyp->t_stop = cxstop;
115 c->ttyp->t_param = cxparam;
116 }
117 dev->si_tty = c->ttyp;
118 tp = c->ttyp;
119 tp->t_dev = dev;
120 if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) &&
121 suser(td))
122 return (EBUSY);
123 if (! (tp->t_state & TS_ISOPEN)) {
124 ttychars (tp);
125 if (tp->t_ispeed == 0) {
126 tp->t_iflag = 0;
127 tp->t_oflag = 0;
128 tp->t_lflag = 0;
129 tp->t_cflag = CREAD | CS8 | HUPCL;
130 tp->t_ispeed = c->rxbaud;
131 tp->t_ospeed = c->txbaud;
132 }
133 cxparam (tp, &tp->t_termios);
134 ttsetwater (tp);
135 }
136
137 spltty ();
138 if (! (tp->t_state & TS_ISOPEN)) {
139 /*
140 * Compute optimal receiver buffer length.
141 * The best choice is rxbaud/400.
142 * Make it even, to avoid byte-wide DMA transfers.
143 * --------------------------
144 * Baud rate Buffer length
145 * --------------------------
146 * 300 4
147 * 1200 4
148 * 9600 24
149 * 19200 48
150 * 38400 96
151 * 57600 192
152 * 115200 288
153 * --------------------------
154 */
155 int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
156 if (rbsz < 4)
157 rbsz = 4;
158 else if (rbsz > DMABUFSZ)
159 rbsz = DMABUFSZ;
160
161 /* Initialize channel, enable receiver. */
162 cx_cmd (port, CCR_INITCH | CCR_ENRX);
163 cx_cmd (port, CCR_INITCH | CCR_ENRX);
164
165 /* Start receiver. */
166 outw (ARBCNT(port), rbsz);
167 outw (BRBCNT(port), rbsz);
168 outw (ARBSTS(port), BSTS_OWN24);
169 outw (BRBSTS(port), BSTS_OWN24);
170
171 /* Enable interrupts. */
172 outb (IER(port), IER_RXD | IER_RET | IER_TXD | IER_MDM);
173
174 cx_chan_dtr (c, 1);
175 cx_chan_rts (c, 1);
176 }
177 if (cx_chan_cd (c))
178 (*linesw[tp->t_line].l_modem)(tp, 1);
179 if (! (flag & O_NONBLOCK)) {
180 /* Lock the channel against cxconfig while we are
181 * waiting for carrier. */
182 c->sopt.lock = 1;
183 while (!(tp->t_cflag & CLOCAL) && !(tp->t_state & TS_CARR_ON))
184 if ((error = tsleep (TSA_CARR_ON(tp), TTIPRI | PCATCH,
185 "cxdcd", 0)))
186 break;
187 c->sopt.lock = 0; /* Unlock the channel. */
188 }
189 print (("cx%d.%d: cxopen done csr=%b\n", c->board->num, c->num,
190 inb(CSR(c->chip->port)), CSRA_BITS));
191 spl0 ();
192 if (error)
193 return (error);
194 error = (*linesw[tp->t_line].l_open) (dev, tp);
195 return (error);
196 }
197
198 static int
199 cxclose (dev_t dev, int flag, int mode, struct thread *td)
200 {
201 int unit = UNIT (dev);
202 cx_chan_t *c = cxchan[unit];
203 struct tty *tp;
204 int s;
205
206 if (unit == UNIT_CTL)
207 return (0);
208 tp = c->ttyp;
209 (*linesw[tp->t_line].l_close) (tp, flag);
210
211 /* Disable receiver.
212 * Transmitter continues sending the queued data. */
213 s = spltty ();
214 outb (CAR(c->chip->port), c->num & 3);
215 outb (IER(c->chip->port), IER_TXD | IER_MDM);
216 cx_cmd (c->chip->port, CCR_DISRX);
217
218 /* Clear DTR and RTS. */
219 if ((tp->t_cflag & HUPCL) || ! (tp->t_state & TS_ISOPEN)) {
220 cx_chan_dtr (c, 0);
221 cx_chan_rts (c, 0);
222 }
223
224 /* Stop sending break. */
225 if (c->brk == BRK_SEND) {
226 c->brk = BRK_STOP;
227 if (! (tp->t_state & TS_BUSY))
228 cxoproc (tp);
229 }
230 splx (s);
231 ttyclose (tp);
232 return (0);
233 }
234
235 static int
236 cxioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
237 {
238 int unit = UNIT (dev);
239 cx_chan_t *c, *m;
240 cx_stat_t *st;
241 struct tty *tp;
242 int error, s;
243 unsigned char msv;
244 struct ifnet *master;
245
246 if (unit == UNIT_CTL) {
247 /* Process an ioctl request on /dev/cronyx */
248 cx_options_t *o = (cx_options_t*) data;
249
250 if (o->board >= NCX || o->channel >= NCHAN)
251 return (EINVAL);
252 c = &cxboard[o->board].chan[o->channel];
253 if (c->type == T_NONE)
254 return (ENXIO);
255 switch (cmd) {
256 default:
257 return (EINVAL);
258
259 case CXIOCSETMODE:
260 print (("cx%d.%d: CXIOCSETMODE\n", o->board, o->channel));
261 if (c->type == T_NONE)
262 return (EINVAL);
263 if (c->type == T_ASYNC && o->mode != M_ASYNC)
264 return (EINVAL);
265 if (o->mode == M_ASYNC)
266 switch (c->type) {
267 case T_SYNC_RS232:
268 case T_SYNC_V35:
269 case T_SYNC_RS449:
270 return (EINVAL);
271 }
272 /* Somebody is waiting for carrier? */
273 if (c->sopt.lock)
274 return (EBUSY);
275 /* /dev/ttyXX is already opened by someone? */
276 if (c->mode == M_ASYNC && c->ttyp &&
277 (c->ttyp->t_state & TS_ISOPEN))
278 return (EBUSY);
279 /* Network interface is up? */
280 if (c->mode != M_ASYNC && (c->ifp->if_flags & IFF_UP))
281 return (EBUSY);
282
283 /* Find the master interface. */
284 master = *o->master ? ifunit (o->master) : c->ifp;
285 if (! master)
286 return (EINVAL);
287 m = cxchan[master->if_unit];
288
289 /* Leave the previous master queue. */
290 if (c->master != c->ifp) {
291 cx_chan_t *p = cxchan[c->master->if_unit];
292
293 for (; p; p=p->slaveq)
294 if (p->slaveq == c)
295 p->slaveq = c->slaveq;
296 }
297
298 /* Set up new master. */
299 c->master = master;
300 c->slaveq = 0;
301
302 /* Join the new master queue. */
303 if (c->master != c->ifp) {
304 c->slaveq = m->slaveq;
305 m->slaveq = c;
306 }
307
308 c->mode = o->mode;
309 c->rxbaud = o->rxbaud;
310 c->txbaud = o->txbaud;
311 c->opt = o->opt;
312 c->aopt = o->aopt;
313 c->hopt = o->hopt;
314 c->bopt = o->bopt;
315 c->xopt = o->xopt;
316 switch (c->num) {
317 case 0: c->board->if0type = o->iftype; break;
318 case 8: c->board->if8type = o->iftype; break;
319 }
320 s = spltty ();
321 cxswitch (c, o->sopt);
322 cx_setup_chan (c);
323 outb (IER(c->chip->port), 0);
324 splx (s);
325 break;
326
327 case CXIOCGETSTAT:
328 st = (cx_stat_t*) data;
329 st->rintr = c->stat->rintr;
330 st->tintr = c->stat->tintr;
331 st->mintr = c->stat->mintr;
332 st->ibytes = c->stat->ibytes;
333 st->ipkts = c->stat->ipkts;
334 st->ierrs = c->stat->ierrs;
335 st->obytes = c->stat->obytes;
336 st->opkts = c->stat->opkts;
337 st->oerrs = c->stat->oerrs;
338 break;
339
340 case CXIOCGETMODE:
341 print (("cx%d.%d: CXIOCGETMODE\n", o->board, o->channel));
342 o->type = c->type;
343 o->mode = c->mode;
344 o->rxbaud = c->rxbaud;
345 o->txbaud = c->txbaud;
346 o->opt = c->opt;
347 o->aopt = c->aopt;
348 o->hopt = c->hopt;
349 o->bopt = c->bopt;
350 o->xopt = c->xopt;
351 o->sopt = c->sopt;
352 switch (c->num) {
353 case 0: o->iftype = c->board->if0type; break;
354 case 8: o->iftype = c->board->if8type; break;
355 }
356 if (c->master != c->ifp)
357 snprintf (o->master, sizeof(o->master),
358 "%s%d", c->master->if_name,
359 c->master->if_unit);
360 else
361 *o->master = 0;
362 break;
363 }
364 return (0);
365 }
366
367 c = cxchan[unit];
368 tp = c->ttyp;
369 if (! tp)
370 return (EINVAL);
371 error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag, td);
372 if (error != ENOIOCTL)
373 return (error);
374 error = ttioctl (tp, cmd, data, flag);
375 if (error != ENOIOCTL)
376 return (error);
377
378 s = spltty ();
379 switch (cmd) {
380 default:
381 splx (s);
382 return (ENOTTY);
383 case TIOCSBRK: /* Start sending line break */
384 c->brk = BRK_SEND;
385 if (! (tp->t_state & TS_BUSY))
386 cxoproc (tp);
387 break;
388 case TIOCCBRK: /* Stop sending line break */
389 c->brk = BRK_STOP;
390 if (! (tp->t_state & TS_BUSY))
391 cxoproc (tp);
392 break;
393 case TIOCSDTR: /* Set DTR */
394 cx_chan_dtr (c, 1);
395 break;
396 case TIOCCDTR: /* Clear DTR */
397 cx_chan_dtr (c, 0);
398 break;
399 case TIOCMSET: /* Set DTR/RTS */
400 cx_chan_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
401 cx_chan_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
402 break;
403 case TIOCMBIS: /* Add DTR/RTS */
404 if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 1);
405 if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 1);
406 break;
407 case TIOCMBIC: /* Clear DTR/RTS */
408 if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 0);
409 if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 0);
410 break;
411 case TIOCMGET: /* Get modem status */
412 msv = inb (MSVR(c->chip->port));
413 *(int*)data = TIOCM_LE; /* always enabled while open */
414 if (msv & MSV_DSR) *(int*)data |= TIOCM_DSR;
415 if (msv & MSV_CTS) *(int*)data |= TIOCM_CTS;
416 if (msv & MSV_CD) *(int*)data |= TIOCM_CD;
417 if (c->dtr) *(int*)data |= TIOCM_DTR;
418 if (c->rts) *(int*)data |= TIOCM_RTS;
419 break;
420 }
421 splx (s);
422 return (0);
423 }
424
425 /*
426 * Fill transmitter buffer with data.
427 */
428 static void
429 cxout (cx_chan_t *c, char b)
430 {
431 unsigned char *buf, *p, sym;
432 unsigned short port = c->chip->port, len = 0, cnt_port, sts_port;
433 struct tty *tp = c->ttyp;
434
435 if (! tp)
436 return;
437
438 /* Choose the buffer. */
439 if (b == 'A') {
440 buf = c->atbuf;
441 cnt_port = ATBCNT(port);
442 sts_port = ATBSTS(port);
443 } else {
444 buf = c->btbuf;
445 cnt_port = BTBCNT(port);
446 sts_port = BTBSTS(port);
447 }
448
449 /* Is it busy? */
450 if (inb (sts_port) & BSTS_OWN24) {
451 tp->t_state |= TS_BUSY;
452 return;
453 }
454
455 switch (c->brk) {
456 case BRK_SEND:
457 *buf++ = 0; /* extended transmit command */
458 *buf++ = 0x81; /* send break */
459 *buf++ = 0; /* extended transmit command */
460 *buf++ = 0x82; /* insert delay */
461 *buf++ = 250; /* 1/4 of second */
462 *buf++ = 0; /* extended transmit command */
463 *buf++ = 0x82; /* insert delay */
464 *buf++ = 250; /* + 1/4 of second */
465 len = 8;
466 c->brk = BRK_IDLE;
467 break;
468 case BRK_STOP:
469 *buf++ = 0; /* extended transmit command */
470 *buf++ = 0x83; /* stop break */
471 len = 2;
472 c->brk = BRK_IDLE;
473 break;
474 case BRK_IDLE:
475 p = buf;
476 if (tp->t_iflag & IXOFF)
477 while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) {
478 sym = RB_GETC (tp->t_out);
479 /* Send XON/XOFF out of band. */
480 if (sym == tp->t_cc[VSTOP]) {
481 outb (STCR(port), STC_SNDSPC|STC_SSPC_2);
482 continue;
483 }
484 if (sym == tp->t_cc[VSTART]) {
485 outb (STCR(port), STC_SNDSPC|STC_SSPC_1);
486 continue;
487 }
488 /* Duplicate NULLs in ETC mode. */
489 if (! sym)
490 *p++ = 0;
491 *p++ = sym;
492 }
493 else
494 while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) {
495 sym = RB_GETC (tp->t_out);
496 /* Duplicate NULLs in ETC mode. */
497 if (! sym)
498 *p++ = 0;
499 *p++ = sym;
500 }
501 len = p - buf;
502 break;
503 }
504
505 /* Start transmitter. */
506 if (len) {
507 outw (cnt_port, len);
508 outb (sts_port, BSTS_INTR | BSTS_OWN24);
509 c->stat->obytes += len;
510 tp->t_state |= TS_BUSY;
511 print (("cx%d.%d: out %d bytes to %c\n",
512 c->board->num, c->num, len, b));
513 }
514 }
515
516 static void
517 cxoproc (struct tty *tp)
518 {
519 int unit = UNIT (tp->t_dev);
520 cx_chan_t *c = cxchan[unit];
521 unsigned short port = c->chip->port;
522 int s = spltty ();
523
524 /* Set current channel number */
525 outb (CAR(port), c->num & 3);
526
527 if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) {
528 /* Start transmitter. */
529 if (! (inb (CSR(port)) & CSRA_TXEN))
530 cx_cmd (port, CCR_ENTX);
531
532 /* Determine the buffer order. */
533 if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
534 cxout (c, 'B');
535 cxout (c, 'A');
536 } else {
537 cxout (c, 'A');
538 cxout (c, 'B');
539 }
540 }
541 #ifndef TS_ASLEEP /* FreeBSD some time after 2.0.5 */
542 ttwwakeup(tp);
543 #else
544 if (RB_LEN (tp->t_out) <= tp->t_lowat) {
545 if (tp->t_state & TS_ASLEEP) {
546 tp->t_state &= ~TS_ASLEEP;
547 wakeup(TSA_OLOWAT(tp));
548 }
549 selwakeup(&tp->t_wsel);
550 }
551 #endif
552 splx (s);
553 }
554
555 static int
556 cxparam (struct tty *tp, struct termios *t)
557 {
558 int unit = UNIT (tp->t_dev);
559 cx_chan_t *c = cxchan[unit];
560 unsigned short port = c->chip->port;
561 int clock, period, s;
562 cx_cor1_async_t cor1;
563
564 if (t->c_ospeed == 0) {
565 /* Clear DTR and RTS. */
566 s = spltty ();
567 cx_chan_dtr (c, 0);
568 cx_chan_rts (c, 0);
569 splx (s);
570 print (("cx%d.%d: cxparam (hangup)\n", c->board->num, c->num));
571 return (0);
572 }
573 print (("cx%d.%d: cxparam\n", c->board->num, c->num));
574
575 /* Check requested parameters. */
576 if (t->c_ospeed < 300 || t->c_ospeed > 256*1024)
577 return(EINVAL);
578 if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024))
579 return(EINVAL);
580
581 /* And copy them to tty and channel structures. */
582 c->rxbaud = tp->t_ispeed = t->c_ispeed;
583 c->txbaud = tp->t_ospeed = t->c_ospeed;
584 tp->t_cflag = t->c_cflag;
585
586 /* Set character length and parity mode. */
587 BYTE cor1 = 0;
588 switch (t->c_cflag & CSIZE) {
589 default:
590 case CS8: cor1.charlen = 7; break;
591 case CS7: cor1.charlen = 6; break;
592 case CS6: cor1.charlen = 5; break;
593 case CS5: cor1.charlen = 4; break;
594 }
595 if (t->c_cflag & PARENB) {
596 cor1.parmode = PARM_NORMAL;
597 cor1.ignpar = 0;
598 cor1.parity = (t->c_cflag & PARODD) ? PAR_ODD : PAR_EVEN;
599 } else {
600 cor1.parmode = PARM_NOPAR;
601 cor1.ignpar = 1;
602 }
603
604 /* Enable/disable hardware CTS. */
605 c->aopt.cor2.ctsae = (t->c_cflag & CRTSCTS) ? 1 : 0;
606 /* Handle DSR as CTS. */
607 c->aopt.cor2.dsrae = (t->c_cflag & CRTSCTS) ? 1 : 0;
608 /* Enable extended transmit command mode.
609 * Unfortunately, there is no other method for sending break. */
610 c->aopt.cor2.etc = 1;
611 /* Enable/disable hardware XON/XOFF. */
612 c->aopt.cor2.ixon = (t->c_iflag & IXON) ? 1 : 0;
613 c->aopt.cor2.ixany = (t->c_iflag & IXANY) ? 1 : 0;
614
615 /* Set the number of stop bits. */
616 if (t->c_cflag & CSTOPB)
617 c->aopt.cor3.stopb = STOPB_2;
618 else
619 c->aopt.cor3.stopb = STOPB_1;
620 /* Disable/enable passing XON/XOFF chars to the host. */
621 c->aopt.cor3.scde = (t->c_iflag & IXON) ? 1 : 0;
622 c->aopt.cor3.flowct = (t->c_iflag & IXON) ? FLOWCC_NOTPASS : FLOWCC_PASS;
623
624 c->aopt.schr1 = t->c_cc[VSTART]; /* XON */
625 c->aopt.schr2 = t->c_cc[VSTOP]; /* XOFF */
626
627 /* Set current channel number. */
628 s = spltty ();
629 outb (CAR(port), c->num & 3);
630
631 /* Set up receiver clock values. */
632 cx_clock (c->chip->oscfreq, c->rxbaud, &clock, &period);
633 c->opt.rcor.clk = clock;
634 outb (RCOR(port), BYTE c->opt.rcor);
635 outb (RBPR(port), period);
636
637 /* Set up transmitter clock values. */
638 cx_clock (c->chip->oscfreq, c->txbaud, &clock, &period);
639 c->opt.tcor.clk = clock;
640 c->opt.tcor.ext1x = 0;
641 outb (TCOR(port), BYTE c->opt.tcor);
642 outb (TBPR(port), period);
643
644 outb (COR2(port), BYTE c->aopt.cor2);
645 outb (COR3(port), BYTE c->aopt.cor3);
646 outb (SCHR1(port), c->aopt.schr1);
647 outb (SCHR2(port), c->aopt.schr2);
648
649 if (BYTE c->aopt.cor1 != BYTE cor1) {
650 BYTE c->aopt.cor1 = BYTE cor1;
651 outb (COR1(port), BYTE c->aopt.cor1);
652 /* Any change to COR1 require reinitialization. */
653 /* Unfortunately, it may cause transmitter glitches... */
654 cx_cmd (port, CCR_INITCH);
655 }
656 splx (s);
657 return (0);
658 }
659
660 /*
661 * Stop output on a line
662 */
663 static void
664 cxstop (struct tty *tp, int flag)
665 {
666 cx_chan_t *c = cxchan[UNIT(tp->t_dev)];
667 unsigned short port = c->chip->port;
668 int s = spltty ();
669
670 if (tp->t_state & TS_BUSY) {
671 print (("cx%d.%d: cxstop\n", c->board->num, c->num));
672
673 /* Set current channel number */
674 outb (CAR(port), c->num & 3);
675
676 /* Stop transmitter */
677 cx_cmd (port, CCR_DISTX);
678 }
679 splx (s);
680 }
681
682 /*
683 * Handle receive interrupts, including receive errors and
684 * receive timeout interrupt.
685 */
686 int cxrinta (cx_chan_t *c)
687 {
688 unsigned short port = c->chip->port;
689 unsigned short len = 0, risr = inw (RISR(port)), reoir = 0;
690 struct tty *tp = c->ttyp;
691
692 /* Compute optimal receiver buffer length. */
693 int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
694 if (rbsz < 4)
695 rbsz = 4;
696 else if (rbsz > DMABUFSZ)
697 rbsz = DMABUFSZ;
698
699 if (risr & RISA_TIMEOUT) {
700 unsigned long rcbadr = (unsigned short) inw (RCBADRL(port)) |
701 (long) inw (RCBADRU(port)) << 16;
702 unsigned char *buf = 0;
703 unsigned short cnt_port = 0, sts_port = 0;
704 if (rcbadr >= c->brphys && rcbadr < c->brphys+DMABUFSZ) {
705 buf = c->brbuf;
706 len = rcbadr - c->brphys;
707 cnt_port = BRBCNT(port);
708 sts_port = BRBSTS(port);
709 } else if (rcbadr >= c->arphys && rcbadr < c->arphys+DMABUFSZ) {
710 buf = c->arbuf;
711 len = rcbadr - c->arphys;
712 cnt_port = ARBCNT(port);
713 sts_port = ARBSTS(port);
714 } else
715 printf ("cx%d.%d: timeout: invalid buffer address\n",
716 c->board->num, c->num);
717
718 if (len) {
719 print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n",
720 c->board->num, c->num, len, risr, RISA_BITS,
721 inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
722 c->stat->ibytes += len;
723 if (tp && (tp->t_state & TS_ISOPEN)) {
724 int i;
725 int (*rint)(int, struct tty *) =
726 linesw[tp->t_line].l_rint;
727
728 for (i=0; i<len; ++i)
729 (*rint) (buf[i], tp);
730 }
731
732 /* Restart receiver. */
733 outw (cnt_port, rbsz);
734 outb (sts_port, BSTS_OWN24);
735 }
736 return (REOI_TERMBUFF);
737 }
738
739 print (("cx%d.%d: async receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
740 c->board->num, c->num, risr, RISA_BITS,
741 inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
742
743 if (risr & RIS_BUSERR) {
744 printf ("cx%d.%d: receive bus error\n", c->board->num, c->num);
745 ++c->stat->ierrs;
746 }
747 if (risr & (RIS_OVERRUN | RISA_PARERR | RISA_FRERR | RISA_BREAK)) {
748 int err = 0;
749
750 if (risr & RISA_PARERR)
751 err |= TTY_PE;
752 if (risr & RISA_FRERR)
753 err |= TTY_FE;
754 #ifdef TTY_OE
755 if (risr & RIS_OVERRUN)
756 err |= TTY_OE;
757 #endif
758 #ifdef TTY_BI
759 if (risr & RISA_BREAK)
760 err |= TTY_BI;
761 #endif
762 print (("cx%d.%d: receive error %x\n", c->board->num, c->num, err));
763 if (tp && (tp->t_state & TS_ISOPEN))
764 (*linesw[tp->t_line].l_rint) (err, tp);
765 ++c->stat->ierrs;
766 }
767
768 /* Discard exception characters. */
769 if ((risr & RISA_SCMASK) && tp && (tp->t_iflag & IXON))
770 reoir |= REOI_DISCEXC;
771
772 /* Handle received data. */
773 if ((risr & RIS_EOBUF) && tp && (tp->t_state & TS_ISOPEN)) {
774 int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint;
775 unsigned char *buf;
776 int i;
777
778 len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
779
780 print (("cx%d.%d: async: %d bytes received\n",
781 c->board->num, c->num, len));
782 c->stat->ibytes += len;
783
784 buf = (risr & RIS_BB) ? c->brbuf : c->arbuf;
785 for (i=0; i<len; ++i)
786 (*rint) (buf[i], tp);
787 }
788
789 /* Restart receiver. */
790 if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
791 outw (ARBCNT(port), rbsz);
792 outb (ARBSTS(port), BSTS_OWN24);
793 }
794 if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
795 outw (BRBCNT(port), rbsz);
796 outb (BRBSTS(port), BSTS_OWN24);
797 }
798 return (reoir);
799 }
800
801 /*
802 * Handle transmit interrupt.
803 */
804 void cxtinta (cx_chan_t *c)
805 {
806 struct tty *tp = c->ttyp;
807 unsigned short port = c->chip->port;
808 unsigned char tisr = inb (TISR(port));
809
810 print (("cx%d.%d: async transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
811 c->board->num, c->num, tisr, TIS_BITS,
812 inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS));
813
814 if (tisr & TIS_BUSERR) {
815 printf ("cx%d.%d: transmit bus error\n",
816 c->board->num, c->num);
817 ++c->stat->oerrs;
818 } else if (tisr & TIS_UNDERRUN) {
819 printf ("cx%d.%d: transmit underrun error\n",
820 c->board->num, c->num);
821 ++c->stat->oerrs;
822 }
823 if (tp) {
824 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
825 if (tp->t_line)
826 (*linesw[tp->t_line].l_start) (tp);
827 else
828 cxoproc (tp);
829 }
830 }
831
832 /*
833 * Handle modem interrupt.
834 */
835 void cxmint (cx_chan_t *c)
836 {
837 unsigned short port = c->chip->port;
838 unsigned char misr = inb (MISR(port));
839 unsigned char msvr = inb (MSVR(port));
840 struct tty *tp = c->ttyp;
841
842 if (c->mode != M_ASYNC) {
843 printf ("cx%d.%d: unexpected modem interrupt, misr=%b, msvr=%b\n",
844 c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS);
845 return;
846 }
847 print (("cx%d.%d: modem interrupt, misr=%b, msvr=%b\n",
848 c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS));
849
850 /* Ignore DSR events. */
851 /* Ignore RTC/CTS events, handled by hardware. */
852 /* Handle carrier detect/loss. */
853 if (tp && (misr & MIS_CCD))
854 (*linesw[tp->t_line].l_modem) (tp, (msvr & MSV_CD) != 0);
855 }
856
857 /*
858 * Recover after lost transmit interrupts.
859 */
860 void cxtimeout (void *a)
861 {
862 cx_board_t *b;
863 cx_chan_t *c;
864 struct tty *tp;
865 int s;
866
867 for (b=cxboard; b<cxboard+NCX; ++b)
868 for (c=b->chan; c<b->chan+NCHAN; ++c) {
869 tp = c->ttyp;
870 if (c->type==T_NONE || c->mode!=M_ASYNC || !tp)
871 continue;
872 s = spltty ();
873 if (tp->t_state & TS_BUSY) {
874 tp->t_state &= ~TS_BUSY;
875 if (tp->t_line)
876 (*linesw[tp->t_line].l_start) (tp);
877 else
878 cxoproc (tp);
879 }
880 splx (s);
881 }
882 timeout (cxtimeout, 0, hz*5);
883 }
Cache object: e955b665177072d8281b6457987249f0
|