Merge branch 'master' of git://git.theshell.com/dragonfly
[dragonfly.git] / sys / net / i4b / capi / capi_l4if.c
1 /*
2  * Copyright (c) 2001 Cubical Solutions Ltd. 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  * capi/capi_l4if.c     The CAPI i4b L4/device interface.
26  *
27  * $FreeBSD: src/sys/i4b/capi/capi_l4if.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $
28  */
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33 #include <sys/mbuf.h>
34 #include <sys/socket.h>
35 #include <sys/thread2.h>
36 #include <net/if.h>
37
38 #include <net/i4b/include/machine/i4b_debug.h>
39 #include <net/i4b/include/machine/i4b_ioctl.h>
40 #include <net/i4b/include/machine/i4b_cause.h>
41
42 #include "../include/i4b_l3l4.h"
43 #include "../include/i4b_mbuf.h"
44 #include "../include/i4b_global.h"
45 #include "../layer4/i4b_l4.h"
46
47 #include "capi.h"
48 #include "capi_msgs.h"
49
50 static void n_connect_request(u_int cdid);
51 static void n_connect_response(u_int cdid, int response, int cause);
52 static void n_disconnect_request(u_int cdid, int cause);
53 static void n_alert_request(u_int cdid);
54 static void n_mgmt_command(int unit, int cmd, void *parm);
55 static int  n_download(int unit, int, struct isdn_dr_prot *);
56
57 capi_softc_t *capi_sc[MAX_CONTROLLERS] = { NULL, };
58 int ncapi = 0;
59
60 /*
61 //  i4b_capi_{ret,set}_linktab
62 //      i4b driver glue.
63 //
64 //  i4b_capi_bch_config
65 //      Called by i4b driver to flush + {en,dis}able a channel.
66 //
67 //  i4b_capi_bch_start_tx
68 //      Called by i4b driver to transmit a queued mbuf.
69 //
70 //  i4b_capi_bch_stat
71 //      Called by i4b driver to obtain statistics information.
72 */
73
74 static isdn_link_t *
75 i4b_capi_ret_linktab(int unit, int channel)
76 {
77     capi_softc_t *sc = capi_sc[unit];
78     return &sc->sc_bchan[channel].capi_isdn_linktab;
79 }
80
81 static void
82 i4b_capi_set_linktab(int unit, int channel, drvr_link_t *dlt)
83 {
84     capi_softc_t *sc = capi_sc[unit];
85     sc->sc_bchan[channel].capi_drvr_linktab = dlt;
86 }
87
88 static void
89 i4b_capi_bch_config(int unit, int chan, int bprot, int activate)
90 {
91     capi_softc_t *sc = capi_sc[unit];
92
93     i4b_Bcleanifq(&sc->sc_bchan[chan].tx_queue);
94     sc->sc_bchan[chan].tx_queue.ifq_maxlen = IFQ_MAXLEN;
95     sc->sc_bchan[chan].txcount = 0;
96
97     /* The telephony drivers use rx_queue for receive. */
98
99     i4b_Bcleanifq(&sc->sc_bchan[chan].rx_queue);
100     sc->sc_bchan[chan].rx_queue.ifq_maxlen = IFQ_MAXLEN;
101     sc->sc_bchan[chan].rxcount = 0;
102
103     /* HDLC frames are put to in_mbuf */
104
105     i4b_Bfreembuf(sc->sc_bchan[chan].in_mbuf);
106     sc->sc_bchan[chan].in_mbuf = NULL;
107
108     /* Because of the difference, we need to remember the protocol. */
109
110     sc->sc_bchan[chan].bprot = bprot;
111     sc->sc_bchan[chan].busy = 0;
112 }
113
114 static void
115 i4b_capi_bch_start_tx(int unit, int chan)
116 {
117     capi_softc_t *sc = capi_sc[unit];
118
119     crit_enter();
120     if (sc->sc_bchan[chan].state != B_CONNECTED) {
121         crit_exit();
122         kprintf("capi%d: start_tx on unconnected channel\n", sc->sc_unit);
123         return;
124     }
125
126     if (sc->sc_bchan[chan].busy) {
127         crit_exit();
128         return;
129     }
130
131     capi_start_tx(sc, chan);
132
133     crit_exit();
134 }
135
136 static void
137 i4b_capi_bch_stat(int unit, int chan, bchan_statistics_t *bsp)
138 {
139     capi_softc_t *sc = capi_sc[unit];
140
141     crit_enter();
142
143     bsp->outbytes = sc->sc_bchan[chan].txcount;
144     bsp->inbytes = sc->sc_bchan[chan].rxcount;
145
146     sc->sc_bchan[chan].txcount = 0;
147     sc->sc_bchan[chan].rxcount = 0;
148
149     crit_exit();
150 }
151
152 int
153 capi_start_tx(capi_softc_t *sc, int chan)
154 {
155     struct mbuf *m_b3;
156     int sent = 0;
157
158     IF_DEQUEUE(&sc->sc_bchan[chan].tx_queue, m_b3);
159     while (m_b3) {
160         struct mbuf *m = m_b3->m_next;
161
162         sc->sc_bchan[chan].txcount += m_b3->m_len;
163         capi_data_b3_req(sc, chan, m_b3);
164         sent++;
165
166         m_b3 = m;
167     }
168
169     if (sc->sc_bchan[chan].capi_drvr_linktab) {
170         /* Notify i4b driver of activity, and if the queue is drained. */
171
172         if (sent)
173             (*sc->sc_bchan[chan].capi_drvr_linktab->bch_activity)(
174                 sc->sc_bchan[chan].capi_drvr_linktab->unit, ACT_TX);
175
176         if (IF_QEMPTY(&sc->sc_bchan[chan].tx_queue))
177             (*sc->sc_bchan[chan].capi_drvr_linktab->bch_tx_queue_empty)(
178                 sc->sc_bchan[chan].capi_drvr_linktab->unit);
179     }
180
181     return sent;
182 }
183
184 /*
185 //  capi_ll_attach
186 //      Called by a link layer driver at boot time.
187 */
188
189 int
190 capi_ll_attach(capi_softc_t *sc)
191 {
192     int i;
193
194     if (ncapi == NELEM(capi_sc)) {
195         kprintf("capi%d: too many units, increase MAX_CONTROLLERS\n", ncapi);
196         return (ENXIO);
197     }
198
199     /* Unit type and subtype; sc is partly filled by ll driver */
200     
201     ctrl_desc[nctrl].unit = ncapi;
202     ctrl_desc[nctrl].ctrl_type = CTRL_CAPI;
203     ctrl_desc[nctrl].card_type = sc->card_type;
204
205     /* L4 callbacks */
206     
207     ctrl_types[CTRL_CAPI].get_linktab = i4b_capi_ret_linktab;
208     ctrl_types[CTRL_CAPI].set_linktab = i4b_capi_set_linktab;
209
210     ctrl_desc[nctrl].N_CONNECT_REQUEST = n_connect_request;
211     ctrl_desc[nctrl].N_CONNECT_RESPONSE = n_connect_response;
212     ctrl_desc[nctrl].N_DISCONNECT_REQUEST = n_disconnect_request;
213     ctrl_desc[nctrl].N_ALERT_REQUEST = n_alert_request;
214     ctrl_desc[nctrl].N_DOWNLOAD = n_download;
215     ctrl_desc[nctrl].N_DIAGNOSTICS = NULL; /* XXX todo */
216     ctrl_desc[nctrl].N_MGMT_COMMAND = n_mgmt_command;
217
218     /* Unit state */
219
220     sc->sc_enabled = FALSE;
221     sc->sc_state = C_DOWN;
222     sc->sc_msgid = 0;
223
224     ctrl_desc[nctrl].dl_est = DL_DOWN;
225     ctrl_desc[nctrl].nbch = sc->sc_nbch;
226
227     for (i = 0; i < sc->sc_nbch; i++) {
228         ctrl_desc[nctrl].bch_state[i] = BCH_ST_FREE;
229         sc->sc_bchan[i].ncci = INVALID;
230         sc->sc_bchan[i].msgid = 0;
231         sc->sc_bchan[i].busy = 0;
232         sc->sc_bchan[i].state = B_FREE;
233
234         memset(&sc->sc_bchan[i].tx_queue, 0, sizeof(struct ifqueue));
235         memset(&sc->sc_bchan[i].rx_queue, 0, sizeof(struct ifqueue));
236         sc->sc_bchan[i].tx_queue.ifq_maxlen = IFQ_MAXLEN;
237         sc->sc_bchan[i].rx_queue.ifq_maxlen = IFQ_MAXLEN;
238         sc->sc_bchan[i].txcount = 0;
239         sc->sc_bchan[i].rxcount = 0;
240
241         sc->sc_bchan[i].cdid = CDID_UNUSED;
242         sc->sc_bchan[i].bprot = BPROT_NONE;
243         sc->sc_bchan[i].in_mbuf = NULL;
244
245         sc->sc_bchan[i].capi_drvr_linktab = NULL;
246
247         sc->sc_bchan[i].capi_isdn_linktab.unit = ncapi;
248         sc->sc_bchan[i].capi_isdn_linktab.channel = i;
249         sc->sc_bchan[i].capi_isdn_linktab.bch_config = i4b_capi_bch_config;
250         sc->sc_bchan[i].capi_isdn_linktab.bch_tx_start = i4b_capi_bch_start_tx;
251         sc->sc_bchan[i].capi_isdn_linktab.bch_stat = i4b_capi_bch_stat;
252         sc->sc_bchan[i].capi_isdn_linktab.tx_queue = &sc->sc_bchan[i].tx_queue;
253         sc->sc_bchan[i].capi_isdn_linktab.rx_queue = &sc->sc_bchan[i].rx_queue;
254         sc->sc_bchan[i].capi_isdn_linktab.rx_mbuf = &sc->sc_bchan[i].in_mbuf;
255     }
256
257     ctrl_desc[nctrl].tei = -1;
258
259     /* Up the controller index and store the softc */
260
261     sc->sc_unit = ncapi;
262     capi_sc[ncapi++] = sc;
263     sc->ctrl_unit = nctrl++;
264
265     kprintf("capi%d: card type %d attached\n", sc->sc_unit, sc->card_type);
266
267     return(0);
268 }
269
270 /*
271 //  n_mgmt_command
272 //      i4b L4 management command.
273 */
274
275 static void
276 n_mgmt_command(int unit, int op, void *arg)
277 {
278     capi_softc_t *sc = capi_sc[unit];
279
280     kprintf("capi%d: mgmt command %d\n", sc->sc_unit, op);
281
282     switch(op) {
283     case CMR_DOPEN:
284         sc->sc_enabled = TRUE;
285         break;
286
287     case CMR_DCLOSE:
288         sc->sc_enabled = FALSE;
289         break;
290
291     case CMR_SETTRACE:
292         break;
293
294     default:
295         break;
296     }
297 }
298
299 /*
300 //  n_connect_request
301 //      i4b L4 wants to connect. We assign a B channel to the call,
302 //      send a CAPI_CONNECT_REQ, and set the channel to B_CONNECT_CONF.
303 */
304
305 static void
306 n_connect_request(u_int cdid)
307 {
308     call_desc_t *cd = cd_by_cdid(cdid);
309     capi_softc_t *sc;
310     int bch;
311
312     if (!cd) {
313         kprintf("capi?: invalid cdid %d\n", cdid);
314         return;
315     }
316
317     sc = capi_sc[ctrl_desc[cd->controller].unit];
318     bch = cd->channelid;
319
320     crit_enter();
321
322     if ((bch < 0) || (bch >= sc->sc_nbch))
323         for (bch = 0; bch < sc->sc_nbch; bch++)
324             if (sc->sc_bchan[bch].state == B_FREE)
325                 break;
326
327     if (bch == sc->sc_nbch) {
328         crit_exit();
329         kprintf("capi%d: no free B channel\n", sc->sc_unit);
330         return;
331     }
332
333     cd->channelid = bch;
334
335     capi_connect_req(sc, cd);
336     crit_exit();
337 }
338
339 /*
340 //  n_connect_response
341 //      i4b L4 answers a call. We send a CONNECT_RESP with the proper
342 //      Reject code, and set the channel to B_CONNECT_B3_IND or B_FREE,
343 //      depending whether we answer or not.
344 */
345
346 static void
347 n_connect_response(u_int cdid, int response, int cause)
348 {
349     call_desc_t *cd = cd_by_cdid(cdid);
350     capi_softc_t *sc;
351     int bch;
352
353     if (!cd) {
354         kprintf("capi?: invalid cdid %d\n", cdid);
355         return;
356     }
357
358     sc = capi_sc[ctrl_desc[cd->controller].unit];
359     bch = cd->channelid;
360
361     T400_stop(cd);
362         
363     cd->response = response;
364     cd->cause_out = cause;
365
366     crit_enter();
367     capi_connect_resp(sc, cd);
368     crit_exit();
369 }
370
371 /*
372 //  n_disconnect_request
373 //      i4b L4 wants to disconnect. We send a DISCONNECT_REQ and
374 //      set the channel to B_DISCONNECT_CONF.
375 */
376
377 static void
378 n_disconnect_request(u_int cdid, int cause)
379 {
380     call_desc_t *cd = cd_by_cdid(cdid);
381     capi_softc_t *sc;
382     int bch;
383
384     if (!cd) {
385         kprintf("capi?: invalid cdid %d\n", cdid);
386         return;
387     }
388
389     sc = capi_sc[ctrl_desc[cd->controller].unit];
390     bch = cd->channelid;
391
392     cd->cause_out = cause;
393
394     crit_enter();
395     capi_disconnect_req(sc, cd);
396     crit_exit();
397 }
398
399 /*
400 //  n_alert_request
401 //      i4b L4 wants to alert an incoming call. We send ALERT_REQ.
402 */
403
404 static void
405 n_alert_request(u_int cdid)
406 {
407     call_desc_t *cd = cd_by_cdid(cdid);
408     capi_softc_t *sc;
409
410     if (!cd) {
411         kprintf("capi?: invalid cdid %d\n", cdid);
412         return;
413     }
414
415     sc = capi_sc[ctrl_desc[cd->controller].unit];
416
417     crit_enter();
418     capi_alert_req(sc, cd);
419     crit_exit();
420 }
421
422 /*
423 //  n_download
424 //      L4 -> firmware download
425 */
426
427 static int
428 n_download(int unit, int numprotos, struct isdn_dr_prot *protocols)
429 {
430     capi_softc_t *sc = capi_sc[unit];
431
432     if (sc->load) {
433         (*capi_sc[unit]->load)(sc, protocols[0].bytecount,
434                                protocols[0].microcode);
435     }
436
437     return(0);
438 }