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