1 /* $NetBSD: i4b_capi_l4if.c,v 1.8 2006/10/16 13:03:03 pooka Exp $ */
4 * Copyright (c) 2001-2003 Cubical Solutions Ltd. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * capi/capi_l4if.c The CAPI i4b L4/device interface.
29 * $FreeBSD: src/sys/i4b/capi/capi_l4if.c,v 1.4 2002/04/04 21:03:20 jhb Exp $
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: i4b_capi_l4if.c,v 1.8 2006/10/16 13:03:03 pooka Exp $");
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
39 #include <sys/socket.h>
40 #include <sys/callout.h>
43 #include <netisdn/i4b_debug.h>
44 #include <netisdn/i4b_ioctl.h>
45 #include <netisdn/i4b_cause.h>
46 #include <netisdn/i4b_l3l4.h>
47 #include <netisdn/i4b_mbuf.h>
48 #include <netisdn/i4b_global.h>
49 #include <netisdn/i4b_l4.h>
50 #include <netisdn/i4b_capi.h>
51 #include <netisdn/i4b_capi_msgs.h>
53 static void n_connect_request(call_desc_t
*);
54 static void n_connect_response(call_desc_t
*, int response
, int cause
);
55 static void n_disconnect_request(call_desc_t
*, int cause
);
56 static void n_alert_request(call_desc_t
*);
57 static void n_mgmt_command(struct isdn_l3_driver
*, int cmd
, void *parm
);
58 static int n_download(void *, int, struct isdn_dr_prot
*);
63 // i4b_capi_{ret,set}_linktab
66 // i4b_capi_bch_config
67 // Called by i4b driver to flush + {en,dis}able a channel.
69 // i4b_capi_bch_start_tx
70 // Called by i4b driver to transmit a queued mbuf.
73 // Called by i4b driver to obtain statistics information.
77 i4b_capi_ret_linktab(void *token
, int channel
)
79 capi_softc_t
*sc
= token
;
81 return &sc
->sc_bchan
[channel
].capi_isdn_linktab
;
85 i4b_capi_set_link(void *token
, int channel
,
86 const struct isdn_l4_driver_functions
*l4_driver
, void *l4_inst
)
88 capi_softc_t
*sc
= token
;
90 sc
->sc_bchan
[channel
].l4_driver
= l4_driver
;
91 sc
->sc_bchan
[channel
].l4_driver_softc
= l4_inst
;
95 i4b_capi_bch_config(void *token
, int chan
, int bprot
, int activate
)
97 capi_softc_t
*sc
= token
;
99 i4b_Bcleanifq(&sc
->sc_bchan
[chan
].tx_queue
);
100 sc
->sc_bchan
[chan
].tx_queue
.ifq_maxlen
= IFQ_MAXLEN
;
101 sc
->sc_bchan
[chan
].txcount
= 0;
103 /* The telephony drivers use rx_queue for receive. */
104 i4b_Bcleanifq(&sc
->sc_bchan
[chan
].rx_queue
);
105 sc
->sc_bchan
[chan
].rx_queue
.ifq_maxlen
= IFQ_MAXLEN
;
106 sc
->sc_bchan
[chan
].rxcount
= 0;
108 /* HDLC frames are put to in_mbuf */
109 i4b_Bfreembuf(sc
->sc_bchan
[chan
].in_mbuf
);
110 sc
->sc_bchan
[chan
].in_mbuf
= NULL
;
112 /* Because of the difference, we need to remember the protocol. */
113 sc
->sc_bchan
[chan
].bprot
= bprot
;
114 sc
->sc_bchan
[chan
].busy
= 0;
118 i4b_capi_bch_start_tx(void *token
, int chan
)
120 capi_softc_t
*sc
= token
;
125 if (sc
->sc_bchan
[chan
].state
!= B_CONNECTED
) {
127 printf("capi%d: start_tx on unconnected channel\n", sc
->sc_unit
);
131 if (sc
->sc_bchan
[chan
].busy
) {
136 capi_start_tx(sc
, chan
);
142 i4b_capi_bch_stat(void *token
, int chan
, bchan_statistics_t
*bsp
)
144 capi_softc_t
*sc
= token
;
147 bsp
->outbytes
= sc
->sc_bchan
[chan
].txcount
;
148 bsp
->inbytes
= sc
->sc_bchan
[chan
].rxcount
;
150 sc
->sc_bchan
[chan
].txcount
= 0;
151 sc
->sc_bchan
[chan
].rxcount
= 0;
156 int capi_start_tx(void *token
, int chan
)
158 capi_softc_t
*sc
= token
;
162 IF_DEQUEUE(&sc
->sc_bchan
[chan
].tx_queue
, m_b3
);
164 struct mbuf
*m
= m_b3
->m_next
;
166 sc
->sc_bchan
[chan
].txcount
+= m_b3
->m_len
;
167 capi_data_b3_req(sc
, chan
, m_b3
);
173 if (sc
->sc_bchan
[chan
].l4_driver
) {
174 capi_bchan_t
*bch
= &sc
->sc_bchan
[chan
];
176 /* Notify i4b driver of activity, and if the queue is drained. */
178 (*bch
->l4_driver
->bch_activity
)(bch
->l4_driver_softc
, ACT_TX
);
180 if (IF_QEMPTY(&bch
->tx_queue
))
181 (*bch
->l4_driver
->bch_tx_queue_empty
)(bch
->l4_driver_softc
);
187 static const struct isdn_l4_bchannel_functions
190 i4b_capi_bch_start_tx
,
196 // i4b L4 management command.
200 n_mgmt_command(struct isdn_l3_driver
*l3
, int op
, void *arg
)
202 capi_softc_t
*sc
= l3
->l1_token
;
205 printf("capi%d: mgmt command %d\n", sc
->sc_unit
, op
);
227 // i4b L4 wants to connect. We assign a B channel to the call,
228 // send a CAPI_CONNECT_REQ, and set the channel to B_CONNECT_CONF.
232 n_connect_request(call_desc_t
*cd
)
237 sc
= cd
->l3drv
->l1_token
;
242 if ((bch
< 0) || (bch
>= sc
->sc_nbch
))
243 for (bch
= 0; bch
< sc
->sc_nbch
; bch
++)
244 if (sc
->sc_bchan
[bch
].state
== B_FREE
)
247 if (bch
== sc
->sc_nbch
) {
249 printf("capi%d: no free B channel\n", sc
->sc_unit
);
255 capi_connect_req(sc
, cd
);
260 // n_connect_response
261 // i4b L4 answers a call. We send a CONNECT_RESP with the proper
262 // Reject code, and set the channel to B_CONNECT_B3_IND or B_FREE,
263 // depending whether we answer or not.
267 n_connect_response(call_desc_t
*cd
, int response
, int cause
)
272 sc
= cd
->l3drv
->l1_token
;
276 cd
->response
= response
;
277 cd
->cause_out
= cause
;
280 capi_connect_resp(sc
, cd
);
285 // n_disconnect_request
286 // i4b L4 wants to disconnect. We send a DISCONNECT_REQ and
287 // set the channel to B_DISCONNECT_CONF.
291 n_disconnect_request(call_desc_t
*cd
, int cause
)
296 sc
= cd
->l3drv
->l1_token
;
298 cd
->cause_out
= cause
;
301 capi_disconnect_req(sc
, cd
);
307 // i4b L4 wants to alert an incoming call. We send ALERT_REQ.
311 n_alert_request(call_desc_t
*cd
)
316 sc
= cd
->l3drv
->l1_token
;
319 capi_alert_req(sc
, cd
);
325 // L4 -> firmware download
329 n_download(void *token
, int numprotos
, struct isdn_dr_prot
*protocols
)
331 capi_softc_t
*sc
= token
;
334 (*sc
->load
)(sc
, protocols
[0].bytecount
,
335 protocols
[0].microcode
);
342 static const struct isdn_l3_driver_functions
343 capi_l3_functions
= {
344 i4b_capi_ret_linktab
,
348 n_disconnect_request
,
357 // Called by a link layer driver at boot time.
361 capi_ll_attach(capi_softc_t
*sc
, const char *devname
, const char *cardname
)
363 struct isdn_l3_driver
*l3drv
;
369 sc
->sc_state
= C_DOWN
;
372 for (i
= 0; i
< sc
->sc_nbch
; i
++) {
373 sc
->sc_bchan
[i
].ncci
= INVALID
;
374 sc
->sc_bchan
[i
].msgid
= 0;
375 sc
->sc_bchan
[i
].busy
= 0;
376 sc
->sc_bchan
[i
].state
= B_FREE
;
378 memset(&sc
->sc_bchan
[i
].tx_queue
, 0, sizeof(struct ifqueue
));
379 memset(&sc
->sc_bchan
[i
].rx_queue
, 0, sizeof(struct ifqueue
));
380 sc
->sc_bchan
[i
].tx_queue
.ifq_maxlen
= IFQ_MAXLEN
;
381 sc
->sc_bchan
[i
].rx_queue
.ifq_maxlen
= IFQ_MAXLEN
;
383 sc
->sc_bchan
[i
].txcount
= 0;
384 sc
->sc_bchan
[i
].rxcount
= 0;
386 sc
->sc_bchan
[i
].cdid
= CDID_UNUSED
;
387 sc
->sc_bchan
[i
].bprot
= BPROT_NONE
;
388 sc
->sc_bchan
[i
].in_mbuf
= NULL
;
390 sc
->sc_bchan
[i
].capi_isdn_linktab
.l1token
= sc
;
391 sc
->sc_bchan
[i
].capi_isdn_linktab
.channel
= i
;
392 sc
->sc_bchan
[i
].capi_isdn_linktab
.bchannel_driver
= &capi_l4_driver
;
393 sc
->sc_bchan
[i
].capi_isdn_linktab
.tx_queue
= &sc
->sc_bchan
[i
].tx_queue
;
394 sc
->sc_bchan
[i
].capi_isdn_linktab
.rx_queue
= &sc
->sc_bchan
[i
].rx_queue
;
395 sc
->sc_bchan
[i
].capi_isdn_linktab
.rx_mbuf
= &sc
->sc_bchan
[i
].in_mbuf
;
398 l3drv
= isdn_attach_isdnif(devname
, cardname
, sc
, &capi_l3_functions
,
402 l3drv
->dl_est
= DL_DOWN
;
403 l3drv
->nbch
= sc
->sc_nbch
;
405 sc
->sc_unit
= ncapi
++;
406 sc
->capi_isdnif
= l3drv
->isdnif
;
408 isdn_isdnif_ready(l3drv
->isdnif
);
410 printf("capi%d: card type %d attached\n", sc
->sc_unit
, sc
->card_type
);
421 capi_ll_detach(capi_softc_t
*sc
)