Device layer rollup commit.
[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.11 2004/05/19 22:52:59 dillon 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
52 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
53 #include <sys/callout.h>
54 #endif
55
56 #if defined (__NetBSD__) || defined (__OpenBSD__)
57 extern cc_t ttydefchars;
58 #define termioschars(t) memcpy((t)->c_cc, &ttydefchars, sizeof((t)->c_cc))
59 #endif
60
61 #if defined(__DragonFly__) || defined(__FreeBSD__)
62
63 #ifdef DEVFS
64 #include <sys/devfsext.h>
65 #endif
66
67 #endif /* __FreeBSD__ */
68
69 #ifdef __NetBSD__
70 #include <sys/filio.h>
71 #endif
72
73 #if defined(__DragonFly__) || defined(__FreeBSD__)
74 #include <net/i4b/include/machine/i4b_ioctl.h>
75 #include <net/i4b/include/machine/i4b_rbch_ioctl.h>
76 #include <net/i4b/include/machine/i4b_debug.h>
77 #else
78 #include <i4b/i4b_ioctl.h>
79 #include <i4b/i4b_rbch_ioctl.h>
80 #include <i4b/i4b_debug.h>
81 #endif
82
83 #include "../include/i4b_global.h"
84 #include "../include/i4b_mbuf.h"
85 #include "../include/i4b_l3l4.h"
86 #include "../layer4/i4b_l4.h"
87
88 #ifdef __bsdi__
89 #include <sys/device.h>
90 #endif
91
92 #ifdef OS_USES_POLL
93 #include <sys/ioccom.h>
94 #include <sys/poll.h>
95 #else
96 #include <sys/fcntl.h>
97 #include <sys/ioctl.h>
98 #endif
99
100 #if defined(__DragonFly__) || defined(__FreeBSD__)
101 #include <sys/filio.h>
102 #endif
103
104 static drvr_link_t rbch_drvr_linktab[NI4BRBCH];
105 static isdn_link_t *isdn_linktab[NI4BRBCH];
106
107 #define I4BRBCHACCT             1       /* enable accounting messages */
108 #define I4BRBCHACCTINTVL        2       /* accounting msg interval in secs */
109
110 static struct rbch_softc {
111
112         int sc_unit;                    /* unit number          */
113
114         int sc_devstate;                /* state of driver      */
115 #define ST_IDLE         0x00
116 #define ST_CONNECTED    0x01
117 #define ST_ISOPEN       0x02
118 #define ST_RDWAITDATA   0x04
119 #define ST_WRWAITEMPTY  0x08
120 #define ST_NOBLOCK      0x10
121
122         int sc_bprot;                   /* B-ch protocol used   */
123
124         call_desc_t *sc_cd;             /* Call Descriptor */
125
126         struct termios it_in;
127
128         struct ifqueue sc_hdlcq;        /* hdlc read queue      */
129 #define I4BRBCHMAXQLEN  10
130
131         struct selinfo selp;            /* select / poll        */
132
133 #if I4BRBCHACCT
134 #if defined(__DragonFly__) || defined(__FreeBSD__)
135         struct callout_handle sc_callout;
136 #endif  
137 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
138         struct callout  sc_callout;
139 #endif
140
141         int             sc_iinb;        /* isdn driver # of inbytes     */
142         int             sc_ioutb;       /* isdn driver # of outbytes    */
143         int             sc_linb;        /* last # of bytes rx'd         */
144         int             sc_loutb;       /* last # of bytes tx'd         */
145         int             sc_fn;          /* flag, first null acct        */
146 #endif  
147 } rbch_softc[NI4BRBCH];
148
149 static void rbch_rx_data_rdy(int unit);
150 static void rbch_tx_queue_empty(int unit);
151 static void rbch_connect(int unit, void *cdp);
152 static void rbch_disconnect(int unit, void *cdp);
153 static void rbch_init_linktab(int unit);
154 static void rbch_clrq(int unit);
155
156 #if !defined(__DragonFly__) && !defined(__FreeBSD__)
157 #define PDEVSTATIC      /* - not static - */
158 #define IOCTL_CMD_T     u_long
159 void i4brbchattach (void);
160 int i4brbchopen (dev_t dev, int flag, int fmt, struct proc *p);
161 int i4brbchclose (dev_t dev, int flag, int fmt, struct proc *p);
162 int i4brbchread (dev_t dev, struct uio *uio, int ioflag);
163 int i4brbchwrite (dev_t dev, struct uio *uio, int ioflag);
164 int i4brbchioctl (dev_t dev, IOCTL_CMD_T cmd, caddr_t arg, int flag, struct proc* pr);
165 #ifdef OS_USES_POLL
166 int i4brbchpoll (dev_t dev, int events, struct proc *p);
167 #else
168 PDEVSTATIC int i4brbchselect (dev_t dev, int rw, struct proc *p);
169 #endif
170 #endif
171
172 #if defined(__DragonFly__) || (BSD > 199306 && defined(__FreeBSD__))
173 #define PDEVSTATIC      static
174 #define IOCTL_CMD_T     u_long
175
176 PDEVSTATIC d_open_t i4brbchopen;
177 PDEVSTATIC d_close_t i4brbchclose;
178 PDEVSTATIC d_read_t i4brbchread;
179 PDEVSTATIC d_read_t i4brbchwrite;
180 PDEVSTATIC d_ioctl_t i4brbchioctl;
181
182 #ifdef OS_USES_POLL
183 PDEVSTATIC d_poll_t i4brbchpoll;
184 #define POLLFIELD       i4brbchpoll
185 #else
186 PDEVSTATIC d_select_t i4brbchselect;
187 #define POLLFIELD       i4brbchselect
188 #endif
189
190 #define CDEV_MAJOR 57
191
192 static struct cdevsw i4brbch_cdevsw = {
193         /* name */      "i4brbch",
194         /* maj */       CDEV_MAJOR,
195         /* flags */     0,
196         /* port */      NULL,
197         /* clone */     NULL,
198
199         /* open */      i4brbchopen,
200         /* close */     i4brbchclose,
201         /* read */      i4brbchread,
202         /* write */     i4brbchwrite,
203         /* ioctl */     i4brbchioctl,
204         /* poll */      POLLFIELD,
205         /* mmap */      nommap,
206         /* strategy */  nostrategy,
207         /* dump */      nodump,
208         /* psize */     nopsize
209 };
210
211 static void i4brbchattach(void *);
212 PSEUDO_SET(i4brbchattach, i4b_rbch);
213
214 /*===========================================================================*
215  *                      DEVICE DRIVER ROUTINES
216  *===========================================================================*/
217
218 /*---------------------------------------------------------------------------*
219  *      initialization at kernel load time
220  *---------------------------------------------------------------------------*/
221 static void
222 i4brbchinit(void *unused)
223 {
224         cdevsw_add(&i4brbch_cdevsw, 0, 0);
225 }
226
227 SYSINIT(i4brbchdev, SI_SUB_DRIVERS,
228         SI_ORDER_MIDDLE+CDEV_MAJOR, &i4brbchinit, NULL);
229
230 #endif /* BSD > 199306 && defined(__FreeBSD__) */
231
232 #ifdef __bsdi__
233 int i4brbchmatch(struct device *parent, struct cfdata *cf, void *aux);
234 void dummy_i4brbchattach(struct device*, struct device *, void *);
235
236 #define CDEV_MAJOR 61
237
238 static struct cfdriver i4brbchcd =
239         { NULL, "i4brbch", i4brbchmatch, dummy_i4brbchattach, DV_DULL,
240           sizeof(struct cfdriver) };
241 struct devsw i4brbchsw = 
242         { &i4brbchcd,
243           i4brbchopen,  i4brbchclose,   i4brbchread,    i4brbchwrite,
244           i4brbchioctl, seltrue,        nommap,         nostrat,
245           nodump,       nopsize,        0,              nostop
246 };
247
248 int
249 i4brbchmatch(struct device *parent, struct cfdata *cf, void *aux)
250 {
251         printf("i4brbchmatch: aux=0x%x\n", aux);
252         return 1;
253 }
254 void
255 dummy_i4brbchattach(struct device *parent, struct device *self, void *aux)
256 {
257         printf("dummy_i4brbchattach: aux=0x%x\n", aux);
258 }
259 #endif /* __bsdi__ */
260
261 /*---------------------------------------------------------------------------*
262  *      interface attach routine
263  *---------------------------------------------------------------------------*/
264 PDEVSTATIC void
265 #if defined(__DragonFly__) || defined(__FreeBSD__)
266 i4brbchattach(void *dummy)
267 #else
268 i4brbchattach()
269 #endif
270 {
271         int i;
272
273 #ifndef HACK_NO_PSEUDO_ATTACH_MSG
274         printf("i4brbch: %d raw B channel access device(s) attached\n", NI4BRBCH);
275 #endif
276         
277         for(i=0; i < NI4BRBCH; i++)
278         {
279 #if defined(__DragonFly__) || defined(__FreeBSD__)
280                 make_dev(&i4brbch_cdevsw, i,
281                         UID_ROOT, GID_WHEEL, 0600, "i4brbch%d", i);
282 #endif
283
284 #if I4BRBCHACCT
285 #if defined(__DragonFly__) || defined(__FreeBSD__)
286                 callout_handle_init(&rbch_softc[i].sc_callout);
287 #endif
288 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
289                 callout_init(&rbch_softc[i].sc_callout);
290 #endif
291                 rbch_softc[i].sc_fn = 1;
292 #endif
293                 rbch_softc[i].sc_unit = i;
294                 rbch_softc[i].sc_devstate = ST_IDLE;
295                 rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
296 #if defined(__FreeBSD__) && __FreeBSD__ > 4
297                 mtx_init(&rbch_softc[i].sc_hdlcq.ifq_mtx, "i4b_rbch", MTX_DEF);
298 #endif          
299                 rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
300                 termioschars(&rbch_softc[i].it_in);
301                 rbch_init_linktab(i);
302         }
303 }
304
305 /*---------------------------------------------------------------------------*
306  *      open rbch device
307  *---------------------------------------------------------------------------*/
308 PDEVSTATIC int
309 i4brbchopen(dev_t dev, int flag, int fmt, struct thread *td)
310 {
311         int unit = minor(dev);
312         
313         if(unit >= NI4BRBCH)
314                 return(ENXIO);
315
316         if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
317                 return(EBUSY);
318
319 #if 0
320         rbch_clrq(unit);
321 #endif
322         
323         rbch_softc[unit].sc_devstate |= ST_ISOPEN;              
324
325         NDBGL4(L4_RBCHDBG, "unit %d, open", unit);      
326
327         return(0);
328 }
329
330 /*---------------------------------------------------------------------------*
331  *      close rbch device
332  *---------------------------------------------------------------------------*/
333 PDEVSTATIC int
334 i4brbchclose(dev_t dev, int flag, int fmt, struct thread *td)
335 {
336         int unit = minor(dev);
337         struct rbch_softc *sc = &rbch_softc[unit];
338         
339         if(sc->sc_devstate & ST_CONNECTED)
340                 i4b_l4_drvrdisc(BDRV_RBCH, unit);
341
342         sc->sc_devstate &= ~ST_ISOPEN;          
343
344         rbch_clrq(unit);
345         
346         NDBGL4(L4_RBCHDBG, "unit %d, closed", unit);
347         
348         return(0);
349 }
350
351 /*---------------------------------------------------------------------------*
352  *      read from rbch device
353  *---------------------------------------------------------------------------*/
354 PDEVSTATIC int
355 i4brbchread(dev_t dev, struct uio *uio, int ioflag)
356 {
357         struct mbuf *m;
358         int error = 0;
359         int unit = minor(dev);
360         struct ifqueue *iqp;
361         struct rbch_softc *sc = &rbch_softc[unit];
362
363         CRIT_VAR;
364         
365         NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
366         
367         CRIT_BEG;
368         if(!(sc->sc_devstate & ST_ISOPEN))
369         {
370                 CRIT_END;
371                 NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
372                 return(EIO);
373         }
374
375         if((sc->sc_devstate & ST_NOBLOCK))
376         {
377                 if(!(sc->sc_devstate & ST_CONNECTED)) {
378                         CRIT_END;
379                         return(EWOULDBLOCK);
380                 }
381
382                 if(sc->sc_bprot == BPROT_RHDLC)
383                         iqp = &sc->sc_hdlcq;
384                 else
385                         iqp = isdn_linktab[unit]->rx_queue;     
386
387                 if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
388                         CRIT_END;
389                         return(EWOULDBLOCK);
390         }
391         }
392         else
393         {
394                 while(!(sc->sc_devstate & ST_CONNECTED))
395                 {
396                         NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
397                 
398                         if((error = tsleep((caddr_t) &rbch_softc[unit],
399                                                PCATCH, "rrrbch", 0 )) != 0)
400                         {
401                                 CRIT_END;
402                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
403                                 return(error);
404                         }
405                 }
406
407                 if(sc->sc_bprot == BPROT_RHDLC)
408                         iqp = &sc->sc_hdlcq;
409                 else
410                         iqp = isdn_linktab[unit]->rx_queue;     
411
412                 while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
413                 {
414                         sc->sc_devstate |= ST_RDWAITDATA;
415                 
416                         NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
417                 
418                         if((error = tsleep((caddr_t) &isdn_linktab[unit]->rx_queue,
419                                            PCATCH, "rrbch", 0 )) != 0)
420                         {
421                                 CRIT_END;
422                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
423                                 sc->sc_devstate &= ~ST_RDWAITDATA;
424                                 return(error);
425                         }
426                 }
427         }
428
429         IF_DEQUEUE(iqp, m);
430
431         NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
432         
433         if(m && m->m_len)
434         {
435                 error = uiomove(m->m_data, m->m_len, uio);
436         }
437         else
438         {
439                 NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
440                 error = EIO;
441         }
442                 
443         if(m)
444                 i4b_Bfreembuf(m);
445
446         CRIT_END;
447
448         return(error);
449 }
450
451 /*---------------------------------------------------------------------------*
452  *      write to rbch device
453  *---------------------------------------------------------------------------*/
454 PDEVSTATIC int
455 i4brbchwrite(dev_t dev, struct uio * uio, int ioflag)
456 {
457         struct mbuf *m;
458         int error = 0;
459         int unit = minor(dev);
460         struct rbch_softc *sc = &rbch_softc[unit];
461
462         CRIT_VAR;
463         
464         NDBGL4(L4_RBCHDBG, "unit %d, write", unit);     
465
466         CRIT_BEG;
467         if(!(sc->sc_devstate & ST_ISOPEN))
468         {
469                 NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
470                 CRIT_END;
471                 return(EIO);
472         }
473
474         if((sc->sc_devstate & ST_NOBLOCK))
475         {
476                 if(!(sc->sc_devstate & ST_CONNECTED)) {
477                         CRIT_END;
478                         return(EWOULDBLOCK);
479                 }
480                 if(_IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
481                         CRIT_END;
482                         return(EWOULDBLOCK);
483         }
484         }
485         else
486         {
487                 while(!(sc->sc_devstate & ST_CONNECTED))
488                 {
489                         NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
490                 
491                         error = tsleep((caddr_t) &rbch_softc[unit],
492                                                    PCATCH, "wrrbch", 0 );
493                         if(error == ERESTART) {
494                                 CRIT_END;
495                                 return (ERESTART);
496                         }
497                         else if(error == EINTR)
498                         {
499                                 CRIT_END;
500                                 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
501                                 return(EINTR);
502                         }
503                         else if(error)
504                         {
505                                 CRIT_END;
506                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
507                                 return(error);
508                         }
509                         tsleep((caddr_t) &rbch_softc[unit], PCATCH, "xrbch", (hz*1));
510                 }
511
512                 while(_IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
513                 {
514                         sc->sc_devstate |= ST_WRWAITEMPTY;
515
516                         NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
517                 
518                         if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue,
519                                             PCATCH, "wrbch", 0)) != 0) {
520                                 sc->sc_devstate &= ~ST_WRWAITEMPTY;
521                                 if(error == ERESTART)
522                                 {
523                                         CRIT_END;
524                                         return(ERESTART);
525                                 }
526                                 else if(error == EINTR)
527                                 {
528                                         CRIT_END;
529                                         NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
530                                         return(error);
531                                 }
532                                 else if(error)
533                                 {
534                                         CRIT_END;
535                                         NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
536                                         return(error);
537                                 }
538                         }
539                 }
540         }
541
542         if(!(sc->sc_devstate & ST_ISOPEN))
543         {
544                 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
545                 CRIT_END;
546                 return(EIO);
547         }
548
549         if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
550         {
551                 m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
552
553                 NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
554                 
555                 error = uiomove(m->m_data, m->m_len, uio);
556
557 #if defined (__FreeBSD__) && __FreeBSD__ > 4            
558                 (void) IF_HANDOFF(isdn_linktab[unit]->tx_queue, m, NULL);
559 #else
560                 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
561                         m_freem(m);
562                 else
563                         IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
564 #endif
565                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
566         }
567
568         CRIT_END;
569         
570         return(error);
571 }
572
573 /*---------------------------------------------------------------------------*
574  *      rbch device ioctl handlibg
575  *---------------------------------------------------------------------------*/
576 PDEVSTATIC int
577 i4brbchioctl(dev_t dev, IOCTL_CMD_T cmd, caddr_t data, int flag, struct thread *td)
578 {
579         int error = 0;
580         int unit = minor(dev);
581         struct rbch_softc *sc = &rbch_softc[unit];
582         
583         switch(cmd)
584         {
585                 case FIOASYNC:  /* Set async mode */
586                         if (*(int *)data)
587                         {
588                                 NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
589                         }
590                         else
591                         {
592                                 NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
593                         }
594                         break;
595
596                 case FIONBIO:
597                         if (*(int *)data)
598                         {
599                                 NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit);
600                                 sc->sc_devstate |= ST_NOBLOCK;
601                         }
602                         else
603                         {
604                                 NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit);
605                                 sc->sc_devstate &= ~ST_NOBLOCK;
606                         }
607                         break;
608
609                 case TIOCCDTR:  /* Clear DTR */
610                         if(sc->sc_devstate & ST_CONNECTED)
611                         {
612                                 NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
613                                 i4b_l4_drvrdisc(BDRV_RBCH, unit);
614                         }
615                         break;
616
617                 case I4B_RBCH_DIALOUT:
618                 {
619                         size_t l;
620
621                         for (l = 0; l < TELNO_MAX && ((char *)data)[l]; l++)
622                                 ;
623                         if (l)
624                         {
625                                 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout to %s", unit, (char *)data);
626                                 i4b_l4_dialoutnumber(BDRV_RBCH, unit, l, (char *)data);
627                                 break;
628                         }
629                         /* fall through to SDTR */
630                 }
631
632                 case TIOCSDTR:  /* Set DTR */
633                         NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
634                         i4b_l4_dialout(BDRV_RBCH, unit);
635                         break;
636
637                 case TIOCSETA:  /* Set termios struct */
638                         break;
639
640                 case TIOCGETA:  /* Get termios struct */
641                         *(struct termios *)data = sc->it_in;
642                         break;
643
644                 case TIOCMGET:
645                         *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
646                         if (sc->sc_devstate & ST_CONNECTED)
647                                 *(int *)data |= TIOCM_CD;
648                         break;
649
650                 case I4B_RBCH_VR_REQ:
651                 {
652                         msg_vr_req_t *mvr;
653
654                         mvr = (msg_vr_req_t *)data;
655
656                         mvr->version = VERSION;
657                         mvr->release = REL;
658                         mvr->step = STEP;                       
659                         break;
660                 }
661
662                 default:        /* Unknown stuff */
663                         NDBGL4(L4_RBCHDBG, "unit %d, ioctl, unknown cmd %lx", unit, (u_long)cmd);
664                         error = EINVAL;
665                         break;
666         }
667         return(error);
668 }
669
670 #ifdef OS_USES_POLL
671
672 /*---------------------------------------------------------------------------*
673  *      device driver poll
674  *---------------------------------------------------------------------------*/
675 PDEVSTATIC int
676 i4brbchpoll(dev_t dev, int events, struct thread *td)
677 {
678         int revents = 0;        /* Events we found */
679         int s;
680         int unit = minor(dev);
681         struct rbch_softc *sc = &rbch_softc[unit];
682         
683         /* We can't check for anything but IN or OUT */
684
685         s = splhigh();
686
687         if(!(sc->sc_devstate & ST_ISOPEN))
688         {
689                 splx(s);
690                 return(POLLNVAL);
691         }
692
693         /*
694          * Writes are OK if we are connected and the
695          * transmit queue can take them
696          */
697          
698         if((events & (POLLOUT|POLLWRNORM)) &&
699            (sc->sc_devstate & ST_CONNECTED) &&
700            !_IF_QFULL(isdn_linktab[unit]->tx_queue))
701         {
702                 revents |= (events & (POLLOUT|POLLWRNORM));
703         }
704         
705         /* ... while reads are OK if we have any data */
706
707         if((events & (POLLIN|POLLRDNORM)) &&
708            (sc->sc_devstate & ST_CONNECTED))
709         {
710                 struct ifqueue *iqp;
711
712                 if(sc->sc_bprot == BPROT_RHDLC)
713                         iqp = &sc->sc_hdlcq;
714                 else
715                         iqp = isdn_linktab[unit]->rx_queue;     
716
717                 if(!IF_QEMPTY(iqp))
718                         revents |= (events & (POLLIN|POLLRDNORM));
719         }
720                 
721         if(revents == 0)
722                 selrecord(td, &sc->selp);
723
724         splx(s);
725         return(revents);
726 }
727
728 #else /* OS_USES_POLL */
729
730 /*---------------------------------------------------------------------------*
731  *      device driver select
732  *---------------------------------------------------------------------------*/
733 PDEVSTATIC int
734 i4brbchselect(dev_t dev, int rw, struct thread *td)
735 {
736         int unit = minor(dev);
737         struct rbch_softc *sc = &rbch_softc[unit];
738         int s;
739
740         s = splhigh();
741
742         if(!(sc->sc_devstate & ST_ISOPEN))
743         {
744                 splx(s);
745                 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
746                 return(1);
747         }
748         
749         if(sc->sc_devstate & ST_CONNECTED)
750         {
751                 struct ifqueue *iqp;
752
753                 switch(rw)
754                 {
755                         case FREAD:
756                                 if(sc->sc_bprot == BPROT_RHDLC)
757                                         iqp = &sc->sc_hdlcq;
758                                 else
759                                         iqp = isdn_linktab[unit]->rx_queue;     
760
761                                 if(!IF_QEMPTY(iqp))
762                                 {
763                                         splx(s);
764                                         return(1);
765                                 }
766                                 break;
767
768                         case FWRITE:
769                                 if(!_IF_QFULL(isdn_linktab[unit]->rx_queue))
770                                 {
771                                         splx(s);
772                                         return(1);
773                                 }
774                                 break;
775
776                         default:
777                                 splx(s);
778                                 return 0;
779                 }
780         }
781         selrecord(p, &sc->selp);
782         splx(s);
783         return(0);
784 }
785
786 #endif /* OS_USES_POLL */
787
788 #if I4BRBCHACCT
789 /*---------------------------------------------------------------------------*
790  *      watchdog routine
791  *---------------------------------------------------------------------------*/
792 static void
793 rbch_timeout(struct rbch_softc *sc)
794 {
795         bchan_statistics_t bs;
796         int unit = sc->sc_unit;
797
798         /* get # of bytes in and out from the HSCX driver */ 
799         
800         (*isdn_linktab[unit]->bch_stat)
801                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
802
803         sc->sc_ioutb += bs.outbytes;
804         sc->sc_iinb += bs.inbytes;
805         
806         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
807         {
808                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
809                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
810
811                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
812                         sc->sc_fn = 0;
813                 else
814                         sc->sc_fn = 1;
815                         
816                 sc->sc_linb = sc->sc_iinb;
817                 sc->sc_loutb = sc->sc_ioutb;
818
819                 i4b_l4_accounting(BDRV_RBCH, unit, ACCT_DURING,
820                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
821         }
822         START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
823 }
824 #endif /* I4BRBCHACCT */
825
826 /*===========================================================================*
827  *                      ISDN INTERFACE ROUTINES
828  *===========================================================================*/
829
830 /*---------------------------------------------------------------------------*
831  *      this routine is called from L4 handler at connect time
832  *---------------------------------------------------------------------------*/
833 static void
834 rbch_connect(int unit, void *cdp)
835 {
836         call_desc_t *cd = (call_desc_t *)cdp;
837         struct rbch_softc *sc = &rbch_softc[unit];
838
839         sc->sc_bprot = cd->bprot;
840
841 #if I4BRBCHACCT
842         if(sc->sc_bprot == BPROT_RHDLC)
843         {       
844                 sc->sc_iinb = 0;
845                 sc->sc_ioutb = 0;
846                 sc->sc_linb = 0;
847                 sc->sc_loutb = 0;
848
849                 START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
850         }
851 #endif          
852         if(!(sc->sc_devstate & ST_CONNECTED))
853         {
854                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
855                 sc->sc_devstate |= ST_CONNECTED;
856                 sc->sc_cd = cdp;
857                 wakeup((caddr_t)sc);
858         }
859 }
860
861 /*---------------------------------------------------------------------------*
862  *      this routine is called from L4 handler at disconnect time
863  *---------------------------------------------------------------------------*/
864 static void
865 rbch_disconnect(int unit, void *cdp)
866 {
867         call_desc_t *cd = (call_desc_t *)cdp;
868         struct rbch_softc *sc = &rbch_softc[unit];
869
870         CRIT_VAR;
871         
872         if(cd != sc->sc_cd)
873         {
874                 NDBGL4(L4_RBCHDBG, "rbch%d: channel %d not active",
875                         cd->driver_unit, cd->channelid);
876                 return;
877         }
878
879         CRIT_BEG;
880         
881         NDBGL4(L4_RBCHDBG, "unit %d, disconnect", unit);
882
883         sc->sc_devstate &= ~ST_CONNECTED;
884
885         sc->sc_cd = NULL;
886         
887 #if I4BRBCHACCT
888         i4b_l4_accounting(BDRV_RBCH, unit, ACCT_FINAL,
889                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
890
891         STOP_TIMER(sc->sc_callout, rbch_timeout, sc);
892 #endif          
893         CRIT_END;
894 }
895         
896 /*---------------------------------------------------------------------------*
897  *      feedback from daemon in case of dial problems
898  *---------------------------------------------------------------------------*/
899 static void
900 rbch_dialresponse(int unit, int status, cause_t cause)
901 {
902 }
903         
904 /*---------------------------------------------------------------------------*
905  *      interface up/down
906  *---------------------------------------------------------------------------*/
907 static void
908 rbch_updown(int unit, int updown)
909 {
910 }
911         
912 /*---------------------------------------------------------------------------*
913  *      this routine is called from the HSCX interrupt handler
914  *      when a new frame (mbuf) has been received and is to be put on
915  *      the rx queue.
916  *---------------------------------------------------------------------------*/
917 static void
918 rbch_rx_data_rdy(int unit)
919 {
920         if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
921         {
922                 struct mbuf *m;
923                 
924                 if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
925                         return;
926
927                 m->m_pkthdr.len = m->m_len;
928
929 #if defined (__FreeBSD__) && __FreeBSD__ > 4
930                 if (! IF_HANDOFF(&(rbch_softc[unit].sc_hdlcq), m, NULL))
931                 {
932                         NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
933                 }
934 #else
935                 if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq)))
936                 {
937                         NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
938                         m_freem(m);
939                 }                       
940                 else
941                 {
942                         IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m);
943                 }
944 #endif          
945         }
946
947         if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA)
948         {
949                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
950                 rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
951                 wakeup((caddr_t) &isdn_linktab[unit]->rx_queue);
952         }
953         else
954         {
955                 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
956         }
957         selwakeup(&rbch_softc[unit].selp);
958 }
959
960 /*---------------------------------------------------------------------------*
961  *      this routine is called from the HSCX interrupt handler
962  *      when the last frame has been sent out and there is no
963  *      further frame (mbuf) in the tx queue.
964  *---------------------------------------------------------------------------*/
965 static void
966 rbch_tx_queue_empty(int unit)
967 {
968         if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY)
969         {
970                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
971                 rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
972                 wakeup((caddr_t) &isdn_linktab[unit]->tx_queue);
973         }
974         else
975         {
976                 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
977         }
978         selwakeup(&rbch_softc[unit].selp);
979 }
980
981 /*---------------------------------------------------------------------------*
982  *      this routine is called from the HSCX interrupt handler
983  *      each time a packet is received or transmitted
984  *---------------------------------------------------------------------------*/
985 static void
986 rbch_activity(int unit, int rxtx)
987 {
988         if (rbch_softc[unit].sc_cd)
989                 rbch_softc[unit].sc_cd->last_active_time = SECOND;
990         selwakeup(&rbch_softc[unit].selp);
991 }
992
993 /*---------------------------------------------------------------------------*
994  *      clear an hdlc rx queue for a rbch unit
995  *---------------------------------------------------------------------------*/
996 static void
997 rbch_clrq(int unit)
998 {
999         CRIT_VAR;
1000
1001 #if defined (__FreeBSD__) && __FreeBSD__ > 4
1002         CRIT_BEG;
1003         IF_DRAIN(&rbch_softc[unit].sc_hdlcq);
1004         CRIT_END;
1005 #else
1006         struct mbuf *m;
1007         for(;;)
1008         {
1009                 CRIT_BEG;
1010                 IF_DEQUEUE(&rbch_softc[unit].sc_hdlcq, m);
1011                 CRIT_END;
1012
1013                 if(m)
1014                         m_freem(m);
1015                 else
1016                         break;
1017         }
1018 #endif  
1019 }
1020                                 
1021 /*---------------------------------------------------------------------------*
1022  *      return this drivers linktab address
1023  *---------------------------------------------------------------------------*/
1024 drvr_link_t *
1025 rbch_ret_linktab(int unit)
1026 {
1027         rbch_init_linktab(unit);
1028         return(&rbch_drvr_linktab[unit]);
1029 }
1030
1031 /*---------------------------------------------------------------------------*
1032  *      setup the isdn_linktab for this driver
1033  *---------------------------------------------------------------------------*/
1034 void
1035 rbch_set_linktab(int unit, isdn_link_t *ilt)
1036 {
1037         isdn_linktab[unit] = ilt;
1038 }
1039
1040 /*---------------------------------------------------------------------------*
1041  *      initialize this drivers linktab
1042  *---------------------------------------------------------------------------*/
1043 static void
1044 rbch_init_linktab(int unit)
1045 {
1046         rbch_drvr_linktab[unit].unit = unit;
1047         rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy;
1048         rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty;
1049         rbch_drvr_linktab[unit].bch_activity = rbch_activity;   
1050         rbch_drvr_linktab[unit].line_connected = rbch_connect;
1051         rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect;
1052         rbch_drvr_linktab[unit].dial_response = rbch_dialresponse;
1053         rbch_drvr_linktab[unit].updown_ind = rbch_updown;       
1054 }
1055
1056 /*===========================================================================*/
1057
1058 #endif /* NI4BRBCH > 0 */