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