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