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