Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:28:39 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                                            TTIPRI | PCATCH,
399                                            "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                                            TTIPRI | PCATCH,
420                                            "rrbch", 0 )) != 0)
421                         {
422                                 CRIT_END;
423                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
424                                 sc->sc_devstate &= ~ST_RDWAITDATA;
425                                 return(error);
426                         }
427                 }
428         }
429
430         IF_DEQUEUE(iqp, m);
431
432         NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
433         
434         if(m && m->m_len)
435         {
436                 error = uiomove(m->m_data, m->m_len, uio);
437         }
438         else
439         {
440                 NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
441                 error = EIO;
442         }
443                 
444         if(m)
445                 i4b_Bfreembuf(m);
446
447         CRIT_END;
448
449         return(error);
450 }
451
452 /*---------------------------------------------------------------------------*
453  *      write to rbch device
454  *---------------------------------------------------------------------------*/
455 PDEVSTATIC int
456 i4brbchwrite(dev_t dev, struct uio * uio, int ioflag)
457 {
458         struct mbuf *m;
459         int error = 0;
460         int unit = minor(dev);
461         struct rbch_softc *sc = &rbch_softc[unit];
462
463         CRIT_VAR;
464         
465         NDBGL4(L4_RBCHDBG, "unit %d, write", unit);     
466
467         CRIT_BEG;
468         if(!(sc->sc_devstate & ST_ISOPEN))
469         {
470                 NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
471                 CRIT_END;
472                 return(EIO);
473         }
474
475         if((sc->sc_devstate & ST_NOBLOCK))
476         {
477                 if(!(sc->sc_devstate & ST_CONNECTED)) {
478                         CRIT_END;
479                         return(EWOULDBLOCK);
480                 }
481                 if(_IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
482                         CRIT_END;
483                         return(EWOULDBLOCK);
484         }
485         }
486         else
487         {
488                 while(!(sc->sc_devstate & ST_CONNECTED))
489                 {
490                         NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
491                 
492                         error = tsleep((caddr_t) &rbch_softc[unit],
493                                                    TTIPRI | PCATCH,
494                                                    "wrrbch", 0 );
495                         if(error == ERESTART) {
496                                 CRIT_END;
497                                 return (ERESTART);
498                         }
499                         else if(error == EINTR)
500                         {
501                                 CRIT_END;
502                                 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
503                                 return(EINTR);
504                         }
505                         else if(error)
506                         {
507                                 CRIT_END;
508                                 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
509                                 return(error);
510                         }
511                         tsleep((caddr_t) &rbch_softc[unit], TTIPRI | PCATCH, "xrbch", (hz*1));
512                 }
513
514                 while(_IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
515                 {
516                         sc->sc_devstate |= ST_WRWAITEMPTY;
517
518                         NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
519                 
520                         if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue,
521                                             TTIPRI | PCATCH,
522                                             "wrbch", 0)) != 0) {
523                                 sc->sc_devstate &= ~ST_WRWAITEMPTY;
524                                 if(error == ERESTART)
525                                 {
526                                         CRIT_END;
527                                         return(ERESTART);
528                                 }
529                                 else if(error == EINTR)
530                                 {
531                                         CRIT_END;
532                                         NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
533                                         return(error);
534                                 }
535                                 else if(error)
536                                 {
537                                         CRIT_END;
538                                         NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
539                                         return(error);
540                                 }
541                         }
542                 }
543         }
544
545         if(!(sc->sc_devstate & ST_ISOPEN))
546         {
547                 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
548                 CRIT_END;
549                 return(EIO);
550         }
551
552         if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
553         {
554                 m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
555
556                 NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
557                 
558                 error = uiomove(m->m_data, m->m_len, uio);
559
560 #if defined (__FreeBSD__) && __FreeBSD__ > 4            
561                 (void) IF_HANDOFF(isdn_linktab[unit]->tx_queue, m, NULL);
562 #else
563                 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
564                         m_freem(m);
565                 else
566                         IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
567 #endif
568                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
569         }
570
571         CRIT_END;
572         
573         return(error);
574 }
575
576 /*---------------------------------------------------------------------------*
577  *      rbch device ioctl handlibg
578  *---------------------------------------------------------------------------*/
579 PDEVSTATIC int
580 i4brbchioctl(dev_t dev, IOCTL_CMD_T cmd, caddr_t data, int flag, struct proc *p)
581 {
582         int error = 0;
583         int unit = minor(dev);
584         struct rbch_softc *sc = &rbch_softc[unit];
585         
586         switch(cmd)
587         {
588                 case FIOASYNC:  /* Set async mode */
589                         if (*(int *)data)
590                         {
591                                 NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
592                         }
593                         else
594                         {
595                                 NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
596                         }
597                         break;
598
599                 case FIONBIO:
600                         if (*(int *)data)
601                         {
602                                 NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit);
603                                 sc->sc_devstate |= ST_NOBLOCK;
604                         }
605                         else
606                         {
607                                 NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit);
608                                 sc->sc_devstate &= ~ST_NOBLOCK;
609                         }
610                         break;
611
612                 case TIOCCDTR:  /* Clear DTR */
613                         if(sc->sc_devstate & ST_CONNECTED)
614                         {
615                                 NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
616                                 i4b_l4_drvrdisc(BDRV_RBCH, unit);
617                         }
618                         break;
619
620                 case I4B_RBCH_DIALOUT:
621                 {
622                         size_t l;
623
624                         for (l = 0; l < TELNO_MAX && ((char *)data)[l]; l++)
625                                 ;
626                         if (l)
627                         {
628                                 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout to %s", unit, (char *)data);
629                                 i4b_l4_dialoutnumber(BDRV_RBCH, unit, l, (char *)data);
630                                 break;
631                         }
632                         /* fall through to SDTR */
633                 }
634
635                 case TIOCSDTR:  /* Set DTR */
636                         NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
637                         i4b_l4_dialout(BDRV_RBCH, unit);
638                         break;
639
640                 case TIOCSETA:  /* Set termios struct */
641                         break;
642
643                 case TIOCGETA:  /* Get termios struct */
644                         *(struct termios *)data = sc->it_in;
645                         break;
646
647                 case TIOCMGET:
648                         *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
649                         if (sc->sc_devstate & ST_CONNECTED)
650                                 *(int *)data |= TIOCM_CD;
651                         break;
652
653                 case I4B_RBCH_VR_REQ:
654                 {
655                         msg_vr_req_t *mvr;
656
657                         mvr = (msg_vr_req_t *)data;
658
659                         mvr->version = VERSION;
660                         mvr->release = REL;
661                         mvr->step = STEP;                       
662                         break;
663                 }
664
665                 default:        /* Unknown stuff */
666                         NDBGL4(L4_RBCHDBG, "unit %d, ioctl, unknown cmd %lx", unit, (u_long)cmd);
667                         error = EINVAL;
668                         break;
669         }
670         return(error);
671 }
672
673 #ifdef OS_USES_POLL
674
675 /*---------------------------------------------------------------------------*
676  *      device driver poll
677  *---------------------------------------------------------------------------*/
678 PDEVSTATIC int
679 i4brbchpoll(dev_t dev, int events, struct proc *p)
680 {
681         int revents = 0;        /* Events we found */
682         int s;
683         int unit = minor(dev);
684         struct rbch_softc *sc = &rbch_softc[unit];
685         
686         /* We can't check for anything but IN or OUT */
687
688         s = splhigh();
689
690         if(!(sc->sc_devstate & ST_ISOPEN))
691         {
692                 splx(s);
693                 return(POLLNVAL);
694         }
695
696         /*
697          * Writes are OK if we are connected and the
698          * transmit queue can take them
699          */
700          
701         if((events & (POLLOUT|POLLWRNORM)) &&
702            (sc->sc_devstate & ST_CONNECTED) &&
703            !_IF_QFULL(isdn_linktab[unit]->tx_queue))
704         {
705                 revents |= (events & (POLLOUT|POLLWRNORM));
706         }
707         
708         /* ... while reads are OK if we have any data */
709
710         if((events & (POLLIN|POLLRDNORM)) &&
711            (sc->sc_devstate & ST_CONNECTED))
712         {
713                 struct ifqueue *iqp;
714
715                 if(sc->sc_bprot == BPROT_RHDLC)
716                         iqp = &sc->sc_hdlcq;
717                 else
718                         iqp = isdn_linktab[unit]->rx_queue;     
719
720                 if(!IF_QEMPTY(iqp))
721                         revents |= (events & (POLLIN|POLLRDNORM));
722         }
723                 
724         if(revents == 0)
725                 selrecord(p, &sc->selp);
726
727         splx(s);
728         return(revents);
729 }
730
731 #else /* OS_USES_POLL */
732
733 /*---------------------------------------------------------------------------*
734  *      device driver select
735  *---------------------------------------------------------------------------*/
736 PDEVSTATIC int
737 i4brbchselect(dev_t dev, int rw, struct proc *p)
738 {
739         int unit = minor(dev);
740         struct rbch_softc *sc = &rbch_softc[unit];
741         int s;
742
743         s = splhigh();
744
745         if(!(sc->sc_devstate & ST_ISOPEN))
746         {
747                 splx(s);
748                 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
749                 return(1);
750         }
751         
752         if(sc->sc_devstate & ST_CONNECTED)
753         {
754                 struct ifqueue *iqp;
755
756                 switch(rw)
757                 {
758                         case FREAD:
759                                 if(sc->sc_bprot == BPROT_RHDLC)
760                                         iqp = &sc->sc_hdlcq;
761                                 else
762                                         iqp = isdn_linktab[unit]->rx_queue;     
763
764                                 if(!IF_QEMPTY(iqp))
765                                 {
766                                         splx(s);
767                                         return(1);
768                                 }
769                                 break;
770
771                         case FWRITE:
772                                 if(!_IF_QFULL(isdn_linktab[unit]->rx_queue))
773                                 {
774                                         splx(s);
775                                         return(1);
776                                 }
777                                 break;
778
779                         default:
780                                 splx(s);
781                                 return 0;
782                 }
783         }
784         selrecord(p, &sc->selp);
785         splx(s);
786         return(0);
787 }
788
789 #endif /* OS_USES_POLL */
790
791 #if I4BRBCHACCT
792 /*---------------------------------------------------------------------------*
793  *      watchdog routine
794  *---------------------------------------------------------------------------*/
795 static void
796 rbch_timeout(struct rbch_softc *sc)
797 {
798         bchan_statistics_t bs;
799         int unit = sc->sc_unit;
800
801         /* get # of bytes in and out from the HSCX driver */ 
802         
803         (*isdn_linktab[unit]->bch_stat)
804                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
805
806         sc->sc_ioutb += bs.outbytes;
807         sc->sc_iinb += bs.inbytes;
808         
809         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
810         {
811                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
812                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
813
814                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
815                         sc->sc_fn = 0;
816                 else
817                         sc->sc_fn = 1;
818                         
819                 sc->sc_linb = sc->sc_iinb;
820                 sc->sc_loutb = sc->sc_ioutb;
821
822                 i4b_l4_accounting(BDRV_RBCH, unit, ACCT_DURING,
823                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
824         }
825         START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
826 }
827 #endif /* I4BRBCHACCT */
828
829 /*===========================================================================*
830  *                      ISDN INTERFACE ROUTINES
831  *===========================================================================*/
832
833 /*---------------------------------------------------------------------------*
834  *      this routine is called from L4 handler at connect time
835  *---------------------------------------------------------------------------*/
836 static void
837 rbch_connect(int unit, void *cdp)
838 {
839         call_desc_t *cd = (call_desc_t *)cdp;
840         struct rbch_softc *sc = &rbch_softc[unit];
841
842         sc->sc_bprot = cd->bprot;
843
844 #if I4BRBCHACCT
845         if(sc->sc_bprot == BPROT_RHDLC)
846         {       
847                 sc->sc_iinb = 0;
848                 sc->sc_ioutb = 0;
849                 sc->sc_linb = 0;
850                 sc->sc_loutb = 0;
851
852                 START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
853         }
854 #endif          
855         if(!(sc->sc_devstate & ST_CONNECTED))
856         {
857                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
858                 sc->sc_devstate |= ST_CONNECTED;
859                 sc->sc_cd = cdp;
860                 wakeup((caddr_t)sc);
861         }
862 }
863
864 /*---------------------------------------------------------------------------*
865  *      this routine is called from L4 handler at disconnect time
866  *---------------------------------------------------------------------------*/
867 static void
868 rbch_disconnect(int unit, void *cdp)
869 {
870         call_desc_t *cd = (call_desc_t *)cdp;
871         struct rbch_softc *sc = &rbch_softc[unit];
872
873         CRIT_VAR;
874         
875         if(cd != sc->sc_cd)
876         {
877                 NDBGL4(L4_RBCHDBG, "rbch%d: channel %d not active",
878                         cd->driver_unit, cd->channelid);
879                 return;
880         }
881
882         CRIT_BEG;
883         
884         NDBGL4(L4_RBCHDBG, "unit %d, disconnect", unit);
885
886         sc->sc_devstate &= ~ST_CONNECTED;
887
888         sc->sc_cd = NULL;
889         
890 #if I4BRBCHACCT
891         i4b_l4_accounting(BDRV_RBCH, unit, ACCT_FINAL,
892                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
893
894         STOP_TIMER(sc->sc_callout, rbch_timeout, sc);
895 #endif          
896         CRIT_END;
897 }
898         
899 /*---------------------------------------------------------------------------*
900  *      feedback from daemon in case of dial problems
901  *---------------------------------------------------------------------------*/
902 static void
903 rbch_dialresponse(int unit, int status, cause_t cause)
904 {
905 }
906         
907 /*---------------------------------------------------------------------------*
908  *      interface up/down
909  *---------------------------------------------------------------------------*/
910 static void
911 rbch_updown(int unit, int updown)
912 {
913 }
914         
915 /*---------------------------------------------------------------------------*
916  *      this routine is called from the HSCX interrupt handler
917  *      when a new frame (mbuf) has been received and is to be put on
918  *      the rx queue.
919  *---------------------------------------------------------------------------*/
920 static void
921 rbch_rx_data_rdy(int unit)
922 {
923         if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
924         {
925                 register struct mbuf *m;
926                 
927                 if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
928                         return;
929
930                 m->m_pkthdr.len = m->m_len;
931
932 #if defined (__FreeBSD__) && __FreeBSD__ > 4
933                 if (! IF_HANDOFF(&(rbch_softc[unit].sc_hdlcq), m, NULL))
934                 {
935                         NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
936                 }
937 #else
938                 if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq)))
939                 {
940                         NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
941                         m_freem(m);
942                 }                       
943                 else
944                 {
945                         IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m);
946                 }
947 #endif          
948         }
949
950         if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA)
951         {
952                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
953                 rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
954                 wakeup((caddr_t) &isdn_linktab[unit]->rx_queue);
955         }
956         else
957         {
958                 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
959         }
960         selwakeup(&rbch_softc[unit].selp);
961 }
962
963 /*---------------------------------------------------------------------------*
964  *      this routine is called from the HSCX interrupt handler
965  *      when the last frame has been sent out and there is no
966  *      further frame (mbuf) in the tx queue.
967  *---------------------------------------------------------------------------*/
968 static void
969 rbch_tx_queue_empty(int unit)
970 {
971         if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY)
972         {
973                 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
974                 rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
975                 wakeup((caddr_t) &isdn_linktab[unit]->tx_queue);
976         }
977         else
978         {
979                 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
980         }
981         selwakeup(&rbch_softc[unit].selp);
982 }
983
984 /*---------------------------------------------------------------------------*
985  *      this routine is called from the HSCX interrupt handler
986  *      each time a packet is received or transmitted
987  *---------------------------------------------------------------------------*/
988 static void
989 rbch_activity(int unit, int rxtx)
990 {
991         if (rbch_softc[unit].sc_cd)
992                 rbch_softc[unit].sc_cd->last_active_time = SECOND;
993         selwakeup(&rbch_softc[unit].selp);
994 }
995
996 /*---------------------------------------------------------------------------*
997  *      clear an hdlc rx queue for a rbch unit
998  *---------------------------------------------------------------------------*/
999 static void
1000 rbch_clrq(int unit)
1001 {
1002         CRIT_VAR;
1003
1004 #if defined (__FreeBSD__) && __FreeBSD__ > 4
1005         CRIT_BEG;
1006         IF_DRAIN(&rbch_softc[unit].sc_hdlcq);
1007         CRIT_END;
1008 #else
1009         struct mbuf *m;
1010         for(;;)
1011         {
1012                 CRIT_BEG;
1013                 IF_DEQUEUE(&rbch_softc[unit].sc_hdlcq, m);
1014                 CRIT_END;
1015
1016                 if(m)
1017                         m_freem(m);
1018                 else
1019                         break;
1020         }
1021 #endif  
1022 }
1023                                 
1024 /*---------------------------------------------------------------------------*
1025  *      return this drivers linktab address
1026  *---------------------------------------------------------------------------*/
1027 drvr_link_t *
1028 rbch_ret_linktab(int unit)
1029 {
1030         rbch_init_linktab(unit);
1031         return(&rbch_drvr_linktab[unit]);
1032 }
1033
1034 /*---------------------------------------------------------------------------*
1035  *      setup the isdn_linktab for this driver
1036  *---------------------------------------------------------------------------*/
1037 void
1038 rbch_set_linktab(int unit, isdn_link_t *ilt)
1039 {
1040         isdn_linktab[unit] = ilt;
1041 }
1042
1043 /*---------------------------------------------------------------------------*
1044  *      initialize this drivers linktab
1045  *---------------------------------------------------------------------------*/
1046 static void
1047 rbch_init_linktab(int unit)
1048 {
1049         rbch_drvr_linktab[unit].unit = unit;
1050         rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy;
1051         rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty;
1052         rbch_drvr_linktab[unit].bch_activity = rbch_activity;   
1053         rbch_drvr_linktab[unit].line_connected = rbch_connect;
1054         rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect;
1055         rbch_drvr_linktab[unit].dial_response = rbch_dialresponse;
1056         rbch_drvr_linktab[unit].updown_ind = rbch_updown;       
1057 }
1058
1059 /*===========================================================================*/
1060
1061 #endif /* NI4BRBCH > 0 */