Remove spl*() calls from net/i4b, replacing them with critical sections.
[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.7 2005/06/03 16:49:54 dillon Exp $
29  */
30
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/mbuf.h>
35 #include <sys/socket.h>
36 #include <sys/thread2.h>
37 #include <net/if.h>
38
39 #include <net/i4b/include/machine/i4b_debug.h>
40 #include <net/i4b/include/machine/i4b_ioctl.h>
41 #include <net/i4b/include/machine/i4b_cause.h>
42
43 #include "../include/i4b_l3l4.h"
44 #include "../include/i4b_mbuf.h"
45 #include "../include/i4b_global.h"
46 #include "../layer4/i4b_l4.h"
47
48 #include "capi.h"
49 #include "capi_msgs.h"
50
51 static void n_connect_request(u_int cdid);
52 static void n_connect_response(u_int cdid, int response, int cause);
53 static void n_disconnect_request(u_int cdid, int cause);
54 static void n_alert_request(u_int cdid);
55 static void n_mgmt_command(int unit, int cmd, void *parm);
56 static int  n_download(int unit, int, struct isdn_dr_prot *);
57
58 capi_softc_t *capi_sc[MAX_CONTROLLERS] = { NULL, };
59 int ncapi = 0;
60
61 /*
62 //  i4b_capi_{ret,set}_linktab
63 //      i4b driver glue.
64 //
65 //  i4b_capi_bch_config
66 //      Called by i4b driver to flush + {en,dis}able a channel.
67 //
68 //  i4b_capi_bch_start_tx
69 //      Called by i4b driver to transmit a queued mbuf.
70 //
71 //  i4b_capi_bch_stat
72 //      Called by i4b driver to obtain statistics information.
73 */
74
75 static isdn_link_t *
76 i4b_capi_ret_linktab(int unit, int channel)
77 {
78     capi_softc_t *sc = capi_sc[unit];
79     return &sc->sc_bchan[channel].capi_isdn_linktab;
80 }
81
82 static void
83 i4b_capi_set_linktab(int unit, int channel, drvr_link_t *dlt)
84 {
85     capi_softc_t *sc = capi_sc[unit];
86     sc->sc_bchan[channel].capi_drvr_linktab = dlt;
87 }
88
89 static void
90 i4b_capi_bch_config(int unit, int chan, int bprot, int activate)
91 {
92     capi_softc_t *sc = capi_sc[unit];
93
94     i4b_Bcleanifq(&sc->sc_bchan[chan].tx_queue);
95     sc->sc_bchan[chan].tx_queue.ifq_maxlen = IFQ_MAXLEN;
96     sc->sc_bchan[chan].txcount = 0;
97
98     /* The telephony drivers use rx_queue for receive. */
99
100     i4b_Bcleanifq(&sc->sc_bchan[chan].rx_queue);
101     sc->sc_bchan[chan].rx_queue.ifq_maxlen = IFQ_MAXLEN;
102     sc->sc_bchan[chan].rxcount = 0;
103
104     /* HDLC frames are put to in_mbuf */
105
106     i4b_Bfreembuf(sc->sc_bchan[chan].in_mbuf);
107     sc->sc_bchan[chan].in_mbuf = NULL;
108
109     /* Because of the difference, we need to remember the protocol. */
110
111     sc->sc_bchan[chan].bprot = bprot;
112     sc->sc_bchan[chan].busy = 0;
113 }
114
115 static void
116 i4b_capi_bch_start_tx(int unit, int chan)
117 {
118     capi_softc_t *sc = capi_sc[unit];
119
120     crit_enter();
121     if (sc->sc_bchan[chan].state != B_CONNECTED) {
122         crit_exit();
123         printf("capi%d: start_tx on unconnected channel\n", sc->sc_unit);
124         return;
125     }
126
127     if (sc->sc_bchan[chan].busy) {
128         crit_exit();
129         return;
130     }
131
132     capi_start_tx(sc, chan);
133
134     crit_exit();
135 }
136
137 static void
138 i4b_capi_bch_stat(int unit, int chan, bchan_statistics_t *bsp)
139 {
140     capi_softc_t *sc = capi_sc[unit];
141
142     crit_enter();
143
144     bsp->outbytes = sc->sc_bchan[chan].txcount;
145     bsp->inbytes = sc->sc_bchan[chan].rxcount;
146
147     sc->sc_bchan[chan].txcount = 0;
148     sc->sc_bchan[chan].rxcount = 0;
149
150     crit_exit();
151 }
152
153 int 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 == (sizeof(capi_sc) / sizeof(capi_sc[0]))) {
195         printf("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
239 #if defined (__FreeBSD__) && __FreeBSD__ > 4
240         mtx_init(&sc->sc_bchan[i].tx_queue.ifq_mtx, "i4b_capi_tx", MTX_DEF);
241         mtx_init(&sc->sc_bchan[i].rx_queue.ifq_mtx, "i4b_capi_rx", MTX_DEF);    
242 #endif    
243
244         sc->sc_bchan[i].txcount = 0;
245         sc->sc_bchan[i].rxcount = 0;
246
247         sc->sc_bchan[i].cdid = CDID_UNUSED;
248         sc->sc_bchan[i].bprot = BPROT_NONE;
249         sc->sc_bchan[i].in_mbuf = NULL;
250
251         sc->sc_bchan[i].capi_drvr_linktab = NULL;
252
253         sc->sc_bchan[i].capi_isdn_linktab.unit = ncapi;
254         sc->sc_bchan[i].capi_isdn_linktab.channel = i;
255         sc->sc_bchan[i].capi_isdn_linktab.bch_config = i4b_capi_bch_config;
256         sc->sc_bchan[i].capi_isdn_linktab.bch_tx_start = i4b_capi_bch_start_tx;
257         sc->sc_bchan[i].capi_isdn_linktab.bch_stat = i4b_capi_bch_stat;
258         sc->sc_bchan[i].capi_isdn_linktab.tx_queue = &sc->sc_bchan[i].tx_queue;
259         sc->sc_bchan[i].capi_isdn_linktab.rx_queue = &sc->sc_bchan[i].rx_queue;
260         sc->sc_bchan[i].capi_isdn_linktab.rx_mbuf = &sc->sc_bchan[i].in_mbuf;
261     }
262
263     ctrl_desc[nctrl].tei = -1;
264
265     /* Up the controller index and store the softc */
266
267     sc->sc_unit = ncapi;
268     capi_sc[ncapi++] = sc;
269     sc->ctrl_unit = nctrl++;
270
271     printf("capi%d: card type %d attached\n", sc->sc_unit, sc->card_type);
272
273     return(0);
274 }
275
276 /*
277 //  n_mgmt_command
278 //      i4b L4 management command.
279 */
280
281 static void
282 n_mgmt_command(int unit, int op, void *arg)
283 {
284     capi_softc_t *sc = capi_sc[unit];
285
286     printf("capi%d: mgmt command %d\n", sc->sc_unit, op);
287
288     switch(op) {
289     case CMR_DOPEN:
290         sc->sc_enabled = TRUE;
291         break;
292
293     case CMR_DCLOSE:
294         sc->sc_enabled = FALSE;
295         break;
296
297     case CMR_SETTRACE:
298         break;
299
300     default:
301         break;
302     }
303 }
304
305 /*
306 //  n_connect_request
307 //      i4b L4 wants to connect. We assign a B channel to the call,
308 //      send a CAPI_CONNECT_REQ, and set the channel to B_CONNECT_CONF.
309 */
310
311 static void
312 n_connect_request(u_int cdid)
313 {
314     call_desc_t *cd = cd_by_cdid(cdid);
315     capi_softc_t *sc;
316     int bch;
317
318     if (!cd) {
319         printf("capi?: invalid cdid %d\n", cdid);
320         return;
321     }
322
323     sc = capi_sc[ctrl_desc[cd->controller].unit];
324     bch = cd->channelid;
325
326     crit_enter();
327
328     if ((bch < 0) || (bch >= sc->sc_nbch))
329         for (bch = 0; bch < sc->sc_nbch; bch++)
330             if (sc->sc_bchan[bch].state == B_FREE)
331                 break;
332
333     if (bch == sc->sc_nbch) {
334         crit_exit();
335         printf("capi%d: no free B channel\n", sc->sc_unit);
336         return;
337     }
338
339     cd->channelid = bch;
340
341     capi_connect_req(sc, cd);
342     crit_exit();
343 }
344
345 /*
346 //  n_connect_response
347 //      i4b L4 answers a call. We send a CONNECT_RESP with the proper
348 //      Reject code, and set the channel to B_CONNECT_B3_IND or B_FREE,
349 //      depending whether we answer or not.
350 */
351
352 static void
353 n_connect_response(u_int cdid, int response, int cause)
354 {
355     call_desc_t *cd = cd_by_cdid(cdid);
356     capi_softc_t *sc;
357     int bch;
358
359     if (!cd) {
360         printf("capi?: invalid cdid %d\n", cdid);
361         return;
362     }
363
364     sc = capi_sc[ctrl_desc[cd->controller].unit];
365     bch = cd->channelid;
366
367     T400_stop(cd);
368         
369     cd->response = response;
370     cd->cause_out = cause;
371
372     crit_enter();
373     capi_connect_resp(sc, cd);
374     crit_exit();
375 }
376
377 /*
378 //  n_disconnect_request
379 //      i4b L4 wants to disconnect. We send a DISCONNECT_REQ and
380 //      set the channel to B_DISCONNECT_CONF.
381 */
382
383 static void
384 n_disconnect_request(u_int cdid, int cause)
385 {
386     call_desc_t *cd = cd_by_cdid(cdid);
387     capi_softc_t *sc;
388     int bch;
389
390     if (!cd) {
391         printf("capi?: invalid cdid %d\n", cdid);
392         return;
393     }
394
395     sc = capi_sc[ctrl_desc[cd->controller].unit];
396     bch = cd->channelid;
397
398     cd->cause_out = cause;
399
400     crit_enter();
401     capi_disconnect_req(sc, cd);
402     crit_exit();
403 }
404
405 /*
406 //  n_alert_request
407 //      i4b L4 wants to alert an incoming call. We send ALERT_REQ.
408 */
409
410 static void
411 n_alert_request(u_int cdid)
412 {
413     call_desc_t *cd = cd_by_cdid(cdid);
414     capi_softc_t *sc;
415
416     if (!cd) {
417         printf("capi?: invalid cdid %d\n", cdid);
418         return;
419     }
420
421     sc = capi_sc[ctrl_desc[cd->controller].unit];
422
423     crit_enter();
424     capi_alert_req(sc, cd);
425     crit_exit();
426 }
427
428 /*
429 //  n_download
430 //      L4 -> firmware download
431 */
432
433 static int
434 n_download(int unit, int numprotos, struct isdn_dr_prot *protocols)
435 {
436     capi_softc_t *sc = capi_sc[unit];
437
438     if (sc->load) {
439         (*capi_sc[unit]->load)(sc, protocols[0].bytecount,
440                                protocols[0].microcode);
441     }
442
443     return(0);
444 }