1 /* $NetBSD: i4b_capi_l4if.c,v 1.4 2003/10/03 16:47:57 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2001-2003 Cubical Solutions Ltd. All rights reserved.
5 *
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.
14 *
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.
26 *
27 * capi/capi_l4if.c The CAPI i4b L4/device interface.
28 *
29 * $FreeBSD: src/sys/i4b/capi/capi_l4if.c,v 1.4 2002/04/04 21:03:20 jhb Exp $
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: i4b_capi_l4if.c,v 1.4 2003/10/03 16:47:57 pooka Exp $");
34
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>
42
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>
52
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 *);
59
60 static int ncapi = 0;
61
62 /*
63 // i4b_capi_{ret,set}_linktab
64 // i4b driver glue.
65 //
66 // i4b_capi_bch_config
67 // Called by i4b driver to flush + {en,dis}able a channel.
68 //
69 // i4b_capi_bch_start_tx
70 // Called by i4b driver to transmit a queued mbuf.
71 //
72 // i4b_capi_bch_stat
73 // Called by i4b driver to obtain statistics information.
74 */
75
76 static isdn_link_t *
77 i4b_capi_ret_linktab(void *token, int channel)
78 {
79 capi_softc_t *sc = token;
80
81 return &sc->sc_bchan[channel].capi_isdn_linktab;
82 }
83
84 static void
85 i4b_capi_set_link(void *token, int channel,
86 const struct isdn_l4_driver_functions *l4_driver, void *l4_inst)
87 {
88 capi_softc_t *sc = token;
89
90 sc->sc_bchan[channel].l4_driver = l4_driver;
91 sc->sc_bchan[channel].l4_driver_softc = l4_inst;
92 }
93
94 static void
95 i4b_capi_bch_config(void *token, int chan, int bprot, int activate)
96 {
97 capi_softc_t *sc = token;
98
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;
102
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;
107
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;
111
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;
115 }
116
117 static void
118 i4b_capi_bch_start_tx(void *token, int chan)
119 {
120 capi_softc_t *sc = token;
121 int s;
122
123 s = splnet();
124
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;
129 }
130
131 if (sc->sc_bchan[chan].busy) {
132 splx(s);
133 return;
134 }
135
136 capi_start_tx(sc, chan);
137
138 splx(s);
139 }
140
141 static void
142 i4b_capi_bch_stat(void *token, int chan, bchan_statistics_t *bsp)
143 {
144 capi_softc_t *sc = token;
145 int s = splnet();
146
147 bsp->outbytes = sc->sc_bchan[chan].txcount;
148 bsp->inbytes = sc->sc_bchan[chan].rxcount;
149
150 sc->sc_bchan[chan].txcount = 0;
151 sc->sc_bchan[chan].rxcount = 0;
152
153 splx(s);
154 }
155
156 int capi_start_tx(void *token, int chan)
157 {
158 capi_softc_t *sc = token;
159 struct mbuf *m_b3;
160 int sent = 0;
161
162 IF_DEQUEUE(&sc->sc_bchan[chan].tx_queue, m_b3);
163 while (m_b3) {
164 struct mbuf *m = m_b3->m_next;
165
166 sc->sc_bchan[chan].txcount += m_b3->m_len;
167 capi_data_b3_req(sc, chan, m_b3);
168 sent++;
169
170 m_b3 = m;
171 }
172
173 if (sc->sc_bchan[chan].l4_driver) {
174 capi_bchan_t *bch = &sc->sc_bchan[chan];
175
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);
179
180 if (IF_QEMPTY(&bch->tx_queue))
181 (*bch->l4_driver->bch_tx_queue_empty)(bch->l4_driver_softc);
182 }
183
184 return sent;
185 }
186
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
192 };
193
194 /*
195 // n_mgmt_command
196 // i4b L4 management command.
197 */
198
199 static void
200 n_mgmt_command(struct isdn_l3_driver *l3, int op, void *arg)
201 {
202 capi_softc_t *sc = l3->l1_token;
203
204 #if 0
205 printf("capi%d: mgmt command %d\n", sc->sc_unit, op);
206 #endif
207
208 switch(op) {
209 case CMR_DOPEN:
210 sc->sc_enabled = 1;
211 break;
212
213 case CMR_DCLOSE:
214 sc->sc_enabled = 0;
215 break;
216
217 case CMR_SETTRACE:
218 break;
219
220 default:
221 break;
222 }
223 }
224
225 /*
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.
229 */
230
231 static void
232 n_connect_request(call_desc_t *cd)
233 {
234 capi_softc_t *sc;
235 int bch, s;
236
237 sc = cd->l3drv->l1_token;
238 bch = cd->channelid;
239
240 s = splnet();
241
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;
246
247 if (bch == sc->sc_nbch) {
248 splx(s);
249 printf("capi%d: no free B channel\n", sc->sc_unit);
250 return;
251 }
252
253 cd->channelid = bch;
254
255 capi_connect_req(sc, cd);
256 splx(s);
257 }
258
259 /*
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.
264 */
265
266 static void
267 n_connect_response(call_desc_t *cd, int response, int cause)
268 {
269 capi_softc_t *sc;
270 int s;
271
272 sc = cd->l3drv->l1_token;
273
274 T400_stop(cd);
275
276 cd->response = response;
277 cd->cause_out = cause;
278
279 s = splnet();
280 capi_connect_resp(sc, cd);
281 splx(s);
282 }
283
284 /*
285 // n_disconnect_request
286 // i4b L4 wants to disconnect. We send a DISCONNECT_REQ and
287 // set the channel to B_DISCONNECT_CONF.
288 */
289
290 static void
291 n_disconnect_request(call_desc_t *cd, int cause)
292 {
293 capi_softc_t *sc;
294 int s;
295
296 sc = cd->l3drv->l1_token;
297
298 cd->cause_out = cause;
299
300 s = splnet();
301 capi_disconnect_req(sc, cd);
302 splx(s);
303 }
304
305 /*
306 // n_alert_request
307 // i4b L4 wants to alert an incoming call. We send ALERT_REQ.
308 */
309
310 static void
311 n_alert_request(call_desc_t *cd)
312 {
313 capi_softc_t *sc;
314 int s;
315
316 sc = cd->l3drv->l1_token;
317
318 s = splnet();
319 capi_alert_req(sc, cd);
320 splx(s);
321 }
322
323 /*
324 // n_download
325 // L4 -> firmware download
326 */
327
328 static int
329 n_download(void *token, int numprotos, struct isdn_dr_prot *protocols)
330 {
331 capi_softc_t *sc = token;
332
333 if (sc->load) {
334 (*sc->load)(sc, protocols[0].bytecount,
335 protocols[0].microcode);
336 return(0);
337 }
338
339 return(ENXIO);
340 }
341
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
353 };
354
355 /*
356 // capi_ll_attach
357 // Called by a link layer driver at boot time.
358 */
359
360 int
361 capi_ll_attach(capi_softc_t *sc, const char *devname, const char *cardname)
362 {
363 struct isdn_l3_driver *l3drv;
364 int i;
365
366 /* Unit state */
367
368 sc->sc_enabled = 0;
369 sc->sc_state = C_DOWN;
370 sc->sc_msgid = 0;
371
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;
377
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;
382
383 sc->sc_bchan[i].txcount = 0;
384 sc->sc_bchan[i].rxcount = 0;
385
386 sc->sc_bchan[i].cdid = CDID_UNUSED;
387 sc->sc_bchan[i].bprot = BPROT_NONE;
388 sc->sc_bchan[i].in_mbuf = NULL;
389
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;
396 }
397
398 l3drv = isdn_attach_isdnif(devname, cardname, sc, &capi_l3_functions,
399 sc->sc_nbch);
400
401 l3drv->tei = -1;
402 l3drv->dl_est = DL_DOWN;
403 l3drv->nbch = sc->sc_nbch;
404
405 sc->sc_unit = ncapi++;
406 sc->capi_isdnif = l3drv->isdnif;
407
408 isdn_isdnif_ready(l3drv->isdnif);
409
410 printf("capi%d: card type %d attached\n", sc->sc_unit, sc->card_type);
411
412 return(0);
413 }
414
415
416 /*
417 // capi_ll_detach
418 */
419
420 int
421 capi_ll_detach(capi_softc_t *sc)
422 {
423
424 /* TODO */
425 return(0);
426 }
Cache object: c4ec225243e9916ae324f0f49f25d3ef
|