kernel - Remove D_KQFILTER flag
[dragonfly.git] / sys / net / i4b / driver / i4b_rbch.c
... / ...
CommitLineData
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.22 2006/12/22 23:44:55 swildner Exp $
32 *
33 * last edit-date: [Sat Aug 11 18:06:57 2001]
34 *
35 *---------------------------------------------------------------------------*/
36
37#include "use_i4brbch.h"
38
39#if NI4BRBCH > 0
40
41#include <sys/param.h>
42#include <sys/systm.h>
43
44#include <sys/conf.h>
45#include <sys/uio.h>
46#include <sys/kernel.h>
47#include <sys/mbuf.h>
48#include <sys/socket.h>
49#include <net/if.h>
50#include <sys/tty.h>
51#include <sys/thread2.h>
52#include <sys/vnode.h>
53
54#include <net/i4b/include/machine/i4b_ioctl.h>
55#include <net/i4b/include/machine/i4b_rbch_ioctl.h>
56#include <net/i4b/include/machine/i4b_debug.h>
57
58#include "../include/i4b_global.h"
59#include "../include/i4b_mbuf.h"
60#include "../include/i4b_l3l4.h"
61#include "../layer4/i4b_l4.h"
62
63#include <sys/event.h>
64#include <sys/filio.h>
65
66static drvr_link_t rbch_drvr_linktab[NI4BRBCH];
67static isdn_link_t *isdn_linktab[NI4BRBCH];
68
69#define I4BRBCHACCT 1 /* enable accounting messages */
70#define I4BRBCHACCTINTVL 2 /* accounting msg interval in secs */
71
72static struct rbch_softc {
73
74 int sc_unit; /* unit number */
75
76 int sc_devstate; /* state of driver */
77#define ST_IDLE 0x00
78#define ST_CONNECTED 0x01
79#define ST_ISOPEN 0x02
80#define ST_RDWAITDATA 0x04
81#define ST_WRWAITEMPTY 0x08
82#define ST_NOBLOCK 0x10
83
84 int sc_bprot; /* B-ch protocol used */
85
86 call_desc_t *sc_cd; /* Call Descriptor */
87
88 struct termios it_in;
89
90 struct ifqueue sc_hdlcq; /* hdlc read queue */
91#define I4BRBCHMAXQLEN 10
92
93 struct kqinfo kqp; /* select / poll / kevent */
94
95#if I4BRBCHACCT
96 struct callout sc_timeout;
97
98 int sc_iinb; /* isdn driver # of inbytes */
99 int sc_ioutb; /* isdn driver # of outbytes */
100 int sc_linb; /* last # of bytes rx'd */
101 int sc_loutb; /* last # of bytes tx'd */
102 int sc_fn; /* flag, first null acct */
103#endif
104} rbch_softc[NI4BRBCH];
105
106static void rbch_rx_data_rdy(int unit);
107static void rbch_tx_queue_empty(int unit);
108static void rbch_connect(int unit, void *cdp);
109static void rbch_disconnect(int unit, void *cdp);
110static void rbch_init_linktab(int unit);
111static void rbch_clrq(int unit);
112
113#define PDEVSTATIC static
114#define IOCTL_CMD_T u_long
115
116PDEVSTATIC d_open_t i4brbchopen;
117PDEVSTATIC d_close_t i4brbchclose;
118PDEVSTATIC d_read_t i4brbchread;
119PDEVSTATIC d_write_t i4brbchwrite;
120PDEVSTATIC d_ioctl_t i4brbchioctl;
121PDEVSTATIC d_kqfilter_t i4brbchkqfilter;
122
123PDEVSTATIC void i4brbchkfilt_detach(struct knote *);
124PDEVSTATIC int i4brbchkfilt_read(struct knote *, long);
125PDEVSTATIC int i4brbchkfilt_write(struct knote *, long);
126
127#define CDEV_MAJOR 57
128
129static struct dev_ops i4brbch_ops = {
130 { "i4brbch", CDEV_MAJOR, 0 },
131 .d_open = i4brbchopen,
132 .d_close = i4brbchclose,
133 .d_read = i4brbchread,
134 .d_write = i4brbchwrite,
135 .d_ioctl = i4brbchioctl,
136 .d_kqfilter = i4brbchkqfilter
137};
138
139static void i4brbchattach(void *);
140PSEUDO_SET(i4brbchattach, i4b_rbch);
141
142/*===========================================================================*
143 * DEVICE DRIVER ROUTINES
144 *===========================================================================*/
145
146/*---------------------------------------------------------------------------*
147 * interface attach routine
148 *---------------------------------------------------------------------------*/
149PDEVSTATIC void
150i4brbchattach(void *dummy)
151{
152 int i;
153
154#ifndef HACK_NO_PSEUDO_ATTACH_MSG
155 kprintf("i4brbch: %d raw B channel access device(s) attached\n", NI4BRBCH);
156#endif
157
158 for(i=0; i < NI4BRBCH; i++)
159 {
160 make_dev(&i4brbch_ops, i,
161 UID_ROOT, GID_WHEEL, 0600, "i4brbch%d", i);
162
163#if I4BRBCHACCT
164 callout_init(&rbch_softc[i].sc_timeout);
165 rbch_softc[i].sc_fn = 1;
166#endif
167 rbch_softc[i].sc_unit = i;
168 rbch_softc[i].sc_devstate = ST_IDLE;
169 rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
170 rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
171 termioschars(&rbch_softc[i].it_in);
172 rbch_init_linktab(i);
173 }
174}
175
176/*---------------------------------------------------------------------------*
177 * open rbch device
178 *---------------------------------------------------------------------------*/
179PDEVSTATIC int
180i4brbchopen(struct dev_open_args *ap)
181{
182 cdev_t dev = ap->a_head.a_dev;
183 int unit = minor(dev);
184
185 if(unit >= NI4BRBCH)
186 return(ENXIO);
187
188 if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
189 return(EBUSY);
190
191#if 0
192 rbch_clrq(unit);
193#endif
194
195 rbch_softc[unit].sc_devstate |= ST_ISOPEN;
196
197 NDBGL4(L4_RBCHDBG, "unit %d, open", unit);
198
199 return(0);
200}
201
202/*---------------------------------------------------------------------------*
203 * close rbch device
204 *---------------------------------------------------------------------------*/
205PDEVSTATIC int
206i4brbchclose(struct dev_close_args *ap)
207{
208 cdev_t dev = ap->a_head.a_dev;
209 int unit = minor(dev);
210 struct rbch_softc *sc = &rbch_softc[unit];
211
212 if(sc->sc_devstate & ST_CONNECTED)
213 i4b_l4_drvrdisc(BDRV_RBCH, unit);
214
215 sc->sc_devstate &= ~ST_ISOPEN;
216
217 rbch_clrq(unit);
218
219 NDBGL4(L4_RBCHDBG, "unit %d, closed", unit);
220
221 return(0);
222}
223
224/*---------------------------------------------------------------------------*
225 * read from rbch device
226 *---------------------------------------------------------------------------*/
227PDEVSTATIC int
228i4brbchread(struct dev_read_args *ap)
229{
230 cdev_t dev = ap->a_head.a_dev;
231 struct uio *uio = ap->a_uio;
232 struct mbuf *m;
233 int error = 0;
234 int unit = minor(dev);
235 struct ifqueue *iqp;
236 struct rbch_softc *sc = &rbch_softc[unit];
237
238 CRIT_VAR;
239
240 NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
241
242 CRIT_BEG;
243 if(!(sc->sc_devstate & ST_ISOPEN))
244 {
245 CRIT_END;
246 NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
247 return(EIO);
248 }
249
250 if((sc->sc_devstate & ST_NOBLOCK) || (ap->a_ioflag & IO_NDELAY))
251 {
252 if(!(sc->sc_devstate & ST_CONNECTED)) {
253 CRIT_END;
254 return(EWOULDBLOCK);
255 }
256
257 if(sc->sc_bprot == BPROT_RHDLC)
258 iqp = &sc->sc_hdlcq;
259 else
260 iqp = isdn_linktab[unit]->rx_queue;
261
262 if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
263 CRIT_END;
264 return(EWOULDBLOCK);
265 }
266 }
267 else
268 {
269 while(!(sc->sc_devstate & ST_CONNECTED))
270 {
271 NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
272
273 if((error = tsleep((caddr_t) &rbch_softc[unit],
274 PCATCH, "rrrbch", 0 )) != 0)
275 {
276 CRIT_END;
277 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
278 return(error);
279 }
280 }
281
282 if(sc->sc_bprot == BPROT_RHDLC)
283 iqp = &sc->sc_hdlcq;
284 else
285 iqp = isdn_linktab[unit]->rx_queue;
286
287 while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
288 {
289 sc->sc_devstate |= ST_RDWAITDATA;
290
291 NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
292
293 if((error = tsleep((caddr_t) &isdn_linktab[unit]->rx_queue,
294 PCATCH, "rrbch", 0 )) != 0)
295 {
296 CRIT_END;
297 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
298 sc->sc_devstate &= ~ST_RDWAITDATA;
299 return(error);
300 }
301 }
302 }
303
304 IF_DEQUEUE(iqp, m);
305
306 NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
307
308 if(m && m->m_len)
309 {
310 error = uiomove(m->m_data, m->m_len, uio);
311 }
312 else
313 {
314 NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
315 error = EIO;
316 }
317
318 if(m)
319 i4b_Bfreembuf(m);
320
321 CRIT_END;
322
323 return(error);
324}
325
326/*---------------------------------------------------------------------------*
327 * write to rbch device
328 *---------------------------------------------------------------------------*/
329PDEVSTATIC int
330i4brbchwrite(struct dev_write_args *ap)
331{
332 cdev_t dev = ap->a_head.a_dev;
333 struct uio *uio = ap->a_uio;
334 struct mbuf *m;
335 int error = 0;
336 int unit = minor(dev);
337 struct rbch_softc *sc = &rbch_softc[unit];
338
339 CRIT_VAR;
340
341 NDBGL4(L4_RBCHDBG, "unit %d, write", unit);
342
343 CRIT_BEG;
344 if(!(sc->sc_devstate & ST_ISOPEN))
345 {
346 NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
347 CRIT_END;
348 return(EIO);
349 }
350
351 if((sc->sc_devstate & ST_NOBLOCK) || (ap->a_ioflag & IO_NDELAY))
352 {
353 if(!(sc->sc_devstate & ST_CONNECTED)) {
354 CRIT_END;
355 return(EWOULDBLOCK);
356 }
357 if(IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
358 CRIT_END;
359 return(EWOULDBLOCK);
360 }
361 }
362 else
363 {
364 while(!(sc->sc_devstate & ST_CONNECTED))
365 {
366 NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
367
368 error = tsleep((caddr_t) &rbch_softc[unit],
369 PCATCH, "wrrbch", 0 );
370 if(error == ERESTART) {
371 CRIT_END;
372 return (ERESTART);
373 }
374 else if(error == EINTR)
375 {
376 CRIT_END;
377 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
378 return(EINTR);
379 }
380 else if(error)
381 {
382 CRIT_END;
383 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
384 return(error);
385 }
386 tsleep((caddr_t) &rbch_softc[unit], PCATCH, "xrbch", (hz*1));
387 }
388
389 while(IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
390 {
391 sc->sc_devstate |= ST_WRWAITEMPTY;
392
393 NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
394
395 if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue,
396 PCATCH, "wrbch", 0)) != 0) {
397 sc->sc_devstate &= ~ST_WRWAITEMPTY;
398 if(error == ERESTART)
399 {
400 CRIT_END;
401 return(ERESTART);
402 }
403 else if(error == EINTR)
404 {
405 CRIT_END;
406 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
407 return(error);
408 }
409 else if(error)
410 {
411 CRIT_END;
412 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
413 return(error);
414 }
415 }
416 }
417 }
418
419 if(!(sc->sc_devstate & ST_ISOPEN))
420 {
421 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
422 CRIT_END;
423 return(EIO);
424 }
425
426 if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
427 {
428 m->m_len = (int)szmin(BCH_MAX_DATALEN, uio->uio_resid);
429
430 NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
431
432 error = uiomove(m->m_data, (size_t)m->m_len, uio);
433
434 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
435 m_freem(m);
436 else
437 IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
438 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
439 }
440
441 CRIT_END;
442
443 return(error);
444}
445
446/*---------------------------------------------------------------------------*
447 * rbch device ioctl handlibg
448 *---------------------------------------------------------------------------*/
449PDEVSTATIC int
450i4brbchioctl(struct dev_ioctl_args *ap)
451{
452 cdev_t dev = ap->a_head.a_dev;
453 int error = 0;
454 int unit = minor(dev);
455 struct rbch_softc *sc = &rbch_softc[unit];
456
457 switch(ap->a_cmd)
458 {
459 case FIOASYNC: /* Set async mode */
460 if (*(int *)ap->a_data)
461 {
462 NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
463 }
464 else
465 {
466 NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
467 }
468 break;
469
470 case TIOCCDTR: /* Clear DTR */
471 if(sc->sc_devstate & ST_CONNECTED)
472 {
473 NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
474 i4b_l4_drvrdisc(BDRV_RBCH, unit);
475 }
476 break;
477
478 case I4B_RBCH_DIALOUT:
479 {
480 size_t l;
481
482 for (l = 0; l < TELNO_MAX && ((char *)ap->a_data)[l]; l++)
483 ;
484 if (l)
485 {
486 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout to %s", unit, (char *)ap->a_data);
487 i4b_l4_dialoutnumber(BDRV_RBCH, unit, l, (char *)ap->a_data);
488 break;
489 }
490 /* fall through to SDTR */
491 }
492
493 case TIOCSDTR: /* Set DTR */
494 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
495 i4b_l4_dialout(BDRV_RBCH, unit);
496 break;
497
498 case TIOCSETA: /* Set termios struct */
499 break;
500
501 case TIOCGETA: /* Get termios struct */
502 *(struct termios *)ap->a_data = sc->it_in;
503 break;
504
505 case TIOCMGET:
506 *(int *)ap->a_data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
507 if (sc->sc_devstate & ST_CONNECTED)
508 *(int *)ap->a_data |= TIOCM_CD;
509 break;
510
511 case I4B_RBCH_VR_REQ:
512 {
513 msg_vr_req_t *mvr;
514
515 mvr = (msg_vr_req_t *)ap->a_data;
516
517 mvr->version = VERSION;
518 mvr->release = REL;
519 mvr->step = STEP;
520 break;
521 }
522
523 default: /* Unknown stuff */
524 NDBGL4(L4_RBCHDBG, "unit %d, ioctl, unknown cmd %lx", unit, ap->a_cmd);
525 error = EINVAL;
526 break;
527 }
528 return(error);
529}
530
531/*---------------------------------------------------------------------------*
532 * device driver poll
533 *---------------------------------------------------------------------------*/
534static struct filterops i4brbchkfiltops_read =
535 { FILTEROP_ISFD, NULL, i4brbchkfilt_detach, i4brbchkfilt_read };
536static struct filterops i4brbchkfiltops_write =
537 { FILTEROP_ISFD, NULL, i4brbchkfilt_detach, i4brbchkfilt_write };
538
539PDEVSTATIC int
540i4brbchkqfilter(struct dev_kqfilter_args *ap)
541{
542 cdev_t dev = ap->a_head.a_dev;
543 int unit = minor(dev);
544 struct rbch_softc *sc = &rbch_softc[unit];
545 struct knote *kn = ap->a_kn;
546 struct klist *klist;
547
548 ap->a_result = 0;
549
550 switch (kn->kn_filter) {
551 case EVFILT_READ:
552 kn->kn_fop = &i4brbchkfiltops_read;
553 kn->kn_hook = (caddr_t)dev;
554 break;
555 case EVFILT_WRITE:
556 kn->kn_fop = &i4brbchkfiltops_write;
557 kn->kn_hook = (caddr_t)dev;
558 break;
559 default:
560 ap->a_result = EOPNOTSUPP;
561 return (0);
562 }
563
564 klist = &sc->kqp.ki_note;
565 knote_insert(klist, kn);
566
567 return (0);
568}
569
570PDEVSTATIC void
571i4brbchkfilt_detach(struct knote *kn)
572{
573 cdev_t dev = (cdev_t)kn->kn_hook;
574 int unit = minor(dev);
575 struct rbch_softc *sc = &rbch_softc[unit];
576 struct klist *klist;
577
578 klist = &sc->kqp.ki_note;
579 knote_remove(klist, kn);
580}
581
582PDEVSTATIC int
583i4brbchkfilt_read(struct knote *kn, long hint)
584{
585 cdev_t dev = (cdev_t)kn->kn_hook;
586 int unit = minor(dev);
587 struct rbch_softc *sc = &rbch_softc[unit];
588 int ready = 0;
589
590 crit_enter();
591
592 if (!(sc->sc_devstate & ST_ISOPEN)) {
593 crit_exit();
594 kn->kn_flags |= EV_ERROR;
595 kn->kn_data = EBADF;
596 return (0);
597 }
598
599 if (sc->sc_devstate & ST_CONNECTED) {
600 struct ifqueue *iqp;
601
602 if(sc->sc_bprot == BPROT_RHDLC)
603 iqp = &sc->sc_hdlcq;
604 else
605 iqp = isdn_linktab[unit]->rx_queue;
606
607 if(!IF_QEMPTY(iqp))
608 ready = 1;
609 }
610
611 crit_exit();
612
613 return (ready);
614}
615
616PDEVSTATIC int
617i4brbchkfilt_write(struct knote *kn, long hint)
618{
619 cdev_t dev = (cdev_t)kn->kn_hook;
620 int unit = minor(dev);
621 struct rbch_softc *sc = &rbch_softc[unit];
622 int ready = 0;
623
624 crit_enter();
625
626 if (!(sc->sc_devstate & ST_ISOPEN)) {
627 crit_exit();
628 kn->kn_flags |= EV_ERROR;
629 kn->kn_data = EBADF;
630 return (0);
631 }
632
633 /*
634 * Writes are OK if we are connected and the
635 * transmit queue can take them
636 */
637 if ((sc->sc_devstate & ST_CONNECTED) &&
638 !IF_QFULL(isdn_linktab[unit]->tx_queue))
639 {
640 ready = 1;
641 }
642
643 crit_exit();
644
645 return (ready);
646}
647
648#if I4BRBCHACCT
649/*---------------------------------------------------------------------------*
650 * watchdog routine
651 *---------------------------------------------------------------------------*/
652static void
653rbch_timeout(struct rbch_softc *sc)
654{
655 bchan_statistics_t bs;
656 int unit = sc->sc_unit;
657
658 /* get # of bytes in and out from the HSCX driver */
659
660 (*isdn_linktab[unit]->bch_stat)
661 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
662
663 sc->sc_ioutb += bs.outbytes;
664 sc->sc_iinb += bs.inbytes;
665
666 if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
667 {
668 int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
669 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
670
671 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
672 sc->sc_fn = 0;
673 else
674 sc->sc_fn = 1;
675
676 sc->sc_linb = sc->sc_iinb;
677 sc->sc_loutb = sc->sc_ioutb;
678
679 i4b_l4_accounting(BDRV_RBCH, unit, ACCT_DURING,
680 sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
681 }
682 callout_reset(&sc->sc_timeout, I4BRBCHACCTINTVL * hz,
683 (void *)rbch_timeout, sc);
684}
685#endif /* I4BRBCHACCT */
686
687/*===========================================================================*
688 * ISDN INTERFACE ROUTINES
689 *===========================================================================*/
690
691/*---------------------------------------------------------------------------*
692 * this routine is called from L4 handler at connect time
693 *---------------------------------------------------------------------------*/
694static void
695rbch_connect(int unit, void *cdp)
696{
697 call_desc_t *cd = (call_desc_t *)cdp;
698 struct rbch_softc *sc = &rbch_softc[unit];
699
700 sc->sc_bprot = cd->bprot;
701
702#if I4BRBCHACCT
703 if(sc->sc_bprot == BPROT_RHDLC)
704 {
705 sc->sc_iinb = 0;
706 sc->sc_ioutb = 0;
707 sc->sc_linb = 0;
708 sc->sc_loutb = 0;
709
710 callout_reset(&sc->sc_timeout, I4BRBCHACCTINTVL * hz,
711 (void *)rbch_timeout, sc);
712 }
713#endif
714 if(!(sc->sc_devstate & ST_CONNECTED))
715 {
716 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
717 sc->sc_devstate |= ST_CONNECTED;
718 sc->sc_cd = cdp;
719 wakeup((caddr_t)sc);
720 }
721}
722
723/*---------------------------------------------------------------------------*
724 * this routine is called from L4 handler at disconnect time
725 *---------------------------------------------------------------------------*/
726static void
727rbch_disconnect(int unit, void *cdp)
728{
729 call_desc_t *cd = (call_desc_t *)cdp;
730 struct rbch_softc *sc = &rbch_softc[unit];
731
732 CRIT_VAR;
733
734 if(cd != sc->sc_cd)
735 {
736 NDBGL4(L4_RBCHDBG, "rbch%d: channel %d not active",
737 cd->driver_unit, cd->channelid);
738 return;
739 }
740
741 CRIT_BEG;
742
743 NDBGL4(L4_RBCHDBG, "unit %d, disconnect", unit);
744
745 sc->sc_devstate &= ~ST_CONNECTED;
746
747 sc->sc_cd = NULL;
748
749#if I4BRBCHACCT
750 i4b_l4_accounting(BDRV_RBCH, unit, ACCT_FINAL,
751 sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
752 callout_stop(&sc->sc_timeout);
753#endif
754 CRIT_END;
755}
756
757/*---------------------------------------------------------------------------*
758 * feedback from daemon in case of dial problems
759 *---------------------------------------------------------------------------*/
760static void
761rbch_dialresponse(int unit, int status, cause_t cause)
762{
763}
764
765/*---------------------------------------------------------------------------*
766 * interface up/down
767 *---------------------------------------------------------------------------*/
768static void
769rbch_updown(int unit, int updown)
770{
771}
772
773/*---------------------------------------------------------------------------*
774 * this routine is called from the HSCX interrupt handler
775 * when a new frame (mbuf) has been received and is to be put on
776 * the rx queue.
777 *---------------------------------------------------------------------------*/
778static void
779rbch_rx_data_rdy(int unit)
780{
781 if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
782 {
783 struct mbuf *m;
784
785 if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
786 return;
787
788 m->m_pkthdr.len = m->m_len;
789
790 if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq)))
791 {
792 NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
793 m_freem(m);
794 }
795 else
796 {
797 IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m);
798 }
799 }
800
801 if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA)
802 {
803 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
804 rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
805 wakeup((caddr_t) &isdn_linktab[unit]->rx_queue);
806 }
807 else
808 {
809 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
810 }
811 KNOTE(&rbch_softc[unit].kqp.ki_note, 0);
812}
813
814/*---------------------------------------------------------------------------*
815 * this routine is called from the HSCX interrupt handler
816 * when the last frame has been sent out and there is no
817 * further frame (mbuf) in the tx queue.
818 *---------------------------------------------------------------------------*/
819static void
820rbch_tx_queue_empty(int unit)
821{
822 if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY)
823 {
824 NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
825 rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
826 wakeup((caddr_t) &isdn_linktab[unit]->tx_queue);
827 }
828 else
829 {
830 NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
831 }
832 KNOTE(&rbch_softc[unit].kqp.ki_note, 0);
833}
834
835/*---------------------------------------------------------------------------*
836 * this routine is called from the HSCX interrupt handler
837 * each time a packet is received or transmitted
838 *---------------------------------------------------------------------------*/
839static void
840rbch_activity(int unit, int rxtx)
841{
842 if (rbch_softc[unit].sc_cd)
843 rbch_softc[unit].sc_cd->last_active_time = SECOND;
844 KNOTE(&rbch_softc[unit].kqp.ki_note, 0);
845}
846
847/*---------------------------------------------------------------------------*
848 * clear an hdlc rx queue for a rbch unit
849 *---------------------------------------------------------------------------*/
850static void
851rbch_clrq(int unit)
852{
853 CRIT_VAR;
854
855 CRIT_BEG;
856 IF_DRAIN(&rbch_softc[unit].sc_hdlcq);
857 CRIT_END;
858}
859
860/*---------------------------------------------------------------------------*
861 * return this drivers linktab address
862 *---------------------------------------------------------------------------*/
863drvr_link_t *
864rbch_ret_linktab(int unit)
865{
866 rbch_init_linktab(unit);
867 return(&rbch_drvr_linktab[unit]);
868}
869
870/*---------------------------------------------------------------------------*
871 * setup the isdn_linktab for this driver
872 *---------------------------------------------------------------------------*/
873void
874rbch_set_linktab(int unit, isdn_link_t *ilt)
875{
876 isdn_linktab[unit] = ilt;
877}
878
879/*---------------------------------------------------------------------------*
880 * initialize this drivers linktab
881 *---------------------------------------------------------------------------*/
882static void
883rbch_init_linktab(int unit)
884{
885 rbch_drvr_linktab[unit].unit = unit;
886 rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy;
887 rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty;
888 rbch_drvr_linktab[unit].bch_activity = rbch_activity;
889 rbch_drvr_linktab[unit].line_connected = rbch_connect;
890 rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect;
891 rbch_drvr_linktab[unit].dial_response = rbch_dialresponse;
892 rbch_drvr_linktab[unit].updown_ind = rbch_updown;
893}
894
895/*===========================================================================*/
896
897#endif /* NI4BRBCH > 0 */