1 /*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. 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 *---------------------------------------------------------------------------
26 *
27 * i4b_bchan.c - B channel handling L1 procedures
28 * ----------------------------------------------
29 *
30 * $Id: isic_bchan.c,v 1.13 2008/04/08 12:07:26 cegger Exp $
31 *
32 * last edit-date: [Fri Jan 5 11:36:11 2001]
33 *
34 *---------------------------------------------------------------------------*/
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: isic_bchan.c,v 1.13 2008/04/08 12:07:26 cegger Exp $");
38
39 #include <sys/param.h>
40 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
41 #include <sys/ioccom.h>
42 #else
43 #include <sys/ioctl.h>
44 #endif
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
47 #include <sys/mbuf.h>
48 #include <machine/stdarg.h>
49
50 #ifdef __FreeBSD__
51 #include <machine/clock.h>
52 #include <i386/isa/isa_device.h>
53 #else
54 #ifndef __bsdi__
55 #include <sys/bus.h>
56 #endif
57 #include <sys/device.h>
58 #endif
59
60 #include <sys/socket.h>
61 #include <net/if.h>
62
63 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
64 #include <sys/callout.h>
65 #endif
66
67 #include <netisdn/i4b_debug.h>
68 #include <netisdn/i4b_ioctl.h>
69 #include <netisdn/i4b_trace.h>
70
71 #include <netisdn/i4b_l2.h>
72 #include <netisdn/i4b_l1l2.h>
73 #include <netisdn/i4b_mbuf.h>
74 #include <netisdn/i4b_global.h>
75
76 #include <dev/ic/isic_l1.h>
77 #include <dev/ic/isac.h>
78 #include <dev/ic/hscx.h>
79
80 static void isic_bchannel_start(isdn_layer1token, int h_chan);
81 static void isic_bchannel_stat(isdn_layer1token, int h_chan, bchan_statistics_t *bsp);
82
83 void isic_set_link(void*, int channel, const struct isdn_l4_driver_functions *l4_driver, void *l4_driver_softc);
84 isdn_link_t *isic_ret_linktab(void*, int channel);
85
86 /*---------------------------------------------------------------------------*
87 * initialize one B channels rx/tx data structures and init/deinit HSCX
88 *---------------------------------------------------------------------------*/
89 void
90 isic_bchannel_setup(isdn_layer1token t, int h_chan, int bprot, int activate)
91 {
92 struct isic_softc *sc = (struct isic_softc*)t;
93 l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
94
95 int s = splnet();
96
97 if(activate == 0)
98 {
99 /* deactivation */
100 isic_hscx_init(sc, h_chan, activate);
101 }
102
103 NDBGL1(L1_BCHAN, "%s, channel=%d, %s",
104 device_xname(&sc->sc_dev), h_chan, activate ? "activate" : "deactivate");
105
106 /* general part */
107
108 chan->channel = h_chan; /* B channel */
109 chan->bprot = bprot; /* B channel protocol */
110 chan->state = HSCX_IDLE; /* B channel state */
111
112 /* receiver part */
113
114 i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */
115
116 chan->rx_queue.ifq_maxlen = IFQ_MAXLEN;
117
118 chan->rxcount = 0; /* reset rx counter */
119
120 i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */
121
122 chan->in_mbuf = NULL; /* reset mbuf ptr */
123 chan->in_cbptr = NULL; /* reset mbuf curr ptr */
124 chan->in_len = 0; /* reset mbuf data len */
125
126 /* transmitter part */
127
128 i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */
129
130 chan->tx_queue.ifq_maxlen = IFQ_MAXLEN;
131
132 chan->txcount = 0; /* reset tx counter */
133
134 i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */
135
136 chan->out_mbuf_head = NULL; /* reset head mbuf ptr */
137 chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */
138 chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */
139 chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */
140
141 if(activate != 0)
142 {
143 /* activation */
144 isic_hscx_init(sc, h_chan, activate);
145 }
146
147 splx(s);
148 }
149
150 /*---------------------------------------------------------------------------*
151 * start transmission on a b channel
152 *---------------------------------------------------------------------------*/
153 static void
154 isic_bchannel_start(isdn_layer1token t, int h_chan)
155 {
156 struct isic_softc *sc = (struct isic_softc*)t;
157
158 register l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
159 register int next_len;
160 register int len;
161
162 int s;
163 int activity = -1;
164 int cmd = 0;
165
166 s = splnet(); /* enter critical section */
167 if(chan->state & HSCX_TX_ACTIVE) /* already running ? */
168 {
169 splx(s);
170 return; /* yes, leave */
171 }
172
173 /* get next mbuf from queue */
174
175 IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
176
177 if(chan->out_mbuf_head == NULL) /* queue empty ? */
178 {
179 splx(s); /* leave critical section */
180 return; /* yes, exit */
181 }
182
183 /* init current mbuf values */
184
185 chan->out_mbuf_cur = chan->out_mbuf_head;
186 chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
187 chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
188
189 /* activity indicator for timeout handling */
190
191 if(chan->bprot == BPROT_NONE)
192 {
193 if(!(isdn_bchan_silence(chan->out_mbuf_cur->m_data,
194 chan->out_mbuf_cur->m_len)))
195 activity = ACT_TX;
196 }
197 else
198 {
199 activity = ACT_TX;
200 }
201
202 chan->state |= HSCX_TX_ACTIVE; /* we start transmitting */
203
204 if(sc->sc_trace & TRACE_B_TX) /* if trace, send mbuf to trace dev */
205 {
206 i4b_trace_hdr hdr;
207 hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
208 hdr.dir = FROM_TE;
209 hdr.count = ++sc->sc_trace_bcount;
210 isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr,
211 chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
212 }
213
214 len = 0; /* # of chars put into HSCX tx fifo this time */
215
216 /*
217 * fill the HSCX tx fifo with data from the current mbuf. if
218 * current mbuf holds less data than HSCX fifo length, try to
219 * get the next mbuf from (a possible) mbuf chain. if there is
220 * not enough data in a single mbuf or in a chain, then this
221 * is the last mbuf and we tell the HSCX that it has to send
222 * CRC and closing flag
223 */
224
225 while((len < sc->sc_bfifolen) && chan->out_mbuf_cur)
226 {
227 /*
228 * put as much data into the HSCX fifo as is
229 * available from the current mbuf
230 */
231
232 if((len + chan->out_mbuf_cur_len) >= sc->sc_bfifolen)
233 next_len = sc->sc_bfifolen - len;
234 else
235 next_len = chan->out_mbuf_cur_len;
236
237 #ifdef NOTDEF
238 printf("b:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ",
239 chan->out_mbuf_head,
240 chan->out_mbuf_cur,
241 chan->out_mbuf_cur_ptr,
242 chan->out_mbuf_cur_len,
243 len,
244 next_len);
245 #endif
246
247 /* wait for tx fifo write enabled */
248
249 isic_hscx_waitxfw(sc, h_chan);
250
251 /* write what we have from current mbuf to HSCX fifo */
252
253 HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, next_len);
254
255 len += next_len; /* update # of bytes written */
256 chan->txcount += next_len; /* statistics */
257 chan->out_mbuf_cur_ptr += next_len; /* data ptr */
258 chan->out_mbuf_cur_len -= next_len; /* data len */
259
260 /*
261 * in case the current mbuf (of a possible chain) data
262 * has been put into the fifo, check if there is a next
263 * mbuf in the chain. If there is one, get ptr to it
264 * and update the data ptr and the length
265 */
266
267 if((chan->out_mbuf_cur_len <= 0) &&
268 ((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL))
269 {
270 chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
271 chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
272
273 if(sc->sc_trace & TRACE_B_TX)
274 {
275 i4b_trace_hdr hdr;
276 hdr.type = (h_chan == HSCX_CH_A ?
277 TRC_CH_B1 : TRC_CH_B2);
278 hdr.dir = FROM_TE;
279 hdr.count = ++sc->sc_trace_bcount;
280 isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token,
281 &hdr,
282 chan->out_mbuf_cur->m_len,
283 chan->out_mbuf_cur->m_data);
284 }
285 }
286 }
287
288 /*
289 * if there is either still data in the current mbuf and/or
290 * there is a successor on the chain available issue just
291 * a XTF (transmit) command to HSCX. if ther is no more
292 * data available from the current mbuf (-chain), issue
293 * an XTF and an XME (message end) command which will then
294 * send the CRC and the closing HDLC flag sequence
295 */
296
297 if(chan->out_mbuf_cur && (chan->out_mbuf_cur_len > 0))
298 {
299 /*
300 * more data available, send current fifo out.
301 * next xfer to HSCX tx fifo is done in the
302 * HSCX interrupt routine.
303 */
304
305 cmd |= HSCX_CMDR_XTF;
306 }
307 else
308 {
309 /* end of mbuf chain */
310
311 if(chan->bprot == BPROT_NONE)
312 cmd |= HSCX_CMDR_XTF;
313 else
314 cmd |= HSCX_CMDR_XTF | HSCX_CMDR_XME;
315
316 i4b_Bfreembuf(chan->out_mbuf_head); /* free mbuf chain */
317
318 chan->out_mbuf_head = NULL;
319 chan->out_mbuf_cur = NULL;
320 chan->out_mbuf_cur_ptr = NULL;
321 chan->out_mbuf_cur_len = 0;
322 }
323
324 /* call timeout handling routine */
325
326 if(activity == ACT_RX || activity == ACT_TX)
327 (*chan->l4_driver->bch_activity)(
328 chan->l4_driver_softc, activity);
329
330 if(cmd)
331 isic_hscx_cmd(sc, h_chan, cmd);
332
333 splx(s);
334 }
335
336 /*---------------------------------------------------------------------------*
337 * fill statistics struct
338 *---------------------------------------------------------------------------*/
339 static void
340 isic_bchannel_stat(isdn_layer1token t, int h_chan, bchan_statistics_t *bsp)
341 {
342 struct isic_softc *sc = (struct isic_softc*)t;
343 l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
344 int s;
345
346 s = splnet();
347
348 bsp->outbytes = chan->txcount;
349 bsp->inbytes = chan->rxcount;
350
351 chan->txcount = 0;
352 chan->rxcount = 0;
353
354 splx(s);
355 }
356
357 /*---------------------------------------------------------------------------*
358 * return the address of isic drivers linktab
359 *---------------------------------------------------------------------------*/
360 isdn_link_t *
361 isic_ret_linktab(void *token, int channel)
362 {
363 struct l2_softc *l2sc = token;
364 struct isic_softc *sc = l2sc->l1_token;
365 l1_bchan_state_t *chan = &sc->sc_chan[channel];
366
367 return(&chan->isdn_linktab);
368 }
369
370 /*---------------------------------------------------------------------------*
371 * set the driver linktab in the b channel softc
372 *---------------------------------------------------------------------------*/
373 void
374 isic_set_link(void *token, int channel, const struct isdn_l4_driver_functions *l4_driver, void *l4_driver_softc)
375 {
376 struct l2_softc *l2sc = token;
377 struct isic_softc *sc = l2sc->l1_token;
378 l1_bchan_state_t *chan = &sc->sc_chan[channel];
379
380 chan->l4_driver = l4_driver;
381 chan->l4_driver_softc = l4_driver_softc;
382 }
383
384 static const struct isdn_l4_bchannel_functions
385 isic_l4_bchannel_functions = {
386 isic_bchannel_setup,
387 isic_bchannel_start,
388 isic_bchannel_stat
389 };
390
391 /*---------------------------------------------------------------------------*
392 * initialize our local linktab
393 *---------------------------------------------------------------------------*/
394 void
395 isic_init_linktab(struct isic_softc *sc)
396 {
397 l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A];
398 isdn_link_t *lt = &chan->isdn_linktab;
399
400 /* local setup */
401 lt->l1token = sc;
402 lt->channel = HSCX_CH_A;
403 lt->bchannel_driver = &isic_l4_bchannel_functions;
404 lt->tx_queue = &chan->tx_queue;
405
406 /* used by non-HDLC data transfers, i.e. telephony drivers */
407 lt->rx_queue = &chan->rx_queue;
408
409 /* used by HDLC data transfers, i.e. ipr and isp drivers */
410 lt->rx_mbuf = &chan->in_mbuf;
411
412 chan = &sc->sc_chan[HSCX_CH_B];
413 lt = &chan->isdn_linktab;
414
415 lt->l1token = sc;
416 lt->channel = HSCX_CH_B;
417 lt->bchannel_driver = &isic_l4_bchannel_functions;
418 lt->tx_queue = &chan->tx_queue;
419
420 /* used by non-HDLC data transfers, i.e. telephony drivers */
421 lt->rx_queue = &chan->rx_queue;
422
423 /* used by HDLC data transfers, i.e. ipr and isp drivers */
424 lt->rx_mbuf = &chan->in_mbuf;
425 }
Cache object: f1f9d63efeb142a21933ae5748bc8cdd
|