Merge from vendor branch LESS:
[dragonfly.git] / sys / dev / netif / cx / if_cx.c
1 /*
2  * Cronyx-Sigma adapter driver for FreeBSD.
3  * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode,
4  * and asyncronous channels with full modem control.
5  * Keepalive protocol implemented in both Cisco and PPP modes.
6  *
7  * Copyright (C) 1994 Cronyx Ltd.
8  * Author: Serge Vakulenko, <vak@zebub.msk.su>
9  *
10  * This software is distributed with NO WARRANTIES, not even the implied
11  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * Authors grant any other persons or organisations permission to use
14  * or modify this software as long as this message is kept with the software,
15  * all derivative works or modified versions.
16  *
17  * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
18  *
19  * $FreeBSD: src/sys/i386/isa/if_cx.c,v 1.32 1999/11/18 08:36:42 peter Exp $
20  * $DragonFly: src/sys/dev/netif/cx/if_cx.c,v 1.10 2004/04/07 05:45:27 dillon Exp $
21  *
22  */
23 #undef DEBUG
24
25 #include "use_cx.h"
26 #include "use_sppp.h"
27 #if NSPPP <= 0
28 #error The device 'cx' requires sppp.
29 #endif
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/mbuf.h>
36 #include <sys/sockio.h>
37 #include <sys/socket.h>
38 #include <sys/conf.h>
39
40 #include <net/if.h>
41
42 #include <net/bpf.h>
43
44 #include <bus/isa/i386/isa_device.h>
45 #define watchdog_func_t void(*)(struct ifnet *)
46 #define start_func_t    void(*)(struct ifnet*)
47
48 #include <net/sppp/if_sppp.h>
49 #include <machine/cronyx.h>
50 #include "cxreg.h"
51 #include "cx.c"
52
53 /* XXX exported. */
54 void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
55
56 static int cxprobe (struct isa_device *id);
57 static int cxattach (struct isa_device *id);
58 static void cxput (cx_chan_t *c, char b);
59 static void cxsend (cx_chan_t *c);
60 static void cxrinth (cx_chan_t *c);
61 static ointhand2_t cxintr;
62 static int cxtinth (cx_chan_t *c);
63
64 #ifdef DEBUG
65 #   define print(s)     printf s
66 #else
67 #   define print(s)     {/*void*/}
68 #endif
69
70 #define TXTIMEOUT       10              /* transmit timeout in seconds */
71 #define DMABUFSZ        (6*256)         /* buffer size */
72 #define PPP_HEADER_LEN  4               /* size of PPP header */
73
74 /*
75  * Under BSDI it's possible to use general p2p protocol scheme,
76  * as well as our own one.  Switching is done via IFF_ALTPHYS flag.
77  * Our ifnet pointer holds the buffer large enough to contain
78  * any of sppp and p2p structures.
79  */
80 #define IFSTRUCTSZ   (sizeof (struct sppp))
81 #define IFNETSZ         (sizeof (struct ifnet))
82
83 static int cxsioctl (struct ifnet *ifp, u_long cmd, caddr_t data,
84                      struct ucred *cr);
85 static void cxstart (struct ifnet *ifp);
86 static void cxwatchdog (struct ifnet *ifp);
87 static void cxinput (cx_chan_t *c, void *buf, unsigned len);
88 extern int cxrinta (cx_chan_t *c);
89 extern void cxtinta (cx_chan_t *c);
90 extern void cxmint (cx_chan_t *c);
91 extern timeout_t cxtimeout;
92 static void cxdown (cx_chan_t *c);
93 static void cxup (cx_chan_t *c);
94
95 cx_board_t cxboard [NCX];           /* adapter state structures */
96 cx_chan_t *cxchan [NCX*NCHAN];      /* unit to channel struct pointer */
97
98 extern struct cdevsw cx_cdevsw;
99
100 static unsigned short irq_valid_values [] = { 3, 5, 7, 10, 11, 12, 15, 0 };
101 static unsigned short drq_valid_values [] = { 5, 6, 7, 0 };
102 static unsigned short port_valid_values [] = {
103         0x240, 0x260, 0x280, 0x300, 0x320, 0x380, 0x3a0, 0,
104 };
105
106 DECLARE_DUMMY_MODULE(if_cx);
107
108 /*
109  * Check that the value is contained in the list of correct values.
110  */
111 static int valid (unsigned short value, unsigned short *list)
112 {
113         while (*list)
114                 if (value == *list++)
115                         return (1);
116         return (0);
117 }
118
119 /*
120  * Print the mbuf chain, for debug purposes only.
121  */
122 static void printmbuf (struct mbuf *m)
123 {
124         printf ("mbuf:");
125         for (; m; m=m->m_next) {
126                 if (m->m_flags & M_PKTHDR)
127                         printf (" HDR %d:", m->m_pkthdr.len);
128                 if (m->m_flags & M_EXT)
129                         printf (" EXT:");
130                 printf (" %d", m->m_len);
131         }
132         printf ("\n");
133 }
134
135 /*
136  * Make an mbuf from data.
137  */
138 static struct mbuf *makembuf (void *buf, unsigned len)
139 {
140         struct mbuf *m, *o, *p;
141
142         MGETHDR (m, M_DONTWAIT, MT_DATA);
143         if (! m)
144                 return (0);
145         if (len >= MINCLSIZE)
146                 MCLGET (m, M_DONTWAIT);
147         m->m_pkthdr.len = len;
148         m->m_len = 0;
149
150         p = m;
151         while (len) {
152                 unsigned n = M_TRAILINGSPACE (p);
153                 if (n > len)
154                         n = len;
155
156                 if (! n) {
157                         /* Allocate new mbuf. */
158                         o = p;
159                         MGET (p, M_DONTWAIT, MT_DATA);
160                         if (! p) {
161                                 m_freem (m);
162                                 return (0);
163                         }
164                         if (len >= MINCLSIZE)
165                                 MCLGET (p, M_DONTWAIT);
166                         p->m_len = 0;
167                         o->m_next = p;
168
169                         n = M_TRAILINGSPACE (p);
170                         if (n > len)
171                                 n = len;
172                 }
173
174                 bcopy (buf, mtod (p, caddr_t) + p->m_len, n);
175
176                 p->m_len += n;
177                 buf = (char *)buf + n;
178                 len -= n;
179         }
180         return (m);
181 }
182
183 /*
184  * Test the presence of the adapter on the given i/o port.
185  */
186 static int
187 cxprobe (struct isa_device *id)
188 {
189         int unit = id->id_unit;
190         int iobase = id->id_iobase;
191         int irq = id->id_irq;
192         int drq = id->id_drq;
193         int irqnum;
194         irqnum = ffs (irq) - 1;
195
196         print (("cx%d: probe iobase=0x%x irq=%d drq=%d\n",
197                 unit, iobase, irqnum, drq));
198         if (! valid (irqnum, irq_valid_values)) {
199                 printf ("cx%d: Incorrect IRQ: %d\n", unit, irqnum);
200                 return (0);
201         }
202         if (! valid (iobase, port_valid_values)) {
203                 printf ("cx%d: Incorrect port address: 0x%x\n", unit, iobase);
204                 return (0);
205         }
206         if (! valid (drq, drq_valid_values)) {
207                 printf ("cx%d: Incorrect DMA channel: %d\n", unit, drq);
208                 return (0);
209         }
210         if (! cx_probe_board (iobase))
211                 return (0);
212
213         return (1);
214 }
215
216 /*
217  * The adapter is present, initialize the driver structures.
218  */
219
220 static int
221 cxattach (struct isa_device *id)
222 {
223         int unit = id->id_unit;
224         int iobase = id->id_iobase;
225         int irq = id->id_irq;
226         int drq = id->id_drq;
227         cx_board_t *b = cxboard + unit;
228         int i;
229         struct sppp *sp;
230
231         id->id_ointr = cxintr;
232
233         /* Initialize the board structure. */
234         cx_init (b, unit, iobase, ffs(irq)-1, drq);
235
236         for (i=0; i<NCHAN; ++i) {
237                 cx_chan_t *c = b->chan + i;
238                 int u = b->num*NCHAN + i;
239                 cxchan[u] = c;
240
241                 if (c->type == T_NONE)
242                         continue;
243
244                 /* Allocate the buffer memory. */
245                 c->arbuf = malloc (DMABUFSZ, M_DEVBUF, M_WAITOK);
246                 c->brbuf = malloc (DMABUFSZ, M_DEVBUF, M_WAITOK);
247                 c->atbuf = malloc (DMABUFSZ, M_DEVBUF, M_WAITOK);
248                 c->btbuf = malloc (DMABUFSZ, M_DEVBUF, M_WAITOK);
249
250 #if 0
251                 /* All buffers should be located in lower 16M of memory! */
252                 /* XXX all buffers located where?  I don't think so! */
253                 if (!c->arbuf || !c->brbuf || !c->atbuf || !c->btbuf) {
254                         printf ("cx%d.%d: No memory for channel buffers\n",
255                                 c->board->num, c->num);
256                         c->type = T_NONE;
257                 }
258 #endif
259
260                 switch (c->type) {
261                 case T_SYNC_RS232:
262                 case T_SYNC_V35:
263                 case T_SYNC_RS449:
264                 case T_UNIV_RS232:
265                 case T_UNIV_RS449:
266                 case T_UNIV_V35:
267                         c->ifp = malloc (IFSTRUCTSZ, M_DEVBUF, M_WAITOK | M_ZERO);
268                         c->master = c->ifp;
269                         c->ifp->if_softc = c;
270                         if_initname(c->ifp, "cx", u);
271                         c->ifp->if_mtu = PP_MTU;
272                         c->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
273                         c->ifp->if_ioctl = cxsioctl;
274                         c->ifp->if_start = (start_func_t) cxstart;
275                         c->ifp->if_watchdog = (watchdog_func_t) cxwatchdog;
276                         /* Init routine is never called by upper level? */
277                         sppp_attach (c->ifp);
278                         if_attach (c->ifp);
279                         sp = (struct sppp*) c->ifp;
280                         /* If BPF is in the kernel, call the attach for it. */
281                         bpfattach (c->ifp, DLT_PPP, PPP_HEADER_LEN);
282                 }
283         }
284
285         /* Reset the adapter. */
286         cx_setup_board (b);
287
288         /* Activate the timeout routine. */
289         if (unit == 0)
290                 timeout (cxtimeout, 0, hz*5);
291
292         printf ("cx%d: <Cronyx-%s>\n", unit, b->name);
293         make_dev(&cx_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, "cx%d", unit);
294         return (1);
295 }
296
297 struct isa_driver cxdriver = { cxprobe, cxattach, "cx" };
298
299 /*
300  * Process an ioctl request.
301  */
302 static int
303 cxsioctl (struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
304 {
305         cx_chan_t *q, *c = ifp->if_softc;
306         int error, s, was_up, should_be_up;
307
308         /*
309          * No socket ioctls while the channel is in async mode.
310          */
311         if (c->type==T_NONE || c->mode==M_ASYNC)
312                 return (EINVAL);
313
314         /*
315          * Socket ioctls on slave subchannels are not allowed.
316          */
317         if (c->master != c->ifp)
318                 return (EBUSY);
319
320         was_up = (ifp->if_flags & IFF_RUNNING) != 0;
321         error = sppp_ioctl (ifp, cmd, data);
322         if (error)
323                 return (error);
324
325         print (("cxioctl (%d.%d, ", c->board->num, c->num));
326         switch (cmd) {
327         default:
328                 print (("0x%x)\n", cmd));
329                 return (0);
330         case SIOCADDMULTI:
331                 print (("SIOCADDMULTI)\n"));
332                 return (0);
333         case SIOCDELMULTI:
334                 print (("SIOCDELMULTI)\n"));
335                 return (0);
336         case SIOCSIFFLAGS:
337                 print (("SIOCSIFFLAGS)\n"));
338                 break;
339         case SIOCSIFADDR:
340                 print (("SIOCSIFADDR)\n"));
341                 break;
342         }
343
344         /* We get here only in case of SIFFLAGS or SIFADDR. */
345         s = splimp ();
346         should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
347         if (!was_up && should_be_up) {
348                 /* Interface goes up -- start it. */
349                 cxup (c);
350
351                 /* Start all slave subchannels. */
352                 for (q=c->slaveq; q; q=q->slaveq)
353                         cxup (q);
354
355                 cxstart (c->ifp);
356         } else if (was_up && !should_be_up) {
357                 /* Interface is going down -- stop it. */
358                 cxdown (c);
359
360                 /* Stop all slave subchannels. */
361                 for (q=c->slaveq; q; q=q->slaveq)
362                         cxdown (q);
363
364                 /* Flush the interface output queue */
365                 if (! c->sopt.ext)
366                         sppp_flush (c->ifp);
367         }
368         splx (s);
369         return (0);
370 }
371
372 /*
373  * Stop the interface.  Called on splimp().
374  */
375 static void
376 cxdown (cx_chan_t *c)
377 {
378         unsigned short port = c->chip->port;
379
380         print (("cx%d.%d: cxdown\n", c->board->num, c->num));
381
382         /* The interface is down, stop it */
383         c->ifp->if_flags &= ~IFF_OACTIVE;
384
385         /* Reset the channel (for sync modes only) */
386                 outb (CAR(port), c->num & 3);
387                 outb (STCR(port), STC_ABORTTX | STC_SNDSPC);
388
389         cx_setup_chan (c);
390 }
391
392 /*
393  * Start the interface.  Called on splimp().
394  */
395 static void
396 cxup (cx_chan_t *c)
397 {
398         unsigned short port = c->chip->port;
399
400                 /* The interface is up, start it */
401                 print (("cx%d.%d: cxup\n", c->board->num, c->num));
402
403                 /* Initialize channel, enable receiver and transmitter */
404                 cx_cmd (port, CCR_INITCH | CCR_ENRX | CCR_ENTX);
405                 /* Repeat the command, to avoid the rev.H bug */
406                 cx_cmd (port, CCR_INITCH | CCR_ENRX | CCR_ENTX);
407
408                 /* Start receiver */
409                 outw (ARBCNT(port), DMABUFSZ);
410                 outb (ARBSTS(port), BSTS_OWN24);
411                 outw (BRBCNT(port), DMABUFSZ);
412                 outb (BRBSTS(port), BSTS_OWN24);
413
414                 /* Raise DTR and RTS */
415                 cx_chan_dtr (c, 1);
416                 cx_chan_rts (c, 1);
417
418                 /* Enable interrupts */
419                 outb (IER(port), IER_RXD | IER_TXD);
420 }
421
422 /*
423  * Fill transmitter buffer with data.
424  */
425 static void 
426 cxput (cx_chan_t *c, char b)
427 {
428         struct mbuf *m;
429         unsigned char *buf;
430         unsigned short port = c->chip->port, len, cnt_port, sts_port;
431
432         /* Choose the buffer. */
433         if (b == 'A') {
434                 buf      = c->atbuf;
435                 cnt_port = ATBCNT(port);
436                 sts_port = ATBSTS(port);
437         } else {
438                 buf      = c->btbuf;
439                 cnt_port = BTBCNT(port);
440                 sts_port = BTBSTS(port);
441         }
442
443         /* Is it busy? */
444         if (inb (sts_port) & BSTS_OWN24) {
445                 if (c->ifp->if_flags & IFF_DEBUG)
446                         print (("cx%d.%d: tbuf %c already busy, bsts=%b\n",
447                                 c->board->num, c->num, b,
448                                 inb (sts_port), BSTS_BITS));
449                 goto ret;
450         }
451
452         /* Get the packet to send. */
453         m = sppp_dequeue (c->master);
454         if (! m)
455                 return;
456         len = m->m_pkthdr.len;
457
458         /* Count the transmitted bytes to the subchannel, not the master. */
459         c->master->if_obytes -= len + 3;
460         c->ifp->if_obytes += len + 3;
461         c->stat->obytes += len + 3;
462
463         if (len >= DMABUFSZ) {
464                 printf ("cx%d.%d: too long packet: %d bytes: ",
465                         c->board->num, c->num, len);
466                 printmbuf (m);
467                 m_freem (m);
468                 return;
469         }
470         m_copydata (m, 0, len, buf);
471         if (c->ifp->if_bpf)
472                 bpf_mtap (c->ifp, m);
473         m_freem (m);
474
475         /* Start transmitter. */
476         outw (cnt_port, len);
477         outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24);
478
479         if (c->ifp->if_flags & IFF_DEBUG)
480                 print (("cx%d.%d: enqueue %d bytes to %c\n",
481                         c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B'));
482 ret:
483         c->ifp->if_flags |= IFF_OACTIVE;
484 }
485
486 /*
487  * Start output on the (slave) interface.  Get another datagram to send
488  * off of the interface queue, and copy it to the interface
489  * before starting the output.
490  */
491 static void
492 cxsend (cx_chan_t *c)
493 {
494         unsigned short port = c->chip->port;
495
496         if (c->ifp->if_flags & IFF_DEBUG)
497                 print (("cx%d.%d: cxsend\n", c->board->num, c->num));
498
499         /* No output if the interface is down. */
500         if (! (c->ifp->if_flags & IFF_RUNNING))
501                 return;
502
503         /* Set the current channel number. */
504         outb (CAR(port), c->num & 3);
505
506         /* Determine the buffer order. */
507         if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
508                 cxput (c, 'B');
509                 cxput (c, 'A');
510         } else {
511                 cxput (c, 'A');
512                 cxput (c, 'B');
513         }
514
515         /* Set up transmit timeout. */
516         if (c->master->if_flags & IFF_OACTIVE)
517                 c->master->if_timer = TXTIMEOUT;
518
519         /*
520          * Enable TXMPTY interrupt,
521          * to catch the case when the second buffer is empty.
522          */
523         if ((inb (ATBSTS(port)) & BSTS_OWN24) &&
524             (inb (BTBSTS(port)) & BSTS_OWN24)) {
525                 outb (IER(port), IER_RXD | IER_TXD | IER_TXMPTY);
526         } else
527                 outb (IER(port), IER_RXD | IER_TXD);
528 }
529
530 /*
531  * Start output on the (master) interface and all slave interfaces.
532  * Always called on splimp().
533  */
534 static void
535 cxstart (struct ifnet *ifp)
536 {
537         cx_chan_t *q, *c = ifp->if_softc;
538
539         if (c->ifp->if_flags & IFF_DEBUG)
540                 print (("cx%d.%d: cxstart\n", c->board->num, c->num));
541
542         /* Start the master subchannel. */
543         cxsend (c);
544
545         /* Start all slave subchannels. */
546         if (c->slaveq && ! sppp_isempty (c->master))
547                 for (q=c->slaveq; q; q=q->slaveq)
548                         if ((q->ifp->if_flags & IFF_RUNNING) &&
549                             ! (q->ifp->if_flags & IFF_OACTIVE))
550                                 cxsend (q);
551 }
552
553 /*
554  * Handle transmit timeouts.
555  * Recover after lost transmit interrupts.
556  * Always called on splimp().
557  */
558 static void
559 cxwatchdog (struct ifnet *ifp)
560 {
561         cx_chan_t *q, *c = ifp->if_softc;
562
563         if (! (ifp->if_flags & IFF_RUNNING))
564                 return;
565         if (ifp->if_flags & IFF_DEBUG)
566                 printf ("cx%d.%d: device timeout\n", c->board->num, c->num);
567
568         cxdown (c);
569         for (q=c->slaveq; q; q=q->slaveq)
570                 cxdown (q);
571
572         cxup (c);
573         for (q=c->slaveq; q; q=q->slaveq)
574                 cxup (q);
575
576                 cxstart (ifp);
577 }
578
579 /*
580  * Handle receive interrupts, including receive errors and
581  * receive timeout interrupt.
582  */
583 static void 
584 cxrinth (cx_chan_t *c)
585 {
586         unsigned short port = c->chip->port;
587         unsigned short len, risr = inw (RISR(port));
588
589         /* Receive errors. */
590         if (risr & (RIS_BUSERR | RIS_OVERRUN | RISH_CRCERR | RISH_RXABORT)) {
591                 if (c->ifp->if_flags & IFF_DEBUG)
592                         printf ("cx%d.%d: receive error, risr=%b\n",
593                                 c->board->num, c->num, risr, RISH_BITS);
594                 ++c->ifp->if_ierrors;
595                 ++c->stat->ierrs;
596                 if (risr & RIS_OVERRUN)
597                         ++c->ifp->if_collisions;
598         } else if (risr & RIS_EOBUF) {
599                 if (c->ifp->if_flags & IFF_DEBUG)
600                         print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
601                                 c->board->num, c->num, risr, RISH_BITS,
602                                 inb (ARBSTS(port)), BSTS_BITS,
603                                 inb (BRBSTS(port)), BSTS_BITS));
604                 ++c->stat->ipkts;
605
606                 /* Handle received data. */
607                 len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
608                 c->stat->ibytes += len;
609                 if (len > DMABUFSZ) {
610                         /* Fatal error: actual DMA transfer size
611                          * exceeds our buffer size.  It could be caused
612                          * by incorrectly programmed DMA register or
613                          * hardware fault.  Possibly, should panic here. */
614                         printf ("cx%d.%d: panic! DMA buffer overflow: %d bytes\n",
615                                c->board->num, c->num, len);
616                         ++c->ifp->if_ierrors;
617                 } else if (! (risr & RIS_EOFR)) {
618                         /* The received frame does not fit in the DMA buffer.
619                          * It could be caused by serial lie noise,
620                          * or if the peer has too big MTU. */
621                         if (c->ifp->if_flags & IFF_DEBUG)
622                                 printf ("cx%d.%d: received frame length exceeds MTU, risr=%b\n",
623                                         c->board->num, c->num, risr, RISH_BITS);
624                         ++c->ifp->if_ierrors;
625                 } else {
626                         /* Valid frame received. */
627                         if (c->ifp->if_flags & IFF_DEBUG)
628                                 print (("cx%d.%d: hdlc received %d bytes\n",
629                                 c->board->num, c->num, len));
630                         cxinput (c, (risr & RIS_BB) ? c->brbuf : c->arbuf, len);
631                         ++c->ifp->if_ipackets;
632                 }
633         } else if (c->ifp->if_flags & IFF_DEBUG) {
634                 print (("cx%d.%d: unknown hdlc receive interrupt, risr=%b\n",
635                         c->board->num, c->num, risr, RISH_BITS));
636                 ++c->stat->ierrs;
637         }
638
639         /* Restart receiver. */
640         if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
641                 outw (ARBCNT(port), DMABUFSZ);
642                 outb (ARBSTS(port), BSTS_OWN24);
643         }
644         if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
645                 outw (BRBCNT(port), DMABUFSZ);
646                 outb (BRBSTS(port), BSTS_OWN24);
647         }
648 }
649
650 /*
651  * Handle transmit interrupt.
652  */
653 static int
654 cxtinth (cx_chan_t *c)
655 {
656         unsigned short port = c->chip->port;
657         unsigned char tisr = inb (TISR(port));
658         unsigned char teoir = 0;
659
660         c->ifp->if_flags &= ~IFF_OACTIVE;
661         if (c->ifp == c->master)
662                 c->ifp->if_timer = 0;
663
664         if (tisr & (TIS_BUSERR | TIS_UNDERRUN)) {
665                 /* if (c->ifp->if_flags & IFF_DEBUG) */
666                         print (("cx%d.%d: transmit error, tisr=%b, atbsts=%b, btbsts=%b\n",
667                                 c->board->num, c->num, tisr, TIS_BITS,
668                                 inb (ATBSTS(port)), BSTS_BITS,
669                                 inb (BTBSTS(port)), BSTS_BITS));
670                 ++c->ifp->if_oerrors;
671                 ++c->stat->oerrs;
672
673                 /* Terminate the failed buffer. */
674                 /* teoir = TEOI_TERMBUFF; */
675         } else if (c->ifp->if_flags & IFF_DEBUG)
676                 print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
677                         c->board->num, c->num, tisr, TIS_BITS,
678                         inb (ATBSTS(port)), BSTS_BITS,
679                         inb (BTBSTS(port)), BSTS_BITS));
680
681         if (tisr & TIS_EOFR) {
682                 ++c->ifp->if_opackets;
683                 ++c->stat->opkts;
684         }
685
686         /* Start output on the (sub-) channel. */
687         cxsend (c);
688
689         return (teoir);
690 }
691
692 static void
693 cxintr (int bnum)
694 {
695         cx_board_t *b = cxboard + bnum;
696         while (! (inw (BSR(b->port)) & BSR_NOINTR)) {
697                 /* Acknowledge the interrupt to enter the interrupt context. */
698                 /* Read the local interrupt vector register. */
699                 unsigned char livr = inb (IACK(b->port, BRD_INTR_LEVEL));
700                 cx_chan_t *c = b->chan + (livr>>2 & 0xf);
701                 unsigned short port = c->chip->port;
702                 unsigned short eoiport = REOIR(port);
703                 unsigned char eoi = 0;
704
705                 if (c->type == T_NONE) {
706                         printf ("cx%d.%d: unexpected interrupt, livr=0x%x\n",
707                                 c->board->num, c->num, livr);
708                         continue;       /* incorrect channel number? */
709                 }
710                 /* print (("cx%d.%d: interrupt, livr=0x%x\n",
711                         c->board->num, c->num, livr)); */
712
713                 /* Clear RTS to stop receiver data flow while we are busy
714                  * processing the interrupt, thus avoiding underruns. */
715                 if (! c->sopt.norts) {
716                         outb (MSVR_RTS(port), 0);
717                         c->rts = 0;
718                 }
719
720                 switch (livr & 3) {
721                 case LIV_EXCEP:         /* receive exception */
722                 case LIV_RXDATA:        /* receive interrupt */
723                         ++c->stat->rintr;
724                         switch (c->mode) {
725                         case M_ASYNC: eoi = cxrinta (c); break;
726                         case M_HDLC:  cxrinth (c);       break;
727                         default:;       /* No bisync and X.21 yet */
728                         }
729                         break;
730                 case LIV_TXDATA:        /* transmit interrupt */
731                         ++c->stat->tintr;
732                         eoiport = TEOIR(port);
733                         switch (c->mode) {
734                         case M_ASYNC: cxtinta (c);       break;
735                         case M_HDLC:  eoi = cxtinth (c); break;
736                         default:;       /* No bisync and X.21 yet */
737                         }
738                         break;
739                 case LIV_MODEM:         /* modem/timer interrupt */
740                         ++c->stat->mintr;
741                         eoiport = MEOIR(port);
742                         cxmint (c);
743                         break;
744                 }
745
746                 /* Raise RTS for this channel if and only if
747                  * both receive buffers are empty. */
748                 if (! c->sopt.norts && (inb (CSR(port)) & CSRA_RXEN) &&
749                     (inb (ARBSTS(port)) & BSTS_OWN24) &&
750                     (inb (BRBSTS(port)) & BSTS_OWN24)) {
751                         outb (MSVR_RTS(port), MSV_RTS);
752                         c->rts = 1;
753                 }
754
755                 /* Exit from interrupt context. */
756                 outb (eoiport, eoi);
757
758                 /* Master channel - start output on all idle subchannels. */
759                 if (c->master == c->ifp && c->slaveq &&
760                     (livr & 3) == LIV_TXDATA && c->mode == M_HDLC &&
761                     ! sppp_isempty (c->ifp)) {
762                         cx_chan_t *q;
763
764                         for (q=c->slaveq; q; q=q->slaveq)
765                                 if ((q->ifp->if_flags & IFF_RUNNING) &&
766                                     ! (q->ifp->if_flags & IFF_OACTIVE))
767                                         cxsend (q);
768                 }
769         }
770 }
771
772 /*
773  * Process the received packet.
774  */
775 static void 
776 cxinput (cx_chan_t *c, void *buf, unsigned len)
777 {
778         /* Make an mbuf. */
779         struct mbuf *m = makembuf (buf, len);
780         if (! m) {
781                 if (c->ifp->if_flags & IFF_DEBUG)
782                         printf ("cx%d.%d: no memory for packet\n",
783                                 c->board->num, c->num);
784                 ++c->ifp->if_iqdrops;
785                 return;
786         }
787         m->m_pkthdr.rcvif = c->master;
788 #ifdef DEBUG
789         if (c->ifp->if_flags & IFF_DEBUG)
790         printmbuf (m);
791 #endif
792
793         /*
794          * Check if there's a BPF listener on this interface.
795          * If so, hand off the raw packet to bpf.
796          */
797         if (c->ifp->if_bpf)
798                 bpf_tap (c->ifp, buf, len);
799
800         /* Count the received bytes to the subchannel, not the master. */
801         c->master->if_ibytes -= len + 3;
802         c->ifp->if_ibytes += len + 3;
803
804         sppp_input (c->master, m);
805 }
806
807 void cxswitch (cx_chan_t *c, cx_soft_opt_t new)
808 {
809         new.ext = 0;
810         if (! new.ext) {
811                 struct sppp *sp = (struct sppp*) c->ifp;
812
813 #if 0 /* Doesn't work this way any more 990402 /phk */
814                 if (new.cisco)
815                         sp->pp_flags |= PP_CISCO;
816                 else
817                         sp->pp_flags &= ~PP_CISCO;
818 #endif
819                 if (new.keepalive)
820                         sp->pp_flags |= PP_KEEPALIVE;
821                 else
822                         sp->pp_flags &= ~PP_KEEPALIVE;
823         }
824         c->sopt = new;
825 }