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