1 /*
2 * Copyright (c) 1997, 2000 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 * $Id: i4b_rbch.c,v 1.19 2006/11/16 01:33:49 christos Exp $
31 *
32 * $FreeBSD$
33 *
34 * last edit-date: [Fri Jan 5 11:33:47 2001]
35 *
36 *---------------------------------------------------------------------------*/
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: i4b_rbch.c,v 1.19 2006/11/16 01:33:49 christos Exp $");
40
41 #include "isdnbchan.h"
42
43 #if NISDNBCHAN > 0
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47
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>
56
57 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
58 #include <sys/callout.h>
59 #endif
60
61 #if defined (__NetBSD__) || defined (__OpenBSD__)
62 #define termioschars(t) memcpy((t)->c_cc, &ttydefchars, sizeof((t)->c_cc))
63 #endif
64
65 #ifdef __FreeBSD__
66
67 #if defined(__FreeBSD__) && __FreeBSD__ == 3
68 #include "opt_devfs.h"
69 #endif
70
71 #ifdef DEVFS
72 #include <sys/devfsext.h>
73 #endif
74
75 #endif /* __FreeBSD__ */
76
77 #ifdef __NetBSD__
78 #include <sys/filio.h>
79 #endif
80
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
90
91 #include <netisdn/i4b_global.h>
92 #include <netisdn/i4b_mbuf.h>
93 #include <netisdn/i4b_l3l4.h>
94
95 #include <netisdn/i4b_l4.h>
96
97 #ifdef __bsdi__
98 #include <sys/device.h>
99 #endif
100
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
108
109 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
110 #include <sys/filio.h>
111 #endif
112
113 #define I4BRBCHACCT 1 /* enable accounting messages */
114 #define I4BRBCHACCTINTVL 2 /* accounting msg interval in secs */
115
116 static struct rbch_softc {
117
118 int sc_unit; /* unit number */
119
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
127
128 int sc_bprot; /* B-ch protocol used */
129
130 call_desc_t *sc_cd; /* Call Descriptor */
131 isdn_link_t *sc_ilt; /* B-channel driver/state */
132
133 struct termios it_in;
134
135 struct ifqueue sc_hdlcq; /* hdlc read queue */
136 #define I4BRBCHMAXQLEN 10
137
138 struct selinfo selp; /* select / poll */
139
140 #if defined(__FreeBSD__) && __FreeBSD__ == 3
141 #ifdef DEVFS
142 void *devfs_token; /* device filesystem */
143 #endif
144 #endif
145
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
153
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];
161
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);
172
173
174 #ifndef __FreeBSD__
175 #define PDEVSTATIC /* - not static - */
176 #define IOCTL_CMD_T u_long
177 void isdnbchanattach __P((void));
178 int isdnbchanopen __P((dev_t dev, int flag, int fmt, struct lwp *l));
179 int isdnbchanclose __P((dev_t dev, int flag, int fmt, struct lwp *l));
180 int isdnbchanread __P((dev_t dev, struct uio *uio, int ioflag));
181 int isdnbchanwrite __P((dev_t dev, struct uio *uio, int ioflag));
182 int isdnbchanioctl __P((dev_t dev, IOCTL_CMD_T cmd, caddr_t arg, int flag, struct lwp* l));
183 #ifdef OS_USES_POLL
184 int isdnbchanpoll __P((dev_t dev, int events, struct lwp *l));
185 int isdnbchankqfilter __P((dev_t dev, struct knote *kn));
186 #else
187 PDEVSTATIC int isdnbchanselect __P((dev_t dev, int rw, struct lwp *l));
188 #endif
189 #endif
190
191 #ifdef __NetBSD__
192 const struct cdevsw isdnbchan_cdevsw = {
193 isdnbchanopen, isdnbchanclose, isdnbchanread, isdnbchanwrite,
194 isdnbchanioctl, nostop, notty, isdnbchanpoll, nommap, nokqfilter,
195 D_OTHER
196 };
197 #endif /* __NetBSD__ */
198
199 #if BSD > 199306 && defined(__FreeBSD__)
200 #define PDEVSTATIC static
201 #define IOCTL_CMD_T u_long
202
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;
208
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
216
217 #define CDEV_MAJOR 57
218
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
235 };
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
241 };
242 #endif
243
244 static void isdnbchanattach(void *);
245 PSEUDO_SET(isdnbchanattach, i4b_rbch);
246
247 /*===========================================================================*
248 * DEVICE DRIVER ROUTINES
249 *===========================================================================*/
250
251 /*---------------------------------------------------------------------------*
252 * initialization at kernel load time
253 *---------------------------------------------------------------------------*/
254 static void
255 isdnbchaninit(void *unused)
256 {
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
263 }
264
265 SYSINIT(isdnbchandev, SI_SUB_DRIVERS,
266 SI_ORDER_MIDDLE+CDEV_MAJOR, &isdnbchaninit, NULL);
267
268 #endif /* BSD > 199306 && defined(__FreeBSD__) */
269
270 #ifdef __bsdi__
271 int isdnbchanmatch(struct device *parent, struct cfdata *cf, void *aux);
272 void dummy_isdnbchanattach(struct device*, struct device *, void *);
273
274 #define CDEV_MAJOR 61
275
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
284 };
285
286 int
287 isdnbchanmatch(struct device *parent, struct cfdata *cf, void *aux)
288 {
289 printf("isdnbchanmatch: aux=0x%x\n", aux);
290 return 1;
291 }
292 void
293 dummy_isdnbchanattach(struct device *parent, struct device *self, void *aux)
294 {
295 printf("dummy_isdnbchanattach: aux=0x%x\n", aux);
296 }
297 #endif /* __bsdi__ */
298
299
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
312 };
313
314 static int rbch_driver_id = -1;
315
316 /*---------------------------------------------------------------------------*
317 * interface attach routine
318 *---------------------------------------------------------------------------*/
319 PDEVSTATIC void
320 #ifdef __FreeBSD__
321 isdnbchanattach(void *dummy)
322 #else
323 isdnbchanattach()
324 #endif
325 {
326 int i;
327
328 rbch_driver_id = isdn_l4_driver_attach("isdnbchan", NISDNBCHAN, &rbch_driver_functions);
329
330 for(i=0; i < NISDNBCHAN; i++)
331 {
332 #if defined(__FreeBSD__)
333 #if __FreeBSD__ == 3
334
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
341
342 #else
343 make_dev(&isdnbchan_cdevsw, i,
344 UID_ROOT, GID_WHEEL, 0600, "isdnbchan%d", i);
345 #endif
346 #endif
347
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);
354 #endif
355 rbch_softc[i].sc_fn = 1;
356 #endif
357 rbch_softc[i].sc_unit = i;
358 rbch_softc[i].sc_devstate = ST_IDLE;
359 rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
360 rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
361 termioschars(&rbch_softc[i].it_in);
362 }
363 }
364
365 /*---------------------------------------------------------------------------*
366 * open rbch device
367 *---------------------------------------------------------------------------*/
368 PDEVSTATIC int
369 isdnbchanopen(dev_t dev, int flag, int fmt,
370 struct lwp *l)
371 {
372 int unit = minor(dev);
373
374 if(unit >= NISDNBCHAN)
375 return(ENXIO);
376
377 if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
378 return(EBUSY);
379
380 #if 0
381 rbch_clrq(unit);
382 #endif
383
384 rbch_softc[unit].sc_devstate |= ST_ISOPEN;
385
386 NDBGL4(L4_RBCHDBG, "unit %d, open", unit);
387
388 return(0);
389 }
390
391 /*---------------------------------------------------------------------------*
392 * close rbch device
393 *---------------------------------------------------------------------------*/
394 PDEVSTATIC int
395 isdnbchanclose(dev_t dev, int flag, int fmt,
396 struct lwp *l)
397 {
398 int unit = minor(dev);
399 struct rbch_softc *sc = &rbch_softc[unit];
400
401 if(sc->sc_devstate & ST_CONNECTED)
402 i4b_l4_drvrdisc(sc->sc_cd->cdid);
403
404 sc->sc_devstate &= ~ST_ISOPEN;
405
406 rbch_clrq(sc);
407
408 NDBGL4(L4_RBCHDBG, "channel %d, closed", unit);
409
410 return(0);
411 }
412
413 /*---------------------------------------------------------------------------*
414 * read from rbch device
415 *---------------------------------------------------------------------------*/
416 PDEVSTATIC int
417 isdnbchanread(dev_t dev, struct uio *uio, int ioflag)
418 {
419 struct mbuf *m;
420 int error = 0;
421 int unit = minor(dev);
422 struct ifqueue *iqp;
423 struct rbch_softc *sc = &rbch_softc[unit];
424
425 int s;
426
427 NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
428
429 s = splnet();
430 if(!(sc->sc_devstate & ST_ISOPEN))
431 {
432 splx(s);
433 NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
434 return(EIO);
435 }
436
437 if((sc->sc_devstate & ST_NOBLOCK))
438 {
439 if(!(sc->sc_devstate & ST_CONNECTED)) {
440 splx(s);
441 return(EWOULDBLOCK);
442 }
443
444 if(sc->sc_bprot == BPROT_RHDLC)
445 iqp = &sc->sc_hdlcq;
446 else
447 iqp = sc->sc_ilt->rx_queue;
448
449 if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
450 splx(s);
451 return(EWOULDBLOCK);
452 }
453 }
454 else
455 {
456 while(!(sc->sc_devstate & ST_CONNECTED))
457 {
458 NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
459
460 if((error = tsleep((caddr_t) &rbch_softc[unit],
461 TTIPRI | PCATCH,
462 "rrrbch", 0 )) != 0)
463 {
464 splx(s);
465 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
466 return(error);
467 }
468 }
469
470 if(sc->sc_bprot == BPROT_RHDLC)
471 iqp = &sc->sc_hdlcq;
472 else
473 iqp = sc->sc_ilt->rx_queue;
474
475 while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
476 {
477 sc->sc_devstate |= ST_RDWAITDATA;
478
479 NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
480
481 if((error = tsleep((caddr_t) &sc->sc_ilt->rx_queue,
482 TTIPRI | PCATCH,
483 "rrbch", 0 )) != 0)
484 {
485 splx(s);
486 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
487 sc->sc_devstate &= ~ST_RDWAITDATA;
488 return(error);
489 } else if (!(sc->sc_devstate & ST_CONNECTED)) {
490 splx(s);
491 return 0;
492 }
493 }
494 }
495
496 IF_DEQUEUE(iqp, m);
497
498 NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
499
500 if(m && m->m_len)
501 {
502 error = uiomove(m->m_data, m->m_len, uio);
503 }
504 else
505 {
506 NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
507 error = EIO;
508 }
509
510 if(m)
511 i4b_Bfreembuf(m);
512
513 splx(s);
514
515 return(error);
516 }
517
518 /*---------------------------------------------------------------------------*
519 * write to rbch device
520 *---------------------------------------------------------------------------*/
521 PDEVSTATIC int
522 isdnbchanwrite(dev_t dev, struct uio * uio, int ioflag)
523 {
524 struct mbuf *m;
525 int error = 0;
526 int unit = minor(dev);
527 struct rbch_softc *sc = &rbch_softc[unit];
528
529 int s;
530
531 NDBGL4(L4_RBCHDBG, "unit %d, write", unit);
532
533 s = splnet();
534 if(!(sc->sc_devstate & ST_ISOPEN))
535 {
536 NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
537 splx(s);
538 return(EIO);
539 }
540
541 if((sc->sc_devstate & ST_NOBLOCK))
542 {
543 if(!(sc->sc_devstate & ST_CONNECTED)) {
544 splx(s);
545 return(EWOULDBLOCK);
546 }
547 if(IF_QFULL(sc->sc_ilt->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
548 splx(s);
549 return(EWOULDBLOCK);
550 }
551 }
552 else
553 {
554 while(!(sc->sc_devstate & ST_CONNECTED))
555 {
556 NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
557
558 error = tsleep((caddr_t) &rbch_softc[unit],
559 TTIPRI | PCATCH,
560 "wrrbch", 0 );
561 if(error == ERESTART) {
562 splx(s);
563 return (ERESTART);
564 }
565 else if(error == EINTR)
566 {
567 splx(s);
568 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
569 return(EINTR);
570 }
571 else if(error)
572 {
573 splx(s);
574 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
575 return(error);
576 }
577 tsleep((caddr_t) &rbch_softc[unit], TTIPRI | PCATCH, "xrbch", (hz*1));
578 }
579
580 while(IF_QFULL(sc->sc_ilt->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
581 {
582 sc->sc_devstate |= ST_WRWAITEMPTY;
583
584 NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
585
586 if ((error = tsleep((caddr_t) &sc->sc_ilt->tx_queue,
587 TTIPRI | PCATCH,
588 "wrbch", 0)) != 0) {
589 sc->sc_devstate &= ~ST_WRWAITEMPTY;
590 if(error == ERESTART)
591 {
592 splx(s);
593 return(ERESTART);
594 }
595 else if(error == EINTR)
596 {
597 splx(s);
598 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
599 return(error);
600 }
601 else if(error)
602 {
603 splx(s);
604 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
605 return(error);
606 }
607 else if (!(sc->sc_devstate & ST_CONNECTED)) {
608 splx(s);
609 return 0;
610 }
611 }
612 }
613 }
614
615 if(!(sc->sc_devstate & ST_ISOPEN))
616 {
617 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
618 splx(s);
619 return(EIO);
620 }
621
622 if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
623 {
624 m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
625
626 NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
627
628 error = uiomove(m->m_data, m->m_len, uio);
629
630 if(IF_QFULL(sc->sc_ilt->tx_queue))
631 {
632 m_freem(m);
633 }
634 else
635 {
636 IF_ENQUEUE(sc->sc_ilt->tx_queue, m);
637 }
638
639 (*sc->sc_ilt->bchannel_driver->bch_tx_start)(sc->sc_ilt->l1token, sc->sc_ilt->channel);
640 }
641
642 splx(s);
643
644 return(error);
645 }
646
647 /*---------------------------------------------------------------------------*
648 * rbch device ioctl handlibg
649 *---------------------------------------------------------------------------*/
650 PDEVSTATIC int
651 isdnbchanioctl(dev_t dev, IOCTL_CMD_T cmd, caddr_t data, int flag,
652 struct lwp *l)
653 {
654 int error = 0;
655 int unit = minor(dev);
656 struct rbch_softc *sc = &rbch_softc[unit];
657
658 switch(cmd)
659 {
660 case FIOASYNC: /* Set async mode */
661 if (*(int *)data)
662 {
663 NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
664 }
665 else
666 {
667 NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
668 }
669 break;
670
671 case FIONBIO:
672 if (*(int *)data)
673 {
674 NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit);
675 sc->sc_devstate |= ST_NOBLOCK;
676 }
677 else
678 {
679 NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit);
680 sc->sc_devstate &= ~ST_NOBLOCK;
681 }
682 break;
683
684 case TIOCCDTR: /* Clear DTR */
685 if(sc->sc_devstate & ST_CONNECTED)
686 {
687 NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
688 i4b_l4_drvrdisc(sc->sc_cd->cdid);
689 }
690 break;
691
692 case I4B_RBCH_DIALOUT:
693 {
694 size_t x;
695
696 for (x = 0; x < TELNO_MAX && ((char *)data)[x]; x++)
697 ;
698 if (x)
699 {
700 NDBGL4(L4_RBCHDBG, "%d, attempting dialout to %s", unit, (char *)data);
701 i4b_l4_dialoutnumber(rbch_driver_id, unit, x, (char *)data);
702 break;
703 }
704 /* fall through to SDTR */
705 }
706
707 case TIOCSDTR: /* Set DTR */
708 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
709 i4b_l4_dialout(rbch_driver_id, unit);
710 break;
711
712 case TIOCSETA: /* Set termios struct */
713 break;
714
715 case TIOCGETA: /* Get termios struct */
716 *(struct termios *)data = sc->it_in;
717 break;
718
719 case TIOCMGET:
720 *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
721 if (sc->sc_devstate & ST_CONNECTED)
722 *(int *)data |= TIOCM_CD;
723 break;
724
725 case I4B_RBCH_VR_REQ:
726 {
727 msg_vr_req_t *mvr;
728
729 mvr = (msg_vr_req_t *)data;
730
731 mvr->version = VERSION;
732 mvr->release = REL;
733 mvr->step = STEP;
734 break;
735 }
736
737 default: /* Unknown stuff */
738 NDBGL4(L4_RBCHDBG, "(minor=%d) ioctl, unknown cmd %lx", unit, (u_long)cmd);
739 error = EINVAL;
740 break;
741 }
742 return(error);
743 }
744
745 #ifdef OS_USES_POLL
746
747 /*---------------------------------------------------------------------------*
748 * device driver poll
749 *---------------------------------------------------------------------------*/
750 PDEVSTATIC int
751 isdnbchanpoll(dev_t dev, int events, struct lwp *l)
752 {
753 int revents = 0; /* Events we found */
754 int s;
755 int unit = minor(dev);
756 struct rbch_softc *sc = &rbch_softc[unit];
757
758 /* We can't check for anything but IN or OUT */
759
760 s = splhigh();
761
762 if(!(sc->sc_devstate & ST_ISOPEN))
763 {
764 splx(s);
765 return(POLLNVAL);
766 }
767
768 /*
769 * Writes are OK if we are connected and the
770 * transmit queue can take them
771 */
772
773 if((events & (POLLOUT|POLLWRNORM)) &&
774 (sc->sc_devstate & ST_CONNECTED) &&
775 !IF_QFULL(sc->sc_ilt->tx_queue))
776 {
777 revents |= (events & (POLLOUT|POLLWRNORM));
778 }
779
780 /* ... while reads are OK if we have any data */
781
782 if((events & (POLLIN|POLLRDNORM)) &&
783 (sc->sc_devstate & ST_CONNECTED))
784 {
785 struct ifqueue *iqp;
786
787 if(sc->sc_bprot == BPROT_RHDLC)
788 iqp = &sc->sc_hdlcq;
789 else
790 iqp = sc->sc_ilt->rx_queue;
791
792 if(!IF_QEMPTY(iqp))
793 revents |= (events & (POLLIN|POLLRDNORM));
794 }
795
796 if(revents == 0)
797 selrecord(l, &sc->selp);
798
799 splx(s);
800 return(revents);
801 }
802
803 static void
804 filt_i4brbchdetach(struct knote *kn)
805 {
806 struct rbch_softc *sc = kn->kn_hook;
807 int s;
808
809 s = splhigh();
810 SLIST_REMOVE(&sc->selp.sel_klist, kn, knote, kn_selnext);
811 splx(s);
812 }
813
814 static int
815 filt_i4brbchread(struct knote *kn, long hint)
816 {
817 struct rbch_softc *sc = kn->kn_hook;
818 struct ifqueue *iqp;
819
820 if ((sc->sc_devstate & ST_CONNECTED) == 0)
821 return (0);
822
823 if (sc->sc_bprot == BPROT_RHDLC)
824 iqp = &sc->sc_hdlcq;
825 else
826 iqp = sc->sc_ilt->rx_queue;
827
828 if (IF_QEMPTY(iqp))
829 return (0);
830
831 kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
832 return (1);
833 }
834
835 static const struct filterops i4brbchread_filtops =
836 { 1, NULL, filt_i4brbchdetach, filt_i4brbchread };
837
838 static int
839 filt_i4brbchwrite(struct knote *kn, long hint)
840 {
841 struct rbch_softc *sc = kn->kn_hook;
842
843 if ((sc->sc_devstate & ST_CONNECTED) == 0)
844 return (0);
845
846 if (IF_QFULL(sc->sc_ilt->tx_queue))
847 return (0);
848
849 kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
850 return (1);
851 }
852
853 static const struct filterops i4brbchwrite_filtops =
854 { 1, NULL, filt_i4brbchdetach, filt_i4brbchwrite };
855
856 int
857 isdnbchankqfilter(dev_t dev, struct knote *kn)
858 {
859 struct rbch_softc *sc = &rbch_softc[minor(dev)];
860 struct klist *klist;
861 int s;
862
863 switch (kn->kn_filter) {
864 case EVFILT_READ:
865 klist = &sc->selp.sel_klist;
866 kn->kn_fop = &i4brbchread_filtops;
867 break;
868
869 case EVFILT_WRITE:
870 klist = &sc->selp.sel_klist;
871 kn->kn_fop = &i4brbchwrite_filtops;
872 break;
873
874 default:
875 return (1);
876 }
877
878 kn->kn_hook = sc;
879
880 s = splhigh();
881 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
882 splx(s);
883
884 return (0);
885 }
886
887 #else /* OS_USES_POLL */
888
889 /*---------------------------------------------------------------------------*
890 * device driver select
891 *---------------------------------------------------------------------------*/
892 PDEVSTATIC int
893 isdnbchanselect(dev_t dev, int rw, struct lwp *l)
894 {
895 int unit = minor(dev);
896 struct rbch_softc *sc = &rbch_softc[unit];
897 int s;
898
899 s = splhigh();
900
901 if(!(sc->sc_devstate & ST_ISOPEN))
902 {
903 splx(s);
904 NDBGL4(L4_RBCHDBG, "(minor=%d) not open anymore", unit);
905 return(1);
906 }
907
908 if(sc->sc_devstate & ST_CONNECTED)
909 {
910 struct ifqueue *iqp;
911
912 switch(rw)
913 {
914 case FREAD:
915 if(sc->sc_bprot == BPROT_RHDLC)
916 iqp = &sc->sc_hdlcq;
917 else
918 iqp = isdn_linktab[unit]->rx_queue;
919
920 if(!IF_QEMPTY(iqp))
921 {
922 splx(s);
923 return(1);
924 }
925 break;
926
927 case FWRITE:
928 if(!IF_QFULL(isdn_linktab[unit]->rx_queue))
929 {
930 splx(s);
931 return(1);
932 }
933 break;
934
935 default:
936 splx(s);
937 return 0;
938 }
939 }
940 selrecord(l, &sc->selp);
941 splx(s);
942 return(0);
943 }
944
945 #endif /* OS_USES_POLL */
946
947 #if I4BRBCHACCT
948 /*---------------------------------------------------------------------------*
949 * watchdog routine
950 *---------------------------------------------------------------------------*/
951 static void
952 rbch_timeout(struct rbch_softc *sc)
953 {
954 bchan_statistics_t bs;
955
956 /* get # of bytes in and out from the HSCX driver */
957
958 (*sc->sc_ilt->bchannel_driver->bch_stat)
959 (sc->sc_ilt->l1token, sc->sc_ilt->channel, &bs);
960
961 sc->sc_ioutb += bs.outbytes;
962 sc->sc_iinb += bs.inbytes;
963
964 if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
965 {
966 int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
967 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
968
969 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
970 sc->sc_fn = 0;
971 else
972 sc->sc_fn = 1;
973
974 sc->sc_linb = sc->sc_iinb;
975 sc->sc_loutb = sc->sc_ioutb;
976
977 if (sc->sc_cd)
978 i4b_l4_accounting(sc->sc_cd->cdid, ACCT_DURING,
979 sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
980 }
981 START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
982 }
983 #endif /* I4BRBCHACCT */
984
985 /*===========================================================================*
986 * ISDN INTERFACE ROUTINES
987 *===========================================================================*/
988
989 /*---------------------------------------------------------------------------*
990 * this routine is called from L4 handler at connect time
991 *---------------------------------------------------------------------------*/
992 static void
993 rbch_connect(void *softc, void *cdp)
994 {
995 call_desc_t *cd = (call_desc_t *)cdp;
996 struct rbch_softc *sc = softc;
997
998 sc->sc_bprot = cd->bprot;
999
1000 #if I4BRBCHACCT
1001 if(sc->sc_bprot == BPROT_RHDLC)
1002 {
1003 sc->sc_iinb = 0;
1004 sc->sc_ioutb = 0;
1005 sc->sc_linb = 0;
1006 sc->sc_loutb = 0;
1007
1008 START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
1009 }
1010 #endif
1011 if(!(sc->sc_devstate & ST_CONNECTED))
1012 {
1013 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d, wakeup",
1014 cd->channelid, cd->isdnif);
1015 sc->sc_devstate |= ST_CONNECTED;
1016 sc->sc_cd = cdp;
1017 wakeup((caddr_t)sc);
1018 selwakeup(&sc->selp);
1019 }
1020 }
1021
1022 /*---------------------------------------------------------------------------*
1023 * this routine is called from L4 handler at disconnect time
1024 *---------------------------------------------------------------------------*/
1025 static void
1026 rbch_disconnect(void *softc, void *cdp)
1027 {
1028 call_desc_t *cd = cdp;
1029 struct rbch_softc *sc = softc;
1030
1031 int s;
1032
1033 if(cd != sc->sc_cd)
1034 {
1035 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d not active",
1036 cd->channelid, cd->isdnif);
1037 return;
1038 }
1039
1040 s = splnet();
1041
1042 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d disconnect",
1043 cd->channelid, cd->isdnif);
1044
1045 sc->sc_devstate &= ~ST_CONNECTED;
1046
1047 #if I4BRBCHACCT
1048 if (sc->sc_cd)
1049 i4b_l4_accounting(sc->sc_cd->cdid, ACCT_FINAL,
1050 sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
1051
1052 STOP_TIMER(sc->sc_callout, rbch_timeout, sc);
1053 #endif
1054
1055 sc->sc_cd = NULL;
1056 if (sc->sc_devstate & ST_RDWAITDATA)
1057 wakeup(&sc->sc_ilt->rx_queue);
1058 if (sc->sc_devstate & ST_WRWAITEMPTY)
1059 wakeup(&sc->sc_ilt->tx_queue);
1060
1061 splx(s);
1062
1063 selwakeup(&sc->selp);
1064 }
1065
1066 /*---------------------------------------------------------------------------*
1067 * feedback from daemon in case of dial problems
1068 *---------------------------------------------------------------------------*/
1069 static void
1070 rbch_dialresponse(void *softc, int status,
1071 cause_t cause)
1072 {
1073 }
1074
1075 /*---------------------------------------------------------------------------*
1076 * interface up/down
1077 *---------------------------------------------------------------------------*/
1078 static void
1079 rbch_updown(void *softc, int updown)
1080 {
1081 }
1082
1083 /*---------------------------------------------------------------------------*
1084 * this routine is called from the HSCX interrupt handler
1085 * when a new frame (mbuf) has been received and is to be put on
1086 * the rx queue.
1087 *---------------------------------------------------------------------------*/
1088 static void
1089 rbch_rx_data_rdy(void *softc)
1090 {
1091 struct rbch_softc *sc = softc;
1092
1093 if(sc->sc_bprot == BPROT_RHDLC)
1094 {
1095 register struct mbuf *m;
1096
1097 if((m = *sc->sc_ilt->rx_mbuf) == NULL)
1098 return;
1099
1100 m->m_pkthdr.len = m->m_len;
1101
1102 if(IF_QFULL(&sc->sc_hdlcq))
1103 {
1104 NDBGL4(L4_RBCHDBG, "(minor=%d) hdlc rx queue full!", sc->sc_unit);
1105 m_freem(m);
1106 }
1107 else
1108 {
1109 IF_ENQUEUE(&sc->sc_hdlcq, m);
1110 }
1111 }
1112
1113 if(sc->sc_devstate & ST_RDWAITDATA)
1114 {
1115 NDBGL4(L4_RBCHDBG, "(minor=%d) wakeup", sc->sc_unit);
1116 sc->sc_devstate &= ~ST_RDWAITDATA;
1117 wakeup((caddr_t) &sc->sc_ilt->rx_queue);
1118 }
1119 else
1120 {
1121 NDBGL4(L4_RBCHDBG, "(minor=%d) NO wakeup", sc->sc_unit);
1122 }
1123 selnotify(&sc->selp, 0);
1124 }
1125
1126 /*---------------------------------------------------------------------------*
1127 * this routine is called from the HSCX interrupt handler
1128 * when the last frame has been sent out and there is no
1129 * further frame (mbuf) in the tx queue.
1130 *---------------------------------------------------------------------------*/
1131 static void
1132 rbch_tx_queue_empty(void *softc)
1133 {
1134 struct rbch_softc *sc = softc;
1135
1136 if(sc->sc_devstate & ST_WRWAITEMPTY)
1137 {
1138 NDBGL4(L4_RBCHDBG, "(minor=%d): wakeup", sc->sc_unit);
1139 sc->sc_devstate &= ~ST_WRWAITEMPTY;
1140 wakeup((caddr_t) &sc->sc_ilt->tx_queue);
1141 }
1142 else
1143 {
1144 NDBGL4(L4_RBCHDBG, "(minor=%d) NO wakeup", sc->sc_unit);
1145 }
1146 selnotify(&sc->selp, 0);
1147 }
1148
1149 /*---------------------------------------------------------------------------*
1150 * this routine is called from the HSCX interrupt handler
1151 * each time a packet is received or transmitted
1152 *---------------------------------------------------------------------------*/
1153 static void
1154 rbch_activity(void *softc, int rxtx)
1155 {
1156 struct rbch_softc *sc = softc;
1157
1158 if (sc->sc_cd)
1159 sc->sc_cd->last_active_time = SECOND;
1160 selnotify(&sc->selp, 0);
1161 }
1162
1163 /*---------------------------------------------------------------------------*
1164 * clear an hdlc rx queue for a rbch unit
1165 *---------------------------------------------------------------------------*/
1166 static void
1167 rbch_clrq(void *softc)
1168 {
1169 struct rbch_softc *sc = softc;
1170 struct mbuf *m;
1171 int s;
1172
1173 for(;;)
1174 {
1175 s = splnet();
1176 IF_DEQUEUE(&sc->sc_hdlcq, m);
1177 splx(s);
1178
1179 if(m)
1180 m_freem(m);
1181 else
1182 break;
1183 }
1184 }
1185
1186 /*---------------------------------------------------------------------------*
1187 * setup the isdn_linktab for this driver
1188 *---------------------------------------------------------------------------*/
1189 static void
1190 rbch_set_linktab(void *softc, isdn_link_t *ilt)
1191 {
1192 struct rbch_softc *sc = softc;
1193 sc->sc_ilt = ilt;
1194 }
1195
1196 /*---------------------------------------------------------------------------*
1197 * initialize this drivers linktab
1198 *---------------------------------------------------------------------------*/
1199 static void*
1200 rbch_get_softc(int unit)
1201 {
1202 return &rbch_softc[unit];
1203 }
1204
1205 /*===========================================================================*/
1206
1207 #endif /* NISDNBCHAN > 0 */
Cache object: 724a32aee70e6f2fb5d5ba826b2f5ac3
|