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