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