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