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