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