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