1 /*-
2 * Copyright (c) 1997, 2002 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 *
28 * i4b_i4bdrv.c - i4b userland interface driver
29 * --------------------------------------------
30 * last edit-date: [Sun Aug 11 12:42:46 2002]
31 *
32 *---------------------------------------------------------------------------*/
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD: releng/5.4/sys/i4b/layer4/i4b_i4bdrv.c 141090 2005-01-31 23:27:04Z imp $");
36
37 #include "i4bipr.h"
38 #include "i4btel.h"
39 #include "i4bing.h"
40 #include "i4bisppp.h"
41
42 #include <sys/param.h>
43 #include <sys/ioccom.h>
44 #include <sys/malloc.h>
45 #include <sys/uio.h>
46 #include <sys/kernel.h>
47 #include <sys/systm.h>
48 #include <sys/conf.h>
49 #include <sys/mbuf.h>
50 #include <sys/socket.h>
51 #include <sys/selinfo.h>
52 #include <net/if.h>
53
54 #include <machine/i4b_debug.h>
55 #include <machine/i4b_ioctl.h>
56 #include <machine/i4b_cause.h>
57
58 #include <i4b/include/i4b_l3l4.h>
59 #include <i4b/include/i4b_mbuf.h>
60 #include <i4b/include/i4b_global.h>
61
62 #include <i4b/layer4/i4b_l4.h>
63
64 #include <sys/poll.h>
65
66 struct selinfo select_rd_info;
67
68 static struct ifqueue i4b_rdqueue;
69 static int openflag = 0;
70 static int selflag = 0;
71 static int readflag = 0;
72
73 static d_open_t i4bopen;
74 static d_close_t i4bclose;
75 static d_read_t i4bread;
76 static d_ioctl_t i4bioctl;
77 static d_poll_t i4bpoll;
78
79
80 static struct cdevsw i4b_cdevsw = {
81 .d_version = D_VERSION,
82 .d_flags = D_NEEDGIANT,
83 .d_open = i4bopen,
84 .d_close = i4bclose,
85 .d_read = i4bread,
86 .d_ioctl = i4bioctl,
87 .d_poll = i4bpoll,
88 .d_name = "i4b",
89 };
90
91 static void i4battach(void *);
92 PSEUDO_SET(i4battach, i4b_i4bdrv);
93
94 /*---------------------------------------------------------------------------*
95 * interface attach routine
96 *---------------------------------------------------------------------------*/
97 static void
98 i4battach(void *dummy)
99 {
100 printf("i4b: ISDN call control device attached\n");
101
102 i4b_rdqueue.ifq_maxlen = IFQ_MAXLEN;
103
104 if(!mtx_initialized(&i4b_rdqueue.ifq_mtx))
105 mtx_init(&i4b_rdqueue.ifq_mtx, "i4b_rdqueue", NULL, MTX_DEF);
106
107 make_dev(&i4b_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "i4b");
108 }
109
110 /*---------------------------------------------------------------------------*
111 * i4bopen - device driver open routine
112 *---------------------------------------------------------------------------*/
113 static int
114 i4bopen(struct cdev *dev, int flag, int fmt, struct thread *td)
115 {
116 int x;
117
118 if(minor(dev))
119 return(ENXIO);
120
121 if(openflag)
122 return(EBUSY);
123
124 x = splimp();
125 openflag = 1;
126 i4b_l4_daemon_attached();
127 splx(x);
128
129 return(0);
130 }
131
132 /*---------------------------------------------------------------------------*
133 * i4bclose - device driver close routine
134 *---------------------------------------------------------------------------*/
135 static int
136 i4bclose(struct cdev *dev, int flag, int fmt, struct thread *td)
137 {
138 int x = splimp();
139 openflag = 0;
140 i4b_l4_daemon_detached();
141 i4b_Dcleanifq(&i4b_rdqueue);
142 splx(x);
143 return(0);
144 }
145
146 /*---------------------------------------------------------------------------*
147 * i4bread - device driver read routine
148 *---------------------------------------------------------------------------*/
149 static int
150 i4bread(struct cdev *dev, struct uio *uio, int ioflag)
151 {
152 struct mbuf *m;
153 int x;
154 int error = 0;
155
156 if(minor(dev))
157 return(ENODEV);
158
159 x = splimp();
160 IF_LOCK(&i4b_rdqueue);
161 while(IF_QEMPTY(&i4b_rdqueue))
162 {
163 readflag = 1;
164
165 error = msleep( &i4b_rdqueue, &i4b_rdqueue.ifq_mtx,
166 (PZERO + 1) | PCATCH, "bird", 0);
167
168 if (error != 0) {
169 IF_UNLOCK(&i4b_rdqueue);
170 splx(x);
171 return error;
172 }
173 }
174
175 _IF_DEQUEUE(&i4b_rdqueue, m);
176 IF_UNLOCK(&i4b_rdqueue);
177
178 splx(x);
179
180 if(m && m->m_len)
181 error = uiomove(m->m_data, m->m_len, 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 static int
195 i4bioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
196 {
197 call_desc_t *cd;
198 int error = 0;
199
200 if(minor(dev))
201 return(ENODEV);
202
203 switch(cmd)
204 {
205 /* cdid request, reserve cd and return cdid */
206
207 case I4B_CDID_REQ:
208 {
209 msg_cdid_req_t *mir;
210 mir = (msg_cdid_req_t *)data;
211 cd = reserve_cd();
212 mir->cdid = cd->cdid;
213 break;
214 }
215
216 /* connect request, dial out to remote */
217
218 case I4B_CONNECT_REQ:
219 {
220 msg_connect_req_t *mcr;
221 mcr = (msg_connect_req_t *)data; /* setup ptr */
222
223 if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */
224 {
225 NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!");
226 error = EINVAL;
227 break;
228 }
229
230 /* prevent dialling on leased lines */
231 if(ctrl_desc[mcr->controller].protocol == PROTOCOL_D64S)
232 {
233 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
234 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL);
235 i4b_l4_disconnect_ind(cd);
236 freecd_by_cd(cd);
237 break;
238 }
239
240 cd->controller = mcr->controller; /* fill cd */
241 cd->bprot = mcr->bprot;
242 cd->bcap = mcr->bcap;
243 cd->driver = mcr->driver;
244 cd->driver_unit = mcr->driver_unit;
245 cd->cr = get_rand_cr(ctrl_desc[cd->controller].unit);
246
247 cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm;
248 cd->shorthold_data.unitlen_time = mcr->shorthold_data.unitlen_time;
249 cd->shorthold_data.idle_time = mcr->shorthold_data.idle_time;
250 cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time;
251
252 cd->last_aocd_time = 0;
253 if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC)
254 cd->aocd_flag = 1;
255 else
256 cd->aocd_flag = 0;
257
258 cd->cunits = 0;
259
260 cd->max_idle_time = 0; /* this is outgoing */
261
262 cd->dir = DIR_OUTGOING;
263
264 NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld",
265 (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time,
266 (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time);
267
268 strcpy(cd->dst_telno, mcr->dst_telno);
269 strcpy(cd->src_telno, mcr->src_telno);
270
271 strcpy(cd->dst_subaddr, mcr->dst_subaddr);
272 strcpy(cd->src_subaddr, mcr->src_subaddr);
273
274 if(mcr->keypad[0] != '\0')
275 strcpy(cd->keypad, mcr->keypad);
276 else
277 cd->keypad[0] = '\0';
278
279 cd->display[0] = '\0';
280
281 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
282 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL);
283
284 switch(mcr->channel)
285 {
286 case CHAN_B1:
287 case CHAN_B2:
288 if(ctrl_desc[mcr->controller].bch_state[mcr->channel] != BCH_ST_FREE)
289 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
290 break;
291
292 case CHAN_ANY:
293 {
294 int i;
295 for (i = 0;
296 i < ctrl_desc[mcr->controller].nbch &&
297 ctrl_desc[mcr->controller].bch_state[i] != BCH_ST_FREE;
298 i++);
299 if (i == ctrl_desc[mcr->controller].nbch)
300 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
301 /* else mcr->channel = i; XXX */
302 }
303 break;
304
305 default:
306 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
307 break;
308 }
309
310 cd->channelid = mcr->channel;
311
312 cd->isdntxdelay = mcr->txdelay;
313
314 /* check whether we have a pointer. Seems like */
315 /* this should be adequate. GJ 19.09.97 */
316 if(ctrl_desc[cd->controller].N_CONNECT_REQUEST == NULL)
317 /*XXX*/ SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
318
319 if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL)
320 {
321 i4b_l4_disconnect_ind(cd);
322 freecd_by_cd(cd);
323 }
324 else
325 {
326 (*ctrl_desc[cd->controller].N_CONNECT_REQUEST)(mcr->cdid);
327 }
328 break;
329 }
330
331 /* connect response, accept/reject/ignore incoming call */
332
333 case I4B_CONNECT_RESP:
334 {
335 msg_connect_resp_t *mcrsp;
336
337 mcrsp = (msg_connect_resp_t *)data;
338
339 if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */
340 {
341 NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!");
342 error = EINVAL;
343 break;
344 }
345
346 T400_stop(cd);
347
348 cd->driver = mcrsp->driver;
349 cd->driver_unit = mcrsp->driver_unit;
350 cd->max_idle_time = mcrsp->max_idle_time;
351
352 cd->shorthold_data.shorthold_algorithm = SHA_FIXU;
353 cd->shorthold_data.unitlen_time = 0; /* this is incoming */
354 cd->shorthold_data.idle_time = 0;
355 cd->shorthold_data.earlyhup_time = 0;
356
357 cd->isdntxdelay = mcrsp->txdelay;
358
359 NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time);
360
361 (*ctrl_desc[cd->controller].N_CONNECT_RESPONSE)(mcrsp->cdid, mcrsp->response, mcrsp->cause);
362 break;
363 }
364
365 /* disconnect request, actively terminate connection */
366
367 case I4B_DISCONNECT_REQ:
368 {
369 msg_discon_req_t *mdr;
370
371 mdr = (msg_discon_req_t *)data;
372
373 if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */
374 {
375 NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid not found!");
376 error = EINVAL;
377 break;
378 }
379
380 /* preset causes with our cause */
381 cd->cause_in = cd->cause_out = mdr->cause;
382
383 (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(mdr->cdid, mdr->cause);
384 break;
385 }
386
387 /* controller info request */
388
389 case I4B_CTRL_INFO_REQ:
390 {
391 msg_ctrl_info_req_t *mcir;
392
393 mcir = (msg_ctrl_info_req_t *)data;
394 mcir->ncontroller = nctrl;
395
396 if(mcir->controller > nctrl)
397 {
398 mcir->ctrl_type = -1;
399 mcir->card_type = -1;
400 }
401 else
402 {
403 mcir->ctrl_type =
404 ctrl_desc[mcir->controller].ctrl_type;
405 mcir->card_type =
406 ctrl_desc[mcir->controller].card_type;
407 mcir->nbch =
408 ctrl_desc[mcir->controller].nbch;
409
410 if(ctrl_desc[mcir->controller].ctrl_type == CTRL_PASSIVE)
411 mcir->tei = ctrl_desc[mcir->controller].tei;
412 else
413 mcir->tei = -1;
414 }
415 break;
416 }
417
418 /* dial response */
419
420 case I4B_DIALOUT_RESP:
421 {
422 drvr_link_t *dlt = NULL;
423 msg_dialout_resp_t *mdrsp;
424
425 mdrsp = (msg_dialout_resp_t *)data;
426
427 switch(mdrsp->driver)
428 {
429 #if NI4BIPR > 0
430 case BDRV_IPR:
431 dlt = ipr_ret_linktab(mdrsp->driver_unit);
432 break;
433 #endif
434
435 #if NI4BISPPP > 0
436 case BDRV_ISPPP:
437 dlt = i4bisppp_ret_linktab(mdrsp->driver_unit);
438 break;
439 #endif
440
441 #if NI4BTEL > 0
442 case BDRV_TEL:
443 dlt = tel_ret_linktab(mdrsp->driver_unit);
444 break;
445 #endif
446
447 #if NIBC > 0
448 case BDRV_IBC:
449 dlt = ibc_ret_linktab(mdrsp->driver_unit);
450 break;
451 #endif
452
453 #if NI4BING > 0
454 case BDRV_ING:
455 dlt = ing_ret_linktab(mdrsp->driver_unit);
456 break;
457 #endif
458 }
459
460 if(dlt != NULL)
461 (*dlt->dial_response)(mdrsp->driver_unit, mdrsp->stat, mdrsp->cause);
462 break;
463 }
464
465 /* update timeout value */
466
467 case I4B_TIMEOUT_UPD:
468 {
469 msg_timeout_upd_t *mtu;
470 int x;
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 x = SPLI4B();
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 splx(x);
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 = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
631 M_DEVBUF, M_WAITOK);
632
633 prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
634 M_DEVBUF, M_WAITOK);
635
636 if(!prots || !prots2)
637 {
638 error = ENOMEM;
639 goto download_done;
640 }
641
642 copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
643
644 for(i = 0; i < r->numprotos; i++)
645 {
646 prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
647 copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
648 prots2[i].bytecount = prots[i].bytecount;
649 }
650
651 error = ctrl_desc[r->controller].N_DOWNLOAD(
652 ctrl_desc[r->controller].unit,
653 r->numprotos, prots2);
654
655 download_done:
656 if(prots2)
657 {
658 for(i = 0; i < r->numprotos; i++)
659 {
660 if(prots2[i].microcode)
661 {
662 free(prots2[i].microcode, M_DEVBUF);
663 }
664 }
665 free(prots2, M_DEVBUF);
666 }
667
668 if(prots)
669 {
670 free(prots, M_DEVBUF);
671 }
672 break;
673 }
674
675 /* Diagnostic request */
676
677 case I4B_ACTIVE_DIAGNOSTIC:
678 {
679 struct isdn_diagnostic_request req, *r =
680 (struct isdn_diagnostic_request*)data;
681
682 req.in_param = req.out_param = NULL;
683 if (r->controller < 0 || r->controller >= nctrl)
684 {
685 error = ENODEV;
686 goto diag_done;
687 }
688
689 if(!ctrl_desc[r->controller].N_DIAGNOSTICS)
690 {
691 error = ENODEV;
692 goto diag_done;
693 }
694
695 memcpy(&req, r, sizeof(req));
696
697 if(req.in_param_len)
698 {
699 /* XXX arbitrary limit */
700 if (req.in_param_len >
701 I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) {
702 error = EINVAL;
703 goto diag_done;
704 }
705
706 req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK);
707
708 if(!req.in_param)
709 {
710 error = ENOMEM;
711 goto diag_done;
712 }
713 error = copyin(r->in_param, req.in_param, req.in_param_len);
714 if (error)
715 goto diag_done;
716 }
717
718 if(req.out_param_len)
719 {
720 req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK);
721
722 if(!req.out_param)
723 {
724 error = ENOMEM;
725 goto diag_done;
726 }
727 }
728
729 error = ctrl_desc[r->controller].N_DIAGNOSTICS(r->controller, &req);
730
731 if(!error && req.out_param_len)
732 error = copyout(req.out_param, r->out_param, req.out_param_len);
733
734 diag_done:
735 if(req.in_param)
736 free(req.in_param, M_DEVBUF);
737
738 if(req.out_param)
739 free(req.out_param, M_DEVBUF);
740
741 break;
742 }
743
744 /* default */
745
746 default:
747 error = ENOTTY;
748 break;
749 }
750
751 return(error);
752 }
753
754 /*---------------------------------------------------------------------------*
755 * i4bpoll - device driver poll routine
756 *---------------------------------------------------------------------------*/
757 static int
758 i4bpoll(struct cdev *dev, int events, struct thread *td)
759 {
760 int x;
761
762 if(minor(dev))
763 return(ENODEV);
764
765 if((events & POLLIN) || (events & POLLRDNORM))
766 {
767 if(!IF_QEMPTY(&i4b_rdqueue))
768 return(1);
769
770 x = splimp();
771 selrecord(td, &select_rd_info);
772 selflag = 1;
773 splx(x);
774 return(0);
775 }
776 else if((events & POLLOUT) || (events & POLLWRNORM))
777 {
778 return(1);
779 }
780
781 return(0);
782 }
783
784 /*---------------------------------------------------------------------------*
785 * i4bputqueue - put message into queue to userland
786 *---------------------------------------------------------------------------*/
787 void
788 i4bputqueue(struct mbuf *m)
789 {
790 int x;
791
792 if(!openflag)
793 {
794 i4b_Dfreembuf(m);
795 return;
796 }
797
798 x = splimp();
799
800 IF_LOCK(&i4b_rdqueue);
801 if(_IF_QFULL(&i4b_rdqueue))
802 {
803 struct mbuf *m1;
804 _IF_DEQUEUE(&i4b_rdqueue, m1);
805 i4b_Dfreembuf(m1);
806 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
807 }
808
809 _IF_ENQUEUE(&i4b_rdqueue, m);
810 IF_UNLOCK(&i4b_rdqueue);
811
812 splx(x);
813
814 if(readflag)
815 {
816 readflag = 0;
817 wakeup( &i4b_rdqueue);
818 }
819
820 if(selflag)
821 {
822 selflag = 0;
823 selwakeuppri(&select_rd_info, I4BPRI);
824 }
825 }
826
827 /*---------------------------------------------------------------------------*
828 * i4bputqueue_hipri - put message into front of queue to userland
829 *---------------------------------------------------------------------------*/
830 void
831 i4bputqueue_hipri(struct mbuf *m)
832 {
833 int x;
834
835 if(!openflag)
836 {
837 i4b_Dfreembuf(m);
838 return;
839 }
840
841 x = splimp();
842
843 IF_LOCK(&i4b_rdqueue);
844 if(_IF_QFULL(&i4b_rdqueue))
845 {
846 struct mbuf *m1;
847 _IF_DEQUEUE(&i4b_rdqueue, m1);
848 i4b_Dfreembuf(m1);
849 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
850 }
851
852 _IF_PREPEND(&i4b_rdqueue, m);
853 IF_UNLOCK(&i4b_rdqueue);
854
855 splx(x);
856
857 if(readflag)
858 {
859 readflag = 0;
860 wakeup( &i4b_rdqueue);
861 }
862
863 if(selflag)
864 {
865 selflag = 0;
866 selwakeuppri(&select_rd_info, I4BPRI);
867 }
868 }
Cache object: 2145a792b0d05578196b00c27079447d
|