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