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