Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / netisdn / i4b_rbch.c
blob124af3432f96745267d3b512587ceec69baffac4
1 /*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
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.
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.
25 *---------------------------------------------------------------------------
27 * i4b_rbch.c - device driver for raw B channel data
28 * ---------------------------------------------------
30 * $Id: i4b_rbch.c,v 1.25 2009/03/18 10:22:43 cegger Exp $
32 * $FreeBSD$
34 * last edit-date: [Fri Jan 5 11:33:47 2001]
36 *---------------------------------------------------------------------------*/
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: i4b_rbch.c,v 1.24 2009/03/14 14:46:11 dsl Exp $");
41 #include "isdnbchan.h"
43 #if NISDNBCHAN > 0
45 #include <sys/param.h>
46 #include <sys/systm.h>
48 #include <sys/conf.h>
49 #include <sys/uio.h>
50 #include <sys/kernel.h>
51 #include <sys/mbuf.h>
52 #include <sys/socket.h>
53 #include <net/if.h>
54 #include <sys/proc.h>
55 #include <sys/tty.h>
57 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
58 #include <sys/callout.h>
59 #endif
61 #if defined (__NetBSD__) || defined (__OpenBSD__)
62 #define termioschars(t) memcpy((t)->c_cc, &ttydefchars, sizeof((t)->c_cc))
63 #endif
65 #ifdef __FreeBSD__
67 #if defined(__FreeBSD__) && __FreeBSD__ == 3
68 #include "opt_devfs.h"
69 #endif
71 #ifdef DEVFS
72 #include <sys/devfsext.h>
73 #endif
75 #endif /* __FreeBSD__ */
77 #ifdef __NetBSD__
78 #include <sys/filio.h>
79 #endif
81 #ifdef __FreeBSD__
82 #include <machine/i4b_ioctl.h>
83 #include <machine/i4b_rbch_ioctl.h>
84 #include <machine/i4b_debug.h>
85 #else
86 #include <netisdn/i4b_ioctl.h>
87 #include <netisdn/i4b_rbch_ioctl.h>
88 #include <netisdn/i4b_debug.h>
89 #endif
91 #include <netisdn/i4b_global.h>
92 #include <netisdn/i4b_mbuf.h>
93 #include <netisdn/i4b_l3l4.h>
95 #include <netisdn/i4b_l4.h>
97 #ifdef __bsdi__
98 #include <sys/device.h>
99 #endif
101 #ifdef OS_USES_POLL
102 #include <sys/ioccom.h>
103 #include <sys/poll.h>
104 #else
105 #include <sys/fcntl.h>
106 #include <sys/ioctl.h>
107 #endif
109 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
110 #include <sys/filio.h>
111 #endif
113 #define I4BRBCHACCT 1 /* enable accounting messages */
114 #define I4BRBCHACCTINTVL 2 /* accounting msg interval in secs */
116 static struct rbch_softc {
118 int sc_unit; /* unit number */
120 int sc_devstate; /* state of driver */
121 #define ST_IDLE 0x00
122 #define ST_CONNECTED 0x01
123 #define ST_ISOPEN 0x02
124 #define ST_RDWAITDATA 0x04
125 #define ST_WRWAITEMPTY 0x08
126 #define ST_NOBLOCK 0x10
128 int sc_bprot; /* B-ch protocol used */
130 call_desc_t *sc_cd; /* Call Descriptor */
131 isdn_link_t *sc_ilt; /* B-channel driver/state */
133 struct termios it_in;
135 struct ifqueue sc_hdlcq; /* hdlc read queue */
136 #define I4BRBCHMAXQLEN 10
138 struct selinfo selp; /* select / poll */
140 #if defined(__FreeBSD__) && __FreeBSD__ == 3
141 #ifdef DEVFS
142 void *devfs_token; /* device filesystem */
143 #endif
144 #endif
146 #if I4BRBCHACCT
147 #if defined(__FreeBSD__)
148 struct callout_handle sc_callout;
149 #endif
150 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
151 struct callout sc_callout;
152 #endif
154 int sc_iinb; /* isdn driver # of inbytes */
155 int sc_ioutb; /* isdn driver # of outbytes */
156 int sc_linb; /* last # of bytes rx'd */
157 int sc_loutb; /* last # of bytes tx'd */
158 int sc_fn; /* flag, first null acct */
159 #endif
160 } rbch_softc[NISDNBCHAN];
162 static void rbch_rx_data_rdy(void *softc);
163 static void rbch_tx_queue_empty(void *softc);
164 static void rbch_connect(void *softc, void *cdp);
165 static void rbch_disconnect(void *softc, void *cdp);
166 static void rbch_clrq(void *softc);
167 static void rbch_activity(void *softc, int rxtx);
168 static void rbch_dialresponse(void *softc, int status, cause_t cause);
169 static void rbch_updown(void *softc, int updown);
170 static void rbch_set_linktab(void *softc, isdn_link_t *ilt);
171 static void* rbch_get_softc(int unit);
174 #ifndef __FreeBSD__
175 #define PDEVSTATIC /* - not static - */
176 #define IOCTL_CMD_T u_long
177 void isdnbchanattach(void);
178 int isdnbchanopen(dev_t dev, int flag, int fmt, struct lwp *l);
179 int isdnbchanclose(dev_t dev, int flag, int fmt, struct lwp *l);
180 int isdnbchanread(dev_t dev, struct uio *uio, int ioflag);
181 int isdnbchanwrite(dev_t dev, struct uio *uio, int ioflag);
182 int isdnbchanioctl(dev_t dev, IOCTL_CMD_T cmd, void *arg, int flag, struct lwp* l);
183 #ifdef OS_USES_POLL
184 int isdnbchanpoll(dev_t dev, int events, struct lwp *l);
185 int isdnbchankqfilter(dev_t dev, struct knote *kn);
186 #else
187 PDEVSTATIC int isdnbchanselect(dev_t dev, int rw, struct lwp *l);
188 #endif
189 #endif
191 #ifdef __NetBSD__
192 const struct cdevsw isdnbchan_cdevsw = {
193 isdnbchanopen, isdnbchanclose, isdnbchanread, isdnbchanwrite,
194 isdnbchanioctl, nostop, notty, isdnbchanpoll, nommap, nokqfilter,
195 D_OTHER
197 #endif /* __NetBSD__ */
199 #if BSD > 199306 && defined(__FreeBSD__)
200 #define PDEVSTATIC static
201 #define IOCTL_CMD_T u_long
203 PDEVSTATIC d_open_t isdnbchanopen;
204 PDEVSTATIC d_close_t isdnbchanclose;
205 PDEVSTATIC d_read_t isdnbchanread;
206 PDEVSTATIC d_read_t isdnbchanwrite;
207 PDEVSTATIC d_ioctl_t isdnbchanioctl;
209 #ifdef OS_USES_POLL
210 PDEVSTATIC d_poll_t isdnbchanpoll;
211 #define POLLFIELD isdnbchanpoll
212 #else
213 PDEVSTATIC d_select_t isdnbchanselect;
214 #define POLLFIELD isdnbchanselect
215 #endif
217 #define CDEV_MAJOR 57
219 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
220 static struct cdevsw isdnbchan_cdevsw = {
221 /* open */ isdnbchanopen,
222 /* close */ isdnbchanclose,
223 /* read */ isdnbchanread,
224 /* write */ isdnbchanwrite,
225 /* ioctl */ isdnbchanioctl,
226 /* poll */ POLLFIELD,
227 /* mmap */ nommap,
228 /* strategy */ nostrategy,
229 /* name */ "isdnbchan",
230 /* maj */ CDEV_MAJOR,
231 /* dump */ nodump,
232 /* psize */ nopsize,
233 /* flags */ 0,
234 /* bmaj */ -1
236 #else
237 static struct cdevsw isdnbchan_cdevsw = {
238 isdnbchanopen, isdnbchanclose, isdnbchanread, isdnbchanwrite,
239 isdnbchanioctl, nostop, noreset, nodevtotty,
240 POLLFIELD, nommap, NULL, "isdnbchan", NULL, -1
242 #endif
244 static void isdnbchanattach(void *);
245 PSEUDO_SET(isdnbchanattach, i4b_rbch);
247 /*===========================================================================*
248 * DEVICE DRIVER ROUTINES
249 *===========================================================================*/
251 /*---------------------------------------------------------------------------*
252 * initialization at kernel load time
253 *---------------------------------------------------------------------------*/
254 static void
255 isdnbchaninit(void *unused)
257 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
258 cdevsw_add(&isdnbchan_cdevsw);
259 #else
260 dev_t dev = makedev(CDEV_MAJOR, 0);
261 cdevsw_add(&dev, &isdnbchan_cdevsw, NULL);
262 #endif
265 SYSINIT(isdnbchandev, SI_SUB_DRIVERS,
266 SI_ORDER_MIDDLE+CDEV_MAJOR, &isdnbchaninit, NULL);
268 #endif /* BSD > 199306 && defined(__FreeBSD__) */
270 #ifdef __bsdi__
271 int isdnbchanmatch(struct device *parent, struct cfdata *cf, void *aux);
272 void dummy_isdnbchanattach(struct device*, struct device *, void *);
274 #define CDEV_MAJOR 61
276 static struct cfdriver isdnbchancd =
277 { NULL, "isdnbchan", isdnbchanmatch, dummy_isdnbchanattach, DV_DULL,
278 sizeof(struct cfdriver) };
279 struct devsw isdnbchansw =
280 { &isdnbchancd,
281 isdnbchanopen, isdnbchanclose, isdnbchanread, isdnbchanwrite,
282 isdnbchanioctl, seltrue, nommap, nostrat,
283 nodump, nopsize, 0, nostop
287 isdnbchanmatch(struct device *parent, struct cfdata *cf, void *aux)
289 printf("isdnbchanmatch: aux=0x%x\n", aux);
290 return 1;
292 void
293 dummy_isdnbchanattach(struct device *parent, struct device *self, void *aux)
295 printf("dummy_isdnbchanattach: aux=0x%x\n", aux);
297 #endif /* __bsdi__ */
300 static const struct isdn_l4_driver_functions
301 rbch_driver_functions = {
302 rbch_rx_data_rdy,
303 rbch_tx_queue_empty,
304 rbch_activity,
305 rbch_connect,
306 rbch_disconnect,
307 rbch_dialresponse,
308 rbch_updown,
309 rbch_get_softc,
310 rbch_set_linktab,
311 NULL
314 static int rbch_driver_id = -1;
316 /*---------------------------------------------------------------------------*
317 * interface attach routine
318 *---------------------------------------------------------------------------*/
319 PDEVSTATIC void
320 #ifdef __FreeBSD__
321 isdnbchanattach(void *dummy)
322 #else
323 isdnbchanattach(void)
324 #endif
326 int i;
328 rbch_driver_id = isdn_l4_driver_attach("isdnbchan", NISDNBCHAN, &rbch_driver_functions);
330 for(i=0; i < NISDNBCHAN; i++)
332 #if defined(__FreeBSD__)
333 #if __FreeBSD__ == 3
335 #ifdef DEVFS
336 rbch_softc[i].devfs_token =
337 devfs_add_devswf(&isdnbchan_cdevsw, i, DV_CHR,
338 UID_ROOT, GID_WHEEL, 0600,
339 "isdnbchan%d", i);
340 #endif
342 #else
343 make_dev(&isdnbchan_cdevsw, i,
344 UID_ROOT, GID_WHEEL, 0600, "isdnbchan%d", i);
345 #endif
346 #endif
348 #if I4BRBCHACCT
349 #if defined(__FreeBSD__)
350 callout_handle_init(&rbch_softc[i].sc_callout);
351 #endif
352 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
353 callout_init(&rbch_softc[i].sc_callout, 0);
354 selinit(&rbch_softc[i].selp);
355 #endif
356 rbch_softc[i].sc_fn = 1;
357 #endif
358 rbch_softc[i].sc_unit = i;
359 rbch_softc[i].sc_devstate = ST_IDLE;
360 rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
361 rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
362 termioschars(&rbch_softc[i].it_in);
366 /*---------------------------------------------------------------------------*
367 * open rbch device
368 *---------------------------------------------------------------------------*/
369 PDEVSTATIC int
370 isdnbchanopen(dev_t dev, int flag, int fmt,
371 struct lwp *l)
373 int unit = minor(dev);
375 if(unit >= NISDNBCHAN)
376 return(ENXIO);
378 if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
379 return(EBUSY);
381 #if 0
382 rbch_clrq(unit);
383 #endif
385 rbch_softc[unit].sc_devstate |= ST_ISOPEN;
387 NDBGL4(L4_RBCHDBG, "unit %d, open", unit);
389 return(0);
392 /*---------------------------------------------------------------------------*
393 * close rbch device
394 *---------------------------------------------------------------------------*/
395 PDEVSTATIC int
396 isdnbchanclose(dev_t dev, int flag, int fmt,
397 struct lwp *l)
399 int unit = minor(dev);
400 struct rbch_softc *sc = &rbch_softc[unit];
402 if(sc->sc_devstate & ST_CONNECTED)
403 i4b_l4_drvrdisc(sc->sc_cd->cdid);
405 sc->sc_devstate &= ~ST_ISOPEN;
407 rbch_clrq(sc);
409 NDBGL4(L4_RBCHDBG, "channel %d, closed", unit);
411 return(0);
414 /*---------------------------------------------------------------------------*
415 * read from rbch device
416 *---------------------------------------------------------------------------*/
417 PDEVSTATIC int
418 isdnbchanread(dev_t dev, struct uio *uio, int ioflag)
420 struct mbuf *m;
421 int error = 0;
422 int unit = minor(dev);
423 struct ifqueue *iqp;
424 struct rbch_softc *sc = &rbch_softc[unit];
426 int s;
428 NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
430 s = splnet();
431 if(!(sc->sc_devstate & ST_ISOPEN))
433 splx(s);
434 NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
435 return(EIO);
438 if((sc->sc_devstate & ST_NOBLOCK))
440 if(!(sc->sc_devstate & ST_CONNECTED)) {
441 splx(s);
442 return(EWOULDBLOCK);
445 if(sc->sc_bprot == BPROT_RHDLC)
446 iqp = &sc->sc_hdlcq;
447 else
448 iqp = sc->sc_ilt->rx_queue;
450 if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
451 splx(s);
452 return(EWOULDBLOCK);
455 else
457 while(!(sc->sc_devstate & ST_CONNECTED))
459 NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
461 if((error = tsleep((void *) &rbch_softc[unit],
462 TTIPRI | PCATCH,
463 "rrrbch", 0 )) != 0)
465 splx(s);
466 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
467 return(error);
471 if(sc->sc_bprot == BPROT_RHDLC)
472 iqp = &sc->sc_hdlcq;
473 else
474 iqp = sc->sc_ilt->rx_queue;
476 while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
478 sc->sc_devstate |= ST_RDWAITDATA;
480 NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
482 if((error = tsleep((void *) &sc->sc_ilt->rx_queue,
483 TTIPRI | PCATCH,
484 "rrbch", 0 )) != 0)
486 splx(s);
487 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
488 sc->sc_devstate &= ~ST_RDWAITDATA;
489 return(error);
490 } else if (!(sc->sc_devstate & ST_CONNECTED)) {
491 splx(s);
492 return 0;
497 IF_DEQUEUE(iqp, m);
499 NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
501 if(m && m->m_len)
503 error = uiomove(m->m_data, m->m_len, uio);
505 else
507 NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
508 error = EIO;
511 if(m)
512 i4b_Bfreembuf(m);
514 splx(s);
516 return(error);
519 /*---------------------------------------------------------------------------*
520 * write to rbch device
521 *---------------------------------------------------------------------------*/
522 PDEVSTATIC int
523 isdnbchanwrite(dev_t dev, struct uio * uio, int ioflag)
525 struct mbuf *m;
526 int error = 0;
527 int unit = minor(dev);
528 struct rbch_softc *sc = &rbch_softc[unit];
530 int s;
532 NDBGL4(L4_RBCHDBG, "unit %d, write", unit);
534 s = splnet();
535 if(!(sc->sc_devstate & ST_ISOPEN))
537 NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
538 splx(s);
539 return(EIO);
542 if((sc->sc_devstate & ST_NOBLOCK))
544 if(!(sc->sc_devstate & ST_CONNECTED)) {
545 splx(s);
546 return(EWOULDBLOCK);
548 if(IF_QFULL(sc->sc_ilt->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
549 splx(s);
550 return(EWOULDBLOCK);
553 else
555 while(!(sc->sc_devstate & ST_CONNECTED))
557 NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
559 error = tsleep((void *) &rbch_softc[unit],
560 TTIPRI | PCATCH,
561 "wrrbch", 0 );
562 if(error == ERESTART) {
563 splx(s);
564 return (ERESTART);
566 else if(error == EINTR)
568 splx(s);
569 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
570 return(EINTR);
572 else if(error)
574 splx(s);
575 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
576 return(error);
578 tsleep((void *) &rbch_softc[unit], TTIPRI | PCATCH, "xrbch", (hz*1));
581 while(IF_QFULL(sc->sc_ilt->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
583 sc->sc_devstate |= ST_WRWAITEMPTY;
585 NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
587 if ((error = tsleep((void *) &sc->sc_ilt->tx_queue,
588 TTIPRI | PCATCH,
589 "wrbch", 0)) != 0) {
590 sc->sc_devstate &= ~ST_WRWAITEMPTY;
591 if(error == ERESTART)
593 splx(s);
594 return(ERESTART);
596 else if(error == EINTR)
598 splx(s);
599 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
600 return(error);
602 else if(error)
604 splx(s);
605 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
606 return(error);
608 else if (!(sc->sc_devstate & ST_CONNECTED)) {
609 splx(s);
610 return 0;
616 if(!(sc->sc_devstate & ST_ISOPEN))
618 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
619 splx(s);
620 return(EIO);
623 if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
625 m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
627 NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
629 error = uiomove(m->m_data, m->m_len, uio);
631 if(IF_QFULL(sc->sc_ilt->tx_queue))
633 m_freem(m);
635 else
637 IF_ENQUEUE(sc->sc_ilt->tx_queue, m);
640 (*sc->sc_ilt->bchannel_driver->bch_tx_start)(sc->sc_ilt->l1token, sc->sc_ilt->channel);
643 splx(s);
645 return(error);
648 /*---------------------------------------------------------------------------*
649 * rbch device ioctl handlibg
650 *---------------------------------------------------------------------------*/
651 PDEVSTATIC int
652 isdnbchanioctl(dev_t dev, IOCTL_CMD_T cmd, void *data, int flag,
653 struct lwp *l)
655 int error = 0;
656 int unit = minor(dev);
657 struct rbch_softc *sc = &rbch_softc[unit];
659 switch(cmd)
661 case FIOASYNC: /* Set async mode */
662 if (*(int *)data)
664 NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
666 else
668 NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
670 break;
672 case FIONBIO:
673 if (*(int *)data)
675 NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit);
676 sc->sc_devstate |= ST_NOBLOCK;
678 else
680 NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit);
681 sc->sc_devstate &= ~ST_NOBLOCK;
683 break;
685 case TIOCCDTR: /* Clear DTR */
686 if(sc->sc_devstate & ST_CONNECTED)
688 NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
689 i4b_l4_drvrdisc(sc->sc_cd->cdid);
691 break;
693 case I4B_RBCH_DIALOUT:
695 size_t x;
697 for (x = 0; x < TELNO_MAX && ((char *)data)[x]; x++)
699 if (x)
701 NDBGL4(L4_RBCHDBG, "%d, attempting dialout to %s", unit, (char *)data);
702 i4b_l4_dialoutnumber(rbch_driver_id, unit, x, (char *)data);
703 break;
705 /* fall through to SDTR */
708 case TIOCSDTR: /* Set DTR */
709 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
710 i4b_l4_dialout(rbch_driver_id, unit);
711 break;
713 case TIOCSETA: /* Set termios struct */
714 break;
716 case TIOCGETA: /* Get termios struct */
717 *(struct termios *)data = sc->it_in;
718 break;
720 case TIOCMGET:
721 *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
722 if (sc->sc_devstate & ST_CONNECTED)
723 *(int *)data |= TIOCM_CD;
724 break;
726 case I4B_RBCH_VR_REQ:
728 msg_vr_req_t *mvr;
730 mvr = (msg_vr_req_t *)data;
732 mvr->version = VERSION;
733 mvr->release = REL;
734 mvr->step = STEP;
735 break;
738 default: /* Unknown stuff */
739 NDBGL4(L4_RBCHDBG, "(minor=%d) ioctl, unknown cmd %lx", unit, (u_long)cmd);
740 error = EINVAL;
741 break;
743 return(error);
746 #ifdef OS_USES_POLL
748 /*---------------------------------------------------------------------------*
749 * device driver poll
750 *---------------------------------------------------------------------------*/
751 PDEVSTATIC int
752 isdnbchanpoll(dev_t dev, int events, struct lwp *l)
754 int revents = 0; /* Events we found */
755 int s;
756 int unit = minor(dev);
757 struct rbch_softc *sc = &rbch_softc[unit];
759 /* We can't check for anything but IN or OUT */
761 s = splhigh();
763 if(!(sc->sc_devstate & ST_ISOPEN))
765 splx(s);
766 return(POLLNVAL);
770 * Writes are OK if we are connected and the
771 * transmit queue can take them
774 if((events & (POLLOUT|POLLWRNORM)) &&
775 (sc->sc_devstate & ST_CONNECTED) &&
776 !IF_QFULL(sc->sc_ilt->tx_queue))
778 revents |= (events & (POLLOUT|POLLWRNORM));
781 /* ... while reads are OK if we have any data */
783 if((events & (POLLIN|POLLRDNORM)) &&
784 (sc->sc_devstate & ST_CONNECTED))
786 struct ifqueue *iqp;
788 if(sc->sc_bprot == BPROT_RHDLC)
789 iqp = &sc->sc_hdlcq;
790 else
791 iqp = sc->sc_ilt->rx_queue;
793 if(!IF_QEMPTY(iqp))
794 revents |= (events & (POLLIN|POLLRDNORM));
797 if(revents == 0)
798 selrecord(l, &sc->selp);
800 splx(s);
801 return(revents);
804 static void
805 filt_i4brbchdetach(struct knote *kn)
807 struct rbch_softc *sc = kn->kn_hook;
808 int s;
810 s = splhigh();
811 SLIST_REMOVE(&sc->selp.sel_klist, kn, knote, kn_selnext);
812 splx(s);
815 static int
816 filt_i4brbchread(struct knote *kn, long hint)
818 struct rbch_softc *sc = kn->kn_hook;
819 struct ifqueue *iqp;
821 if ((sc->sc_devstate & ST_CONNECTED) == 0)
822 return (0);
824 if (sc->sc_bprot == BPROT_RHDLC)
825 iqp = &sc->sc_hdlcq;
826 else
827 iqp = sc->sc_ilt->rx_queue;
829 if (IF_QEMPTY(iqp))
830 return (0);
832 kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
833 return (1);
836 static const struct filterops i4brbchread_filtops =
837 { 1, NULL, filt_i4brbchdetach, filt_i4brbchread };
839 static int
840 filt_i4brbchwrite(struct knote *kn, long hint)
842 struct rbch_softc *sc = kn->kn_hook;
844 if ((sc->sc_devstate & ST_CONNECTED) == 0)
845 return (0);
847 if (IF_QFULL(sc->sc_ilt->tx_queue))
848 return (0);
850 kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
851 return (1);
854 static const struct filterops i4brbchwrite_filtops =
855 { 1, NULL, filt_i4brbchdetach, filt_i4brbchwrite };
858 isdnbchankqfilter(dev_t dev, struct knote *kn)
860 struct rbch_softc *sc = &rbch_softc[minor(dev)];
861 struct klist *klist;
862 int s;
864 switch (kn->kn_filter) {
865 case EVFILT_READ:
866 klist = &sc->selp.sel_klist;
867 kn->kn_fop = &i4brbchread_filtops;
868 break;
870 case EVFILT_WRITE:
871 klist = &sc->selp.sel_klist;
872 kn->kn_fop = &i4brbchwrite_filtops;
873 break;
875 default:
876 return (EINVAL);
879 kn->kn_hook = sc;
881 s = splhigh();
882 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
883 splx(s);
885 return (0);
888 #else /* OS_USES_POLL */
890 /*---------------------------------------------------------------------------*
891 * device driver select
892 *---------------------------------------------------------------------------*/
893 PDEVSTATIC int
894 isdnbchanselect(dev_t dev, int rw, struct lwp *l)
896 int unit = minor(dev);
897 struct rbch_softc *sc = &rbch_softc[unit];
898 int s;
900 s = splhigh();
902 if(!(sc->sc_devstate & ST_ISOPEN))
904 splx(s);
905 NDBGL4(L4_RBCHDBG, "(minor=%d) not open anymore", unit);
906 return(1);
909 if(sc->sc_devstate & ST_CONNECTED)
911 struct ifqueue *iqp;
913 switch(rw)
915 case FREAD:
916 if(sc->sc_bprot == BPROT_RHDLC)
917 iqp = &sc->sc_hdlcq;
918 else
919 iqp = isdn_linktab[unit]->rx_queue;
921 if(!IF_QEMPTY(iqp))
923 splx(s);
924 return(1);
926 break;
928 case FWRITE:
929 if(!IF_QFULL(isdn_linktab[unit]->rx_queue))
931 splx(s);
932 return(1);
934 break;
936 default:
937 splx(s);
938 return 0;
941 selrecord(l, &sc->selp);
942 splx(s);
943 return(0);
946 #endif /* OS_USES_POLL */
948 #if I4BRBCHACCT
949 /*---------------------------------------------------------------------------*
950 * watchdog routine
951 *---------------------------------------------------------------------------*/
952 static void
953 rbch_timeout(struct rbch_softc *sc)
955 bchan_statistics_t bs;
957 /* get # of bytes in and out from the HSCX driver */
959 (*sc->sc_ilt->bchannel_driver->bch_stat)
960 (sc->sc_ilt->l1token, sc->sc_ilt->channel, &bs);
962 sc->sc_ioutb += bs.outbytes;
963 sc->sc_iinb += bs.inbytes;
965 if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
967 int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
968 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
970 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
971 sc->sc_fn = 0;
972 else
973 sc->sc_fn = 1;
975 sc->sc_linb = sc->sc_iinb;
976 sc->sc_loutb = sc->sc_ioutb;
978 if (sc->sc_cd)
979 i4b_l4_accounting(sc->sc_cd->cdid, ACCT_DURING,
980 sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
982 START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
984 #endif /* I4BRBCHACCT */
986 /*===========================================================================*
987 * ISDN INTERFACE ROUTINES
988 *===========================================================================*/
990 /*---------------------------------------------------------------------------*
991 * this routine is called from L4 handler at connect time
992 *---------------------------------------------------------------------------*/
993 static void
994 rbch_connect(void *softc, void *cdp)
996 call_desc_t *cd = (call_desc_t *)cdp;
997 struct rbch_softc *sc = softc;
999 sc->sc_bprot = cd->bprot;
1001 #if I4BRBCHACCT
1002 if(sc->sc_bprot == BPROT_RHDLC)
1004 sc->sc_iinb = 0;
1005 sc->sc_ioutb = 0;
1006 sc->sc_linb = 0;
1007 sc->sc_loutb = 0;
1009 START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
1011 #endif
1012 if(!(sc->sc_devstate & ST_CONNECTED))
1014 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d, wakeup",
1015 cd->channelid, cd->isdnif);
1016 sc->sc_devstate |= ST_CONNECTED;
1017 sc->sc_cd = cdp;
1018 wakeup((void *)sc);
1019 selnotify(&sc->selp, 0, 0);
1023 /*---------------------------------------------------------------------------*
1024 * this routine is called from L4 handler at disconnect time
1025 *---------------------------------------------------------------------------*/
1026 static void
1027 rbch_disconnect(void *softc, void *cdp)
1029 call_desc_t *cd = cdp;
1030 struct rbch_softc *sc = softc;
1032 int s;
1034 if(cd != sc->sc_cd)
1036 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d not active",
1037 cd->channelid, cd->isdnif);
1038 return;
1041 s = splnet();
1043 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d disconnect",
1044 cd->channelid, cd->isdnif);
1046 sc->sc_devstate &= ~ST_CONNECTED;
1048 #if I4BRBCHACCT
1049 if (sc->sc_cd)
1050 i4b_l4_accounting(sc->sc_cd->cdid, ACCT_FINAL,
1051 sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
1053 STOP_TIMER(sc->sc_callout, rbch_timeout, sc);
1054 #endif
1056 sc->sc_cd = NULL;
1057 if (sc->sc_devstate & ST_RDWAITDATA)
1058 wakeup(&sc->sc_ilt->rx_queue);
1059 if (sc->sc_devstate & ST_WRWAITEMPTY)
1060 wakeup(&sc->sc_ilt->tx_queue);
1062 splx(s);
1064 selnotify(&sc->selp, 0, 0);
1067 /*---------------------------------------------------------------------------*
1068 * feedback from daemon in case of dial problems
1069 *---------------------------------------------------------------------------*/
1070 static void
1071 rbch_dialresponse(void *softc, int status,
1072 cause_t cause)
1076 /*---------------------------------------------------------------------------*
1077 * interface up/down
1078 *---------------------------------------------------------------------------*/
1079 static void
1080 rbch_updown(void *softc, int updown)
1084 /*---------------------------------------------------------------------------*
1085 * this routine is called from the HSCX interrupt handler
1086 * when a new frame (mbuf) has been received and is to be put on
1087 * the rx queue.
1088 *---------------------------------------------------------------------------*/
1089 static void
1090 rbch_rx_data_rdy(void *softc)
1092 struct rbch_softc *sc = softc;
1094 if(sc->sc_bprot == BPROT_RHDLC)
1096 register struct mbuf *m;
1098 if((m = *sc->sc_ilt->rx_mbuf) == NULL)
1099 return;
1101 m->m_pkthdr.len = m->m_len;
1103 if(IF_QFULL(&sc->sc_hdlcq))
1105 NDBGL4(L4_RBCHDBG, "(minor=%d) hdlc rx queue full!", sc->sc_unit);
1106 m_freem(m);
1108 else
1110 IF_ENQUEUE(&sc->sc_hdlcq, m);
1114 if(sc->sc_devstate & ST_RDWAITDATA)
1116 NDBGL4(L4_RBCHDBG, "(minor=%d) wakeup", sc->sc_unit);
1117 sc->sc_devstate &= ~ST_RDWAITDATA;
1118 wakeup((void *) &sc->sc_ilt->rx_queue);
1120 else
1122 NDBGL4(L4_RBCHDBG, "(minor=%d) NO wakeup", sc->sc_unit);
1124 selnotify(&sc->selp, 0, 0);
1127 /*---------------------------------------------------------------------------*
1128 * this routine is called from the HSCX interrupt handler
1129 * when the last frame has been sent out and there is no
1130 * further frame (mbuf) in the tx queue.
1131 *---------------------------------------------------------------------------*/
1132 static void
1133 rbch_tx_queue_empty(void *softc)
1135 struct rbch_softc *sc = softc;
1137 if(sc->sc_devstate & ST_WRWAITEMPTY)
1139 NDBGL4(L4_RBCHDBG, "(minor=%d): wakeup", sc->sc_unit);
1140 sc->sc_devstate &= ~ST_WRWAITEMPTY;
1141 wakeup((void *) &sc->sc_ilt->tx_queue);
1143 else
1145 NDBGL4(L4_RBCHDBG, "(minor=%d) NO wakeup", sc->sc_unit);
1147 selnotify(&sc->selp, 0, 0);
1150 /*---------------------------------------------------------------------------*
1151 * this routine is called from the HSCX interrupt handler
1152 * each time a packet is received or transmitted
1153 *---------------------------------------------------------------------------*/
1154 static void
1155 rbch_activity(void *softc, int rxtx)
1157 struct rbch_softc *sc = softc;
1159 if (sc->sc_cd)
1160 sc->sc_cd->last_active_time = SECOND;
1161 selnotify(&sc->selp, 0, 0);
1164 /*---------------------------------------------------------------------------*
1165 * clear an hdlc rx queue for a rbch unit
1166 *---------------------------------------------------------------------------*/
1167 static void
1168 rbch_clrq(void *softc)
1170 struct rbch_softc *sc = softc;
1171 struct mbuf *m;
1172 int s;
1174 for(;;)
1176 s = splnet();
1177 IF_DEQUEUE(&sc->sc_hdlcq, m);
1178 splx(s);
1180 if(m)
1181 m_freem(m);
1182 else
1183 break;
1187 /*---------------------------------------------------------------------------*
1188 * setup the isdn_linktab for this driver
1189 *---------------------------------------------------------------------------*/
1190 static void
1191 rbch_set_linktab(void *softc, isdn_link_t *ilt)
1193 struct rbch_softc *sc = softc;
1194 sc->sc_ilt = ilt;
1197 /*---------------------------------------------------------------------------*
1198 * initialize this drivers linktab
1199 *---------------------------------------------------------------------------*/
1200 static void*
1201 rbch_get_softc(int unit)
1203 return &rbch_softc[unit];
1206 /*===========================================================================*/
1208 #endif /* NISDNBCHAN > 0 */