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