kernel: Remove most definitions of CDEV_MAJOR.
[dragonfly.git] / sys / net / i4b / driver / i4b_rbch.c
1 /*
2  * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b_rbch.c - device driver for raw B channel data
28  *      ---------------------------------------------------
29  *
30  * $FreeBSD: src/sys/i4b/driver/i4b_rbch.c,v 1.10.2.3 2001/08/12 16:22:48 hm Exp $
31  *
32  *      last edit-date: [Sat Aug 11 18:06:57 2001]
33  *
34  *---------------------------------------------------------------------------*/
35
36 #include "use_i4brbch.h"
37
38 #if NI4BRBCH > 0
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42
43 #include <sys/conf.h>
44 #include <sys/uio.h>
45 #include <sys/kernel.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48 #include <net/if.h>
49 #include <sys/tty.h>
50 #include <sys/thread2.h>
51 #include <sys/vnode.h>
52
53 #include <net/i4b/include/machine/i4b_ioctl.h>
54 #include <net/i4b/include/machine/i4b_rbch_ioctl.h>
55 #include <net/i4b/include/machine/i4b_debug.h>
56
57 #include "../include/i4b_global.h"
58 #include "../include/i4b_mbuf.h"
59 #include "../include/i4b_l3l4.h"
60 #include "../layer4/i4b_l4.h"
61
62 #include <sys/event.h>
63 #include <sys/filio.h>
64
65 static drvr_link_t rbch_drvr_linktab[NI4BRBCH];
66 static isdn_link_t *isdn_linktab[NI4BRBCH];
67
68 #define I4BRBCHACCT             1       /* enable accounting messages */
69 #define I4BRBCHACCTINTVL        2       /* accounting msg interval in secs */
70
71 static struct rbch_softc {
72
73         int sc_unit;                    /* unit number          */
74
75         int sc_devstate;                /* state of driver      */
76 #define ST_IDLE         0x00
77 #define ST_CONNECTED    0x01
78 #define ST_ISOPEN       0x02
79 #define ST_RDWAITDATA   0x04
80 #define ST_WRWAITEMPTY  0x08
81 #define ST_NOBLOCK      0x10
82
83         int sc_bprot;                   /* B-ch protocol used   */
84
85         call_desc_t *sc_cd;             /* Call Descriptor */
86
87         struct termios it_in;
88
89         struct ifqueue sc_hdlcq;        /* hdlc read queue      */
90 #define I4BRBCHMAXQLEN  10
91
92         struct kqinfo kqp;              /* select / poll / kevent */
93
94 #if I4BRBCHACCT
95         struct callout  sc_timeout;
96
97         int             sc_iinb;        /* isdn driver # of inbytes     */
98         int             sc_ioutb;       /* isdn driver # of outbytes    */
99         int             sc_linb;        /* last # of bytes rx'd         */
100         int             sc_loutb;       /* last # of bytes tx'd         */
101         int             sc_fn;          /* flag, first null acct        */
102 #endif  
103 } rbch_softc[NI4BRBCH];
104
105 static void rbch_rx_data_rdy(int unit);
106 static void rbch_tx_queue_empty(int unit);
107 static void rbch_connect(int unit, void *cdp);
108 static void rbch_disconnect(int unit, void *cdp);
109 static void rbch_init_linktab(int unit);
110 static void rbch_clrq(int unit);
111
112 #define PDEVSTATIC      static
113 #define IOCTL_CMD_T     u_long
114
115 PDEVSTATIC d_open_t i4brbchopen;
116 PDEVSTATIC d_close_t i4brbchclose;
117 PDEVSTATIC d_read_t i4brbchread;
118 PDEVSTATIC d_write_t i4brbchwrite;
119 PDEVSTATIC d_ioctl_t i4brbchioctl;
120 PDEVSTATIC d_kqfilter_t i4brbchkqfilter;
121
122 PDEVSTATIC void i4brbchkfilt_detach(struct knote *);
123 PDEVSTATIC int i4brbchkfilt_read(struct knote *, long);
124 PDEVSTATIC int i4brbchkfilt_write(struct knote *, long);
125
126 static struct dev_ops i4brbch_ops = {
127         { "i4brbch", 0, 0 },
128         .d_open =       i4brbchopen,
129         .d_close =      i4brbchclose,
130         .d_read =       i4brbchread,
131         .d_write =      i4brbchwrite,
132         .d_ioctl =      i4brbchioctl,
133         .d_kqfilter =   i4brbchkqfilter
134 };
135
136 static void i4brbchattach(void *);
137 PSEUDO_SET(i4brbchattach, i4b_rbch);
138
139 /*===========================================================================*
140  *                      DEVICE DRIVER ROUTINES
141  *===========================================================================*/
142
143 /*---------------------------------------------------------------------------*
144  *      interface attach routine
145  *---------------------------------------------------------------------------*/
146 PDEVSTATIC void
147 i4brbchattach(void *dummy)
148 {
149         int i;
150
151 #ifndef HACK_NO_PSEUDO_ATTACH_MSG
152         kprintf("i4brbch: %d raw B channel access device(s) attached\n", NI4BRBCH);
153 #endif
154         
155         for(i=0; i < NI4BRBCH; i++)
156         {
157                 make_dev(&i4brbch_ops, i,
158                         UID_ROOT, GID_WHEEL, 0600, "i4brbch%d", i);
159
160 #if I4BRBCHACCT
161                 callout_init(&rbch_softc[i].sc_timeout);
162                 rbch_softc[i].sc_fn = 1;
163 #endif
164                 rbch_softc[i].sc_unit = i;
165                 rbch_softc[i].sc_devstate = ST_IDLE;
166                 rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
167                 rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
168                 termioschars(&rbch_softc[i].it_in);
169                 rbch_init_linktab(i);
170         }
171 }
172
173 /*---------------------------------------------------------------------------*
174  *      open rbch device
175  *---------------------------------------------------------------------------*/
176 PDEVSTATIC int
177 i4brbchopen(struct dev_open_args *ap)
178 {
179         cdev_t dev = ap->a_head.a_dev;
180         int unit = minor(dev);
181         
182         if(unit >= NI4BRBCH)
183                 return(ENXIO);
184
185         if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
186                 return(EBUSY);
187
188 #if 0
189         rbch_clrq(unit);
190 #endif
191         
192         rbch_softc[unit].sc_devstate |= ST_ISOPEN;              
193
194         NDBGL4(L4_RBCHDBG, "unit %d, open", unit);      
195
196         return(0);
197 }
198
199 /*---------------------------------------------------------------------------*
200  *      close rbch device
201  *---------------------------------------------------------------------------*/
202 PDEVSTATIC int
203 i4brbchclose(struct dev_close_args *ap)
204 {
205         cdev_t dev = ap->a_head.a_dev;
206         int unit = minor(dev);
207         struct rbch_softc *sc = &rbch_softc[unit];
208         
209         if(sc->sc_devstate & ST_CONNECTED)
210                 i4b_l4_drvrdisc(BDRV_RBCH, unit);
211
212         sc->sc_devstate &= ~ST_ISOPEN;          
213
214         rbch_clrq(unit);
215         
216         NDBGL4(L4_RBCHDBG, "unit %d, closed", unit);
217         
218         return(0);
219 }
220
221 /*---------------------------------------------------------------------------*
222  *      read from rbch device
223  *---------------------------------------------------------------------------*/
224 PDEVSTATIC int
225 i4brbchread(struct dev_read_args *ap)
226 {
227         cdev_t dev = ap->a_head.a_dev;
228         struct uio *uio = ap->a_uio;
229         struct mbuf *m;
230         int error = 0;
231         int unit = minor(dev);
232         struct ifqueue *iqp;
233         struct rbch_softc *sc = &rbch_softc[unit];
234
235         CRIT_VAR;
236         
237         NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
238         
239         CRIT_BEG;
240         if(!(sc->sc_devstate & ST_ISOPEN))
241         {
242                 CRIT_END;
243                 NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
244                 return(EIO);
245         }
246
247         if((sc->sc_devstate & ST_NOBLOCK) || (ap->a_ioflag & IO_NDELAY))
248         {
249                 if(!(sc->sc_devstate & ST_CONNECTED)) {
250                         CRIT_END;
251                         return(EWOULDBLOCK);
252                 }
253
254                 if(sc->sc_bprot == BPROT_RHDLC)
255                         iqp = &sc->sc_hdlcq;
256                 else
257                         iqp = isdn_linktab[unit]->rx_queue;     
258
259                 if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
260                         CRIT_END;
261                         return(EWOULDBLOCK);
262         }
263         }
264         else
265         {
266                 while(!(sc->sc_devstate & ST_CONNECTED))
267                 {
268                         NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
269                 
270                         if((error = tsleep((caddr_t) &rbch_softc[unit],
271                                                PCATCH, "rrrbch", 0 )) != 0)
272                         {
273                                 CRIT_END;
274                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
275                                 return(error);
276                         }
277                 }
278
279                 if(sc->sc_bprot == BPROT_RHDLC)
280                         iqp = &sc->sc_hdlcq;
281                 else
282                         iqp = isdn_linktab[unit]->rx_queue;     
283
284                 while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
285                 {
286                         sc->sc_devstate |= ST_RDWAITDATA;
287                 
288                         NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
289                 
290                         if((error = tsleep((caddr_t) &isdn_linktab[unit]->rx_queue,
291                                            PCATCH, "rrbch", 0 )) != 0)
292                         {
293                                 CRIT_END;
294                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
295                                 sc->sc_devstate &= ~ST_RDWAITDATA;
296                                 return(error);
297                         }
298                 }
299         }
300
301         IF_DEQUEUE(iqp, m);
302
303         NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
304         
305         if(m && m->m_len)
306         {
307                 error = uiomove(m->m_data, m->m_len, uio);
308         }
309         else
310         {
311                 NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
312                 error = EIO;
313         }
314                 
315         if(m)
316                 i4b_Bfreembuf(m);
317
318         CRIT_END;
319
320         return(error);
321 }
322
323 /*---------------------------------------------------------------------------*
324  *      write to rbch device
325  *---------------------------------------------------------------------------*/
326 PDEVSTATIC int
327 i4brbchwrite(struct dev_write_args *ap)
328 {
329         cdev_t dev = ap->a_head.a_dev;
330         struct uio *uio = ap->a_uio;
331         struct mbuf *m;
332         int error = 0;
333         int unit = minor(dev);
334         struct rbch_softc *sc = &rbch_softc[unit];
335
336         CRIT_VAR;
337         
338         NDBGL4(L4_RBCHDBG, "unit %d, write", unit);     
339
340         CRIT_BEG;
341         if(!(sc->sc_devstate & ST_ISOPEN))
342         {
343                 NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
344                 CRIT_END;
345                 return(EIO);
346         }
347
348         if((sc->sc_devstate & ST_NOBLOCK) || (ap->a_ioflag & IO_NDELAY))
349         {
350                 if(!(sc->sc_devstate & ST_CONNECTED)) {
351                         CRIT_END;
352                         return(EWOULDBLOCK);
353                 }
354                 if(IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
355                         CRIT_END;
356                         return(EWOULDBLOCK);
357         }
358         }
359         else
360         {
361                 while(!(sc->sc_devstate & ST_CONNECTED))
362                 {
363                         NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
364                 
365                         error = tsleep((caddr_t) &rbch_softc[unit],
366                                                    PCATCH, "wrrbch", 0 );
367                         if(error == ERESTART) {
368                                 CRIT_END;
369                                 return (ERESTART);
370                         }
371                         else if(error == EINTR)
372                         {
373                                 CRIT_END;
374                                 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
375                                 return(EINTR);
376                         }
377                         else if(error)
378                         {
379                                 CRIT_END;
380                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
381                                 return(error);
382                         }
383                         tsleep((caddr_t) &rbch_softc[unit], PCATCH, "xrbch", (hz*1));
384                 }
385
386                 while(IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
387                 {
388                         sc->sc_devstate |= ST_WRWAITEMPTY;
389
390                         NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
391                 
392                         if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue,
393                                             PCATCH, "wrbch", 0)) != 0) {
394                                 sc->sc_devstate &= ~ST_WRWAITEMPTY;
395                                 if(error == ERESTART)
396                                 {
397                                         CRIT_END;
398                                         return(ERESTART);
399                                 }
400                                 else if(error == EINTR)
401                                 {
402                                         CRIT_END;
403                                         NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
404                                         return(error);
405                                 }
406                                 else if(error)
407                                 {
408                                         CRIT_END;
409                                         NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
410                                         return(error);
411                                 }
412                         }
413                 }
414         }
415
416         if(!(sc->sc_devstate & ST_ISOPEN))
417         {
418                 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
419                 CRIT_END;
420                 return(EIO);
421         }
422
423         if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
424         {
425                 m->m_len = (int)szmin(BCH_MAX_DATALEN, uio->uio_resid);
426
427                 NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
428                 
429                 error = uiomove(m->m_data, (size_t)m->m_len, uio);
430
431                 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
432                         m_freem(m);
433                 else
434                         IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
435                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
436         }
437
438         CRIT_END;
439         
440         return(error);
441 }
442
443 /*---------------------------------------------------------------------------*
444  *      rbch device ioctl handlibg
445  *---------------------------------------------------------------------------*/
446 PDEVSTATIC int
447 i4brbchioctl(struct dev_ioctl_args *ap)
448 {
449         cdev_t dev = ap->a_head.a_dev;
450         int error = 0;
451         int unit = minor(dev);
452         struct rbch_softc *sc = &rbch_softc[unit];
453         
454         switch(ap->a_cmd)
455         {
456                 case FIOASYNC:  /* Set async mode */
457                         if (*(int *)ap->a_data)
458                         {
459                                 NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
460                         }
461                         else
462                         {
463                                 NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
464                         }
465                         break;
466
467                 case TIOCCDTR:  /* Clear DTR */
468                         if(sc->sc_devstate & ST_CONNECTED)
469                         {
470                                 NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
471                                 i4b_l4_drvrdisc(BDRV_RBCH, unit);
472                         }
473                         break;
474
475                 case I4B_RBCH_DIALOUT:
476                 {
477                         size_t l;
478
479                         for (l = 0; l < TELNO_MAX && ((char *)ap->a_data)[l]; l++)
480                                 ;
481                         if (l)
482                         {
483                                 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout to %s", unit, (char *)ap->a_data);
484                                 i4b_l4_dialoutnumber(BDRV_RBCH, unit, l, (char *)ap->a_data);
485                                 break;
486                         }
487                         /* fall through to SDTR */
488                 }
489
490                 case TIOCSDTR:  /* Set DTR */
491                         NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
492                         i4b_l4_dialout(BDRV_RBCH, unit);
493                         break;
494
495                 case TIOCSETA:  /* Set termios struct */
496                         break;
497
498                 case TIOCGETA:  /* Get termios struct */
499                         *(struct termios *)ap->a_data = sc->it_in;
500                         break;
501
502                 case TIOCMGET:
503                         *(int *)ap->a_data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
504                         if (sc->sc_devstate & ST_CONNECTED)
505                                 *(int *)ap->a_data |= TIOCM_CD;
506                         break;
507
508                 case I4B_RBCH_VR_REQ:
509                 {
510                         msg_vr_req_t *mvr;
511
512                         mvr = (msg_vr_req_t *)ap->a_data;
513
514                         mvr->version = VERSION;
515                         mvr->release = REL;
516                         mvr->step = STEP;                       
517                         break;
518                 }
519
520                 default:        /* Unknown stuff */
521                         NDBGL4(L4_RBCHDBG, "unit %d, ioctl, unknown cmd %lx", unit, ap->a_cmd);
522                         error = EINVAL;
523                         break;
524         }
525         return(error);
526 }
527
528 /*---------------------------------------------------------------------------*
529  *      device driver poll
530  *---------------------------------------------------------------------------*/
531 static struct filterops i4brbchkfiltops_read =
532         { FILTEROP_ISFD, NULL, i4brbchkfilt_detach, i4brbchkfilt_read };
533 static struct filterops i4brbchkfiltops_write =
534         { FILTEROP_ISFD, NULL, i4brbchkfilt_detach, i4brbchkfilt_write };
535
536 PDEVSTATIC int
537 i4brbchkqfilter(struct dev_kqfilter_args *ap)
538 {
539         cdev_t dev = ap->a_head.a_dev;
540         int unit = minor(dev);
541         struct rbch_softc *sc = &rbch_softc[unit];
542         struct knote *kn = ap->a_kn;
543         struct klist *klist;
544
545         ap->a_result = 0;
546
547         switch (kn->kn_filter) {
548         case EVFILT_READ:
549                 kn->kn_fop = &i4brbchkfiltops_read;
550                 kn->kn_hook = (caddr_t)dev;
551                 break;
552         case EVFILT_WRITE:
553                 kn->kn_fop = &i4brbchkfiltops_write;
554                 kn->kn_hook = (caddr_t)dev;
555                 break;
556         default:
557                 ap->a_result = EOPNOTSUPP;
558                 return (0);
559         }
560
561         klist = &sc->kqp.ki_note;
562         knote_insert(klist, kn);
563
564         return (0);
565 }
566
567 PDEVSTATIC void
568 i4brbchkfilt_detach(struct knote *kn)
569 {
570         cdev_t dev = (cdev_t)kn->kn_hook;
571         int unit = minor(dev);
572         struct rbch_softc *sc = &rbch_softc[unit];
573         struct klist *klist;
574
575         klist = &sc->kqp.ki_note;
576         knote_remove(klist, kn);
577 }
578
579 PDEVSTATIC int
580 i4brbchkfilt_read(struct knote *kn, long hint)
581 {
582         cdev_t dev = (cdev_t)kn->kn_hook;
583         int unit = minor(dev);
584         struct rbch_softc *sc = &rbch_softc[unit];
585         int ready = 0;
586
587         crit_enter();
588
589         if (!(sc->sc_devstate & ST_ISOPEN)) {
590                 crit_exit();
591                 kn->kn_flags |= EV_ERROR;
592                 kn->kn_data = EBADF;
593                 return (0);
594         }
595
596         if (sc->sc_devstate & ST_CONNECTED) {
597                 struct ifqueue *iqp;
598
599                 if(sc->sc_bprot == BPROT_RHDLC)
600                         iqp = &sc->sc_hdlcq;
601                 else
602                         iqp = isdn_linktab[unit]->rx_queue;
603
604                 if(!IF_QEMPTY(iqp))
605                         ready = 1;
606         }
607
608         crit_exit();
609
610         return (ready);
611 }
612
613 PDEVSTATIC int
614 i4brbchkfilt_write(struct knote *kn, long hint)
615 {
616         cdev_t dev = (cdev_t)kn->kn_hook;
617         int unit = minor(dev);
618         struct rbch_softc *sc = &rbch_softc[unit];
619         int ready = 0;
620
621         crit_enter();
622
623         if (!(sc->sc_devstate & ST_ISOPEN)) {
624                 crit_exit();
625                 kn->kn_flags |= EV_ERROR;
626                 kn->kn_data = EBADF;
627                 return (0);
628         }
629
630         /*
631          * Writes are OK if we are connected and the
632          * transmit queue can take them
633          */
634         if ((sc->sc_devstate & ST_CONNECTED) &&
635            !IF_QFULL(isdn_linktab[unit]->tx_queue))
636         {
637                 ready = 1;
638         }
639
640         crit_exit();
641
642         return (ready);
643 }
644
645 #if I4BRBCHACCT
646 /*---------------------------------------------------------------------------*
647  *      watchdog routine
648  *---------------------------------------------------------------------------*/
649 static void
650 rbch_timeout(struct rbch_softc *sc)
651 {
652         bchan_statistics_t bs;
653         int unit = sc->sc_unit;
654
655         /* get # of bytes in and out from the HSCX driver */ 
656         
657         (*isdn_linktab[unit]->bch_stat)
658                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
659
660         sc->sc_ioutb += bs.outbytes;
661         sc->sc_iinb += bs.inbytes;
662         
663         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
664         {
665                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
666                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
667
668                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
669                         sc->sc_fn = 0;
670                 else
671                         sc->sc_fn = 1;
672                         
673                 sc->sc_linb = sc->sc_iinb;
674                 sc->sc_loutb = sc->sc_ioutb;
675
676                 i4b_l4_accounting(BDRV_RBCH, unit, ACCT_DURING,
677                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
678         }
679         callout_reset(&sc->sc_timeout, I4BRBCHACCTINTVL * hz,
680                         (void *)rbch_timeout, sc);
681 }
682 #endif /* I4BRBCHACCT */
683
684 /*===========================================================================*
685  *                      ISDN INTERFACE ROUTINES
686  *===========================================================================*/
687
688 /*---------------------------------------------------------------------------*
689  *      this routine is called from L4 handler at connect time
690  *---------------------------------------------------------------------------*/
691 static void
692 rbch_connect(int unit, void *cdp)
693 {
694         call_desc_t *cd = (call_desc_t *)cdp;
695         struct rbch_softc *sc = &rbch_softc[unit];
696
697         sc->sc_bprot = cd->bprot;
698
699 #if I4BRBCHACCT
700         if(sc->sc_bprot == BPROT_RHDLC)
701         {       
702                 sc->sc_iinb = 0;
703                 sc->sc_ioutb = 0;
704                 sc->sc_linb = 0;
705                 sc->sc_loutb = 0;
706
707                 callout_reset(&sc->sc_timeout, I4BRBCHACCTINTVL * hz,
708                                 (void *)rbch_timeout, sc);
709         }
710 #endif          
711         if(!(sc->sc_devstate & ST_CONNECTED))
712         {
713                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
714                 sc->sc_devstate |= ST_CONNECTED;
715                 sc->sc_cd = cdp;
716                 wakeup((caddr_t)sc);
717         }
718 }
719
720 /*---------------------------------------------------------------------------*
721  *      this routine is called from L4 handler at disconnect time
722  *---------------------------------------------------------------------------*/
723 static void
724 rbch_disconnect(int unit, void *cdp)
725 {
726         call_desc_t *cd = (call_desc_t *)cdp;
727         struct rbch_softc *sc = &rbch_softc[unit];
728
729         CRIT_VAR;
730         
731         if(cd != sc->sc_cd)
732         {
733                 NDBGL4(L4_RBCHDBG, "rbch%d: channel %d not active",
734                         cd->driver_unit, cd->channelid);
735                 return;
736         }
737
738         CRIT_BEG;
739         
740         NDBGL4(L4_RBCHDBG, "unit %d, disconnect", unit);
741
742         sc->sc_devstate &= ~ST_CONNECTED;
743
744         sc->sc_cd = NULL;
745         
746 #if I4BRBCHACCT
747         i4b_l4_accounting(BDRV_RBCH, unit, ACCT_FINAL,
748                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
749         callout_stop(&sc->sc_timeout);
750 #endif          
751         CRIT_END;
752 }
753         
754 /*---------------------------------------------------------------------------*
755  *      feedback from daemon in case of dial problems
756  *---------------------------------------------------------------------------*/
757 static void
758 rbch_dialresponse(int unit, int status, cause_t cause)
759 {
760 }
761         
762 /*---------------------------------------------------------------------------*
763  *      interface up/down
764  *---------------------------------------------------------------------------*/
765 static void
766 rbch_updown(int unit, int updown)
767 {
768 }
769         
770 /*---------------------------------------------------------------------------*
771  *      this routine is called from the HSCX interrupt handler
772  *      when a new frame (mbuf) has been received and is to be put on
773  *      the rx queue.
774  *---------------------------------------------------------------------------*/
775 static void
776 rbch_rx_data_rdy(int unit)
777 {
778         if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
779         {
780                 struct mbuf *m;
781                 
782                 if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
783                         return;
784
785                 m->m_pkthdr.len = m->m_len;
786
787                 if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq)))
788                 {
789                         NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
790                         m_freem(m);
791                 }                       
792                 else
793                 {
794                         IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m);
795                 }
796         }
797
798         if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA)
799         {
800                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
801                 rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
802                 wakeup((caddr_t) &isdn_linktab[unit]->rx_queue);
803         }
804         else
805         {
806                 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
807         }
808         KNOTE(&rbch_softc[unit].kqp.ki_note, 0);
809 }
810
811 /*---------------------------------------------------------------------------*
812  *      this routine is called from the HSCX interrupt handler
813  *      when the last frame has been sent out and there is no
814  *      further frame (mbuf) in the tx queue.
815  *---------------------------------------------------------------------------*/
816 static void
817 rbch_tx_queue_empty(int unit)
818 {
819         if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY)
820         {
821                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
822                 rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
823                 wakeup((caddr_t) &isdn_linktab[unit]->tx_queue);
824         }
825         else
826         {
827                 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
828         }
829         KNOTE(&rbch_softc[unit].kqp.ki_note, 0);
830 }
831
832 /*---------------------------------------------------------------------------*
833  *      this routine is called from the HSCX interrupt handler
834  *      each time a packet is received or transmitted
835  *---------------------------------------------------------------------------*/
836 static void
837 rbch_activity(int unit, int rxtx)
838 {
839         if (rbch_softc[unit].sc_cd)
840                 rbch_softc[unit].sc_cd->last_active_time = SECOND;
841         KNOTE(&rbch_softc[unit].kqp.ki_note, 0);
842 }
843
844 /*---------------------------------------------------------------------------*
845  *      clear an hdlc rx queue for a rbch unit
846  *---------------------------------------------------------------------------*/
847 static void
848 rbch_clrq(int unit)
849 {
850         CRIT_VAR;
851
852         CRIT_BEG;
853         IF_DRAIN(&rbch_softc[unit].sc_hdlcq);
854         CRIT_END;
855 }
856                                 
857 /*---------------------------------------------------------------------------*
858  *      return this drivers linktab address
859  *---------------------------------------------------------------------------*/
860 drvr_link_t *
861 rbch_ret_linktab(int unit)
862 {
863         rbch_init_linktab(unit);
864         return(&rbch_drvr_linktab[unit]);
865 }
866
867 /*---------------------------------------------------------------------------*
868  *      setup the isdn_linktab for this driver
869  *---------------------------------------------------------------------------*/
870 void
871 rbch_set_linktab(int unit, isdn_link_t *ilt)
872 {
873         isdn_linktab[unit] = ilt;
874 }
875
876 /*---------------------------------------------------------------------------*
877  *      initialize this drivers linktab
878  *---------------------------------------------------------------------------*/
879 static void
880 rbch_init_linktab(int unit)
881 {
882         rbch_drvr_linktab[unit].unit = unit;
883         rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy;
884         rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty;
885         rbch_drvr_linktab[unit].bch_activity = rbch_activity;   
886         rbch_drvr_linktab[unit].line_connected = rbch_connect;
887         rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect;
888         rbch_drvr_linktab[unit].dial_response = rbch_dialresponse;
889         rbch_drvr_linktab[unit].updown_ind = rbch_updown;       
890 }
891
892 /*===========================================================================*/
893
894 #endif /* NI4BRBCH > 0 */