Initial import from FreeBSD RELENG_4:
[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  *
21  */
22 #undef DEBUG
23
24 #include "cx.h"
25 #include "sppp.h"
26 #if NSPPP <= 0
27 #error The device 'cx' requires sppp.
28 #endif
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/mbuf.h>
35 #include <sys/sockio.h>
36 #include <sys/socket.h>
37 #include <sys/conf.h>
38
39 #include <net/if.h>
40
41 #include <net/bpf.h>
42
43 #include <i386/isa/isa_device.h>
44 #define watchdog_func_t void(*)(struct ifnet *)
45 #define start_func_t    void(*)(struct ifnet*)
46
47 #include <net/if_sppp.h>
48 #include <machine/cronyx.h>
49 #include <i386/isa/cxreg.h>
50
51 /* XXX exported. */
52 void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
53
54 static int cxprobe __P((struct isa_device *id));
55 static int cxattach __P((struct isa_device *id));
56 static void cxput __P((cx_chan_t *c, char b));
57 static void cxsend __P((cx_chan_t *c));
58 static void cxrinth __P((cx_chan_t *c));
59 static ointhand2_t cxintr;
60 static int cxtinth __P((cx_chan_t *c));
61
62 #ifdef DEBUG
63 #   define print(s)     printf s
64 #else
65 #   define print(s)     {/*void*/}
66 #endif
67
68 #define TXTIMEOUT       10              /* transmit timeout in seconds */
69 #define DMABUFSZ        (6*256)         /* buffer size */
70 #define PPP_HEADER_LEN  4               /* size of PPP header */
71
72 /*
73  * Under BSDI it's possible to use general p2p protocol scheme,
74  * as well as our own one.  Switching is done via IFF_ALTPHYS flag.
75  * Our ifnet pointer holds the buffer large enough to contain
76  * any of sppp and p2p structures.
77  */
78 #define IFSTRUCTSZ   (sizeof (struct sppp))
79 #define IFNETSZ         (sizeof (struct ifnet))
80
81 static int cxsioctl (struct ifnet *ifp, u_long cmd, caddr_t data);
82 static void cxstart (struct ifnet *ifp);
83 static void cxwatchdog (struct ifnet *ifp);
84 static void cxinput (cx_chan_t *c, void *buf, unsigned len);
85 extern int cxrinta (cx_chan_t *c);
86 extern void cxtinta (cx_chan_t *c);
87 extern void cxmint (cx_chan_t *c);
88 extern timeout_t cxtimeout;
89 static void cxdown (cx_chan_t *c);
90 static void cxup (cx_chan_t *c);
91
92 cx_board_t cxboard [NCX];           /* adapter state structures */
93 cx_chan_t *cxchan [NCX*NCHAN];      /* unit to channel struct pointer */
94
95 extern struct cdevsw cx_cdevsw;
96
97 static unsigned short irq_valid_values [] = { 3, 5, 7, 10, 11, 12, 15, 0 };
98 static unsigned short drq_valid_values [] = { 5, 6, 7, 0 };
99 static unsigned short port_valid_values [] = {
100         0x240, 0x260, 0x280, 0x300, 0x320, 0x380, 0x3a0, 0,
101 };
102
103 /*
104  * Check that the value is contained in the list of correct values.
105  */
106 static int valid (unsigned short value, unsigned short *list)
107 {
108         while (*list)
109                 if (value == *list++)
110                         return (1);
111         return (0);
112 }
113
114 /*
115  * Print the mbuf chain, for debug purposes only.
116  */
117 static void printmbuf (struct mbuf *m)
118 {
119         printf ("mbuf:");
120         for (; m; m=m->m_next) {
121                 if (m->m_flags & M_PKTHDR)
122                         printf (" HDR %d:", m->m_pkthdr.len);
123                 if (m->m_flags & M_EXT)
124                         printf (" EXT:");
125                 printf (" %d", m->m_len);
126         }
127         printf ("\n");
128 }
129
130 /*
131  * Make an mbuf from data.
132  */
133 static struct mbuf *makembuf (void *buf, unsigned len)
134 {
135         struct mbuf *m, *o, *p;
136
137         MGETHDR (m, M_DONTWAIT, MT_DATA);
138         if (! m)
139                 return (0);
140         if (len >= MINCLSIZE)
141                 MCLGET (m, M_DONTWAIT);
142         m->m_pkthdr.len = len;
143         m->m_len = 0;
144
145         p = m;
146         while (len) {
147                 unsigned n = M_TRAILINGSPACE (p);
148                 if (n > len)
149                         n = len;
150
151                 if (! n) {
152                         /* Allocate new mbuf. */
153                         o = p;
154                         MGET (p, M_DONTWAIT, MT_DATA);
155                         if (! p) {
156                                 m_freem (m);
157                                 return (0);
158                         }
159                         if (len >= MINCLSIZE)
160                                 MCLGET (p, M_DONTWAIT);
161                         p->m_len = 0;
162                         o->m_next = p;
163
164                         n = M_TRAILINGSPACE (p);
165                         if (n > len)
166                                 n = len;
167                 }
168
169                 bcopy (buf, mtod (p, caddr_t) + p->m_len, n);
170
171                 p->m_len += n;
172                 buf = (char *)buf + n;
173                 len -= n;
174         }
175         return (m);
176 }
177
178 /*
179  * Test the presence of the adapter on the given i/o port.
180  */
181 static int
182 cxprobe (struct isa_device *id)
183 {
184         int unit = id->id_unit;
185         int iobase = id->id_iobase;
186         int irq = id->id_irq;
187         int drq = id->id_drq;
188         int irqnum;
189         irqnum = ffs (irq) - 1;
190
191         print (("cx%d: probe iobase=0x%x irq=%d drq=%d\n",
192                 unit, iobase, irqnum, drq));
193         if (! valid (irqnum, irq_valid_values)) {
194                 printf ("cx%d: Incorrect IRQ: %d\n", unit, irqnum);
195                 return (0);
196         }
197         if (! valid (iobase, port_valid_values)) {
198                 printf ("cx%d: Incorrect port address: 0x%x\n", unit, iobase);
199                 return (0);
200         }
201         if (! valid (drq, drq_valid_values)) {
202                 printf ("cx%d: Incorrect DMA channel: %d\n", unit, drq);
203                 return (0);
204         }
205         if (! cx_probe_board (iobase))
206                 return (0);
207
208         return (1);
209 }
210
211 /*
212  * The adapter is present, initialize the driver structures.
213  */
214
215 static int
216 cxattach (struct isa_device *id)
217 {
218         int unit = id->id_unit;
219         int iobase = id->id_iobase;
220         int irq = id->id_irq;
221         int drq = id->id_drq;
222         cx_board_t *b = cxboard + unit;
223         int i;
224         struct sppp *sp;
225
226         id->id_ointr = cxintr;
227
228         /* Initialize the board structure. */
229         cx_init (b, unit, iobase, ffs(irq)-1, drq);
230
231         for (i=0; i<NCHAN; ++i) {
232                 cx_chan_t *c = b->chan + i;
233                 int u = b->num*NCHAN + i;
234                 cxchan[u] = c;
235
236                 if (c->type == T_NONE)
237                         continue;
238
239                 /* Allocate the buffer memory. */
240                 c->arbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
241                 c->brbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
242                 c->atbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
243                 c->btbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
244
245                 /* All buffers should be located in lower 16M of memory! */
246                 if (!c->arbuf || !c->brbuf || !c->atbuf || !c->btbuf) {
247                         printf ("cx%d.%d: No memory for channel buffers\n",
248                                 c->board->num, c->num);
249                         c->type = T_NONE;
250                 }
251
252                 switch (c->type) {
253                 case T_SYNC_RS232:
254                 case T_SYNC_V35:
255                 case T_SYNC_RS449:
256                 case T_UNIV_RS232:
257                 case T_UNIV_RS449:
258                 case T_UNIV_V35:
259                         c->ifp = malloc (IFSTRUCTSZ, M_DEVBUF, M_NOWAIT);
260                         if (! c->ifp) {
261                                 printf ("cx%d.%d: No memory for ifnet buffer\n",
262                                         c->board->num, c->num);
263                                 c->type = T_NONE;
264                                 continue;
265                         }
266                         bzero (c->ifp, IFSTRUCTSZ);
267                         c->master = c->ifp;
268                         c->ifp->if_softc = c;
269                         c->ifp->if_unit = u;
270                         c->ifp->if_name = "cx";
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)
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 }