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