Sync usage with man page.
[netbsd-mini2440.git] / sys / netisdn / i4b_i4bdrv.c
blob7a2c10e49067dcb93a690f342aaf4d79d442dc43
1 /*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
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.
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.
25 *---------------------------------------------------------------------------
27 * i4b_i4bdrv.c - i4b userland interface driver
28 * --------------------------------------------
30 * $Id: i4b_i4bdrv.c,v 1.36 2009/03/18 10:22:43 cegger Exp $
32 * $FreeBSD$
34 * last edit-date: [Fri Jan 5 11:33:47 2001]
36 *---------------------------------------------------------------------------*/
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: i4b_i4bdrv.c,v 1.35 2009/03/14 14:46:10 dsl Exp $");
41 #include "isdn.h"
43 #if NISDN > 0
45 #include <sys/param.h>
47 #if defined(__FreeBSD__)
48 #include <sys/ioccom.h>
49 #include <sys/malloc.h>
50 #include <sys/uio.h>
51 #else
52 #include <sys/ioctl.h>
53 #endif
55 #include <sys/kernel.h>
56 #include <sys/systm.h>
57 #include <sys/conf.h>
58 #include <sys/mbuf.h>
59 #include <sys/proc.h>
60 #include <sys/fcntl.h>
61 #include <sys/socket.h>
62 #include <sys/select.h>
63 #include <net/if.h>
65 #ifdef __FreeBSD__
67 #if defined(__FreeBSD__) && __FreeBSD__ == 3
68 #include "opt_devfs.h"
69 #endif
71 #ifdef DEVFS
72 #include <sys/devfsext.h>
73 #endif
75 #endif /* __FreeBSD__*/
77 #ifdef __FreeBSD__
78 #include <machine/i4b_debug.h>
79 #include <machine/i4b_ioctl.h>
80 #include <machine/i4b_cause.h>
81 #else
82 #include <netisdn/i4b_debug.h>
83 #include <netisdn/i4b_ioctl.h>
84 #include <netisdn/i4b_cause.h>
85 #endif
87 #include <netisdn/i4b_l3l4.h>
88 #include <netisdn/i4b_mbuf.h>
89 #include <netisdn/i4b_global.h>
91 #include <netisdn/i4b_l4.h>
93 #ifdef OS_USES_POLL
94 #include <sys/poll.h>
95 #endif
97 struct selinfo select_rd_info;
99 static struct ifqueue i4b_rdqueue;
100 static int openflag = 0;
101 static int selflag = 0;
102 static int readflag = 0;
104 #if defined(__FreeBSD__) && __FreeBSD__ == 3
105 #ifdef DEVFS
106 static void *devfs_token;
107 #endif
108 #endif
110 #ifndef __FreeBSD__
112 #define PDEVSTATIC /* - not static - */
113 PDEVSTATIC void isdnattach(void);
114 PDEVSTATIC int isdnopen(dev_t dev, int flag, int fmt, struct lwp *l);
115 PDEVSTATIC int isdnclose(dev_t dev, int flag, int fmt, struct lwp *l);
116 PDEVSTATIC int isdnread(dev_t dev, struct uio *uio, int ioflag);
117 PDEVSTATIC int isdnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l);
119 #ifdef OS_USES_POLL
120 PDEVSTATIC int isdnpoll(dev_t dev, int events, struct lwp *l);
121 PDEVSTATIC int isdnkqfilter(dev_t dev, struct knote *kn);
122 #else
123 PDEVSTATIC int isdnselect(dev_t dev, int rw, struct lwp *l);
124 #endif
126 #endif /* #ifndef __FreeBSD__ */
128 #if BSD > 199306 && defined(__FreeBSD__)
130 #define PDEVSTATIC static
132 PDEVSTATIC d_open_t i4bopen;
133 PDEVSTATIC d_close_t i4bclose;
134 PDEVSTATIC d_read_t i4bread;
135 PDEVSTATIC d_ioctl_t i4bioctl;
137 #ifdef OS_USES_POLL
138 PDEVSTATIC d_poll_t i4bpoll;
139 #define POLLFIELD i4bpoll
140 #else
141 PDEVSTATIC d_select_t i4bselect;
142 #define POLLFIELD i4bselect
143 #endif
145 #define CDEV_MAJOR 60
147 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
148 static struct cdevsw i4b_cdevsw = {
149 /* open */ i4bopen,
150 /* close */ i4bclose,
151 /* read */ i4bread,
152 /* write */ nowrite,
153 /* ioctl */ i4bioctl,
154 /* poll */ POLLFIELD,
155 /* mmap */ nommap,
156 /* strategy */ nostrategy,
157 /* name */ "i4b",
158 /* maj */ CDEV_MAJOR,
159 /* dump */ nodump,
160 /* psize */ nopsize,
161 /* flags */ 0,
162 /* bmaj */ -1
164 #else
165 static struct cdevsw i4b_cdevsw = {
166 i4bopen, i4bclose, i4bread, nowrite,
167 i4bioctl, nostop, nullreset, nodevtotty,
168 POLLFIELD, nommap, NULL, "i4b", NULL, -1
170 #endif
172 PDEVSTATIC void i4battach(void *);
173 PSEUDO_SET(i4battach, i4b_i4bdrv);
175 static void
176 i4b_drvinit(void *unused)
178 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
179 cdevsw_add(&i4b_cdevsw);
180 #else
181 static int i4b_devsw_installed = 0;
182 dev_t dev;
184 if( ! i4b_devsw_installed )
186 dev = makedev(CDEV_MAJOR,0);
187 cdevsw_add(&dev,&i4b_cdevsw,NULL);
188 i4b_devsw_installed = 1;
190 #endif
193 SYSINIT(i4bdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,i4b_drvinit,NULL)
195 #endif /* BSD > 199306 && defined(__FreeBSD__) */
197 #ifdef __NetBSD__
198 const struct cdevsw isdn_cdevsw = {
199 isdnopen, isdnclose, isdnread, nowrite, isdnioctl,
200 nostop, notty, isdnpoll, nommap, isdnkqfilter, D_OTHER
202 #endif /* __NetBSD__ */
204 #ifdef __bsdi__
205 #include <sys/device.h>
206 int i4bmatch(struct device *parent, struct cfdata *cf, void *aux);
207 void dummy_i4battach(struct device*, struct device *, void *);
209 #define CDEV_MAJOR 65
211 static struct cfdriver i4bcd =
212 { NULL, "i4b", i4bmatch, dummy_i4battach, DV_DULL,
213 sizeof(struct cfdriver) };
214 struct devsw i4bsw =
215 { &i4bcd,
216 i4bopen, i4bclose, i4bread, nowrite,
217 i4bioctl, i4bselect, nommap, nostrat,
218 nodump, nopsize, 0, nostop
222 i4bmatch(struct device *parent, struct cfdata *cf, void *aux)
224 printf("i4bmatch: aux=0x%x\n", aux);
225 return 1;
227 void
228 dummy_i4battach(struct device *parent, struct device *self, void *aux)
230 printf("dummy_i4battach: aux=0x%x\n", aux);
232 #endif /* __bsdi__ */
234 /*---------------------------------------------------------------------------*
235 * interface attach routine
236 *---------------------------------------------------------------------------*/
237 PDEVSTATIC void
238 #ifdef __FreeBSD__
239 isdnattach(void *dummy)
240 #else
241 isdnattach(void)
242 #endif
244 i4b_rdqueue.ifq_maxlen = IFQ_MAXLEN;
245 selinit(&select_rd_info);
247 #if defined(__FreeBSD__)
248 #if __FreeBSD__ == 3
250 #ifdef DEVFS
251 devfs_token = devfs_add_devswf(&i4b_cdevsw, 0, DV_CHR,
252 UID_ROOT, GID_WHEEL, 0600,
253 "i4b");
254 #endif
256 #else
257 make_dev(&i4b_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "i4b");
258 #endif
259 #endif
262 /*---------------------------------------------------------------------------*
263 * i4bopen - device driver open routine
264 *---------------------------------------------------------------------------*/
265 PDEVSTATIC int
266 isdnopen(dev_t dev, int flag, int fmt, struct lwp *l)
268 int x;
270 if(minor(dev))
271 return(ENXIO);
273 if(openflag)
274 return(EBUSY);
276 x = splnet();
277 openflag = 1;
278 i4b_l4_daemon_attached();
279 splx(x);
281 return(0);
284 /*---------------------------------------------------------------------------*
285 * i4bclose - device driver close routine
286 *---------------------------------------------------------------------------*/
287 PDEVSTATIC int
288 isdnclose(dev_t dev, int flag, int fmt,
289 struct lwp *l)
291 int x = splnet();
292 openflag = 0;
293 i4b_l4_daemon_detached();
294 i4b_Dcleanifq(&i4b_rdqueue);
295 splx(x);
296 return(0);
299 /*---------------------------------------------------------------------------*
300 * i4bread - device driver read routine
301 *---------------------------------------------------------------------------*/
302 PDEVSTATIC int
303 isdnread(dev_t dev, struct uio *uio, int ioflag)
305 struct mbuf *m;
306 int x;
307 int error = 0;
309 if(minor(dev))
310 return(ENODEV);
312 x = splnet();
313 while(IF_QEMPTY(&i4b_rdqueue))
315 readflag = 1;
316 error = tsleep((void *) &i4b_rdqueue, (PZERO + 1) | PCATCH, "bird", 0);
317 if (error != 0) {
318 splx(x);
319 return error;
323 IF_DEQUEUE(&i4b_rdqueue, m);
325 splx(x);
327 if(m && m->m_len)
328 error = uiomove(m->m_data, m->m_len, uio);
329 else
330 error = EIO;
332 if(m)
333 i4b_Dfreembuf(m);
335 return(error);
338 /*---------------------------------------------------------------------------*
339 * i4bioctl - device driver ioctl routine
340 *---------------------------------------------------------------------------*/
341 PDEVSTATIC int
342 isdnioctl(dev_t dev, u_long cmd, void *data, int flag,
343 struct lwp *l)
345 struct isdn_l3_driver *d;
346 call_desc_t *cd;
347 int error = 0;
349 if(minor(dev))
350 return(ENODEV);
352 switch(cmd)
354 /* cdid request, reserve cd and return cdid */
356 case I4B_CDID_REQ:
358 msg_cdid_req_t *mir;
359 mir = (msg_cdid_req_t *)data;
360 cd = reserve_cd();
361 mir->cdid = cd->cdid;
362 break;
365 /* connect request, dial out to remote */
367 case I4B_CONNECT_REQ:
369 msg_connect_req_t *mcr;
370 mcr = (msg_connect_req_t *)data; /* setup ptr */
372 if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */
374 NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!");
375 error = EINVAL;
376 break;
378 cd->isdnif = -1;
379 cd->l3drv = NULL;
381 d = isdn_find_l3_by_isdnif(mcr->controller);
382 if (d == NULL) {
383 error = EINVAL;
384 break;
387 /* prevent dialling on leased lines */
388 if(d->protocol == PROTOCOL_D64S)
390 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
391 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL);
392 i4b_l4_disconnect_ind(cd);
393 freecd_by_cd(cd);
394 break;
397 cd->isdnif = mcr->controller; /* fill cd */
398 cd->l3drv = d;
399 cd->bprot = mcr->bprot;
400 cd->bchan_driver_index = mcr->driver;
401 cd->bchan_driver_unit = mcr->driver_unit;
402 cd->cr = get_rand_cr(cd->isdnif);
404 cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm;
405 cd->shorthold_data.unitlen_time = mcr->shorthold_data.unitlen_time;
406 cd->shorthold_data.idle_time = mcr->shorthold_data.idle_time;
407 cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time;
409 cd->last_aocd_time = 0;
410 if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC)
411 cd->aocd_flag = 1;
412 else
413 cd->aocd_flag = 0;
415 cd->cunits = 0;
417 cd->max_idle_time = 0; /* this is outgoing */
419 cd->dir = DIR_OUTGOING;
421 NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld",
422 (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time,
423 (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time);
425 strlcpy(cd->dst_telno, mcr->dst_telno,
426 sizeof(cd->dst_telno));
427 strlcpy(cd->src_telno, mcr->src_telno,
428 sizeof(cd->src_telno));
429 cd->display[0] = '\0';
431 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
432 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL);
435 * If we want a specific channel, check if that
436 * one is available.
438 if ((mcr->channel >= 0) && (mcr->channel < d->nbch)) {
439 if(d->bch_state[mcr->channel] != BCH_ST_FREE)
440 SET_CAUSE_VAL(cd->cause_in,
441 CAUSE_I4B_NOCHAN);
444 * If any channel will do, see if any are free.
446 } else if (mcr->channel == CHAN_ANY) {
447 int i;
449 for (i = 0; i < d->nbch; i++)
450 if (d->bch_state[i] == BCH_ST_FREE)
451 break;
453 if (i == d->nbch)
454 SET_CAUSE_VAL(cd->cause_in,
455 CAUSE_I4B_NOCHAN);
457 } else {
458 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
461 cd->channelid = mcr->channel;
463 cd->isdntxdelay = mcr->txdelay;
465 if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL)
467 i4b_l4_disconnect_ind(cd);
468 freecd_by_cd(cd);
470 else
472 d->l3driver->N_CONNECT_REQUEST(cd);
474 break;
477 /* connect response, accept/reject/ignore incoming call */
479 case I4B_CONNECT_RESP:
481 msg_connect_resp_t *mcrsp;
483 mcrsp = (msg_connect_resp_t *)data;
485 if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */
487 NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!");
488 error = EINVAL;
489 break;
492 T400_stop(cd);
494 cd->bchan_driver_index = mcrsp->driver;
495 cd->bchan_driver_unit = mcrsp->driver_unit;
496 cd->max_idle_time = mcrsp->max_idle_time;
498 cd->shorthold_data.shorthold_algorithm = SHA_FIXU;
499 cd->shorthold_data.unitlen_time = 0; /* this is incoming */
500 cd->shorthold_data.idle_time = 0;
501 cd->shorthold_data.earlyhup_time = 0;
503 cd->isdntxdelay = mcrsp->txdelay;
505 NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time);
507 d = isdn_find_l3_by_isdnif(cd->isdnif);
508 if (d == NULL) {
509 error = EINVAL;
510 break;
512 d->l3driver->N_CONNECT_RESPONSE(cd, mcrsp->response, mcrsp->cause);
513 break;
516 /* disconnect request, actively terminate connection */
518 case I4B_DISCONNECT_REQ:
520 msg_discon_req_t *mdr;
522 mdr = (msg_discon_req_t *)data;
524 if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */
526 NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid %d not found!", mdr->cdid);
527 error = EINVAL;
528 break;
531 /* preset causes with our cause */
532 cd->cause_in = cd->cause_out = mdr->cause;
534 d = isdn_find_l3_by_isdnif(cd->isdnif);
535 if (d == NULL) {
536 error = EINVAL;
537 break;
540 d->l3driver->N_DISCONNECT_REQUEST(cd, mdr->cause);
541 break;
544 /* controller info request */
546 case I4B_CTRL_INFO_REQ:
548 msg_ctrl_info_req_t *mcir;
549 int isdnif;
551 mcir = (msg_ctrl_info_req_t *)data;
552 isdnif = mcir->controller;
553 memset(mcir, 0, sizeof(msg_ctrl_info_req_t));
554 mcir->controller = isdnif;
555 mcir->ncontroller
556 = isdn_count_isdnif(&mcir->max_isdnif);
557 d = isdn_find_l3_by_isdnif(isdnif);
558 if (d != NULL) {
559 mcir->tei = d->tei;
560 mcir->nbch = d->nbch;
561 strncpy(mcir->devname, d->devname, sizeof(mcir->devname)-1);
562 strncpy(mcir->cardname, d->card_name, sizeof(mcir->cardname)-1);
563 } else {
564 error = ENODEV;
566 break;
569 /* dial response */
571 case I4B_DIALOUT_RESP:
573 const struct isdn_l4_driver_functions *drv;
574 msg_dialout_resp_t *mdrsp;
575 void *l4_softc;
577 mdrsp = (msg_dialout_resp_t *)data;
578 drv = isdn_l4_get_driver(mdrsp->driver, mdrsp->driver_unit);
580 if(drv != NULL) {
581 l4_softc = (*drv->get_softc)(mdrsp->driver_unit);
582 (*drv->dial_response)(l4_softc, mdrsp->stat, mdrsp->cause);
584 break;
587 /* update timeout value */
589 case I4B_TIMEOUT_UPD:
591 msg_timeout_upd_t *mtu;
592 int x;
594 mtu = (msg_timeout_upd_t *)data;
596 NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!",
597 mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time,
598 mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time);
600 if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */
602 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!");
603 error = EINVAL;
604 break;
607 switch( mtu->shorthold_data.shorthold_algorithm )
609 case SHA_FIXU:
611 * For this algorithm unitlen_time,
612 * idle_time and earlyhup_time are used.
615 if(!(mtu->shorthold_data.unitlen_time >= 0 &&
616 mtu->shorthold_data.idle_time >= 0 &&
617 mtu->shorthold_data.earlyhup_time >= 0))
619 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!");
620 error = EINVAL;
622 break;
624 case SHA_VARU:
626 * For this algorithm unitlen_time and
627 * idle_time are used. both must be
628 * positive integers. earlyhup_time is
629 * not used and must be 0.
632 if(!(mtu->shorthold_data.unitlen_time > 0 &&
633 mtu->shorthold_data.idle_time >= 0 &&
634 mtu->shorthold_data.earlyhup_time == 0))
636 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!");
637 error = EINVAL;
639 break;
641 default:
642 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!");
643 error = EINVAL;
644 break;
648 * any error set above requires us to break
649 * out of the outer switch
651 if(error != 0)
652 break;
654 x = splnet();
655 cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm;
656 cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time;
657 cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time;
658 cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time;
659 splx(x);
660 break;
663 /* soft enable/disable interface */
665 case I4B_UPDOWN_IND:
667 msg_updown_ind_t *mui;
668 const struct isdn_l4_driver_functions *drv;
669 void *l4_softc;
671 mui = (msg_updown_ind_t *)data;
672 drv = isdn_l4_get_driver(mui->driver, mui->driver_unit);
674 if (drv)
676 l4_softc = drv->get_softc(mui->driver_unit);
677 (*drv->updown_ind)(l4_softc, mui->updown);
679 break;
682 /* send ALERT request */
684 case I4B_ALERT_REQ:
686 msg_alert_req_t *mar;
688 mar = (msg_alert_req_t *)data;
690 if((cd = cd_by_cdid(mar->cdid)) == NULL)
692 NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!");
693 error = EINVAL;
694 break;
697 T400_stop(cd);
699 d = cd->l3drv;
700 if (d == NULL) {
701 error = EINVAL;
702 break;
704 d->l3driver->N_ALERT_REQUEST(cd);
706 break;
709 /* version/release number request */
711 case I4B_VR_REQ:
713 msg_vr_req_t *mvr;
715 mvr = (msg_vr_req_t *)data;
717 mvr->version = VERSION;
718 mvr->release = REL;
719 mvr->step = STEP;
720 break;
723 /* set D-channel protocol for a controller */
725 case I4B_PROT_IND:
727 msg_prot_ind_t *mpi;
729 mpi = (msg_prot_ind_t *)data;
731 d = isdn_find_l3_by_isdnif(mpi->controller);
732 if (d == NULL) {
733 error = EINVAL;
734 break;
736 d->protocol = mpi->protocol;
738 break;
741 case I4B_L4DRIVER_LOOKUP:
743 msg_l4driver_lookup_t *lookup = (msg_l4driver_lookup_t*)data;
744 lookup->name[L4DRIVER_NAME_SIZ-1] = 0;
745 lookup->driver_id = isdn_l4_find_driverid(lookup->name);
746 if (lookup->driver_id < 0)
747 error = ENXIO;
748 break;
751 /* Download request */
752 case I4B_CTRL_DOWNLOAD:
754 struct isdn_dr_prot *prots = NULL, *prots2 = NULL;
755 struct isdn_download_request *r =
756 (struct isdn_download_request*)data;
757 int i;
759 d = isdn_find_l3_by_isdnif(r->controller);
760 if (d == NULL)
762 error = ENODEV;
763 goto download_done;
766 if(d->l3driver->N_DOWNLOAD == NULL)
768 error = ENODEV;
769 goto download_done;
772 prots = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
773 M_DEVBUF, M_WAITOK);
775 prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
776 M_DEVBUF, M_WAITOK);
778 if(!prots || !prots2)
780 error = ENOMEM;
781 goto download_done;
784 copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
786 for(i = 0; i < r->numprotos; i++)
788 prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
789 copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
790 prots2[i].bytecount = prots[i].bytecount;
793 error = d->l3driver->N_DOWNLOAD(
794 d->l1_token,
795 r->numprotos, prots2);
797 download_done:
798 if(prots2)
800 for(i = 0; i < r->numprotos; i++)
802 if(prots2[i].microcode)
804 free(prots2[i].microcode, M_DEVBUF);
807 free(prots2, M_DEVBUF);
810 if(prots)
812 free(prots, M_DEVBUF);
814 break;
817 /* Diagnostic request */
819 case I4B_ACTIVE_DIAGNOSTIC:
821 struct isdn_diagnostic_request req, *r =
822 (struct isdn_diagnostic_request*)data;
824 req.in_param = req.out_param = NULL;
825 d = isdn_find_l3_by_isdnif(r->controller);
826 if (d == NULL)
828 error = ENODEV;
829 goto diag_done;
832 if (d->l3driver->N_DIAGNOSTICS == NULL)
834 error = ENODEV;
835 goto diag_done;
838 memcpy(&req, r, sizeof(req));
840 if(req.in_param_len)
842 /* XXX arbitrary limit */
843 if (req.in_param_len > I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) {
844 error = EINVAL;
845 goto diag_done;
848 req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK);
850 if(!req.in_param)
852 error = ENOMEM;
853 goto diag_done;
855 error = copyin(r->in_param, req.in_param, req.in_param_len);
856 if (error)
857 goto diag_done;
860 if(req.out_param_len)
862 req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK);
864 if(!req.out_param)
866 error = ENOMEM;
867 goto diag_done;
871 error = d->l3driver->N_DIAGNOSTICS(d->l1_token, &req);
873 if(!error && req.out_param_len)
874 error = copyout(req.out_param, r->out_param, req.out_param_len);
876 diag_done:
877 if(req.in_param)
878 free(req.in_param, M_DEVBUF);
880 if(req.out_param)
881 free(req.out_param, M_DEVBUF);
883 break;
886 /* default */
888 default:
889 error = ENOTTY;
890 break;
893 return(error);
896 #ifdef OS_USES_SELECT
898 /*---------------------------------------------------------------------------*
899 * i4bselect - device driver select routine
900 *---------------------------------------------------------------------------*/
901 PDEVSTATIC int
902 i4bselect(dev_t dev, int rw, struct lwp *l)
904 int x;
906 if(minor(dev))
907 return(ENODEV);
909 switch(rw)
911 case FREAD:
912 if(!IF_QEMPTY(&i4b_rdqueue))
913 return(1);
914 x = splnet();
915 selrecord(l, &select_rd_info);
916 selflag = 1;
917 splx(x);
918 return(0);
919 break;
921 case FWRITE:
922 return(1);
923 break;
925 return(0);
928 #else /* OS_USES_SELECT */
930 /*---------------------------------------------------------------------------*
931 * i4bpoll - device driver poll routine
932 *---------------------------------------------------------------------------*/
933 PDEVSTATIC int
934 isdnpoll(dev_t dev, int events, struct lwp *l)
936 int x;
938 if(minor(dev))
939 return(ENODEV);
941 if((events & POLLIN) || (events & POLLRDNORM))
943 if(!IF_QEMPTY(&i4b_rdqueue))
944 return(1);
946 x = splnet();
947 selrecord(l, &select_rd_info);
948 selflag = 1;
949 splx(x);
950 return(0);
952 else if((events & POLLOUT) || (events & POLLWRNORM))
954 return(1);
957 return(0);
960 static void
961 filt_i4brdetach(struct knote *kn)
963 int s;
965 s = splnet();
966 SLIST_REMOVE(&select_rd_info.sel_klist, kn, knote, kn_selnext);
967 splx(s);
970 static int
971 filt_i4bread(struct knote *kn, long hint)
973 struct mbuf *m;
975 if (IF_QEMPTY(&i4b_rdqueue))
976 return (0);
978 IF_POLL(&i4b_rdqueue, m);
980 kn->kn_data = m->m_len;
981 return (1);
984 static const struct filterops i4bread_filtops =
985 { 1, NULL, filt_i4brdetach, filt_i4bread };
987 static const struct filterops i4b_seltrue_filtops =
988 { 1, NULL, filt_i4brdetach, filt_seltrue };
991 isdnkqfilter(dev_t dev, struct knote *kn)
993 struct klist *klist;
994 int s;
996 switch (kn->kn_filter) {
997 case EVFILT_READ:
998 klist = &select_rd_info.sel_klist;
999 kn->kn_fop = &i4bread_filtops;
1000 break;
1002 case EVFILT_WRITE:
1003 klist = &select_rd_info.sel_klist;
1004 kn->kn_fop = &i4b_seltrue_filtops;
1005 break;
1007 default:
1008 return (EINVAL);
1011 kn->kn_hook = NULL;
1013 s = splnet();
1014 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1015 splx(s);
1017 return (0);
1020 #endif /* OS_USES_SELECT */
1022 /*---------------------------------------------------------------------------*
1023 * i4bputqueue - put message into queue to userland
1024 *---------------------------------------------------------------------------*/
1025 void
1026 i4bputqueue(struct mbuf *m)
1028 int x;
1030 if(!openflag)
1032 i4b_Dfreembuf(m);
1033 return;
1036 x = splnet();
1038 if(IF_QFULL(&i4b_rdqueue))
1040 struct mbuf *m1;
1041 IF_DEQUEUE(&i4b_rdqueue, m1);
1042 i4b_Dfreembuf(m1);
1043 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1046 IF_ENQUEUE(&i4b_rdqueue, m);
1048 splx(x);
1050 if(readflag)
1052 readflag = 0;
1053 wakeup((void *) &i4b_rdqueue);
1056 if(selflag)
1058 selflag = 0;
1059 selnotify(&select_rd_info, 0, 0);
1063 /*---------------------------------------------------------------------------*
1064 * i4bputqueue_hipri - put message into front of queue to userland
1065 *---------------------------------------------------------------------------*/
1066 void
1067 i4bputqueue_hipri(struct mbuf *m)
1069 int x;
1071 if(!openflag)
1073 i4b_Dfreembuf(m);
1074 return;
1077 x = splnet();
1079 if(IF_QFULL(&i4b_rdqueue))
1081 struct mbuf *m1;
1082 IF_DEQUEUE(&i4b_rdqueue, m1);
1083 i4b_Dfreembuf(m1);
1084 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1087 IF_PREPEND(&i4b_rdqueue, m);
1089 splx(x);
1091 if(readflag)
1093 readflag = 0;
1094 wakeup((void *) &i4b_rdqueue);
1097 if(selflag)
1099 selflag = 0;
1100 selnotify(&select_rd_info, 0, 0);
1104 void
1105 isdn_isdnif_ready(int isdnif)
1107 struct isdn_l3_driver *d = isdn_find_l3_by_isdnif(isdnif);
1109 if (d == NULL)
1110 return;
1112 printf("ISDN %d at %s, %d B channels\n", isdnif, d->devname, d->nbch);
1113 if (!openflag) return;
1115 d->l3driver->N_MGMT_COMMAND(d, CMR_DOPEN, 0);
1116 i4b_l4_contr_ev_ind(isdnif, 1);
1119 #endif /* NISDN > 0 */