]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i4b/layer4/i4b_i4bdrv.c
This commit was generated by cvs2svn to compensate for changes in r70494,
[FreeBSD/FreeBSD.git] / sys / i4b / layer4 / i4b_i4bdrv.c
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_i4bdrv.c - i4b userland interface driver
28  *      --------------------------------------------
29  *
30  *      $Id: i4b_i4bdrv.c,v 1.59 2000/10/06 08:37:43 hm Exp $ 
31  *
32  * $FreeBSD$
33  *
34  *      last edit-date: [Mon Oct  2 09:55:28 2000]
35  *
36  *---------------------------------------------------------------------------*/
37
38 #include "i4b.h"
39 #include "i4bipr.h"
40 #include "i4btel.h"
41
42
43 #if NI4B > 1
44 #error "only 1 (one) i4b device possible!"
45 #endif
46
47 #if NI4B > 0
48
49 #include <sys/param.h>
50
51 #if defined(__FreeBSD__)
52 #include <sys/ioccom.h>
53 #include <sys/malloc.h>
54 #include <sys/uio.h>
55 #else
56 #include <sys/ioctl.h>
57 #endif
58
59 #include <sys/kernel.h>
60 #include <sys/systm.h>
61 #include <sys/conf.h>
62 #include <sys/mbuf.h>
63 #include <sys/socket.h>
64 #include <sys/select.h>
65 #include <net/if.h>
66
67 #ifdef __NetBSD__
68 #include <sys/types.h>
69 #endif
70
71 #if defined(__FreeBSD__)
72 #include "i4bing.h"
73 #endif
74
75 #ifdef __bsdi__
76 #include "ibc.h"
77 #else
78 #ifdef __FreeBSD__
79 #include "i4bisppp.h"
80 #else
81 #include <net/if_sppp.h>
82 #endif
83 #endif
84
85 #ifdef __FreeBSD__
86
87 #if defined(__FreeBSD__) && __FreeBSD__ == 3
88 #include "opt_devfs.h"
89 #endif
90
91 #ifdef DEVFS
92 #include <sys/devfsext.h>
93 #endif
94
95 #endif /* __FreeBSD__*/
96
97 #ifdef __FreeBSD__
98 #include <machine/i4b_debug.h>
99 #include <machine/i4b_ioctl.h>
100 #include <machine/i4b_cause.h>
101 #else
102 #include <i4b/i4b_debug.h>
103 #include <i4b/i4b_ioctl.h>
104 #include <i4b/i4b_cause.h>
105 #endif
106
107 #include <i4b/include/i4b_l3l4.h>
108 #include <i4b/include/i4b_mbuf.h>
109 #include <i4b/include/i4b_global.h>
110
111 #include <i4b/layer4/i4b_l4.h>
112
113 #ifdef OS_USES_POLL
114 #include <sys/poll.h>
115 #endif
116
117 struct selinfo select_rd_info;
118
119 static struct ifqueue i4b_rdqueue;
120 static int openflag = 0;
121 static int selflag = 0;
122 static int readflag = 0;
123
124 #if defined(__FreeBSD__) && __FreeBSD__ == 3
125 #ifdef DEVFS
126 static void *devfs_token;
127 #endif
128 #endif
129
130 #ifndef __FreeBSD__
131
132 #define PDEVSTATIC      /* - not static - */
133 PDEVSTATIC void i4battach __P((void));
134 PDEVSTATIC int i4bopen __P((dev_t dev, int flag, int fmt, struct proc *p));
135 PDEVSTATIC int i4bclose __P((dev_t dev, int flag, int fmt, struct proc *p));
136 PDEVSTATIC int i4bread __P((dev_t dev, struct uio *uio, int ioflag));
137
138 #ifdef __bsdi__
139 PDEVSTATIC int i4bioctl __P((dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p));
140 #else
141 PDEVSTATIC int i4bioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
142 #endif
143
144 #ifdef OS_USES_POLL
145 PDEVSTATIC int i4bpoll __P((dev_t dev, int events, struct proc *p));
146 #else
147 PDEVSTATIC int i4bselect __P((dev_t dev, int rw, struct proc *p));
148 #endif
149
150 #endif /* #ifndef __FreeBSD__ */
151
152 #if BSD > 199306 && defined(__FreeBSD__)
153
154 #define PDEVSTATIC      static
155
156 PDEVSTATIC      d_open_t        i4bopen;
157 PDEVSTATIC      d_close_t       i4bclose;
158 PDEVSTATIC      d_read_t        i4bread;
159 PDEVSTATIC      d_ioctl_t       i4bioctl;
160
161 #ifdef OS_USES_POLL
162 PDEVSTATIC      d_poll_t        i4bpoll;
163 #define POLLFIELD               i4bpoll
164 #else
165 PDEVSTATIC      d_select_t      i4bselect;
166 #define POLLFIELD               i4bselect
167 #endif
168
169 #define CDEV_MAJOR 60
170
171 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
172 static struct cdevsw i4b_cdevsw = {
173         /* open */      i4bopen,
174         /* close */     i4bclose,
175         /* read */      i4bread,
176         /* write */     nowrite,
177         /* ioctl */     i4bioctl,
178         /* poll */      POLLFIELD,
179         /* mmap */      nommap,
180         /* strategy */  nostrategy,
181         /* name */      "i4b",
182         /* maj */       CDEV_MAJOR,
183         /* dump */      nodump,
184         /* psize */     nopsize,
185         /* flags */     0,
186         /* bmaj */      -1
187 };
188 #else
189 static struct cdevsw i4b_cdevsw = {
190         i4bopen,        i4bclose,       i4bread,        nowrite,
191         i4bioctl,       nostop,         nullreset,      nodevtotty,
192         POLLFIELD,      nommap,         NULL,           "i4b", NULL,    -1
193 };
194 #endif
195
196 PDEVSTATIC void i4battach(void *);
197 PSEUDO_SET(i4battach, i4b_i4bdrv);
198
199 static void
200 i4b_drvinit(void *unused)
201 {
202 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
203         cdevsw_add(&i4b_cdevsw);
204 #else
205         static int i4b_devsw_installed = 0;
206         dev_t dev;
207
208         if( ! i4b_devsw_installed )
209         {
210                 dev = makedev(CDEV_MAJOR,0);
211                 cdevsw_add(&dev,&i4b_cdevsw,NULL);
212                 i4b_devsw_installed = 1;
213         }
214 #endif
215 }
216
217 SYSINIT(i4bdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,i4b_drvinit,NULL)
218
219 #endif /* BSD > 199306 && defined(__FreeBSD__) */
220
221 #ifdef __bsdi__
222 #include <sys/device.h>
223 int i4bmatch(struct device *parent, struct cfdata *cf, void *aux);
224 void dummy_i4battach(struct device*, struct device *, void *);
225
226 #define CDEV_MAJOR 65
227
228 static struct cfdriver i4bcd =
229         { NULL, "i4b", i4bmatch, dummy_i4battach, DV_DULL,
230           sizeof(struct cfdriver) };
231 struct devsw i4bsw = 
232         { &i4bcd,
233           i4bopen,      i4bclose,       i4bread,        nowrite,
234           i4bioctl,     i4bselect,      nommap,         nostrat,
235           nodump,       nopsize,        0,              nostop
236 };
237
238 int
239 i4bmatch(struct device *parent, struct cfdata *cf, void *aux)
240 {
241         printf("i4bmatch: aux=0x%x\n", aux);
242         return 1;
243 }
244 void
245 dummy_i4battach(struct device *parent, struct device *self, void *aux)
246 {
247         printf("dummy_i4battach: aux=0x%x\n", aux);
248 }
249 #endif /* __bsdi__ */
250
251 /*---------------------------------------------------------------------------*
252  *      interface attach routine
253  *---------------------------------------------------------------------------*/
254 PDEVSTATIC void
255 #ifdef __FreeBSD__
256 i4battach(void *dummy)
257 #else
258 i4battach()
259 #endif
260 {
261 #ifndef HACK_NO_PSEUDO_ATTACH_MSG
262         printf("i4b: ISDN call control device attached\n");
263 #endif
264         i4b_rdqueue.ifq_maxlen = IFQ_MAXLEN;
265         mtx_init(&i4b_rdqueue.ifq_mtx, "i4b_rdqueue", MTX_DEF);
266
267 #if defined(__FreeBSD__)
268 #if __FreeBSD__ == 3
269
270 #ifdef DEVFS
271         devfs_token = devfs_add_devswf(&i4b_cdevsw, 0, DV_CHR,
272                                        UID_ROOT, GID_WHEEL, 0600,
273                                        "i4b");
274 #endif
275
276 #else
277         make_dev(&i4b_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "i4b");
278 #endif
279 #endif
280 }
281
282 /*---------------------------------------------------------------------------*
283  *      i4bopen - device driver open routine
284  *---------------------------------------------------------------------------*/
285 PDEVSTATIC int
286 i4bopen(dev_t dev, int flag, int fmt, struct proc *p)
287 {
288         int x;
289         
290         if(minor(dev))
291                 return(ENXIO);
292
293         if(openflag)
294                 return(EBUSY);
295         
296         x = splimp();
297         openflag = 1;
298         i4b_l4_daemon_attached();
299         splx(x);
300         
301         return(0);
302 }
303
304 /*---------------------------------------------------------------------------*
305  *      i4bclose - device driver close routine
306  *---------------------------------------------------------------------------*/
307 PDEVSTATIC int
308 i4bclose(dev_t dev, int flag, int fmt, struct proc *p)
309 {
310         int x = splimp();       
311         openflag = 0;
312         i4b_l4_daemon_detached();
313         i4b_Dcleanifq(&i4b_rdqueue);
314         splx(x);
315         return(0);
316 }
317
318 /*---------------------------------------------------------------------------*
319  *      i4bread - device driver read routine
320  *---------------------------------------------------------------------------*/
321 PDEVSTATIC int
322 i4bread(dev_t dev, struct uio *uio, int ioflag)
323 {
324         struct mbuf *m;
325         int x;
326         int error = 0;
327
328         if(minor(dev))
329                 return(ENODEV);
330
331         x = splimp();
332         IF_LOCK(&i4b_rdqueue);
333         while(IF_QEMPTY(&i4b_rdqueue))
334         {
335                 readflag = 1;
336                 error = msleep((caddr_t) &i4b_rdqueue, &i4b_rdqueue.ifq_mtx,
337                     (PZERO + 1) | PCATCH, "bird", 0);
338                 if (error != 0) {
339                         IF_UNLOCK(&i4b_rdqueue);
340                         splx(x);
341                         return error;
342                 }
343         }
344
345         _IF_DEQUEUE(&i4b_rdqueue, m);
346         IF_UNLOCK(&i4b_rdqueue);
347
348         splx(x);
349                 
350         if(m && m->m_len)
351                 error = uiomove(m->m_data, m->m_len, uio);
352         else
353                 error = EIO;
354                 
355         if(m)
356                 i4b_Dfreembuf(m);
357
358         return(error);
359 }
360
361 /*---------------------------------------------------------------------------*
362  *      i4bioctl - device driver ioctl routine
363  *---------------------------------------------------------------------------*/
364 PDEVSTATIC int
365 #if defined (__FreeBSD_version) && __FreeBSD_version >= 300003
366 i4bioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
367 #elif defined(__bsdi__)
368 i4bioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
369 #else
370 i4bioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
371 #endif
372 {
373         call_desc_t *cd;
374         int error = 0;
375         
376         if(minor(dev))
377                 return(ENODEV);
378
379         switch(cmd)
380         {
381                 /* cdid request, reserve cd and return cdid */
382
383                 case I4B_CDID_REQ:
384                 {
385                         msg_cdid_req_t *mir;
386                         mir = (msg_cdid_req_t *)data;
387                         cd = reserve_cd();
388                         mir->cdid = cd->cdid;
389                         break;
390                 }
391                 
392                 /* connect request, dial out to remote */
393                 
394                 case I4B_CONNECT_REQ:
395                 {
396                         msg_connect_req_t *mcr;
397                         mcr = (msg_connect_req_t *)data;        /* setup ptr */
398
399                         if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */
400                         {
401                                 NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!"); 
402                                 error = EINVAL;
403                                 break;
404                         }
405
406                         /* prevent dialling on leased lines */
407                         if(ctrl_desc[mcr->controller].protocol == PROTOCOL_D64S)
408                         {
409                                 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
410                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL);
411                                 i4b_l4_disconnect_ind(cd);
412                                 freecd_by_cd(cd);
413                                 break;
414                         }
415
416                         cd->controller = mcr->controller;       /* fill cd */
417                         cd->bprot = mcr->bprot;
418                         cd->driver = mcr->driver;
419                         cd->driver_unit = mcr->driver_unit;
420                         cd->cr = get_rand_cr(ctrl_desc[cd->controller].unit);
421
422                         cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm;
423                         cd->shorthold_data.unitlen_time  = mcr->shorthold_data.unitlen_time;
424                         cd->shorthold_data.idle_time     = mcr->shorthold_data.idle_time;
425                         cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time;
426
427                         cd->last_aocd_time = 0;
428                         if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC)
429                                 cd->aocd_flag = 1;
430                         else
431                                 cd->aocd_flag = 0;
432                                 
433                         cd->cunits = 0;
434
435                         cd->max_idle_time = 0;  /* this is outgoing */
436
437                         cd->dir = DIR_OUTGOING;
438                         
439                         NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld",
440                                         (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time,
441                                         (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time);
442
443                         strcpy(cd->dst_telno, mcr->dst_telno);
444                         strcpy(cd->src_telno, mcr->src_telno);
445                         cd->display[0] = '\0';
446
447                         SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
448                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL);
449                         
450                         switch(mcr->channel)
451                         {
452                                 case CHAN_B1:
453                                 case CHAN_B2:
454                                         if(ctrl_desc[mcr->controller].bch_state[mcr->channel] != BCH_ST_FREE)
455                                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
456                                         break;
457
458                                 case CHAN_ANY:
459                                         if((ctrl_desc[mcr->controller].bch_state[CHAN_B1] != BCH_ST_FREE) &&
460                                            (ctrl_desc[mcr->controller].bch_state[CHAN_B2] != BCH_ST_FREE))
461                                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
462                                         break;
463
464                                 default:
465                                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
466                                         break;
467                         }
468
469                         cd->channelid = mcr->channel;
470
471                         cd->isdntxdelay = mcr->txdelay;
472                         
473                         /* check whether we have a pointer. Seems like */
474                         /* this should be adequate. GJ 19.09.97 */
475                         if(ctrl_desc[cd->controller].N_CONNECT_REQUEST == NULL)
476 /*XXX*/                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
477
478                         if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL)
479                         {
480                                 i4b_l4_disconnect_ind(cd);
481                                 freecd_by_cd(cd);
482                         }
483                         else
484                         {
485                                 (*ctrl_desc[cd->controller].N_CONNECT_REQUEST)(mcr->cdid);
486                         }
487                         break;
488                 }
489                 
490                 /* connect response, accept/reject/ignore incoming call */
491                 
492                 case I4B_CONNECT_RESP:
493                 {
494                         msg_connect_resp_t *mcrsp;
495                         
496                         mcrsp = (msg_connect_resp_t *)data;
497
498                         if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */
499                         {
500                                 NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!"); 
501                                 error = EINVAL;
502                                 break;
503                         }
504
505                         T400_stop(cd);
506
507                         cd->driver = mcrsp->driver;
508                         cd->driver_unit = mcrsp->driver_unit;
509                         cd->max_idle_time = mcrsp->max_idle_time;
510
511                         cd->shorthold_data.shorthold_algorithm = SHA_FIXU;
512                         cd->shorthold_data.unitlen_time = 0;    /* this is incoming */
513                         cd->shorthold_data.idle_time = 0;
514                         cd->shorthold_data.earlyhup_time = 0;
515
516                         cd->isdntxdelay = mcrsp->txdelay;                       
517                         
518                         NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time);
519
520                         (*ctrl_desc[cd->controller].N_CONNECT_RESPONSE)(mcrsp->cdid, mcrsp->response, mcrsp->cause);
521                         break;
522                 }
523                 
524                 /* disconnect request, actively terminate connection */
525                 
526                 case I4B_DISCONNECT_REQ:
527                 {
528                         msg_discon_req_t *mdr;
529                         
530                         mdr = (msg_discon_req_t *)data;
531
532                         if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */
533                         {
534                                 NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid not found!"); 
535                                 error = EINVAL;
536                                 break;
537                         }
538
539                         /* preset causes with our cause */
540                         cd->cause_in = cd->cause_out = mdr->cause;
541                         
542                         (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(mdr->cdid, mdr->cause);
543                         break;
544                 }
545                 
546                 /* controller info request */
547
548                 case I4B_CTRL_INFO_REQ:
549                 {
550                         msg_ctrl_info_req_t *mcir;
551                         
552                         mcir = (msg_ctrl_info_req_t *)data;
553                         mcir->ncontroller = nctrl;
554
555                         if(mcir->controller > nctrl)
556                         {
557                                 mcir->ctrl_type = -1;
558                                 mcir->card_type = -1;
559                         }
560                         else
561                         {
562                                 mcir->ctrl_type = 
563                                         ctrl_desc[mcir->controller].ctrl_type;
564                                 mcir->card_type = 
565                                         ctrl_desc[mcir->controller].card_type;
566
567                                 if(ctrl_desc[mcir->controller].ctrl_type == CTRL_PASSIVE)
568                                         mcir->tei = ctrl_desc[mcir->controller].tei;
569                                 else
570                                         mcir->tei = -1;
571                         }
572                         break;
573                 }
574                 
575                 /* dial response */
576                 
577                 case I4B_DIALOUT_RESP:
578                 {
579                         drvr_link_t *dlt = NULL;
580                         msg_dialout_resp_t *mdrsp;
581                         
582                         mdrsp = (msg_dialout_resp_t *)data;
583
584                         switch(mdrsp->driver)
585                         {
586 #if NI4BIPR > 0
587                                 case BDRV_IPR:
588                                         dlt = ipr_ret_linktab(mdrsp->driver_unit);
589                                         break;
590 #endif                                  
591
592 #if NI4BISPPP > 0
593                                 case BDRV_ISPPP:
594                                         dlt = i4bisppp_ret_linktab(mdrsp->driver_unit);
595                                         break;
596 #endif
597
598 #if NI4BTEL > 0
599                                 case BDRV_TEL:
600                                         dlt = tel_ret_linktab(mdrsp->driver_unit);
601                                         break;
602 #endif
603
604 #if NIBC > 0
605                                 case BDRV_IBC:
606                                         dlt = ibc_ret_linktab(mdrsp->driver_unit);
607                                         break;
608 #endif
609
610 #if NI4BING > 0
611                                 case BDRV_ING:
612                                         dlt = ing_ret_linktab(mdrsp->driver_unit);
613                                         break;
614 #endif                                  
615                         }
616
617                         if(dlt != NULL)         
618                                 (*dlt->dial_response)(mdrsp->driver_unit, mdrsp->stat, mdrsp->cause);
619                         break;
620                 }
621                 
622                 /* update timeout value */
623                 
624                 case I4B_TIMEOUT_UPD:
625                 {
626                         msg_timeout_upd_t *mtu;
627                         int x;
628                         
629                         mtu = (msg_timeout_upd_t *)data;
630
631                         NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!",
632                                         mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time,
633                                         mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time); 
634
635                         if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */
636                         {
637                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!"); 
638                                 error = EINVAL;
639                                 break;
640                         }
641
642                         switch( mtu->shorthold_data.shorthold_algorithm )
643                         {
644                                 case SHA_FIXU:
645                                         /*
646                                          * For this algorithm unitlen_time,
647                                          * idle_time and earlyhup_time are used.
648                                          */
649
650                                         if(!(mtu->shorthold_data.unitlen_time >= 0 &&
651                                              mtu->shorthold_data.idle_time >= 0    &&
652                                              mtu->shorthold_data.earlyhup_time >= 0))
653                                         {
654                                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!"); 
655                                                 error = EINVAL;
656                                         }
657                                         break;
658         
659                                 case SHA_VARU:
660                                         /*
661                                          * For this algorithm unitlen_time and
662                                          * idle_time are used. both must be
663                                          * positive integers. earlyhup_time is
664                                          * not used and must be 0.
665                                          */
666
667                                         if(!(mtu->shorthold_data.unitlen_time > 0 &&
668                                              mtu->shorthold_data.idle_time >= 0   &&
669                                              mtu->shorthold_data.earlyhup_time == 0))
670                                         {
671                                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!"); 
672                                                 error = EINVAL;
673                                         }
674                                         break;
675         
676                                 default:
677                                         NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!"); 
678                                         error = EINVAL;
679                                         break;
680                         }
681
682                         /*
683                          * any error set above requires us to break
684                          * out of the outer switch
685                          */
686                         if(error != 0)
687                                 break;
688
689                         x = SPLI4B();
690                         cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm;
691                         cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time;
692                         cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time;
693                         cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time;
694                         splx(x);
695                         break;
696                 }
697                         
698                 /* soft enable/disable interface */
699                 
700                 case I4B_UPDOWN_IND:
701                 {
702                         msg_updown_ind_t *mui;
703                         
704                         mui = (msg_updown_ind_t *)data;
705
706 #if NI4BIPR > 0
707                         if(mui->driver == BDRV_IPR)
708                         {
709                                 drvr_link_t *dlt;
710                                 dlt = ipr_ret_linktab(mui->driver_unit);
711                                 (*dlt->updown_ind)(mui->driver_unit, mui->updown);
712                         }
713 #endif
714                         break;
715                 }
716                 
717                 /* send ALERT request */
718                 
719                 case I4B_ALERT_REQ:
720                 {
721                         msg_alert_req_t *mar;
722                         
723                         mar = (msg_alert_req_t *)data;
724
725                         if((cd = cd_by_cdid(mar->cdid)) == NULL)
726                         {
727                                 NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!"); 
728                                 error = EINVAL;
729                                 break;
730                         }
731
732                         T400_stop(cd);
733                         
734                         (*ctrl_desc[cd->controller].N_ALERT_REQUEST)(mar->cdid);
735
736                         break;
737                 }
738
739                 /* version/release number request */
740                 
741                 case I4B_VR_REQ:
742                 {
743                         msg_vr_req_t *mvr;
744
745                         mvr = (msg_vr_req_t *)data;
746
747                         mvr->version = VERSION;
748                         mvr->release = REL;
749                         mvr->step = STEP;                       
750                         break;
751                 }
752
753                 /* set D-channel protocol for a controller */
754                 
755                 case I4B_PROT_IND:
756                 {
757                         msg_prot_ind_t *mpi;
758                         
759                         mpi = (msg_prot_ind_t *)data;
760
761                         ctrl_desc[mpi->controller].protocol = mpi->protocol;
762                         
763                         break;
764                 }
765                 
766                 /* Download request */
767
768                 case I4B_CTRL_DOWNLOAD:
769                 {
770                         struct isdn_dr_prot *prots = NULL, *prots2 = NULL;
771                         struct isdn_download_request *r =
772                                 (struct isdn_download_request*)data;
773                         int i;
774
775                         if (r->controller < 0 || r->controller >= nctrl)
776                         {
777                                 error = ENODEV;
778                                 goto download_done;
779                         }
780
781                         if(!ctrl_desc[r->controller].N_DOWNLOAD)
782                         {
783                                 error = ENODEV;
784                                 goto download_done;
785                         }
786
787                         prots = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
788                                         M_DEVBUF, M_WAITOK);
789
790                         prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
791                                         M_DEVBUF, M_WAITOK);
792
793                         if(!prots || !prots2)
794                         {
795                                 error = ENOMEM;
796                                 goto download_done;
797                         }
798
799                         copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
800
801                         for(i = 0; i < r->numprotos; i++)
802                         {
803                                 prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
804                                 copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
805                                 prots2[i].bytecount = prots[i].bytecount; 
806                         }
807
808                         error = ctrl_desc[r->controller].N_DOWNLOAD(
809                                                 ctrl_desc[r->controller].unit,
810                                                 r->numprotos, prots2);
811
812 download_done:
813                         if(prots2)
814                         {
815                                 for(i = 0; i < r->numprotos; i++)
816                                 {
817                                         if(prots2[i].microcode)
818                                         {
819                                                 free(prots2[i].microcode, M_DEVBUF);
820                                         }
821                                 }
822                                 free(prots2, M_DEVBUF);
823                         }
824
825                         if(prots)
826                         {
827                                 free(prots, M_DEVBUF);
828                         }
829                         break;
830                 }
831
832                 /* Diagnostic request */
833
834                 case I4B_ACTIVE_DIAGNOSTIC:
835                 {
836                         struct isdn_diagnostic_request req, *r =
837                                 (struct isdn_diagnostic_request*)data;
838
839                         req.in_param = req.out_param = NULL;
840                         if (r->controller < 0 || r->controller >= nctrl)
841                         {
842                                 error = ENODEV;
843                                 goto diag_done;
844                         }
845
846                         if(!ctrl_desc[r->controller].N_DIAGNOSTICS)
847                         {
848                                 error = ENODEV;
849                                 goto diag_done;
850                         }
851
852                         memcpy(&req, r, sizeof(req));
853
854                         if(req.in_param_len)
855                         {
856                                 req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK);
857
858                                 if(!req.in_param)
859                                 {
860                                         error = ENOMEM;
861                                         goto diag_done;
862                                 }
863                                 error = copyin(r->in_param, req.in_param, req.in_param_len);
864                                 if (error)
865                                         goto diag_done;
866                         }
867
868                         if(req.out_param_len)
869                         {
870                                 req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK);
871
872                                 if(!req.out_param)
873                                 {
874                                         error = ENOMEM;
875                                         goto diag_done;
876                                 }
877                         }
878                         
879                         error = ctrl_desc[r->controller].N_DIAGNOSTICS(r->controller, &req);
880
881                         if(!error && req.out_param_len)
882                                 error = copyout(req.out_param, r->out_param, req.out_param_len);
883
884 diag_done:
885                         if(req.in_param)
886                                 free(req.in_param, M_DEVBUF);
887                                 
888                         if(req.out_param)
889                                 free(req.out_param, M_DEVBUF);
890
891                         break;
892                 }
893
894                 /* default */
895                 
896                 default:
897                         error = ENOTTY;
898                         break;
899         }
900         
901         return(error);
902 }
903
904 #ifdef OS_USES_SELECT
905
906 /*---------------------------------------------------------------------------*
907  *      i4bselect - device driver select routine
908  *---------------------------------------------------------------------------*/
909 PDEVSTATIC int
910 i4bselect(dev_t dev, int rw, struct proc *p)
911 {
912         int x;
913         
914         if(minor(dev))
915                 return(ENODEV);
916
917         switch(rw)
918         {
919                 case FREAD:
920                         if(!IF_QEMPTY(&i4b_rdqueue))
921                                 return(1);
922                         x = splimp();
923                         selrecord(p, &select_rd_info);
924                         selflag = 1;
925                         splx(x);
926                         return(0);
927                         break;
928
929                 case FWRITE:
930                         return(1);
931                         break;
932         }
933         return(0);
934 }
935
936 #else /* OS_USES_SELECT */
937
938 /*---------------------------------------------------------------------------*
939  *      i4bpoll - device driver poll routine
940  *---------------------------------------------------------------------------*/
941 PDEVSTATIC int
942 i4bpoll(dev_t dev, int events, struct proc *p)
943 {
944         int x;
945         
946         if(minor(dev))
947                 return(ENODEV);
948
949         if((events & POLLIN) || (events & POLLRDNORM))
950         {
951                 if(!IF_QEMPTY(&i4b_rdqueue))
952                         return(1);
953
954                 x = splimp();
955                 selrecord(p, &select_rd_info);
956                 selflag = 1;
957                 splx(x);
958                 return(0);
959         }
960         else if((events & POLLOUT) || (events & POLLWRNORM))
961         {
962                 return(1);
963         }
964
965         return(0);
966 }
967
968 #endif /* OS_USES_SELECT */
969
970 /*---------------------------------------------------------------------------*
971  *      i4bputqueue - put message into queue to userland
972  *---------------------------------------------------------------------------*/
973 void
974 i4bputqueue(struct mbuf *m)
975 {
976         int x;
977         
978         if(!openflag)
979         {
980                 i4b_Dfreembuf(m);
981                 return;
982         }
983
984         x = splimp();
985         
986         IF_LOCK(&i4b_rdqueue);
987         if(_IF_QFULL(&i4b_rdqueue))
988         {
989                 struct mbuf *m1;
990                 _IF_DEQUEUE(&i4b_rdqueue, m1);
991                 i4b_Dfreembuf(m1);
992                 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
993         }
994
995         _IF_ENQUEUE(&i4b_rdqueue, m);
996         IF_UNLOCK(&i4b_rdqueue);
997
998         splx(x);        
999
1000         if(readflag)
1001         {
1002                 readflag = 0;
1003                 wakeup((caddr_t) &i4b_rdqueue);
1004         }
1005
1006         if(selflag)
1007         {
1008                 selflag = 0;
1009                 selwakeup(&select_rd_info);
1010         }
1011 }
1012
1013 /*---------------------------------------------------------------------------*
1014  *      i4bputqueue_hipri - put message into front of queue to userland
1015  *---------------------------------------------------------------------------*/
1016 void
1017 i4bputqueue_hipri(struct mbuf *m)
1018 {
1019         int x;
1020         
1021         if(!openflag)
1022         {
1023                 i4b_Dfreembuf(m);
1024                 return;
1025         }
1026
1027         x = splimp();
1028         
1029         IF_LOCK(&i4b_rdqueue);
1030         if(_IF_QFULL(&i4b_rdqueue))
1031         {
1032                 struct mbuf *m1;
1033                 _IF_DEQUEUE(&i4b_rdqueue, m1);
1034                 i4b_Dfreembuf(m1);
1035                 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1036         }
1037
1038         _IF_PREPEND(&i4b_rdqueue, m);
1039         IF_UNLOCK(&i4b_rdqueue);
1040
1041         splx(x);        
1042
1043         if(readflag)
1044         {
1045                 readflag = 0;
1046                 wakeup((caddr_t) &i4b_rdqueue);
1047         }
1048
1049         if(selflag)
1050         {
1051                 selflag = 0;
1052                 selwakeup(&select_rd_info);
1053         }
1054 }
1055
1056 #endif /* NI4B > 0 */