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