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