Merge from vendor branch OPENSSL:
[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  * $DragonFly: src/sys/net/i4b/driver/i4b_rbch.c,v 1.17 2005/06/15 11:56:03 joerg Exp $
32  *
33  *      last edit-date: [Sat Aug 11 18:06:57 2001]
34  *
35  *---------------------------------------------------------------------------*/
36
37 #include "use_i4brbch.h"
38
39 #if NI4BRBCH > 0
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43
44 #include <sys/conf.h>
45 #include <sys/uio.h>
46 #include <sys/kernel.h>
47 #include <sys/mbuf.h>
48 #include <sys/socket.h>
49 #include <net/if.h>
50 #include <sys/tty.h>
51 #include <sys/thread2.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/ioccom.h>
63 #include <sys/poll.h>
64 #include <sys/filio.h>
65
66 static drvr_link_t rbch_drvr_linktab[NI4BRBCH];
67 static isdn_link_t *isdn_linktab[NI4BRBCH];
68
69 #define I4BRBCHACCT             1       /* enable accounting messages */
70 #define I4BRBCHACCTINTVL        2       /* accounting msg interval in secs */
71
72 static struct rbch_softc {
73
74         int sc_unit;                    /* unit number          */
75
76         int sc_devstate;                /* state of driver      */
77 #define ST_IDLE         0x00
78 #define ST_CONNECTED    0x01
79 #define ST_ISOPEN       0x02
80 #define ST_RDWAITDATA   0x04
81 #define ST_WRWAITEMPTY  0x08
82 #define ST_NOBLOCK      0x10
83
84         int sc_bprot;                   /* B-ch protocol used   */
85
86         call_desc_t *sc_cd;             /* Call Descriptor */
87
88         struct termios it_in;
89
90         struct ifqueue sc_hdlcq;        /* hdlc read queue      */
91 #define I4BRBCHMAXQLEN  10
92
93         struct selinfo selp;            /* select / poll        */
94
95 #if I4BRBCHACCT
96         struct callout  sc_timeout;
97
98         int             sc_iinb;        /* isdn driver # of inbytes     */
99         int             sc_ioutb;       /* isdn driver # of outbytes    */
100         int             sc_linb;        /* last # of bytes rx'd         */
101         int             sc_loutb;       /* last # of bytes tx'd         */
102         int             sc_fn;          /* flag, first null acct        */
103 #endif  
104 } rbch_softc[NI4BRBCH];
105
106 static void rbch_rx_data_rdy(int unit);
107 static void rbch_tx_queue_empty(int unit);
108 static void rbch_connect(int unit, void *cdp);
109 static void rbch_disconnect(int unit, void *cdp);
110 static void rbch_init_linktab(int unit);
111 static void rbch_clrq(int unit);
112
113 #define PDEVSTATIC      static
114 #define IOCTL_CMD_T     u_long
115
116 PDEVSTATIC d_open_t i4brbchopen;
117 PDEVSTATIC d_close_t i4brbchclose;
118 PDEVSTATIC d_read_t i4brbchread;
119 PDEVSTATIC d_read_t i4brbchwrite;
120 PDEVSTATIC d_ioctl_t i4brbchioctl;
121
122 PDEVSTATIC d_poll_t i4brbchpoll;
123 #define POLLFIELD       i4brbchpoll
124
125 #define CDEV_MAJOR 57
126
127 static struct cdevsw i4brbch_cdevsw = {
128         /* name */      "i4brbch",
129         /* maj */       CDEV_MAJOR,
130         /* flags */     0,
131         /* port */      NULL,
132         /* clone */     NULL,
133
134         /* open */      i4brbchopen,
135         /* close */     i4brbchclose,
136         /* read */      i4brbchread,
137         /* write */     i4brbchwrite,
138         /* ioctl */     i4brbchioctl,
139         /* poll */      POLLFIELD,
140         /* mmap */      nommap,
141         /* strategy */  nostrategy,
142         /* dump */      nodump,
143         /* psize */     nopsize
144 };
145
146 static void i4brbchattach(void *);
147 PSEUDO_SET(i4brbchattach, i4b_rbch);
148
149 /*===========================================================================*
150  *                      DEVICE DRIVER ROUTINES
151  *===========================================================================*/
152
153 /*---------------------------------------------------------------------------*
154  *      initialization at kernel load time
155  *---------------------------------------------------------------------------*/
156 static void
157 i4brbchinit(void *unused)
158 {
159         cdevsw_add(&i4brbch_cdevsw, 0, 0);
160 }
161
162 SYSINIT(i4brbchdev, SI_SUB_DRIVERS,
163         SI_ORDER_MIDDLE+CDEV_MAJOR, &i4brbchinit, NULL);
164
165 /*---------------------------------------------------------------------------*
166  *      interface attach routine
167  *---------------------------------------------------------------------------*/
168 PDEVSTATIC void
169 i4brbchattach(void *dummy)
170 {
171         int i;
172
173 #ifndef HACK_NO_PSEUDO_ATTACH_MSG
174         printf("i4brbch: %d raw B channel access device(s) attached\n", NI4BRBCH);
175 #endif
176         
177         for(i=0; i < NI4BRBCH; i++)
178         {
179                 make_dev(&i4brbch_cdevsw, i,
180                         UID_ROOT, GID_WHEEL, 0600, "i4brbch%d", i);
181
182 #if I4BRBCHACCT
183                 callout_init(&rbch_softc[i].sc_timeout);
184                 rbch_softc[i].sc_fn = 1;
185 #endif
186                 rbch_softc[i].sc_unit = i;
187                 rbch_softc[i].sc_devstate = ST_IDLE;
188                 rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
189                 rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
190                 termioschars(&rbch_softc[i].it_in);
191                 rbch_init_linktab(i);
192         }
193 }
194
195 /*---------------------------------------------------------------------------*
196  *      open rbch device
197  *---------------------------------------------------------------------------*/
198 PDEVSTATIC int
199 i4brbchopen(dev_t dev, int flag, int fmt, struct thread *td)
200 {
201         int unit = minor(dev);
202         
203         if(unit >= NI4BRBCH)
204                 return(ENXIO);
205
206         if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
207                 return(EBUSY);
208
209 #if 0
210         rbch_clrq(unit);
211 #endif
212         
213         rbch_softc[unit].sc_devstate |= ST_ISOPEN;              
214
215         NDBGL4(L4_RBCHDBG, "unit %d, open", unit);      
216
217         return(0);
218 }
219
220 /*---------------------------------------------------------------------------*
221  *      close rbch device
222  *---------------------------------------------------------------------------*/
223 PDEVSTATIC int
224 i4brbchclose(dev_t dev, int flag, int fmt, struct thread *td)
225 {
226         int unit = minor(dev);
227         struct rbch_softc *sc = &rbch_softc[unit];
228         
229         if(sc->sc_devstate & ST_CONNECTED)
230                 i4b_l4_drvrdisc(BDRV_RBCH, unit);
231
232         sc->sc_devstate &= ~ST_ISOPEN;          
233
234         rbch_clrq(unit);
235         
236         NDBGL4(L4_RBCHDBG, "unit %d, closed", unit);
237         
238         return(0);
239 }
240
241 /*---------------------------------------------------------------------------*
242  *      read from rbch device
243  *---------------------------------------------------------------------------*/
244 PDEVSTATIC int
245 i4brbchread(dev_t dev, struct uio *uio, int ioflag)
246 {
247         struct mbuf *m;
248         int error = 0;
249         int unit = minor(dev);
250         struct ifqueue *iqp;
251         struct rbch_softc *sc = &rbch_softc[unit];
252
253         CRIT_VAR;
254         
255         NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
256         
257         CRIT_BEG;
258         if(!(sc->sc_devstate & ST_ISOPEN))
259         {
260                 CRIT_END;
261                 NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
262                 return(EIO);
263         }
264
265         if((sc->sc_devstate & ST_NOBLOCK))
266         {
267                 if(!(sc->sc_devstate & ST_CONNECTED)) {
268                         CRIT_END;
269                         return(EWOULDBLOCK);
270                 }
271
272                 if(sc->sc_bprot == BPROT_RHDLC)
273                         iqp = &sc->sc_hdlcq;
274                 else
275                         iqp = isdn_linktab[unit]->rx_queue;     
276
277                 if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
278                         CRIT_END;
279                         return(EWOULDBLOCK);
280         }
281         }
282         else
283         {
284                 while(!(sc->sc_devstate & ST_CONNECTED))
285                 {
286                         NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
287                 
288                         if((error = tsleep((caddr_t) &rbch_softc[unit],
289                                                PCATCH, "rrrbch", 0 )) != 0)
290                         {
291                                 CRIT_END;
292                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
293                                 return(error);
294                         }
295                 }
296
297                 if(sc->sc_bprot == BPROT_RHDLC)
298                         iqp = &sc->sc_hdlcq;
299                 else
300                         iqp = isdn_linktab[unit]->rx_queue;     
301
302                 while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
303                 {
304                         sc->sc_devstate |= ST_RDWAITDATA;
305                 
306                         NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
307                 
308                         if((error = tsleep((caddr_t) &isdn_linktab[unit]->rx_queue,
309                                            PCATCH, "rrbch", 0 )) != 0)
310                         {
311                                 CRIT_END;
312                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
313                                 sc->sc_devstate &= ~ST_RDWAITDATA;
314                                 return(error);
315                         }
316                 }
317         }
318
319         IF_DEQUEUE(iqp, m);
320
321         NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
322         
323         if(m && m->m_len)
324         {
325                 error = uiomove(m->m_data, m->m_len, uio);
326         }
327         else
328         {
329                 NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
330                 error = EIO;
331         }
332                 
333         if(m)
334                 i4b_Bfreembuf(m);
335
336         CRIT_END;
337
338         return(error);
339 }
340
341 /*---------------------------------------------------------------------------*
342  *      write to rbch device
343  *---------------------------------------------------------------------------*/
344 PDEVSTATIC int
345 i4brbchwrite(dev_t dev, struct uio * uio, int ioflag)
346 {
347         struct mbuf *m;
348         int error = 0;
349         int unit = minor(dev);
350         struct rbch_softc *sc = &rbch_softc[unit];
351
352         CRIT_VAR;
353         
354         NDBGL4(L4_RBCHDBG, "unit %d, write", unit);     
355
356         CRIT_BEG;
357         if(!(sc->sc_devstate & ST_ISOPEN))
358         {
359                 NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
360                 CRIT_END;
361                 return(EIO);
362         }
363
364         if((sc->sc_devstate & ST_NOBLOCK))
365         {
366                 if(!(sc->sc_devstate & ST_CONNECTED)) {
367                         CRIT_END;
368                         return(EWOULDBLOCK);
369                 }
370                 if(IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
371                         CRIT_END;
372                         return(EWOULDBLOCK);
373         }
374         }
375         else
376         {
377                 while(!(sc->sc_devstate & ST_CONNECTED))
378                 {
379                         NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
380                 
381                         error = tsleep((caddr_t) &rbch_softc[unit],
382                                                    PCATCH, "wrrbch", 0 );
383                         if(error == ERESTART) {
384                                 CRIT_END;
385                                 return (ERESTART);
386                         }
387                         else if(error == EINTR)
388                         {
389                                 CRIT_END;
390                                 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
391                                 return(EINTR);
392                         }
393                         else if(error)
394                         {
395                                 CRIT_END;
396                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
397                                 return(error);
398                         }
399                         tsleep((caddr_t) &rbch_softc[unit], PCATCH, "xrbch", (hz*1));
400                 }
401
402                 while(IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
403                 {
404                         sc->sc_devstate |= ST_WRWAITEMPTY;
405
406                         NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
407                 
408                         if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue,
409                                             PCATCH, "wrbch", 0)) != 0) {
410                                 sc->sc_devstate &= ~ST_WRWAITEMPTY;
411                                 if(error == ERESTART)
412                                 {
413                                         CRIT_END;
414                                         return(ERESTART);
415                                 }
416                                 else if(error == EINTR)
417                                 {
418                                         CRIT_END;
419                                         NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
420                                         return(error);
421                                 }
422                                 else if(error)
423                                 {
424                                         CRIT_END;
425                                         NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
426                                         return(error);
427                                 }
428                         }
429                 }
430         }
431
432         if(!(sc->sc_devstate & ST_ISOPEN))
433         {
434                 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
435                 CRIT_END;
436                 return(EIO);
437         }
438
439         if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
440         {
441                 m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
442
443                 NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
444                 
445                 error = uiomove(m->m_data, m->m_len, uio);
446
447                 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
448                         m_freem(m);
449                 else
450                         IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
451                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
452         }
453
454         CRIT_END;
455         
456         return(error);
457 }
458
459 /*---------------------------------------------------------------------------*
460  *      rbch device ioctl handlibg
461  *---------------------------------------------------------------------------*/
462 PDEVSTATIC int
463 i4brbchioctl(dev_t dev, IOCTL_CMD_T cmd, caddr_t data, int flag, struct thread *td)
464 {
465         int error = 0;
466         int unit = minor(dev);
467         struct rbch_softc *sc = &rbch_softc[unit];
468         
469         switch(cmd)
470         {
471                 case FIOASYNC:  /* Set async mode */
472                         if (*(int *)data)
473                         {
474                                 NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
475                         }
476                         else
477                         {
478                                 NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
479                         }
480                         break;
481
482                 case FIONBIO:
483                         if (*(int *)data)
484                         {
485                                 NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit);
486                                 sc->sc_devstate |= ST_NOBLOCK;
487                         }
488                         else
489                         {
490                                 NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit);
491                                 sc->sc_devstate &= ~ST_NOBLOCK;
492                         }
493                         break;
494
495                 case TIOCCDTR:  /* Clear DTR */
496                         if(sc->sc_devstate & ST_CONNECTED)
497                         {
498                                 NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
499                                 i4b_l4_drvrdisc(BDRV_RBCH, unit);
500                         }
501                         break;
502
503                 case I4B_RBCH_DIALOUT:
504                 {
505                         size_t l;
506
507                         for (l = 0; l < TELNO_MAX && ((char *)data)[l]; l++)
508                                 ;
509                         if (l)
510                         {
511                                 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout to %s", unit, (char *)data);
512                                 i4b_l4_dialoutnumber(BDRV_RBCH, unit, l, (char *)data);
513                                 break;
514                         }
515                         /* fall through to SDTR */
516                 }
517
518                 case TIOCSDTR:  /* Set DTR */
519                         NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
520                         i4b_l4_dialout(BDRV_RBCH, unit);
521                         break;
522
523                 case TIOCSETA:  /* Set termios struct */
524                         break;
525
526                 case TIOCGETA:  /* Get termios struct */
527                         *(struct termios *)data = sc->it_in;
528                         break;
529
530                 case TIOCMGET:
531                         *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
532                         if (sc->sc_devstate & ST_CONNECTED)
533                                 *(int *)data |= TIOCM_CD;
534                         break;
535
536                 case I4B_RBCH_VR_REQ:
537                 {
538                         msg_vr_req_t *mvr;
539
540                         mvr = (msg_vr_req_t *)data;
541
542                         mvr->version = VERSION;
543                         mvr->release = REL;
544                         mvr->step = STEP;                       
545                         break;
546                 }
547
548                 default:        /* Unknown stuff */
549                         NDBGL4(L4_RBCHDBG, "unit %d, ioctl, unknown cmd %lx", unit, (u_long)cmd);
550                         error = EINVAL;
551                         break;
552         }
553         return(error);
554 }
555
556 /*---------------------------------------------------------------------------*
557  *      device driver poll
558  *---------------------------------------------------------------------------*/
559 PDEVSTATIC int
560 i4brbchpoll(dev_t dev, int events, struct thread *td)
561 {
562         int revents = 0;        /* Events we found */
563         int unit = minor(dev);
564         struct rbch_softc *sc = &rbch_softc[unit];
565         
566         /* We can't check for anything but IN or OUT */
567         crit_enter();
568
569         if(!(sc->sc_devstate & ST_ISOPEN))
570         {
571                 crit_exit();
572                 return(POLLNVAL);
573         }
574
575         /*
576          * Writes are OK if we are connected and the
577          * transmit queue can take them
578          */
579          
580         if((events & (POLLOUT|POLLWRNORM)) &&
581            (sc->sc_devstate & ST_CONNECTED) &&
582            !IF_QFULL(isdn_linktab[unit]->tx_queue))
583         {
584                 revents |= (events & (POLLOUT|POLLWRNORM));
585         }
586         
587         /* ... while reads are OK if we have any data */
588
589         if((events & (POLLIN|POLLRDNORM)) &&
590            (sc->sc_devstate & ST_CONNECTED))
591         {
592                 struct ifqueue *iqp;
593
594                 if(sc->sc_bprot == BPROT_RHDLC)
595                         iqp = &sc->sc_hdlcq;
596                 else
597                         iqp = isdn_linktab[unit]->rx_queue;     
598
599                 if(!IF_QEMPTY(iqp))
600                         revents |= (events & (POLLIN|POLLRDNORM));
601         }
602                 
603         if(revents == 0)
604                 selrecord(td, &sc->selp);
605
606         crit_exit();
607         return(revents);
608 }
609
610 #if I4BRBCHACCT
611 /*---------------------------------------------------------------------------*
612  *      watchdog routine
613  *---------------------------------------------------------------------------*/
614 static void
615 rbch_timeout(struct rbch_softc *sc)
616 {
617         bchan_statistics_t bs;
618         int unit = sc->sc_unit;
619
620         /* get # of bytes in and out from the HSCX driver */ 
621         
622         (*isdn_linktab[unit]->bch_stat)
623                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
624
625         sc->sc_ioutb += bs.outbytes;
626         sc->sc_iinb += bs.inbytes;
627         
628         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
629         {
630                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
631                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
632
633                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
634                         sc->sc_fn = 0;
635                 else
636                         sc->sc_fn = 1;
637                         
638                 sc->sc_linb = sc->sc_iinb;
639                 sc->sc_loutb = sc->sc_ioutb;
640
641                 i4b_l4_accounting(BDRV_RBCH, unit, ACCT_DURING,
642                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
643         }
644         callout_reset(&sc->sc_timeout, I4BRBCHACCTINTVL * hz,
645                         (void *)rbch_timeout, sc);
646 }
647 #endif /* I4BRBCHACCT */
648
649 /*===========================================================================*
650  *                      ISDN INTERFACE ROUTINES
651  *===========================================================================*/
652
653 /*---------------------------------------------------------------------------*
654  *      this routine is called from L4 handler at connect time
655  *---------------------------------------------------------------------------*/
656 static void
657 rbch_connect(int unit, void *cdp)
658 {
659         call_desc_t *cd = (call_desc_t *)cdp;
660         struct rbch_softc *sc = &rbch_softc[unit];
661
662         sc->sc_bprot = cd->bprot;
663
664 #if I4BRBCHACCT
665         if(sc->sc_bprot == BPROT_RHDLC)
666         {       
667                 sc->sc_iinb = 0;
668                 sc->sc_ioutb = 0;
669                 sc->sc_linb = 0;
670                 sc->sc_loutb = 0;
671
672                 callout_reset(&sc->sc_timeout, I4BRBCHACCTINTVL * hz,
673                                 (void *)rbch_timeout, sc);
674         }
675 #endif          
676         if(!(sc->sc_devstate & ST_CONNECTED))
677         {
678                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
679                 sc->sc_devstate |= ST_CONNECTED;
680                 sc->sc_cd = cdp;
681                 wakeup((caddr_t)sc);
682         }
683 }
684
685 /*---------------------------------------------------------------------------*
686  *      this routine is called from L4 handler at disconnect time
687  *---------------------------------------------------------------------------*/
688 static void
689 rbch_disconnect(int unit, void *cdp)
690 {
691         call_desc_t *cd = (call_desc_t *)cdp;
692         struct rbch_softc *sc = &rbch_softc[unit];
693
694         CRIT_VAR;
695         
696         if(cd != sc->sc_cd)
697         {
698                 NDBGL4(L4_RBCHDBG, "rbch%d: channel %d not active",
699                         cd->driver_unit, cd->channelid);
700                 return;
701         }
702
703         CRIT_BEG;
704         
705         NDBGL4(L4_RBCHDBG, "unit %d, disconnect", unit);
706
707         sc->sc_devstate &= ~ST_CONNECTED;
708
709         sc->sc_cd = NULL;
710         
711 #if I4BRBCHACCT
712         i4b_l4_accounting(BDRV_RBCH, unit, ACCT_FINAL,
713                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
714         callout_stop(&sc->sc_timeout);
715 #endif          
716         CRIT_END;
717 }
718         
719 /*---------------------------------------------------------------------------*
720  *      feedback from daemon in case of dial problems
721  *---------------------------------------------------------------------------*/
722 static void
723 rbch_dialresponse(int unit, int status, cause_t cause)
724 {
725 }
726         
727 /*---------------------------------------------------------------------------*
728  *      interface up/down
729  *---------------------------------------------------------------------------*/
730 static void
731 rbch_updown(int unit, int updown)
732 {
733 }
734         
735 /*---------------------------------------------------------------------------*
736  *      this routine is called from the HSCX interrupt handler
737  *      when a new frame (mbuf) has been received and is to be put on
738  *      the rx queue.
739  *---------------------------------------------------------------------------*/
740 static void
741 rbch_rx_data_rdy(int unit)
742 {
743         if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
744         {
745                 struct mbuf *m;
746                 
747                 if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
748                         return;
749
750                 m->m_pkthdr.len = m->m_len;
751
752                 if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq)))
753                 {
754                         NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
755                         m_freem(m);
756                 }                       
757                 else
758                 {
759                         IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m);
760                 }
761         }
762
763         if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA)
764         {
765                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
766                 rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
767                 wakeup((caddr_t) &isdn_linktab[unit]->rx_queue);
768         }
769         else
770         {
771                 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
772         }
773         selwakeup(&rbch_softc[unit].selp);
774 }
775
776 /*---------------------------------------------------------------------------*
777  *      this routine is called from the HSCX interrupt handler
778  *      when the last frame has been sent out and there is no
779  *      further frame (mbuf) in the tx queue.
780  *---------------------------------------------------------------------------*/
781 static void
782 rbch_tx_queue_empty(int unit)
783 {
784         if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY)
785         {
786                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
787                 rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
788                 wakeup((caddr_t) &isdn_linktab[unit]->tx_queue);
789         }
790         else
791         {
792                 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
793         }
794         selwakeup(&rbch_softc[unit].selp);
795 }
796
797 /*---------------------------------------------------------------------------*
798  *      this routine is called from the HSCX interrupt handler
799  *      each time a packet is received or transmitted
800  *---------------------------------------------------------------------------*/
801 static void
802 rbch_activity(int unit, int rxtx)
803 {
804         if (rbch_softc[unit].sc_cd)
805                 rbch_softc[unit].sc_cd->last_active_time = SECOND;
806         selwakeup(&rbch_softc[unit].selp);
807 }
808
809 /*---------------------------------------------------------------------------*
810  *      clear an hdlc rx queue for a rbch unit
811  *---------------------------------------------------------------------------*/
812 static void
813 rbch_clrq(int unit)
814 {
815         CRIT_VAR;
816
817         CRIT_BEG;
818         IF_DRAIN(&rbch_softc[unit].sc_hdlcq);
819         CRIT_END;
820 }
821                                 
822 /*---------------------------------------------------------------------------*
823  *      return this drivers linktab address
824  *---------------------------------------------------------------------------*/
825 drvr_link_t *
826 rbch_ret_linktab(int unit)
827 {
828         rbch_init_linktab(unit);
829         return(&rbch_drvr_linktab[unit]);
830 }
831
832 /*---------------------------------------------------------------------------*
833  *      setup the isdn_linktab for this driver
834  *---------------------------------------------------------------------------*/
835 void
836 rbch_set_linktab(int unit, isdn_link_t *ilt)
837 {
838         isdn_linktab[unit] = ilt;
839 }
840
841 /*---------------------------------------------------------------------------*
842  *      initialize this drivers linktab
843  *---------------------------------------------------------------------------*/
844 static void
845 rbch_init_linktab(int unit)
846 {
847         rbch_drvr_linktab[unit].unit = unit;
848         rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy;
849         rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty;
850         rbch_drvr_linktab[unit].bch_activity = rbch_activity;   
851         rbch_drvr_linktab[unit].line_connected = rbch_connect;
852         rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect;
853         rbch_drvr_linktab[unit].dial_response = rbch_dialresponse;
854         rbch_drvr_linktab[unit].updown_ind = rbch_updown;       
855 }
856
857 /*===========================================================================*/
858
859 #endif /* NI4BRBCH > 0 */