Merge branch 'vendor/LIBARCHIVE'
[dragonfly.git] / sys / net / i4b / layer4 / i4b_i4bdrv.c
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_i4bdrv.c - i4b userland interface driver
28  *      --------------------------------------------
29  *
30  * $FreeBSD: src/sys/i4b/layer4/i4b_i4bdrv.c,v 1.11.2.5 2001/12/16 15:12:59 hm Exp $
31  * $DragonFly: src/sys/net/i4b/layer4/i4b_i4bdrv.c,v 1.20 2008/01/06 16:55:52 swildner Exp $
32  *
33  *      last edit-date: [Sat Aug 11 18:08:10 2001]
34  *
35  *---------------------------------------------------------------------------*/
36
37 #include "use_i4b.h"
38 #include "use_i4bipr.h"
39 #include "use_i4btel.h"
40
41 #if NI4B > 1
42 #error "only 1 (one) i4b device possible!"
43 #endif
44
45 #if NI4B > 0
46
47 #include <sys/param.h>
48
49 #include <sys/malloc.h>
50 #include <sys/uio.h>
51 #include <sys/kernel.h>
52 #include <sys/systm.h>
53 #include <sys/conf.h>
54 #include <sys/device.h>
55 #include <sys/mbuf.h>
56 #include <sys/socket.h>
57 #include <sys/thread2.h>
58 #include <sys/selinfo.h>
59
60 #include <net/if.h>
61
62 #include "use_i4bing.h"
63 #include "use_i4bisppp.h"
64
65 #include <net/i4b/include/machine/i4b_debug.h>
66 #include <net/i4b/include/machine/i4b_ioctl.h>
67 #include <net/i4b/include/machine/i4b_cause.h>
68
69 #include "../include/i4b_l3l4.h"
70 #include "../include/i4b_mbuf.h"
71 #include "../include/i4b_global.h"
72
73 #include "i4b_l4.h"
74
75 #include <sys/poll.h>
76
77 struct selinfo select_rd_info;
78
79 static struct ifqueue i4b_rdqueue;
80 static int openflag = 0;
81 static int selflag = 0;
82 static int readflag = 0;
83
84 #define PDEVSTATIC      static
85
86 PDEVSTATIC      d_open_t        i4bopen;
87 PDEVSTATIC      d_close_t       i4bclose;
88 PDEVSTATIC      d_read_t        i4bread;
89 PDEVSTATIC      d_ioctl_t       i4bioctl;
90
91 PDEVSTATIC      d_poll_t        i4bpoll;
92 #define POLLFIELD               i4bpoll
93
94 #define CDEV_MAJOR 60
95
96 static struct dev_ops i4b_ops = {
97         { "i4b", CDEV_MAJOR, 0 },
98         .d_open =       i4bopen,
99         .d_close =      i4bclose,
100         .d_read =       i4bread,
101         .d_ioctl =      i4bioctl,
102         .d_poll =       POLLFIELD,
103 };
104
105 PDEVSTATIC void i4battach(void *);
106 PSEUDO_SET(i4battach, i4b_i4bdrv);
107
108 static void
109 i4b_drvinit(void *unused)
110 {
111         dev_ops_add(&i4b_ops, 0, 0);
112 }
113
114 SYSINIT(i4bdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,i4b_drvinit,NULL)
115
116 /*---------------------------------------------------------------------------*
117  *      interface attach routine
118  *---------------------------------------------------------------------------*/
119 PDEVSTATIC void
120 i4battach(void *dummy)
121 {
122         kprintf("i4b: ISDN call control device attached\n");
123
124         i4b_rdqueue.ifq_maxlen = IFQ_MAXLEN;
125
126         make_dev(&i4b_ops, 0, UID_ROOT, GID_WHEEL, 0600, "i4b");
127 }
128
129 /*---------------------------------------------------------------------------*
130  *      i4bopen - device driver open routine
131  *---------------------------------------------------------------------------*/
132 PDEVSTATIC int
133 i4bopen(struct dev_open_args *ap)
134 {
135         cdev_t dev = ap->a_head.a_dev;
136
137         if (minor(dev))
138                 return(ENXIO);
139         if (openflag)
140                 return(EBUSY);
141         crit_enter();
142         openflag = 1;
143         i4b_l4_daemon_attached();
144         crit_exit();
145         
146         return(0);
147 }
148
149 /*---------------------------------------------------------------------------*
150  *      i4bclose - device driver close routine
151  *---------------------------------------------------------------------------*/
152 PDEVSTATIC int
153 i4bclose(struct dev_close_args *ap)
154 {
155         crit_enter();
156         openflag = 0;
157         i4b_l4_daemon_detached();
158         i4b_Dcleanifq(&i4b_rdqueue);
159         crit_exit();
160         return(0);
161 }
162
163 /*---------------------------------------------------------------------------*
164  *      i4bread - device driver read routine
165  *---------------------------------------------------------------------------*/
166 PDEVSTATIC int
167 i4bread(struct dev_read_args *ap)
168 {
169         cdev_t dev = ap->a_head.a_dev;
170         struct mbuf *m;
171         int error = 0;
172
173         if (minor(dev))
174                 return(ENODEV);
175
176         crit_enter();
177         while(IF_QEMPTY(&i4b_rdqueue))
178         {
179                 readflag = 1;
180                 error = tsleep((caddr_t) &i4b_rdqueue, PCATCH, "bird", 0);
181                 if (error != 0) {
182                         crit_exit();
183                         return error;
184                 }
185         }
186
187         IF_DEQUEUE(&i4b_rdqueue, m);
188
189         crit_exit();
190                 
191         if(m && m->m_len)
192                 error = uiomove(m->m_data, m->m_len, ap->a_uio);
193         else
194                 error = EIO;
195                 
196         if(m)
197                 i4b_Dfreembuf(m);
198
199         return(error);
200 }
201
202 /*---------------------------------------------------------------------------*
203  *      i4bioctl - device driver ioctl routine
204  *---------------------------------------------------------------------------*/
205 PDEVSTATIC int
206 i4bioctl(struct dev_ioctl_args *ap)
207 {
208         cdev_t dev = ap->a_head.a_dev;
209         caddr_t data = ap->a_data;
210         call_desc_t *cd;
211         int error = 0;
212         
213         if(minor(dev))
214                 return(ENODEV);
215
216         switch(ap->a_cmd)
217         {
218                 /* cdid request, reserve cd and return cdid */
219
220                 case I4B_CDID_REQ:
221                 {
222                         msg_cdid_req_t *mir;
223                         mir = (msg_cdid_req_t *)data;
224                         cd = reserve_cd();
225                         mir->cdid = cd->cdid;
226                         break;
227                 }
228                 
229                 /* connect request, dial out to remote */
230                 
231                 case I4B_CONNECT_REQ:
232                 {
233                         msg_connect_req_t *mcr;
234                         mcr = (msg_connect_req_t *)data;        /* setup ptr */
235
236                         if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */
237                         {
238                                 NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!"); 
239                                 error = EINVAL;
240                                 break;
241                         }
242
243                         /* prevent dialling on leased lines */
244                         if(ctrl_desc[mcr->controller].protocol == PROTOCOL_D64S)
245                         {
246                                 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
247                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL);
248                                 i4b_l4_disconnect_ind(cd);
249                                 freecd_by_cd(cd);
250                                 break;
251                         }
252
253                         cd->controller = mcr->controller;       /* fill cd */
254                         cd->bprot = mcr->bprot;
255                         cd->driver = mcr->driver;
256                         cd->driver_unit = mcr->driver_unit;
257                         cd->cr = get_rand_cr(ctrl_desc[cd->controller].unit);
258
259                         cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm;
260                         cd->shorthold_data.unitlen_time  = mcr->shorthold_data.unitlen_time;
261                         cd->shorthold_data.idle_time     = mcr->shorthold_data.idle_time;
262                         cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time;
263
264                         cd->last_aocd_time = 0;
265                         if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC)
266                                 cd->aocd_flag = 1;
267                         else
268                                 cd->aocd_flag = 0;
269                                 
270                         cd->cunits = 0;
271
272                         cd->max_idle_time = 0;  /* this is outgoing */
273
274                         cd->dir = DIR_OUTGOING;
275                         
276                         NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld",
277                                         (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time,
278                                         (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time);
279
280                         strcpy(cd->dst_telno, mcr->dst_telno);
281                         strcpy(cd->src_telno, mcr->src_telno);
282
283                         if(mcr->keypad[0] != '\0')
284                                 strcpy(cd->keypad, mcr->keypad);
285                         else
286                                 cd->keypad[0] = '\0';
287                                 
288                         cd->display[0] = '\0';
289
290                         SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
291                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL);
292                         
293                         switch(mcr->channel)
294                         {
295                                 case CHAN_B1:
296                                 case CHAN_B2:
297                                         if(ctrl_desc[mcr->controller].bch_state[mcr->channel] != BCH_ST_FREE)
298                                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
299                                         break;
300
301                                 case CHAN_ANY:
302                                 {
303                                     int i;
304                                     for (i = 0;
305                                          i < ctrl_desc[mcr->controller].nbch &&
306                                          ctrl_desc[mcr->controller].bch_state[i] != BCH_ST_FREE;
307                                          i++);
308                                     if (i == ctrl_desc[mcr->controller].nbch)
309                                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
310                                     /* else mcr->channel = i; XXX */
311                                 }
312                                         break;
313
314                                 default:
315                                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
316                                         break;
317                         }
318
319                         cd->channelid = mcr->channel;
320
321                         cd->isdntxdelay = mcr->txdelay;
322                         
323                         /* check whether we have a pointer. Seems like */
324                         /* this should be adequate. GJ 19.09.97 */
325                         if(ctrl_desc[cd->controller].N_CONNECT_REQUEST == NULL)
326 /*XXX*/                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
327
328                         if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL)
329                         {
330                                 i4b_l4_disconnect_ind(cd);
331                                 freecd_by_cd(cd);
332                         }
333                         else
334                         {
335                                 (*ctrl_desc[cd->controller].N_CONNECT_REQUEST)(mcr->cdid);
336                         }
337                         break;
338                 }
339                 
340                 /* connect response, accept/reject/ignore incoming call */
341                 
342                 case I4B_CONNECT_RESP:
343                 {
344                         msg_connect_resp_t *mcrsp;
345                         
346                         mcrsp = (msg_connect_resp_t *)data;
347
348                         if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */
349                         {
350                                 NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!"); 
351                                 error = EINVAL;
352                                 break;
353                         }
354
355                         T400_stop(cd);
356
357                         cd->driver = mcrsp->driver;
358                         cd->driver_unit = mcrsp->driver_unit;
359                         cd->max_idle_time = mcrsp->max_idle_time;
360
361                         cd->shorthold_data.shorthold_algorithm = SHA_FIXU;
362                         cd->shorthold_data.unitlen_time = 0;    /* this is incoming */
363                         cd->shorthold_data.idle_time = 0;
364                         cd->shorthold_data.earlyhup_time = 0;
365
366                         cd->isdntxdelay = mcrsp->txdelay;                       
367                         
368                         NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time);
369
370                         (*ctrl_desc[cd->controller].N_CONNECT_RESPONSE)(mcrsp->cdid, mcrsp->response, mcrsp->cause);
371                         break;
372                 }
373                 
374                 /* disconnect request, actively terminate connection */
375                 
376                 case I4B_DISCONNECT_REQ:
377                 {
378                         msg_discon_req_t *mdr;
379                         
380                         mdr = (msg_discon_req_t *)data;
381
382                         if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */
383                         {
384                                 NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid not found!"); 
385                                 error = EINVAL;
386                                 break;
387                         }
388
389                         /* preset causes with our cause */
390                         cd->cause_in = cd->cause_out = mdr->cause;
391                         
392                         (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(mdr->cdid, mdr->cause);
393                         break;
394                 }
395                 
396                 /* controller info request */
397
398                 case I4B_CTRL_INFO_REQ:
399                 {
400                         msg_ctrl_info_req_t *mcir;
401                         
402                         mcir = (msg_ctrl_info_req_t *)data;
403                         mcir->ncontroller = nctrl;
404
405                         if(mcir->controller > nctrl)
406                         {
407                                 mcir->ctrl_type = -1;
408                                 mcir->card_type = -1;
409                         }
410                         else
411                         {
412                                 mcir->ctrl_type = 
413                                         ctrl_desc[mcir->controller].ctrl_type;
414                                 mcir->card_type = 
415                                         ctrl_desc[mcir->controller].card_type;
416                                 mcir->nbch =
417                                         ctrl_desc[mcir->controller].nbch;
418
419                                 if(ctrl_desc[mcir->controller].ctrl_type == CTRL_PASSIVE)
420                                         mcir->tei = ctrl_desc[mcir->controller].tei;
421                                 else
422                                         mcir->tei = -1;
423                         }
424                         break;
425                 }
426                 
427                 /* dial response */
428                 
429                 case I4B_DIALOUT_RESP:
430                 {
431                         drvr_link_t *dlt = NULL;
432                         msg_dialout_resp_t *mdrsp;
433                         
434                         mdrsp = (msg_dialout_resp_t *)data;
435
436                         switch(mdrsp->driver)
437                         {
438 #if NI4BIPR > 0
439                                 case BDRV_IPR:
440                                         dlt = ipr_ret_linktab(mdrsp->driver_unit);
441                                         break;
442 #endif                                  
443
444 #if NI4BISPPP > 0
445                                 case BDRV_ISPPP:
446                                         dlt = i4bisppp_ret_linktab(mdrsp->driver_unit);
447                                         break;
448 #endif
449
450 #if NI4BTEL > 0
451                                 case BDRV_TEL:
452                                         dlt = tel_ret_linktab(mdrsp->driver_unit);
453                                         break;
454 #endif
455
456 #if NIBC > 0
457                                 case BDRV_IBC:
458                                         dlt = ibc_ret_linktab(mdrsp->driver_unit);
459                                         break;
460 #endif
461
462 #if NI4BING > 0
463                                 case BDRV_ING:
464                                         dlt = ing_ret_linktab(mdrsp->driver_unit);
465                                         break;
466 #endif                                  
467                         }
468
469                         if(dlt != NULL)         
470                                 (*dlt->dial_response)(mdrsp->driver_unit, mdrsp->stat, mdrsp->cause);
471                         break;
472                 }
473                 
474                 /* update timeout value */
475                 
476                 case I4B_TIMEOUT_UPD:
477                 {
478                         msg_timeout_upd_t *mtu;
479                         
480                         mtu = (msg_timeout_upd_t *)data;
481
482                         NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!",
483                                         mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time,
484                                         mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time); 
485
486                         if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */
487                         {
488                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!"); 
489                                 error = EINVAL;
490                                 break;
491                         }
492
493                         switch( mtu->shorthold_data.shorthold_algorithm )
494                         {
495                                 case SHA_FIXU:
496                                         /*
497                                          * For this algorithm unitlen_time,
498                                          * idle_time and earlyhup_time are used.
499                                          */
500
501                                         if(!(mtu->shorthold_data.unitlen_time >= 0 &&
502                                              mtu->shorthold_data.idle_time >= 0    &&
503                                              mtu->shorthold_data.earlyhup_time >= 0))
504                                         {
505                                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!"); 
506                                                 error = EINVAL;
507                                         }
508                                         break;
509         
510                                 case SHA_VARU:
511                                         /*
512                                          * For this algorithm unitlen_time and
513                                          * idle_time are used. both must be
514                                          * positive integers. earlyhup_time is
515                                          * not used and must be 0.
516                                          */
517
518                                         if(!(mtu->shorthold_data.unitlen_time > 0 &&
519                                              mtu->shorthold_data.idle_time >= 0   &&
520                                              mtu->shorthold_data.earlyhup_time == 0))
521                                         {
522                                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!"); 
523                                                 error = EINVAL;
524                                         }
525                                         break;
526         
527                                 default:
528                                         NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!"); 
529                                         error = EINVAL;
530                                         break;
531                         }
532
533                         /*
534                          * any error set above requires us to break
535                          * out of the outer switch
536                          */
537                         if(error != 0)
538                                 break;
539
540                         crit_enter();
541                         cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm;
542                         cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time;
543                         cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time;
544                         cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time;
545                         crit_exit();
546                         break;
547                 }
548                         
549                 /* soft enable/disable interface */
550                 
551                 case I4B_UPDOWN_IND:
552                 {
553                         msg_updown_ind_t *mui;
554                         
555                         mui = (msg_updown_ind_t *)data;
556
557 #if NI4BIPR > 0
558                         if(mui->driver == BDRV_IPR)
559                         {
560                                 drvr_link_t *dlt;
561                                 dlt = ipr_ret_linktab(mui->driver_unit);
562                                 (*dlt->updown_ind)(mui->driver_unit, mui->updown);
563                         }
564 #endif
565                         break;
566                 }
567                 
568                 /* send ALERT request */
569                 
570                 case I4B_ALERT_REQ:
571                 {
572                         msg_alert_req_t *mar;
573                         
574                         mar = (msg_alert_req_t *)data;
575
576                         if((cd = cd_by_cdid(mar->cdid)) == NULL)
577                         {
578                                 NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!"); 
579                                 error = EINVAL;
580                                 break;
581                         }
582
583                         T400_stop(cd);
584                         
585                         (*ctrl_desc[cd->controller].N_ALERT_REQUEST)(mar->cdid);
586
587                         break;
588                 }
589
590                 /* version/release number request */
591                 
592                 case I4B_VR_REQ:
593                 {
594                         msg_vr_req_t *mvr;
595
596                         mvr = (msg_vr_req_t *)data;
597
598                         mvr->version = VERSION;
599                         mvr->release = REL;
600                         mvr->step = STEP;                       
601                         break;
602                 }
603
604                 /* set D-channel protocol for a controller */
605                 
606                 case I4B_PROT_IND:
607                 {
608                         msg_prot_ind_t *mpi;
609                         
610                         mpi = (msg_prot_ind_t *)data;
611
612                         ctrl_desc[mpi->controller].protocol = mpi->protocol;
613                         
614                         break;
615                 }
616                 
617                 /* Download request */
618
619                 case I4B_CTRL_DOWNLOAD:
620                 {
621                         struct isdn_dr_prot *prots = NULL, *prots2 = NULL;
622                         struct isdn_download_request *r =
623                                 (struct isdn_download_request*)data;
624                         int i;
625
626                         if (r->controller < 0 || r->controller >= nctrl)
627                         {
628                                 error = ENODEV;
629                                 goto download_done;
630                         }
631
632                         if(!ctrl_desc[r->controller].N_DOWNLOAD)
633                         {
634                                 error = ENODEV;
635                                 goto download_done;
636                         }
637
638                         prots = kmalloc(r->numprotos * sizeof(struct isdn_dr_prot),
639                                         M_DEVBUF, M_WAITOK);
640
641                         prots2 = kmalloc(r->numprotos * sizeof(struct isdn_dr_prot),
642                                         M_DEVBUF, M_WAITOK);
643
644                         copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
645
646                         for(i = 0; i < r->numprotos; i++)
647                         {
648                                 prots2[i].microcode = kmalloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
649                                 copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
650                                 prots2[i].bytecount = prots[i].bytecount; 
651                         }
652
653                         error = ctrl_desc[r->controller].N_DOWNLOAD(
654                                                 ctrl_desc[r->controller].unit,
655                                                 r->numprotos, prots2);
656
657 download_done:
658                         if(prots2)
659                         {
660                                 for(i = 0; i < r->numprotos; i++)
661                                 {
662                                         if(prots2[i].microcode)
663                                         {
664                                                 kfree(prots2[i].microcode, M_DEVBUF);
665                                         }
666                                 }
667                                 kfree(prots2, M_DEVBUF);
668                         }
669
670                         if(prots)
671                         {
672                                 kfree(prots, M_DEVBUF);
673                         }
674                         break;
675                 }
676
677                 /* Diagnostic request */
678
679                 case I4B_ACTIVE_DIAGNOSTIC:
680                 {
681                         struct isdn_diagnostic_request req, *r =
682                                 (struct isdn_diagnostic_request*)data;
683
684                         req.in_param = req.out_param = NULL;
685                         if (r->controller < 0 || r->controller >= nctrl)
686                         {
687                                 error = ENODEV;
688                                 goto diag_done;
689                         }
690
691                         if(!ctrl_desc[r->controller].N_DIAGNOSTICS)
692                         {
693                                 error = ENODEV;
694                                 goto diag_done;
695                         }
696
697                         memcpy(&req, r, sizeof(req));
698
699                         if(req.in_param_len)
700                         {
701                                 /* XXX arbitrary limit */
702                                 if (req.in_param_len >
703                                     I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) {
704                                         error = EINVAL;
705                                         goto diag_done;
706                                 }       
707
708                                 req.in_param = kmalloc(r->in_param_len, M_DEVBUF, M_WAITOK);
709
710                                 error = copyin(r->in_param, req.in_param, req.in_param_len);
711                                 if (error)
712                                         goto diag_done;
713                         }
714
715                         if(req.out_param_len)
716                                 req.out_param = kmalloc(r->out_param_len, M_DEVBUF, M_WAITOK);
717
718                         error = ctrl_desc[r->controller].N_DIAGNOSTICS(r->controller, &req);
719
720                         if(!error && req.out_param_len)
721                                 error = copyout(req.out_param, r->out_param, req.out_param_len);
722
723 diag_done:
724                         if(req.in_param)
725                                 kfree(req.in_param, M_DEVBUF);
726                                 
727                         if(req.out_param)
728                                 kfree(req.out_param, M_DEVBUF);
729
730                         break;
731                 }
732
733                 /* default */
734                 
735                 default:
736                         error = ENOTTY;
737                         break;
738         }
739         
740         return(error);
741 }
742
743 /*---------------------------------------------------------------------------*
744  *      i4bpoll - device driver poll routine
745  *---------------------------------------------------------------------------*/
746 PDEVSTATIC int
747 i4bpoll(struct dev_poll_args *ap)
748 {
749         cdev_t dev = ap->a_head.a_dev;
750         int revents;
751
752         if (minor(dev))
753                 return(ENODEV);
754
755         revents = 0;
756
757         if (ap->a_events & (POLLIN|POLLRDNORM)) {
758                 crit_enter();
759                 if (!IF_QEMPTY(&i4b_rdqueue)) {
760                         revents |= POLLIN | POLLRDNORM;
761                 } else {
762                         selrecord(curthread, &select_rd_info);
763                         selflag = 1;
764                 }
765                 crit_exit();
766                 return(0);
767         }
768         if (ap->a_events & (POLLOUT|POLLWRNORM)) {
769                 revents |= ap->a_events & (POLLOUT | POLLWRNORM);
770         }
771         ap->a_events = revents;
772         return(0);
773 }
774
775 /*---------------------------------------------------------------------------*
776  *      i4bputqueue - put message into queue to userland
777  *---------------------------------------------------------------------------*/
778 void
779 i4bputqueue(struct mbuf *m)
780 {
781         if(!openflag)
782         {
783                 i4b_Dfreembuf(m);
784                 return;
785         }
786
787         crit_enter();
788         
789         if(IF_QFULL(&i4b_rdqueue))
790         {
791                 struct mbuf *m1;
792                 IF_DEQUEUE(&i4b_rdqueue, m1);
793                 i4b_Dfreembuf(m1);
794                 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
795         }
796
797         IF_ENQUEUE(&i4b_rdqueue, m);
798
799         crit_exit();
800
801         if(readflag)
802         {
803                 readflag = 0;
804                 wakeup((caddr_t) &i4b_rdqueue);
805         }
806
807         if(selflag)
808         {
809                 selflag = 0;
810                 selwakeup(&select_rd_info);
811         }
812 }
813
814 /*---------------------------------------------------------------------------*
815  *      i4bputqueue_hipri - put message into front of queue to userland
816  *---------------------------------------------------------------------------*/
817 void
818 i4bputqueue_hipri(struct mbuf *m)
819 {
820         if(!openflag)
821         {
822                 i4b_Dfreembuf(m);
823                 return;
824         }
825
826         crit_enter();
827         
828         if(IF_QFULL(&i4b_rdqueue))
829         {
830                 struct mbuf *m1;
831                 IF_DEQUEUE(&i4b_rdqueue, m1);
832                 i4b_Dfreembuf(m1);
833                 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
834         }
835
836         IF_PREPEND(&i4b_rdqueue, m);
837
838         crit_exit();
839
840         if(readflag)
841         {
842                 readflag = 0;
843                 wakeup((caddr_t) &i4b_rdqueue);
844         }
845
846         if(selflag)
847         {
848                 selflag = 0;
849                 selwakeup(&select_rd_info);
850         }
851 }
852
853 #endif /* NI4B > 0 */