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.23 2008/03/01 14:16:52 rmind 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.23 2008/03/01 14:16:52 rmind 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, void *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, 0);
354 selinit(&rbch_softc[i].selp);
355 #endif
356 rbch_softc[i].sc_fn = 1;
357 #endif
358 rbch_softc[i].sc_unit = i;
359 rbch_softc[i].sc_devstate = ST_IDLE;
360 rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
361 rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
362 termioschars(&rbch_softc[i].it_in);
363 }
364 }
365
366 /*---------------------------------------------------------------------------*
367 * open rbch device
368 *---------------------------------------------------------------------------*/
369 PDEVSTATIC int
370 isdnbchanopen(dev_t dev, int flag, int fmt,
371 struct lwp *l)
372 {
373 int unit = minor(dev);
374
375 if(unit >= NISDNBCHAN)
376 return(ENXIO);
377
378 if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
379 return(EBUSY);
380
381 #if 0
382 rbch_clrq(unit);
383 #endif
384
385 rbch_softc[unit].sc_devstate |= ST_ISOPEN;
386
387 NDBGL4(L4_RBCHDBG, "unit %d, open", unit);
388
389 return(0);
390 }
391
392 /*---------------------------------------------------------------------------*
393 * close rbch device
394 *---------------------------------------------------------------------------*/
395 PDEVSTATIC int
396 isdnbchanclose(dev_t dev, int flag, int fmt,
397 struct lwp *l)
398 {
399 int unit = minor(dev);
400 struct rbch_softc *sc = &rbch_softc[unit];
401
402 if(sc->sc_devstate & ST_CONNECTED)
403 i4b_l4_drvrdisc(sc->sc_cd->cdid);
404
405 sc->sc_devstate &= ~ST_ISOPEN;
406
407 rbch_clrq(sc);
408
409 NDBGL4(L4_RBCHDBG, "channel %d, closed", unit);
410
411 return(0);
412 }
413
414 /*---------------------------------------------------------------------------*
415 * read from rbch device
416 *---------------------------------------------------------------------------*/
417 PDEVSTATIC int
418 isdnbchanread(dev_t dev, struct uio *uio, int ioflag)
419 {
420 struct mbuf *m;
421 int error = 0;
422 int unit = minor(dev);
423 struct ifqueue *iqp;
424 struct rbch_softc *sc = &rbch_softc[unit];
425
426 int s;
427
428 NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
429
430 s = splnet();
431 if(!(sc->sc_devstate & ST_ISOPEN))
432 {
433 splx(s);
434 NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
435 return(EIO);
436 }
437
438 if((sc->sc_devstate & ST_NOBLOCK))
439 {
440 if(!(sc->sc_devstate & ST_CONNECTED)) {
441 splx(s);
442 return(EWOULDBLOCK);
443 }
444
445 if(sc->sc_bprot == BPROT_RHDLC)
446 iqp = &sc->sc_hdlcq;
447 else
448 iqp = sc->sc_ilt->rx_queue;
449
450 if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
451 splx(s);
452 return(EWOULDBLOCK);
453 }
454 }
455 else
456 {
457 while(!(sc->sc_devstate & ST_CONNECTED))
458 {
459 NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
460
461 if((error = tsleep((void *) &rbch_softc[unit],
462 TTIPRI | PCATCH,
463 "rrrbch", 0 )) != 0)
464 {
465 splx(s);
466 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
467 return(error);
468 }
469 }
470
471 if(sc->sc_bprot == BPROT_RHDLC)
472 iqp = &sc->sc_hdlcq;
473 else
474 iqp = sc->sc_ilt->rx_queue;
475
476 while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
477 {
478 sc->sc_devstate |= ST_RDWAITDATA;
479
480 NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
481
482 if((error = tsleep((void *) &sc->sc_ilt->rx_queue,
483 TTIPRI | PCATCH,
484 "rrbch", 0 )) != 0)
485 {
486 splx(s);
487 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
488 sc->sc_devstate &= ~ST_RDWAITDATA;
489 return(error);
490 } else if (!(sc->sc_devstate & ST_CONNECTED)) {
491 splx(s);
492 return 0;
493 }
494 }
495 }
496
497 IF_DEQUEUE(iqp, m);
498
499 NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
500
501 if(m && m->m_len)
502 {
503 error = uiomove(m->m_data, m->m_len, uio);
504 }
505 else
506 {
507 NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
508 error = EIO;
509 }
510
511 if(m)
512 i4b_Bfreembuf(m);
513
514 splx(s);
515
516 return(error);
517 }
518
519 /*---------------------------------------------------------------------------*
520 * write to rbch device
521 *---------------------------------------------------------------------------*/
522 PDEVSTATIC int
523 isdnbchanwrite(dev_t dev, struct uio * uio, int ioflag)
524 {
525 struct mbuf *m;
526 int error = 0;
527 int unit = minor(dev);
528 struct rbch_softc *sc = &rbch_softc[unit];
529
530 int s;
531
532 NDBGL4(L4_RBCHDBG, "unit %d, write", unit);
533
534 s = splnet();
535 if(!(sc->sc_devstate & ST_ISOPEN))
536 {
537 NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
538 splx(s);
539 return(EIO);
540 }
541
542 if((sc->sc_devstate & ST_NOBLOCK))
543 {
544 if(!(sc->sc_devstate & ST_CONNECTED)) {
545 splx(s);
546 return(EWOULDBLOCK);
547 }
548 if(IF_QFULL(sc->sc_ilt->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
549 splx(s);
550 return(EWOULDBLOCK);
551 }
552 }
553 else
554 {
555 while(!(sc->sc_devstate & ST_CONNECTED))
556 {
557 NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
558
559 error = tsleep((void *) &rbch_softc[unit],
560 TTIPRI | PCATCH,
561 "wrrbch", 0 );
562 if(error == ERESTART) {
563 splx(s);
564 return (ERESTART);
565 }
566 else if(error == EINTR)
567 {
568 splx(s);
569 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
570 return(EINTR);
571 }
572 else if(error)
573 {
574 splx(s);
575 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
576 return(error);
577 }
578 tsleep((void *) &rbch_softc[unit], TTIPRI | PCATCH, "xrbch", (hz*1));
579 }
580
581 while(IF_QFULL(sc->sc_ilt->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
582 {
583 sc->sc_devstate |= ST_WRWAITEMPTY;
584
585 NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
586
587 if ((error = tsleep((void *) &sc->sc_ilt->tx_queue,
588 TTIPRI | PCATCH,
589 "wrbch", 0)) != 0) {
590 sc->sc_devstate &= ~ST_WRWAITEMPTY;
591 if(error == ERESTART)
592 {
593 splx(s);
594 return(ERESTART);
595 }
596 else if(error == EINTR)
597 {
598 splx(s);
599 NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
600 return(error);
601 }
602 else if(error)
603 {
604 splx(s);
605 NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
606 return(error);
607 }
608 else if (!(sc->sc_devstate & ST_CONNECTED)) {
609 splx(s);
610 return 0;
611 }
612 }
613 }
614 }
615
616 if(!(sc->sc_devstate & ST_ISOPEN))
617 {
618 NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
619 splx(s);
620 return(EIO);
621 }
622
623 if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
624 {
625 m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
626
627 NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
628
629 error = uiomove(m->m_data, m->m_len, uio);
630
631 if(IF_QFULL(sc->sc_ilt->tx_queue))
632 {
633 m_freem(m);
634 }
635 else
636 {
637 IF_ENQUEUE(sc->sc_ilt->tx_queue, m);
638 }
639
640 (*sc->sc_ilt->bchannel_driver->bch_tx_start)(sc->sc_ilt->l1token, sc->sc_ilt->channel);
641 }
642
643 splx(s);
644
645 return(error);
646 }
647
648 /*---------------------------------------------------------------------------*
649 * rbch device ioctl handlibg
650 *---------------------------------------------------------------------------*/
651 PDEVSTATIC int
652 isdnbchanioctl(dev_t dev, IOCTL_CMD_T cmd, void *data, int flag,
653 struct lwp *l)
654 {
655 int error = 0;
656 int unit = minor(dev);
657 struct rbch_softc *sc = &rbch_softc[unit];
658
659 switch(cmd)
660 {
661 case FIOASYNC: /* Set async mode */
662 if (*(int *)data)
663 {
664 NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
665 }
666 else
667 {
668 NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
669 }
670 break;
671
672 case FIONBIO:
673 if (*(int *)data)
674 {
675 NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit);
676 sc->sc_devstate |= ST_NOBLOCK;
677 }
678 else
679 {
680 NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit);
681 sc->sc_devstate &= ~ST_NOBLOCK;
682 }
683 break;
684
685 case TIOCCDTR: /* Clear DTR */
686 if(sc->sc_devstate & ST_CONNECTED)
687 {
688 NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
689 i4b_l4_drvrdisc(sc->sc_cd->cdid);
690 }
691 break;
692
693 case I4B_RBCH_DIALOUT:
694 {
695 size_t x;
696
697 for (x = 0; x < TELNO_MAX && ((char *)data)[x]; x++)
698 ;
699 if (x)
700 {
701 NDBGL4(L4_RBCHDBG, "%d, attempting dialout to %s", unit, (char *)data);
702 i4b_l4_dialoutnumber(rbch_driver_id, unit, x, (char *)data);
703 break;
704 }
705 /* fall through to SDTR */
706 }
707
708 case TIOCSDTR: /* Set DTR */
709 NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
710 i4b_l4_dialout(rbch_driver_id, unit);
711 break;
712
713 case TIOCSETA: /* Set termios struct */
714 break;
715
716 case TIOCGETA: /* Get termios struct */
717 *(struct termios *)data = sc->it_in;
718 break;
719
720 case TIOCMGET:
721 *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
722 if (sc->sc_devstate & ST_CONNECTED)
723 *(int *)data |= TIOCM_CD;
724 break;
725
726 case I4B_RBCH_VR_REQ:
727 {
728 msg_vr_req_t *mvr;
729
730 mvr = (msg_vr_req_t *)data;
731
732 mvr->version = VERSION;
733 mvr->release = REL;
734 mvr->step = STEP;
735 break;
736 }
737
738 default: /* Unknown stuff */
739 NDBGL4(L4_RBCHDBG, "(minor=%d) ioctl, unknown cmd %lx", unit, (u_long)cmd);
740 error = EINVAL;
741 break;
742 }
743 return(error);
744 }
745
746 #ifdef OS_USES_POLL
747
748 /*---------------------------------------------------------------------------*
749 * device driver poll
750 *---------------------------------------------------------------------------*/
751 PDEVSTATIC int
752 isdnbchanpoll(dev_t dev, int events, struct lwp *l)
753 {
754 int revents = 0; /* Events we found */
755 int s;
756 int unit = minor(dev);
757 struct rbch_softc *sc = &rbch_softc[unit];
758
759 /* We can't check for anything but IN or OUT */
760
761 s = splhigh();
762
763 if(!(sc->sc_devstate & ST_ISOPEN))
764 {
765 splx(s);
766 return(POLLNVAL);
767 }
768
769 /*
770 * Writes are OK if we are connected and the
771 * transmit queue can take them
772 */
773
774 if((events & (POLLOUT|POLLWRNORM)) &&
775 (sc->sc_devstate & ST_CONNECTED) &&
776 !IF_QFULL(sc->sc_ilt->tx_queue))
777 {
778 revents |= (events & (POLLOUT|POLLWRNORM));
779 }
780
781 /* ... while reads are OK if we have any data */
782
783 if((events & (POLLIN|POLLRDNORM)) &&
784 (sc->sc_devstate & ST_CONNECTED))
785 {
786 struct ifqueue *iqp;
787
788 if(sc->sc_bprot == BPROT_RHDLC)
789 iqp = &sc->sc_hdlcq;
790 else
791 iqp = sc->sc_ilt->rx_queue;
792
793 if(!IF_QEMPTY(iqp))
794 revents |= (events & (POLLIN|POLLRDNORM));
795 }
796
797 if(revents == 0)
798 selrecord(l, &sc->selp);
799
800 splx(s);
801 return(revents);
802 }
803
804 static void
805 filt_i4brbchdetach(struct knote *kn)
806 {
807 struct rbch_softc *sc = kn->kn_hook;
808 int s;
809
810 s = splhigh();
811 SLIST_REMOVE(&sc->selp.sel_klist, kn, knote, kn_selnext);
812 splx(s);
813 }
814
815 static int
816 filt_i4brbchread(struct knote *kn, long hint)
817 {
818 struct rbch_softc *sc = kn->kn_hook;
819 struct ifqueue *iqp;
820
821 if ((sc->sc_devstate & ST_CONNECTED) == 0)
822 return (0);
823
824 if (sc->sc_bprot == BPROT_RHDLC)
825 iqp = &sc->sc_hdlcq;
826 else
827 iqp = sc->sc_ilt->rx_queue;
828
829 if (IF_QEMPTY(iqp))
830 return (0);
831
832 kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
833 return (1);
834 }
835
836 static const struct filterops i4brbchread_filtops =
837 { 1, NULL, filt_i4brbchdetach, filt_i4brbchread };
838
839 static int
840 filt_i4brbchwrite(struct knote *kn, long hint)
841 {
842 struct rbch_softc *sc = kn->kn_hook;
843
844 if ((sc->sc_devstate & ST_CONNECTED) == 0)
845 return (0);
846
847 if (IF_QFULL(sc->sc_ilt->tx_queue))
848 return (0);
849
850 kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
851 return (1);
852 }
853
854 static const struct filterops i4brbchwrite_filtops =
855 { 1, NULL, filt_i4brbchdetach, filt_i4brbchwrite };
856
857 int
858 isdnbchankqfilter(dev_t dev, struct knote *kn)
859 {
860 struct rbch_softc *sc = &rbch_softc[minor(dev)];
861 struct klist *klist;
862 int s;
863
864 switch (kn->kn_filter) {
865 case EVFILT_READ:
866 klist = &sc->selp.sel_klist;
867 kn->kn_fop = &i4brbchread_filtops;
868 break;
869
870 case EVFILT_WRITE:
871 klist = &sc->selp.sel_klist;
872 kn->kn_fop = &i4brbchwrite_filtops;
873 break;
874
875 default:
876 return (EINVAL);
877 }
878
879 kn->kn_hook = sc;
880
881 s = splhigh();
882 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
883 splx(s);
884
885 return (0);
886 }
887
888 #else /* OS_USES_POLL */
889
890 /*---------------------------------------------------------------------------*
891 * device driver select
892 *---------------------------------------------------------------------------*/
893 PDEVSTATIC int
894 isdnbchanselect(dev_t dev, int rw, struct lwp *l)
895 {
896 int unit = minor(dev);
897 struct rbch_softc *sc = &rbch_softc[unit];
898 int s;
899
900 s = splhigh();
901
902 if(!(sc->sc_devstate & ST_ISOPEN))
903 {
904 splx(s);
905 NDBGL4(L4_RBCHDBG, "(minor=%d) not open anymore", unit);
906 return(1);
907 }
908
909 if(sc->sc_devstate & ST_CONNECTED)
910 {
911 struct ifqueue *iqp;
912
913 switch(rw)
914 {
915 case FREAD:
916 if(sc->sc_bprot == BPROT_RHDLC)
917 iqp = &sc->sc_hdlcq;
918 else
919 iqp = isdn_linktab[unit]->rx_queue;
920
921 if(!IF_QEMPTY(iqp))
922 {
923 splx(s);
924 return(1);
925 }
926 break;
927
928 case FWRITE:
929 if(!IF_QFULL(isdn_linktab[unit]->rx_queue))
930 {
931 splx(s);
932 return(1);
933 }
934 break;
935
936 default:
937 splx(s);
938 return 0;
939 }
940 }
941 selrecord(l, &sc->selp);
942 splx(s);
943 return(0);
944 }
945
946 #endif /* OS_USES_POLL */
947
948 #if I4BRBCHACCT
949 /*---------------------------------------------------------------------------*
950 * watchdog routine
951 *---------------------------------------------------------------------------*/
952 static void
953 rbch_timeout(struct rbch_softc *sc)
954 {
955 bchan_statistics_t bs;
956
957 /* get # of bytes in and out from the HSCX driver */
958
959 (*sc->sc_ilt->bchannel_driver->bch_stat)
960 (sc->sc_ilt->l1token, sc->sc_ilt->channel, &bs);
961
962 sc->sc_ioutb += bs.outbytes;
963 sc->sc_iinb += bs.inbytes;
964
965 if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
966 {
967 int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
968 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
969
970 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
971 sc->sc_fn = 0;
972 else
973 sc->sc_fn = 1;
974
975 sc->sc_linb = sc->sc_iinb;
976 sc->sc_loutb = sc->sc_ioutb;
977
978 if (sc->sc_cd)
979 i4b_l4_accounting(sc->sc_cd->cdid, ACCT_DURING,
980 sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
981 }
982 START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
983 }
984 #endif /* I4BRBCHACCT */
985
986 /*===========================================================================*
987 * ISDN INTERFACE ROUTINES
988 *===========================================================================*/
989
990 /*---------------------------------------------------------------------------*
991 * this routine is called from L4 handler at connect time
992 *---------------------------------------------------------------------------*/
993 static void
994 rbch_connect(void *softc, void *cdp)
995 {
996 call_desc_t *cd = (call_desc_t *)cdp;
997 struct rbch_softc *sc = softc;
998
999 sc->sc_bprot = cd->bprot;
1000
1001 #if I4BRBCHACCT
1002 if(sc->sc_bprot == BPROT_RHDLC)
1003 {
1004 sc->sc_iinb = 0;
1005 sc->sc_ioutb = 0;
1006 sc->sc_linb = 0;
1007 sc->sc_loutb = 0;
1008
1009 START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
1010 }
1011 #endif
1012 if(!(sc->sc_devstate & ST_CONNECTED))
1013 {
1014 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d, wakeup",
1015 cd->channelid, cd->isdnif);
1016 sc->sc_devstate |= ST_CONNECTED;
1017 sc->sc_cd = cdp;
1018 wakeup((void *)sc);
1019 selnotify(&sc->selp, 0, 0);
1020 }
1021 }
1022
1023 /*---------------------------------------------------------------------------*
1024 * this routine is called from L4 handler at disconnect time
1025 *---------------------------------------------------------------------------*/
1026 static void
1027 rbch_disconnect(void *softc, void *cdp)
1028 {
1029 call_desc_t *cd = cdp;
1030 struct rbch_softc *sc = softc;
1031
1032 int s;
1033
1034 if(cd != sc->sc_cd)
1035 {
1036 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d not active",
1037 cd->channelid, cd->isdnif);
1038 return;
1039 }
1040
1041 s = splnet();
1042
1043 NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d disconnect",
1044 cd->channelid, cd->isdnif);
1045
1046 sc->sc_devstate &= ~ST_CONNECTED;
1047
1048 #if I4BRBCHACCT
1049 if (sc->sc_cd)
1050 i4b_l4_accounting(sc->sc_cd->cdid, ACCT_FINAL,
1051 sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
1052
1053 STOP_TIMER(sc->sc_callout, rbch_timeout, sc);
1054 #endif
1055
1056 sc->sc_cd = NULL;
1057 if (sc->sc_devstate & ST_RDWAITDATA)
1058 wakeup(&sc->sc_ilt->rx_queue);
1059 if (sc->sc_devstate & ST_WRWAITEMPTY)
1060 wakeup(&sc->sc_ilt->tx_queue);
1061
1062 splx(s);
1063
1064 selnotify(&sc->selp, 0, 0);
1065 }
1066
1067 /*---------------------------------------------------------------------------*
1068 * feedback from daemon in case of dial problems
1069 *---------------------------------------------------------------------------*/
1070 static void
1071 rbch_dialresponse(void *softc, int status,
1072 cause_t cause)
1073 {
1074 }
1075
1076 /*---------------------------------------------------------------------------*
1077 * interface up/down
1078 *---------------------------------------------------------------------------*/
1079 static void
1080 rbch_updown(void *softc, int updown)
1081 {
1082 }
1083
1084 /*---------------------------------------------------------------------------*
1085 * this routine is called from the HSCX interrupt handler
1086 * when a new frame (mbuf) has been received and is to be put on
1087 * the rx queue.
1088 *---------------------------------------------------------------------------*/
1089 static void
1090 rbch_rx_data_rdy(void *softc)
1091 {
1092 struct rbch_softc *sc = softc;
1093
1094 if(sc->sc_bprot == BPROT_RHDLC)
1095 {
1096 register struct mbuf *m;
1097
1098 if((m = *sc->sc_ilt->rx_mbuf) == NULL)
1099 return;
1100
1101 m->m_pkthdr.len = m->m_len;
1102
1103 if(IF_QFULL(&sc->sc_hdlcq))
1104 {
1105 NDBGL4(L4_RBCHDBG, "(minor=%d) hdlc rx queue full!", sc->sc_unit);
1106 m_freem(m);
1107 }
1108 else
1109 {
1110 IF_ENQUEUE(&sc->sc_hdlcq, m);
1111 }
1112 }
1113
1114 if(sc->sc_devstate & ST_RDWAITDATA)
1115 {
1116 NDBGL4(L4_RBCHDBG, "(minor=%d) wakeup", sc->sc_unit);
1117 sc->sc_devstate &= ~ST_RDWAITDATA;
1118 wakeup((void *) &sc->sc_ilt->rx_queue);
1119 }
1120 else
1121 {
1122 NDBGL4(L4_RBCHDBG, "(minor=%d) NO wakeup", sc->sc_unit);
1123 }
1124 selnotify(&sc->selp, 0, 0);
1125 }
1126
1127 /*---------------------------------------------------------------------------*
1128 * this routine is called from the HSCX interrupt handler
1129 * when the last frame has been sent out and there is no
1130 * further frame (mbuf) in the tx queue.
1131 *---------------------------------------------------------------------------*/
1132 static void
1133 rbch_tx_queue_empty(void *softc)
1134 {
1135 struct rbch_softc *sc = softc;
1136
1137 if(sc->sc_devstate & ST_WRWAITEMPTY)
1138 {
1139 NDBGL4(L4_RBCHDBG, "(minor=%d): wakeup", sc->sc_unit);
1140 sc->sc_devstate &= ~ST_WRWAITEMPTY;
1141 wakeup((void *) &sc->sc_ilt->tx_queue);
1142 }
1143 else
1144 {
1145 NDBGL4(L4_RBCHDBG, "(minor=%d) NO wakeup", sc->sc_unit);
1146 }
1147 selnotify(&sc->selp, 0, 0);
1148 }
1149
1150 /*---------------------------------------------------------------------------*
1151 * this routine is called from the HSCX interrupt handler
1152 * each time a packet is received or transmitted
1153 *---------------------------------------------------------------------------*/
1154 static void
1155 rbch_activity(void *softc, int rxtx)
1156 {
1157 struct rbch_softc *sc = softc;
1158
1159 if (sc->sc_cd)
1160 sc->sc_cd->last_active_time = SECOND;
1161 selnotify(&sc->selp, 0, 0);
1162 }
1163
1164 /*---------------------------------------------------------------------------*
1165 * clear an hdlc rx queue for a rbch unit
1166 *---------------------------------------------------------------------------*/
1167 static void
1168 rbch_clrq(void *softc)
1169 {
1170 struct rbch_softc *sc = softc;
1171 struct mbuf *m;
1172 int s;
1173
1174 for(;;)
1175 {
1176 s = splnet();
1177 IF_DEQUEUE(&sc->sc_hdlcq, m);
1178 splx(s);
1179
1180 if(m)
1181 m_freem(m);
1182 else
1183 break;
1184 }
1185 }
1186
1187 /*---------------------------------------------------------------------------*
1188 * setup the isdn_linktab for this driver
1189 *---------------------------------------------------------------------------*/
1190 static void
1191 rbch_set_linktab(void *softc, isdn_link_t *ilt)
1192 {
1193 struct rbch_softc *sc = softc;
1194 sc->sc_ilt = ilt;
1195 }
1196
1197 /*---------------------------------------------------------------------------*
1198 * initialize this drivers linktab
1199 *---------------------------------------------------------------------------*/
1200 static void*
1201 rbch_get_softc(int unit)
1202 {
1203 return &rbch_softc[unit];
1204 }
1205
1206 /*===========================================================================*/
1207
1208 #endif /* NISDNBCHAN > 0 */
Cache object: 20c9399551213ce2d347889677cb3eef
|