File:
[DragonFly] /
src /
sys /
net /
i4b /
driver /
i4b_rbch.c
Revision
1.10:
download - view:
text,
annotated -
select for diffs
Thu May 13 23:49:24 2004 UTC (9 years ago) by
dillon
Branches:
MAIN
CVS tags:
HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).
d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device. It was never
used for that purpose.
d_clone will be more fully implemented as work continues. We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads. This is something we will be needing later
on.
1: /*
2: * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3: *
4: * Redistribution and use in source and binary forms, with or without
5: * modification, are permitted provided that the following conditions
6: * are met:
7: * 1. Redistributions of source code must retain the above copyright
8: * notice, this list of conditions and the following disclaimer.
9: * 2. Redistributions in binary form must reproduce the above copyright
10: * notice, this list of conditions and the following disclaimer in the
11: * documentation and/or other materials provided with the distribution.
12: *
13: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23: * SUCH DAMAGE.
24: *
25: *---------------------------------------------------------------------------
26: *
27: * i4b_rbch.c - device driver for raw B channel data
28: * ---------------------------------------------------
29: *
30: * $FreeBSD: src/sys/i4b/driver/i4b_rbch.c,v 1.10.2.3 2001/08/12 16:22:48 hm Exp $
31: * $DragonFly: src/sys/net/i4b/driver/i4b_rbch.c,v 1.10 2004/05/13 23:49:24 dillon Exp $
32: *
33: * last edit-date: [Sat Aug 11 18:06:57 2001]
34: *
35: *---------------------------------------------------------------------------*/
36:
37: #include "use_i4brbch.h"
38:
39: #if NI4BRBCH > 0
40:
41: #include <sys/param.h>
42: #include <sys/systm.h>
43:
44: #include <sys/conf.h>
45: #include <sys/uio.h>
46: #include <sys/kernel.h>
47: #include <sys/mbuf.h>
48: #include <sys/socket.h>
49: #include <net/if.h>
50: #include <sys/tty.h>
51:
52: #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
53: #include <sys/callout.h>
54: #endif
55:
56: #if defined (__NetBSD__) || defined (__OpenBSD__)
57: extern cc_t ttydefchars;
58: #define termioschars(t) memcpy((t)->c_cc, &ttydefchars, sizeof((t)->c_cc))
59: #endif
60:
61: #if defined(__DragonFly__) || defined(__FreeBSD__)
62:
63: #ifdef DEVFS
64: #include <sys/devfsext.h>
65: #endif
66:
67: #endif /* __FreeBSD__ */
68:
69: #ifdef __NetBSD__
70: #include <sys/filio.h>
71: #endif
72:
73: #if defined(__DragonFly__) || defined(__FreeBSD__)
74: #include <net/i4b/include/machine/i4b_ioctl.h>
75: #include <net/i4b/include/machine/i4b_rbch_ioctl.h>
76: #include <net/i4b/include/machine/i4b_debug.h>
77: #else
78: #include <i4b/i4b_ioctl.h>
79: #include <i4b/i4b_rbch_ioctl.h>
80: #include <i4b/i4b_debug.h>
81: #endif
82:
83: #include "../include/i4b_global.h"
84: #include "../include/i4b_mbuf.h"
85: #include "../include/i4b_l3l4.h"
86: #include "../layer4/i4b_l4.h"
87:
88: #ifdef __bsdi__
89: #include <sys/device.h>
90: #endif
91:
92: #ifdef OS_USES_POLL
93: #include <sys/ioccom.h>
94: #include <sys/poll.h>
95: #else
96: #include <sys/fcntl.h>
97: #include <sys/ioctl.h>
98: #endif
99:
100: #if defined(__DragonFly__) || defined(__FreeBSD__)
101: #include <sys/filio.h>
102: #endif
103:
104: static drvr_link_t rbch_drvr_linktab[NI4BRBCH];
105: static isdn_link_t *isdn_linktab[NI4BRBCH];
106:
107: #define I4BRBCHACCT 1 /* enable accounting messages */
108: #define I4BRBCHACCTINTVL 2 /* accounting msg interval in secs */
109:
110: static struct rbch_softc {
111:
112: int sc_unit; /* unit number */
113:
114: int sc_devstate; /* state of driver */
115: #define ST_IDLE 0x00
116: #define ST_CONNECTED 0x01
117: #define ST_ISOPEN 0x02
118: #define ST_RDWAITDATA 0x04
119: #define ST_WRWAITEMPTY 0x08
120: #define ST_NOBLOCK 0x10
121:
122: int sc_bprot; /* B-ch protocol used */
123:
124: call_desc_t *sc_cd; /* Call Descriptor */
125:
126: struct termios it_in;
127:
128: struct ifqueue sc_hdlcq; /* hdlc read queue */
129: #define I4BRBCHMAXQLEN 10
130:
131: struct selinfo selp; /* select / poll */
132:
133: #if I4BRBCHACCT
134: #if defined(__DragonFly__) || defined(__FreeBSD__)
135: struct callout_handle sc_callout;
136: #endif
137: #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
138: struct callout sc_callout;
139: #endif
140:
141: int sc_iinb; /* isdn driver # of inbytes */
142: int sc_ioutb; /* isdn driver # of outbytes */
143: int sc_linb; /* last # of bytes rx'd */
144: int sc_loutb; /* last # of bytes tx'd */
145: int sc_fn; /* flag, first null acct */
146: #endif
147: } rbch_softc[NI4BRBCH];
148:
149: static void rbch_rx_data_rdy(int unit);
150: static void rbch_tx_queue_empty(int unit);
151: static void rbch_connect(int unit, void *cdp);
152: static void rbch_disconnect(int unit, void *cdp);
153: static void rbch_init_linktab(int unit);
154: static void rbch_clrq(int unit);
155:
156: #if !defined(__DragonFly__) && !defined(__FreeBSD__)
157: #define PDEVSTATIC /* - not static - */
158: #define IOCTL_CMD_T u_long
159: void i4brbchattach (void);
160: int i4brbchopen (dev_t dev, int flag, int fmt, struct proc *p);
161: int i4brbchclose (dev_t dev, int flag, int fmt, struct proc *p);
162: int i4brbchread (dev_t dev, struct uio *uio, int ioflag);
163: int i4brbchwrite (dev_t dev, struct uio *uio, int ioflag);
164: int i4brbchioctl (dev_t dev, IOCTL_CMD_T cmd, caddr_t arg, int flag, struct proc* pr);
165: #ifdef OS_USES_POLL
166: int i4brbchpoll (dev_t dev, int events, struct proc *p);
167: #else
168: PDEVSTATIC int i4brbchselect (dev_t dev, int rw, struct proc *p);
169: #endif
170: #endif
171:
172: #if defined(__DragonFly__) || (BSD > 199306 && defined(__FreeBSD__))
173: #define PDEVSTATIC static
174: #define IOCTL_CMD_T u_long
175:
176: PDEVSTATIC d_open_t i4brbchopen;
177: PDEVSTATIC d_close_t i4brbchclose;
178: PDEVSTATIC d_read_t i4brbchread;
179: PDEVSTATIC d_read_t i4brbchwrite;
180: PDEVSTATIC d_ioctl_t i4brbchioctl;
181:
182: #ifdef OS_USES_POLL
183: PDEVSTATIC d_poll_t i4brbchpoll;
184: #define POLLFIELD i4brbchpoll
185: #else
186: PDEVSTATIC d_select_t i4brbchselect;
187: #define POLLFIELD i4brbchselect
188: #endif
189:
190: #define CDEV_MAJOR 57
191:
192: static struct cdevsw i4brbch_cdevsw = {
193: /* name */ "i4brbch",
194: /* maj */ CDEV_MAJOR,
195: /* flags */ 0,
196: /* port */ NULL,
197: /* clone */ NULL,
198:
199: /* open */ i4brbchopen,
200: /* close */ i4brbchclose,
201: /* read */ i4brbchread,
202: /* write */ i4brbchwrite,
203: /* ioctl */ i4brbchioctl,
204: /* poll */ POLLFIELD,
205: /* mmap */ nommap,
206: /* strategy */ nostrategy,
207: /* dump */ nodump,
208: /* psize */ nopsize
209: };
210:
211: static void i4brbchattach(void *);
212: PSEUDO_SET(i4brbchattach, i4b_rbch);
213:
214: /*===========================================================================*
215: * DEVICE DRIVER ROUTINES
216: *===========================================================================*/
217:
218: /*---------------------------------------------------------------------------*
219: * initialization at kernel load time
220: *---------------------------------------------------------------------------*/
221: static void
222: i4brbchinit(void *unused)
223: {
224: cdevsw_add(&i4brbch_cdevsw);
225: }
226:
227: SYSINIT(i4brbchdev, SI_SUB_DRIVERS,
228: SI_ORDER_MIDDLE+CDEV_MAJOR, &i4brbchinit, NULL);
229:
230: #endif /* BSD > 199306 && defined(__FreeBSD__) */
231:
232: #ifdef __bsdi__
233: int i4brbchmatch(struct device *parent, struct cfdata *cf, void *aux);
234: void dummy_i4brbchattach(struct device*, struct device *, void *);
235:
236: #define CDEV_MAJOR 61
237:
238: static struct cfdriver i4brbchcd =
239: { NULL, "i4brbch", i4brbchmatch, dummy_i4brbchattach, DV_DULL,
240: sizeof(struct cfdriver) };
241: struct devsw i4brbchsw =
242: { &i4brbchcd,
243: i4brbchopen, i4brbchclose, i4brbchread, i4brbchwrite,
244: i4brbchioctl, seltrue, nommap, nostrat,
245: nodump, nopsize, 0, nostop
246: };
247:
248: int
249: i4brbchmatch(struct device *parent, struct cfdata *cf, void *aux)
250: {
251: printf("i4brbchmatch: aux=0x%x\n", aux);
252: return 1;
253: }
254: void
255: dummy_i4brbchattach(struct device *parent, struct device *self, void *aux)
256: {
257: printf("dummy_i4brbchattach: aux=0x%x\n", aux);
258: }
259: #endif /* __bsdi__ */
260:
261: /*---------------------------------------------------------------------------*
262: * interface attach routine
263: *---------------------------------------------------------------------------*/
264: PDEVSTATIC void
265: #if defined(__DragonFly__) || defined(__FreeBSD__)
266: i4brbchattach(void *dummy)
267: #else
268: i4brbchattach()
269: #endif
270: {
271: int i;
272:
273: #ifndef HACK_NO_PSEUDO_ATTACH_MSG
274: printf("i4brbch: %d raw B channel access device(s) attached\n", NI4BRBCH);
275: #endif
276:
277: for(i=0; i < NI4BRBCH; i++)
278: {
279: #if defined(__DragonFly__) || defined(__FreeBSD__)
280: make_dev(&i4brbch_cdevsw, i,
281: UID_ROOT, GID_WHEEL, 0600, "i4brbch%d", i);
282: #endif
283:
284: #if I4BRBCHACCT
285: #if defined(__DragonFly__) || defined(__FreeBSD__)
286: callout_handle_init(&rbch_softc[i].sc_callout);
287: #endif
288: #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
289: callout_init(&rbch_softc[i].sc_callout);
290: #endif
291: rbch_softc[i].sc_fn = 1;
292: #endif
293: rbch_softc[i].sc_unit = i;
294: rbch_softc[i].sc_devstate = ST_IDLE;
295: rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
296: #if defined(__FreeBSD__) && __FreeBSD__ > 4
297: mtx_init(&rbch_softc[i].sc_hdlcq.ifq_mtx, "i4b_rbch", MTX_DEF);
298: #endif
299: rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
300: termioschars(&rbch_softc[i].it_in);
301: rbch_init_linktab(i);
302: }
303: }
304:
305: /*---------------------------------------------------------------------------*
306: * open rbch device
307: *---------------------------------------------------------------------------*/
308: PDEVSTATIC int
309: i4brbchopen(dev_t dev, int flag, int fmt, struct thread *td)
310: {
311: int unit = minor(dev);
312:
313: if(unit >= NI4BRBCH)
314: return(ENXIO);
315:
316: if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
317: return(EBUSY);
318:
319: #if 0
320: rbch_clrq(unit);
321: #endif
322:
323: rbch_softc[unit].sc_devstate |= ST_ISOPEN;
324:
325: NDBGL4(L4_RBCHDBG, "unit %d, open", unit);
326:
327: return(0);
328: }
329:
330: /*---------------------------------------------------------------------------*
331: * close rbch device
332: *---------------------------------------------------------------------------*/
333: PDEVSTATIC int
334: i4brbchclose(dev_t dev, int flag, int fmt, struct thread *td)
335: {
336: int unit = minor(dev);
337: struct rbch_softc *sc = &rbch_softc[unit];
338:
339: if(sc->sc_devstate & ST_CONNECTED)
340: i4b_l4_drvrdisc(BDRV_RBCH, unit);
341:
342: sc->sc_devstate &= ~ST_ISOPEN;
343:
344: rbch_clrq(unit);
345:
346: NDBGL4(L4_RBCHDBG, "unit %d, closed", unit);
347:
348: return(0);
349: }
350:
351: /*---------------------------------------------------------------------------*
352: * read from rbch device
353: *---------------------------------------------------------------------------*/
354: PDEVSTATIC int
355: i4brbchread(dev_t dev, struct uio *uio, int ioflag)
356: {
357: struct mbuf *m;
358: int error = 0;
359: int unit = minor(dev);
360: struct ifqueue *iqp;
361: struct rbch_softc *sc = &rbch_softc[unit];
362:
363: CRIT_VAR;
364:
365: NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
366:
367: CRIT_BEG;
368: if(!(sc->sc_devstate & ST_ISOPEN))
369: {
370: CRIT_END;
371: NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
372: return(EIO);
373: }
374:
375: if((sc->sc_devstate & ST_NOBLOCK))
376: {
377: if(!(sc->sc_devstate & ST_CONNECTED)) {
378: CRIT_END;
379: return(EWOULDBLOCK);
380: }
381:
382: if(sc->sc_bprot == BPROT_RHDLC)
383: iqp = &sc->sc_hdlcq;
384: else
385: iqp = isdn_linktab[unit]->rx_queue;
386:
387: if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
388: CRIT_END;
389: return(EWOULDBLOCK);
390: }
391: }
392: else
393: {
394: while(!(sc->sc_devstate & ST_CONNECTED))
395: {
396: NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
397:
398: if((error = tsleep((caddr_t) &rbch_softc[unit],
399: PCATCH, "rrrbch", 0 )) != 0)
400: {
401: CRIT_END;
402: NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
403: return(error);
404: }
405: }
406:
407: if(sc->sc_bprot == BPROT_RHDLC)
408: iqp = &sc->sc_hdlcq;
409: else
410: iqp = isdn_linktab[unit]->rx_queue;
411:
412: while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
413: {
414: sc->sc_devstate |= ST_RDWAITDATA;
415:
416: NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
417:
418: if((error = tsleep((caddr_t) &isdn_linktab[unit]->rx_queue,
419: PCATCH, "rrbch", 0 )) != 0)
420: {
421: CRIT_END;
422: NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
423: sc->sc_devstate &= ~ST_RDWAITDATA;
424: return(error);
425: }
426: }
427: }
428:
429: IF_DEQUEUE(iqp, m);
430:
431: NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
432:
433: if(m && m->m_len)
434: {
435: error = uiomove(m->m_data, m->m_len, uio);
436: }
437: else
438: {
439: NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
440: error = EIO;
441: }
442:
443: if(m)
444: i4b_Bfreembuf(m);
445:
446: CRIT_END;
447:
448: return(error);
449: }
450:
451: /*---------------------------------------------------------------------------*
452: * write to rbch device
453: *---------------------------------------------------------------------------*/
454: PDEVSTATIC int
455: i4brbchwrite(dev_t dev, struct uio * uio, int ioflag)
456: {
457: struct mbuf *m;
458: int error = 0;
459: int unit = minor(dev);
460: struct rbch_softc *sc = &rbch_softc[unit];
461:
462: CRIT_VAR;
463:
464: NDBGL4(L4_RBCHDBG, "unit %d, write", unit);
465:
466: CRIT_BEG;
467: if(!(sc->sc_devstate & ST_ISOPEN))
468: {
469: NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
470: CRIT_END;
471: return(EIO);
472: }
473:
474: if((sc->sc_devstate & ST_NOBLOCK))
475: {
476: if(!(sc->sc_devstate & ST_CONNECTED)) {
477: CRIT_END;
478: return(EWOULDBLOCK);
479: }
480: if(_IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
481: CRIT_END;
482: return(EWOULDBLOCK);
483: }
484: }
485: else
486: {
487: while(!(sc->sc_devstate & ST_CONNECTED))
488: {
489: NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
490:
491: error = tsleep((caddr_t) &rbch_softc[unit],
492: PCATCH, "wrrbch", 0 );
493: if(error == ERESTART) {
494: CRIT_END;
495: return (ERESTART);
496: }
497: else if(error == EINTR)
498: {
499: CRIT_END;
500: NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
501: return(EINTR);
502: }
503: else if(error)
504: {
505: CRIT_END;
506: NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
507: return(error);
508: }
509: tsleep((caddr_t) &rbch_softc[unit], PCATCH, "xrbch", (hz*1));
510: }
511:
512: while(_IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
513: {
514: sc->sc_devstate |= ST_WRWAITEMPTY;
515:
516: NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
517:
518: if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue,
519: PCATCH, "wrbch", 0)) != 0) {
520: sc->sc_devstate &= ~ST_WRWAITEMPTY;
521: if(error == ERESTART)
522: {
523: CRIT_END;
524: return(ERESTART);
525: }
526: else if(error == EINTR)
527: {
528: CRIT_END;
529: NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
530: return(error);
531: }
532: else if(error)
533: {
534: CRIT_END;
535: NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
536: return(error);
537: }
538: }
539: }
540: }
541:
542: if(!(sc->sc_devstate & ST_ISOPEN))
543: {
544: NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
545: CRIT_END;
546: return(EIO);
547: }
548:
549: if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
550: {
551: m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
552:
553: NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
554:
555: error = uiomove(m->m_data, m->m_len, uio);
556:
557: #if defined (__FreeBSD__) && __FreeBSD__ > 4
558: (void) IF_HANDOFF(isdn_linktab[unit]->tx_queue, m, NULL);
559: #else
560: if(IF_QFULL(isdn_linktab[unit]->tx_queue))
561: m_freem(m);
562: else
563: IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
564: #endif
565: (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
566: }
567:
568: CRIT_END;
569:
570: return(error);
571: }
572:
573: /*---------------------------------------------------------------------------*
574: * rbch device ioctl handlibg
575: *---------------------------------------------------------------------------*/
576: PDEVSTATIC int
577: i4brbchioctl(dev_t dev, IOCTL_CMD_T cmd, caddr_t data, int flag, struct thread *td)
578: {
579: int error = 0;
580: int unit = minor(dev);
581: struct rbch_softc *sc = &rbch_softc[unit];
582:
583: switch(cmd)
584: {
585: case FIOASYNC: /* Set async mode */
586: if (*(int *)data)
587: {
588: NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
589: }
590: else
591: {
592: NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
593: }
594: break;
595:
596: case FIONBIO:
597: if (*(int *)data)
598: {
599: NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit);
600: sc->sc_devstate |= ST_NOBLOCK;
601: }
602: else
603: {
604: NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit);
605: sc->sc_devstate &= ~ST_NOBLOCK;
606: }
607: break;
608:
609: case TIOCCDTR: /* Clear DTR */
610: if(sc->sc_devstate & ST_CONNECTED)
611: {
612: NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
613: i4b_l4_drvrdisc(BDRV_RBCH, unit);
614: }
615: break;
616:
617: case I4B_RBCH_DIALOUT:
618: {
619: size_t l;
620:
621: for (l = 0; l < TELNO_MAX && ((char *)data)[l]; l++)
622: ;
623: if (l)
624: {
625: NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout to %s", unit, (char *)data);
626: i4b_l4_dialoutnumber(BDRV_RBCH, unit, l, (char *)data);
627: break;
628: }
629: /* fall through to SDTR */
630: }
631:
632: case TIOCSDTR: /* Set DTR */
633: NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
634: i4b_l4_dialout(BDRV_RBCH, unit);
635: break;
636:
637: case TIOCSETA: /* Set termios struct */
638: break;
639:
640: case TIOCGETA: /* Get termios struct */
641: *(struct termios *)data = sc->it_in;
642: break;
643:
644: case TIOCMGET:
645: *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
646: if (sc->sc_devstate & ST_CONNECTED)
647: *(int *)data |= TIOCM_CD;
648: break;
649:
650: case I4B_RBCH_VR_REQ:
651: {
652: msg_vr_req_t *mvr;
653:
654: mvr = (msg_vr_req_t *)data;
655:
656: mvr->version = VERSION;
657: mvr->release = REL;
658: mvr->step = STEP;
659: break;
660: }
661:
662: default: /* Unknown stuff */
663: NDBGL4(L4_RBCHDBG, "unit %d, ioctl, unknown cmd %lx", unit, (u_long)cmd);
664: error = EINVAL;
665: break;
666: }
667: return(error);
668: }
669:
670: #ifdef OS_USES_POLL
671:
672: /*---------------------------------------------------------------------------*
673: * device driver poll
674: *---------------------------------------------------------------------------*/
675: PDEVSTATIC int
676: i4brbchpoll(dev_t dev, int events, struct thread *td)
677: {
678: int revents = 0; /* Events we found */
679: int s;
680: int unit = minor(dev);
681: struct rbch_softc *sc = &rbch_softc[unit];
682:
683: /* We can't check for anything but IN or OUT */
684:
685: s = splhigh();
686:
687: if(!(sc->sc_devstate & ST_ISOPEN))
688: {
689: splx(s);
690: return(POLLNVAL);
691: }
692:
693: /*
694: * Writes are OK if we are connected and the
695: * transmit queue can take them
696: */
697:
698: if((events & (POLLOUT|POLLWRNORM)) &&
699: (sc->sc_devstate & ST_CONNECTED) &&
700: !_IF_QFULL(isdn_linktab[unit]->tx_queue))
701: {
702: revents |= (events & (POLLOUT|POLLWRNORM));
703: }
704:
705: /* ... while reads are OK if we have any data */
706:
707: if((events & (POLLIN|POLLRDNORM)) &&
708: (sc->sc_devstate & ST_CONNECTED))
709: {
710: struct ifqueue *iqp;
711:
712: if(sc->sc_bprot == BPROT_RHDLC)
713: iqp = &sc->sc_hdlcq;
714: else
715: iqp = isdn_linktab[unit]->rx_queue;
716:
717: if(!IF_QEMPTY(iqp))
718: revents |= (events & (POLLIN|POLLRDNORM));
719: }
720:
721: if(revents == 0)
722: selrecord(td, &sc->selp);
723:
724: splx(s);
725: return(revents);
726: }
727:
728: #else /* OS_USES_POLL */
729:
730: /*---------------------------------------------------------------------------*
731: * device driver select
732: *---------------------------------------------------------------------------*/
733: PDEVSTATIC int
734: i4brbchselect(dev_t dev, int rw, struct thread *td)
735: {
736: int unit = minor(dev);
737: struct rbch_softc *sc = &rbch_softc[unit];
738: int s;
739:
740: s = splhigh();
741:
742: if(!(sc->sc_devstate & ST_ISOPEN))
743: {
744: splx(s);
745: NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
746: return(1);
747: }
748:
749: if(sc->sc_devstate & ST_CONNECTED)
750: {
751: struct ifqueue *iqp;
752:
753: switch(rw)
754: {
755: case FREAD:
756: if(sc->sc_bprot == BPROT_RHDLC)
757: iqp = &sc->sc_hdlcq;
758: else
759: iqp = isdn_linktab[unit]->rx_queue;
760:
761: if(!IF_QEMPTY(iqp))
762: {
763: splx(s);
764: return(1);
765: }
766: break;
767:
768: case FWRITE:
769: if(!_IF_QFULL(isdn_linktab[unit]->rx_queue))
770: {
771: splx(s);
772: return(1);
773: }
774: break;
775:
776: default:
777: splx(s);
778: return 0;
779: }
780: }
781: selrecord(p, &sc->selp);
782: splx(s);
783: return(0);
784: }
785:
786: #endif /* OS_USES_POLL */
787:
788: #if I4BRBCHACCT
789: /*---------------------------------------------------------------------------*
790: * watchdog routine
791: *---------------------------------------------------------------------------*/
792: static void
793: rbch_timeout(struct rbch_softc *sc)
794: {
795: bchan_statistics_t bs;
796: int unit = sc->sc_unit;
797:
798: /* get # of bytes in and out from the HSCX driver */
799:
800: (*isdn_linktab[unit]->bch_stat)
801: (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
802:
803: sc->sc_ioutb += bs.outbytes;
804: sc->sc_iinb += bs.inbytes;
805:
806: if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
807: {
808: int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
809: int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
810:
811: if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
812: sc->sc_fn = 0;
813: else
814: sc->sc_fn = 1;
815:
816: sc->sc_linb = sc->sc_iinb;
817: sc->sc_loutb = sc->sc_ioutb;
818:
819: i4b_l4_accounting(BDRV_RBCH, unit, ACCT_DURING,
820: sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
821: }
822: START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
823: }
824: #endif /* I4BRBCHACCT */
825:
826: /*===========================================================================*
827: * ISDN INTERFACE ROUTINES
828: *===========================================================================*/
829:
830: /*---------------------------------------------------------------------------*
831: * this routine is called from L4 handler at connect time
832: *---------------------------------------------------------------------------*/
833: static void
834: rbch_connect(int unit, void *cdp)
835: {
836: call_desc_t *cd = (call_desc_t *)cdp;
837: struct rbch_softc *sc = &rbch_softc[unit];
838:
839: sc->sc_bprot = cd->bprot;
840:
841: #if I4BRBCHACCT
842: if(sc->sc_bprot == BPROT_RHDLC)
843: {
844: sc->sc_iinb = 0;
845: sc->sc_ioutb = 0;
846: sc->sc_linb = 0;
847: sc->sc_loutb = 0;
848:
849: START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
850: }
851: #endif
852: if(!(sc->sc_devstate & ST_CONNECTED))
853: {
854: NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
855: sc->sc_devstate |= ST_CONNECTED;
856: sc->sc_cd = cdp;
857: wakeup((caddr_t)sc);
858: }
859: }
860:
861: /*---------------------------------------------------------------------------*
862: * this routine is called from L4 handler at disconnect time
863: *---------------------------------------------------------------------------*/
864: static void
865: rbch_disconnect(int unit, void *cdp)
866: {
867: call_desc_t *cd = (call_desc_t *)cdp;
868: struct rbch_softc *sc = &rbch_softc[unit];
869:
870: CRIT_VAR;
871:
872: if(cd != sc->sc_cd)
873: {
874: NDBGL4(L4_RBCHDBG, "rbch%d: channel %d not active",
875: cd->driver_unit, cd->channelid);
876: return;
877: }
878:
879: CRIT_BEG;
880:
881: NDBGL4(L4_RBCHDBG, "unit %d, disconnect", unit);
882:
883: sc->sc_devstate &= ~ST_CONNECTED;
884:
885: sc->sc_cd = NULL;
886:
887: #if I4BRBCHACCT
888: i4b_l4_accounting(BDRV_RBCH, unit, ACCT_FINAL,
889: sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
890:
891: STOP_TIMER(sc->sc_callout, rbch_timeout, sc);
892: #endif
893: CRIT_END;
894: }
895:
896: /*---------------------------------------------------------------------------*
897: * feedback from daemon in case of dial problems
898: *---------------------------------------------------------------------------*/
899: static void
900: rbch_dialresponse(int unit, int status, cause_t cause)
901: {
902: }
903:
904: /*---------------------------------------------------------------------------*
905: * interface up/down
906: *---------------------------------------------------------------------------*/
907: static void
908: rbch_updown(int unit, int updown)
909: {
910: }
911:
912: /*---------------------------------------------------------------------------*
913: * this routine is called from the HSCX interrupt handler
914: * when a new frame (mbuf) has been received and is to be put on
915: * the rx queue.
916: *---------------------------------------------------------------------------*/
917: static void
918: rbch_rx_data_rdy(int unit)
919: {
920: if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
921: {
922: struct mbuf *m;
923:
924: if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
925: return;
926:
927: m->m_pkthdr.len = m->m_len;
928:
929: #if defined (__FreeBSD__) && __FreeBSD__ > 4
930: if (! IF_HANDOFF(&(rbch_softc[unit].sc_hdlcq), m, NULL))
931: {
932: NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
933: }
934: #else
935: if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq)))
936: {
937: NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
938: m_freem(m);
939: }
940: else
941: {
942: IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m);
943: }
944: #endif
945: }
946:
947: if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA)
948: {
949: NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
950: rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
951: wakeup((caddr_t) &isdn_linktab[unit]->rx_queue);
952: }
953: else
954: {
955: NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
956: }
957: selwakeup(&rbch_softc[unit].selp);
958: }
959:
960: /*---------------------------------------------------------------------------*
961: * this routine is called from the HSCX interrupt handler
962: * when the last frame has been sent out and there is no
963: * further frame (mbuf) in the tx queue.
964: *---------------------------------------------------------------------------*/
965: static void
966: rbch_tx_queue_empty(int unit)
967: {
968: if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY)
969: {
970: NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
971: rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
972: wakeup((caddr_t) &isdn_linktab[unit]->tx_queue);
973: }
974: else
975: {
976: NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
977: }
978: selwakeup(&rbch_softc[unit].selp);
979: }
980:
981: /*---------------------------------------------------------------------------*
982: * this routine is called from the HSCX interrupt handler
983: * each time a packet is received or transmitted
984: *---------------------------------------------------------------------------*/
985: static void
986: rbch_activity(int unit, int rxtx)
987: {
988: if (rbch_softc[unit].sc_cd)
989: rbch_softc[unit].sc_cd->last_active_time = SECOND;
990: selwakeup(&rbch_softc[unit].selp);
991: }
992:
993: /*---------------------------------------------------------------------------*
994: * clear an hdlc rx queue for a rbch unit
995: *---------------------------------------------------------------------------*/
996: static void
997: rbch_clrq(int unit)
998: {
999: CRIT_VAR;
1000:
1001: #if defined (__FreeBSD__) && __FreeBSD__ > 4
1002: CRIT_BEG;
1003: IF_DRAIN(&rbch_softc[unit].sc_hdlcq);
1004: CRIT_END;
1005: #else
1006: struct mbuf *m;
1007: for(;;)
1008: {
1009: CRIT_BEG;
1010: IF_DEQUEUE(&rbch_softc[unit].sc_hdlcq, m);
1011: CRIT_END;
1012:
1013: if(m)
1014: m_freem(m);
1015: else
1016: break;
1017: }
1018: #endif
1019: }
1020:
1021: /*---------------------------------------------------------------------------*
1022: * return this drivers linktab address
1023: *---------------------------------------------------------------------------*/
1024: drvr_link_t *
1025: rbch_ret_linktab(int unit)
1026: {
1027: rbch_init_linktab(unit);
1028: return(&rbch_drvr_linktab[unit]);
1029: }
1030:
1031: /*---------------------------------------------------------------------------*
1032: * setup the isdn_linktab for this driver
1033: *---------------------------------------------------------------------------*/
1034: void
1035: rbch_set_linktab(int unit, isdn_link_t *ilt)
1036: {
1037: isdn_linktab[unit] = ilt;
1038: }
1039:
1040: /*---------------------------------------------------------------------------*
1041: * initialize this drivers linktab
1042: *---------------------------------------------------------------------------*/
1043: static void
1044: rbch_init_linktab(int unit)
1045: {
1046: rbch_drvr_linktab[unit].unit = unit;
1047: rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy;
1048: rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty;
1049: rbch_drvr_linktab[unit].bch_activity = rbch_activity;
1050: rbch_drvr_linktab[unit].line_connected = rbch_connect;
1051: rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect;
1052: rbch_drvr_linktab[unit].dial_response = rbch_dialresponse;
1053: rbch_drvr_linktab[unit].updown_ind = rbch_updown;
1054: }
1055:
1056: /*===========================================================================*/
1057:
1058: #endif /* NI4BRBCH > 0 */