DEVFS - remove dev_ops_add(), dev_ops_get(), and get_dev()
[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/poll.h>
76
77 struct selinfo select_rd_info;
78
79 static struct ifqueue i4b_rdqueue;
80 static int openflag = 0;
81 static int selflag = 0;
82 static int readflag = 0;
83
84 #define PDEVSTATIC      static
85
86 PDEVSTATIC      d_open_t        i4bopen;
87 PDEVSTATIC      d_close_t       i4bclose;
88 PDEVSTATIC      d_read_t        i4bread;
89 PDEVSTATIC      d_ioctl_t       i4bioctl;
90
91 PDEVSTATIC      d_poll_t        i4bpoll;
92 #define POLLFIELD               i4bpoll
93
94 #define CDEV_MAJOR 60
95
96 static struct 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_poll =       POLLFIELD,
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 NIBC > 0
449                                 case BDRV_IBC:
450                                         dlt = ibc_ret_linktab(mdrsp->driver_unit);
451                                         break;
452 #endif
453
454 #if NI4BING > 0
455                                 case BDRV_ING:
456                                         dlt = ing_ret_linktab(mdrsp->driver_unit);
457                                         break;
458 #endif                                  
459                         }
460
461                         if(dlt != NULL)         
462                                 (*dlt->dial_response)(mdrsp->driver_unit, mdrsp->stat, mdrsp->cause);
463                         break;
464                 }
465                 
466                 /* update timeout value */
467                 
468                 case I4B_TIMEOUT_UPD:
469                 {
470                         msg_timeout_upd_t *mtu;
471                         
472                         mtu = (msg_timeout_upd_t *)data;
473
474                         NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!",
475                                         mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time,
476                                         mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time); 
477
478                         if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */
479                         {
480                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!"); 
481                                 error = EINVAL;
482                                 break;
483                         }
484
485                         switch( mtu->shorthold_data.shorthold_algorithm )
486                         {
487                                 case SHA_FIXU:
488                                         /*
489                                          * For this algorithm unitlen_time,
490                                          * idle_time and earlyhup_time are used.
491                                          */
492
493                                         if(!(mtu->shorthold_data.unitlen_time >= 0 &&
494                                              mtu->shorthold_data.idle_time >= 0    &&
495                                              mtu->shorthold_data.earlyhup_time >= 0))
496                                         {
497                                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!"); 
498                                                 error = EINVAL;
499                                         }
500                                         break;
501         
502                                 case SHA_VARU:
503                                         /*
504                                          * For this algorithm unitlen_time and
505                                          * idle_time are used. both must be
506                                          * positive integers. earlyhup_time is
507                                          * not used and must be 0.
508                                          */
509
510                                         if(!(mtu->shorthold_data.unitlen_time > 0 &&
511                                              mtu->shorthold_data.idle_time >= 0   &&
512                                              mtu->shorthold_data.earlyhup_time == 0))
513                                         {
514                                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!"); 
515                                                 error = EINVAL;
516                                         }
517                                         break;
518         
519                                 default:
520                                         NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!"); 
521                                         error = EINVAL;
522                                         break;
523                         }
524
525                         /*
526                          * any error set above requires us to break
527                          * out of the outer switch
528                          */
529                         if(error != 0)
530                                 break;
531
532                         crit_enter();
533                         cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm;
534                         cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time;
535                         cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time;
536                         cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time;
537                         crit_exit();
538                         break;
539                 }
540                         
541                 /* soft enable/disable interface */
542                 
543                 case I4B_UPDOWN_IND:
544                 {
545                         msg_updown_ind_t *mui;
546                         
547                         mui = (msg_updown_ind_t *)data;
548
549 #if NI4BIPR > 0
550                         if(mui->driver == BDRV_IPR)
551                         {
552                                 drvr_link_t *dlt;
553                                 dlt = ipr_ret_linktab(mui->driver_unit);
554                                 (*dlt->updown_ind)(mui->driver_unit, mui->updown);
555                         }
556 #endif
557                         break;
558                 }
559                 
560                 /* send ALERT request */
561                 
562                 case I4B_ALERT_REQ:
563                 {
564                         msg_alert_req_t *mar;
565                         
566                         mar = (msg_alert_req_t *)data;
567
568                         if((cd = cd_by_cdid(mar->cdid)) == NULL)
569                         {
570                                 NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!"); 
571                                 error = EINVAL;
572                                 break;
573                         }
574
575                         T400_stop(cd);
576                         
577                         (*ctrl_desc[cd->controller].N_ALERT_REQUEST)(mar->cdid);
578
579                         break;
580                 }
581
582                 /* version/release number request */
583                 
584                 case I4B_VR_REQ:
585                 {
586                         msg_vr_req_t *mvr;
587
588                         mvr = (msg_vr_req_t *)data;
589
590                         mvr->version = VERSION;
591                         mvr->release = REL;
592                         mvr->step = STEP;                       
593                         break;
594                 }
595
596                 /* set D-channel protocol for a controller */
597                 
598                 case I4B_PROT_IND:
599                 {
600                         msg_prot_ind_t *mpi;
601                         
602                         mpi = (msg_prot_ind_t *)data;
603
604                         ctrl_desc[mpi->controller].protocol = mpi->protocol;
605                         
606                         break;
607                 }
608                 
609                 /* Download request */
610
611                 case I4B_CTRL_DOWNLOAD:
612                 {
613                         struct isdn_dr_prot *prots = NULL, *prots2 = NULL;
614                         struct isdn_download_request *r =
615                                 (struct isdn_download_request*)data;
616                         int i;
617
618                         if (r->controller < 0 || r->controller >= nctrl)
619                         {
620                                 error = ENODEV;
621                                 goto download_done;
622                         }
623
624                         if(!ctrl_desc[r->controller].N_DOWNLOAD)
625                         {
626                                 error = ENODEV;
627                                 goto download_done;
628                         }
629
630                         prots = kmalloc(r->numprotos * sizeof(struct isdn_dr_prot),
631                                         M_DEVBUF, M_WAITOK);
632
633                         prots2 = kmalloc(r->numprotos * sizeof(struct isdn_dr_prot),
634                                         M_DEVBUF, M_WAITOK);
635
636                         copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
637
638                         for(i = 0; i < r->numprotos; i++)
639                         {
640                                 prots2[i].microcode = kmalloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
641                                 copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
642                                 prots2[i].bytecount = prots[i].bytecount; 
643                         }
644
645                         error = ctrl_desc[r->controller].N_DOWNLOAD(
646                                                 ctrl_desc[r->controller].unit,
647                                                 r->numprotos, prots2);
648
649 download_done:
650                         if(prots2)
651                         {
652                                 for(i = 0; i < r->numprotos; i++)
653                                 {
654                                         if(prots2[i].microcode)
655                                         {
656                                                 kfree(prots2[i].microcode, M_DEVBUF);
657                                         }
658                                 }
659                                 kfree(prots2, M_DEVBUF);
660                         }
661
662                         if(prots)
663                         {
664                                 kfree(prots, M_DEVBUF);
665                         }
666                         break;
667                 }
668
669                 /* Diagnostic request */
670
671                 case I4B_ACTIVE_DIAGNOSTIC:
672                 {
673                         struct isdn_diagnostic_request req, *r =
674                                 (struct isdn_diagnostic_request*)data;
675
676                         req.in_param = req.out_param = NULL;
677                         if (r->controller < 0 || r->controller >= nctrl)
678                         {
679                                 error = ENODEV;
680                                 goto diag_done;
681                         }
682
683                         if(!ctrl_desc[r->controller].N_DIAGNOSTICS)
684                         {
685                                 error = ENODEV;
686                                 goto diag_done;
687                         }
688
689                         memcpy(&req, r, sizeof(req));
690
691                         if(req.in_param_len)
692                         {
693                                 /* XXX arbitrary limit */
694                                 if (req.in_param_len >
695                                     I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) {
696                                         error = EINVAL;
697                                         goto diag_done;
698                                 }       
699
700                                 req.in_param = kmalloc(r->in_param_len, M_DEVBUF, M_WAITOK);
701
702                                 error = copyin(r->in_param, req.in_param, req.in_param_len);
703                                 if (error)
704                                         goto diag_done;
705                         }
706
707                         if(req.out_param_len)
708                                 req.out_param = kmalloc(r->out_param_len, M_DEVBUF, M_WAITOK);
709
710                         error = ctrl_desc[r->controller].N_DIAGNOSTICS(r->controller, &req);
711
712                         if(!error && req.out_param_len)
713                                 error = copyout(req.out_param, r->out_param, req.out_param_len);
714
715 diag_done:
716                         if(req.in_param)
717                                 kfree(req.in_param, M_DEVBUF);
718                                 
719                         if(req.out_param)
720                                 kfree(req.out_param, M_DEVBUF);
721
722                         break;
723                 }
724
725                 /* default */
726                 
727                 default:
728                         error = ENOTTY;
729                         break;
730         }
731         
732         return(error);
733 }
734
735 /*---------------------------------------------------------------------------*
736  *      i4bpoll - device driver poll routine
737  *---------------------------------------------------------------------------*/
738 PDEVSTATIC int
739 i4bpoll(struct dev_poll_args *ap)
740 {
741         cdev_t dev = ap->a_head.a_dev;
742         int revents;
743
744         if (minor(dev))
745                 return(ENODEV);
746
747         revents = 0;
748
749         if (ap->a_events & (POLLIN|POLLRDNORM)) {
750                 crit_enter();
751                 if (!IF_QEMPTY(&i4b_rdqueue)) {
752                         revents |= POLLIN | POLLRDNORM;
753                 } else {
754                         selrecord(curthread, &select_rd_info);
755                         selflag = 1;
756                 }
757                 crit_exit();
758                 return(0);
759         }
760         if (ap->a_events & (POLLOUT|POLLWRNORM)) {
761                 revents |= ap->a_events & (POLLOUT | POLLWRNORM);
762         }
763         ap->a_events = revents;
764         return(0);
765 }
766
767 /*---------------------------------------------------------------------------*
768  *      i4bputqueue - put message into queue to userland
769  *---------------------------------------------------------------------------*/
770 void
771 i4bputqueue(struct mbuf *m)
772 {
773         if(!openflag)
774         {
775                 i4b_Dfreembuf(m);
776                 return;
777         }
778
779         crit_enter();
780         
781         if(IF_QFULL(&i4b_rdqueue))
782         {
783                 struct mbuf *m1;
784                 IF_DEQUEUE(&i4b_rdqueue, m1);
785                 i4b_Dfreembuf(m1);
786                 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
787         }
788
789         IF_ENQUEUE(&i4b_rdqueue, m);
790
791         crit_exit();
792
793         if(readflag)
794         {
795                 readflag = 0;
796                 wakeup((caddr_t) &i4b_rdqueue);
797         }
798
799         if(selflag)
800         {
801                 selflag = 0;
802                 selwakeup(&select_rd_info);
803         }
804 }
805
806 /*---------------------------------------------------------------------------*
807  *      i4bputqueue_hipri - put message into front of queue to userland
808  *---------------------------------------------------------------------------*/
809 void
810 i4bputqueue_hipri(struct mbuf *m)
811 {
812         if(!openflag)
813         {
814                 i4b_Dfreembuf(m);
815                 return;
816         }
817
818         crit_enter();
819         
820         if(IF_QFULL(&i4b_rdqueue))
821         {
822                 struct mbuf *m1;
823                 IF_DEQUEUE(&i4b_rdqueue, m1);
824                 i4b_Dfreembuf(m1);
825                 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
826         }
827
828         IF_PREPEND(&i4b_rdqueue, m);
829
830         crit_exit();
831
832         if(readflag)
833         {
834                 readflag = 0;
835                 wakeup((caddr_t) &i4b_rdqueue);
836         }
837
838         if(selflag)
839         {
840                 selflag = 0;
841                 selwakeup(&select_rd_info);
842         }
843 }
844
845 #endif /* NI4B > 0 */