Sync usage with man page.
[netbsd-mini2440.git] / sys / netisdn / i4b_capi_l4if.c
blob1f6281bbdc0668a9bbab0bec48677e302a6cdd81
1 /* $NetBSD: i4b_capi_l4if.c,v 1.8 2006/10/16 13:03:03 pooka Exp $ */
3 /*
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
8 * are met:
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
25 * SUCH DAMAGE.
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>
38 #include <sys/mbuf.h>
39 #include <sys/socket.h>
40 #include <sys/callout.h>
41 #include <net/if.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 *);
60 static int ncapi = 0;
63 // i4b_capi_{ret,set}_linktab
64 // i4b driver glue.
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.
72 // i4b_capi_bch_stat
73 // Called by i4b driver to obtain statistics information.
76 static isdn_link_t *
77 i4b_capi_ret_linktab(void *token, int channel)
79 capi_softc_t *sc = token;
81 return &sc->sc_bchan[channel].capi_isdn_linktab;
84 static void
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;
94 static void
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;
117 static void
118 i4b_capi_bch_start_tx(void *token, int chan)
120 capi_softc_t *sc = token;
121 int s;
123 s = splnet();
125 if (sc->sc_bchan[chan].state != B_CONNECTED) {
126 splx(s);
127 printf("capi%d: start_tx on unconnected channel\n", sc->sc_unit);
128 return;
131 if (sc->sc_bchan[chan].busy) {
132 splx(s);
133 return;
136 capi_start_tx(sc, chan);
138 splx(s);
141 static void
142 i4b_capi_bch_stat(void *token, int chan, bchan_statistics_t *bsp)
144 capi_softc_t *sc = token;
145 int s = splnet();
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;
153 splx(s);
156 int capi_start_tx(void *token, int chan)
158 capi_softc_t *sc = token;
159 struct mbuf *m_b3;
160 int sent = 0;
162 IF_DEQUEUE(&sc->sc_bchan[chan].tx_queue, m_b3);
163 while (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);
168 sent++;
170 m_b3 = m;
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. */
177 if (sent)
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);
184 return sent;
187 static const struct isdn_l4_bchannel_functions
188 capi_l4_driver = {
189 i4b_capi_bch_config,
190 i4b_capi_bch_start_tx,
191 i4b_capi_bch_stat
195 // n_mgmt_command
196 // i4b L4 management command.
199 static void
200 n_mgmt_command(struct isdn_l3_driver *l3, int op, void *arg)
202 capi_softc_t *sc = l3->l1_token;
204 #if 0
205 printf("capi%d: mgmt command %d\n", sc->sc_unit, op);
206 #endif
208 switch(op) {
209 case CMR_DOPEN:
210 sc->sc_enabled = 1;
211 break;
213 case CMR_DCLOSE:
214 sc->sc_enabled = 0;
215 break;
217 case CMR_SETTRACE:
218 break;
220 default:
221 break;
226 // n_connect_request
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.
231 static void
232 n_connect_request(call_desc_t *cd)
234 capi_softc_t *sc;
235 int bch, s;
237 sc = cd->l3drv->l1_token;
238 bch = cd->channelid;
240 s = splnet();
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)
245 break;
247 if (bch == sc->sc_nbch) {
248 splx(s);
249 printf("capi%d: no free B channel\n", sc->sc_unit);
250 return;
253 cd->channelid = bch;
255 capi_connect_req(sc, cd);
256 splx(s);
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.
266 static void
267 n_connect_response(call_desc_t *cd, int response, int cause)
269 capi_softc_t *sc;
270 int s;
272 sc = cd->l3drv->l1_token;
274 T400_stop(cd);
276 cd->response = response;
277 cd->cause_out = cause;
279 s = splnet();
280 capi_connect_resp(sc, cd);
281 splx(s);
285 // n_disconnect_request
286 // i4b L4 wants to disconnect. We send a DISCONNECT_REQ and
287 // set the channel to B_DISCONNECT_CONF.
290 static void
291 n_disconnect_request(call_desc_t *cd, int cause)
293 capi_softc_t *sc;
294 int s;
296 sc = cd->l3drv->l1_token;
298 cd->cause_out = cause;
300 s = splnet();
301 capi_disconnect_req(sc, cd);
302 splx(s);
306 // n_alert_request
307 // i4b L4 wants to alert an incoming call. We send ALERT_REQ.
310 static void
311 n_alert_request(call_desc_t *cd)
313 capi_softc_t *sc;
314 int s;
316 sc = cd->l3drv->l1_token;
318 s = splnet();
319 capi_alert_req(sc, cd);
320 splx(s);
324 // n_download
325 // L4 -> firmware download
328 static int
329 n_download(void *token, int numprotos, struct isdn_dr_prot *protocols)
331 capi_softc_t *sc = token;
333 if (sc->load) {
334 (*sc->load)(sc, protocols[0].bytecount,
335 protocols[0].microcode);
336 return(0);
339 return(ENXIO);
342 static const struct isdn_l3_driver_functions
343 capi_l3_functions = {
344 i4b_capi_ret_linktab,
345 i4b_capi_set_link,
346 n_connect_request,
347 n_connect_response,
348 n_disconnect_request,
349 n_alert_request,
350 n_download,
351 NULL,
352 n_mgmt_command
356 // capi_ll_attach
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;
364 int i;
366 /* Unit state */
368 sc->sc_enabled = 0;
369 sc->sc_state = C_DOWN;
370 sc->sc_msgid = 0;
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,
399 sc->sc_nbch);
401 l3drv->tei = -1;
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);
412 return(0);
417 // capi_ll_detach
421 capi_ll_detach(capi_softc_t *sc)
424 (void)sc;
425 /* TODO */
426 return(0);