2 * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
25 *---------------------------------------------------------------------------
27 * i4b_bchan.c - B channel handling L1 procedures
28 * ----------------------------------------------
30 * $FreeBSD: src/sys/i4b/layer1/isic/i4b_bchan.c,v 1.7.2.1 2001/08/10 14:08:38 obrien Exp $
31 * $DragonFly: src/sys/net/i4b/layer1/isic/i4b_bchan.c,v 1.3 2003/07/26 19:20:31 rob Exp $
33 * last edit-date: [Wed Jan 24 09:07:12 2001]
35 *---------------------------------------------------------------------------*/
41 #include <sys/param.h>
42 #include <sys/systm.h>
44 #include <sys/socket.h>
47 #include <machine/i4b_debug.h>
48 #include <machine/i4b_ioctl.h>
49 #include <machine/i4b_trace.h>
51 #include <i4b/layer1/i4b_l1.h>
53 #include <i4b/layer1/isic/i4b_isic.h>
54 #include <i4b/layer1/isic/i4b_hscx.h>
56 #include <i4b/include/i4b_mbuf.h>
57 #include <i4b/include/i4b_global.h>
59 static void isic_bchannel_start(int unit, int h_chan);
60 static void isic_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp);
62 /*---------------------------------------------------------------------------*
63 * initialize one B channels rx/tx data structures and init/deinit HSCX
64 *---------------------------------------------------------------------------*/
66 isic_bchannel_setup(int unit, int h_chan, int bprot, int activate)
68 struct l1_softc *sc = &l1_sc[unit];
69 l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
76 isic_hscx_init(sc, h_chan, activate);
79 NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s",
80 sc->sc_unit, h_chan, activate ? "activate" : "deactivate");
84 chan->unit = sc->sc_unit; /* unit number */
85 chan->channel = h_chan; /* B channel */
86 chan->bprot = bprot; /* B channel protocol */
87 chan->state = HSCX_IDLE; /* B channel state */
91 chan->rx_queue.ifq_maxlen = IFQ_MAXLEN;
93 #if defined (__FreeBSD__) && __FreeBSD__ > 4
94 mtx_init(&chan->rx_queue.ifq_mtx, "i4b_isic_rx", MTX_DEF);
97 i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */
99 chan->rxcount = 0; /* reset rx counter */
101 i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */
103 chan->in_mbuf = NULL; /* reset mbuf ptr */
104 chan->in_cbptr = NULL; /* reset mbuf curr ptr */
105 chan->in_len = 0; /* reset mbuf data len */
107 /* transmitter part */
109 chan->tx_queue.ifq_maxlen = IFQ_MAXLEN;
111 #if defined (__FreeBSD__) && __FreeBSD__ > 4
112 mtx_init(&chan->tx_queue.ifq_mtx, "i4b_isic_tx", MTX_DEF);
115 i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */
117 chan->txcount = 0; /* reset tx counter */
119 i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */
121 chan->out_mbuf_head = NULL; /* reset head mbuf ptr */
122 chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */
123 chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */
124 chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */
129 isic_hscx_init(sc, h_chan, activate);
135 /*---------------------------------------------------------------------------*
136 * start transmission on a b channel
137 *---------------------------------------------------------------------------*/
139 isic_bchannel_start(int unit, int h_chan)
141 struct l1_softc *sc = &l1_sc[unit];
142 l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
150 s = SPLI4B(); /* enter critical section */
151 if(chan->state & HSCX_TX_ACTIVE) /* already running ? */
154 return; /* yes, leave */
157 /* get next mbuf from queue */
159 IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
161 if(chan->out_mbuf_head == NULL) /* queue empty ? */
163 splx(s); /* leave critical section */
164 return; /* yes, exit */
167 /* init current mbuf values */
169 chan->out_mbuf_cur = chan->out_mbuf_head;
170 chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
171 chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
173 /* activity indicator for timeout handling */
175 if(chan->bprot == BPROT_NONE)
177 if(!(i4b_l1_bchan_tel_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
185 chan->state |= HSCX_TX_ACTIVE; /* we start transmitting */
187 if(sc->sc_trace & TRACE_B_TX) /* if trace, send mbuf to trace dev */
190 hdr.unit = L0ISICUNIT(unit);
191 hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
193 hdr.count = ++sc->sc_trace_bcount;
195 i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
198 len = 0; /* # of chars put into HSCX tx fifo this time */
201 * fill the HSCX tx fifo with data from the current mbuf. if
202 * current mbuf holds less data than HSCX fifo length, try to
203 * get the next mbuf from (a possible) mbuf chain. if there is
204 * not enough data in a single mbuf or in a chain, then this
205 * is the last mbuf and we tell the HSCX that it has to send
206 * CRC and closing flag
209 while((len < sc->sc_bfifolen) && chan->out_mbuf_cur)
212 * put as much data into the HSCX fifo as is
213 * available from the current mbuf
216 if((len + chan->out_mbuf_cur_len) >= sc->sc_bfifolen)
217 next_len = sc->sc_bfifolen - len;
219 next_len = chan->out_mbuf_cur_len;
222 printf("b:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ",
225 chan->out_mbuf_cur_ptr,
226 chan->out_mbuf_cur_len,
231 /* wait for tx fifo write enabled */
233 isic_hscx_waitxfw(sc, h_chan);
235 /* write what we have from current mbuf to HSCX fifo */
237 HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, next_len);
239 len += next_len; /* update # of bytes written */
240 chan->txcount += next_len; /* statistics */
241 chan->out_mbuf_cur_ptr += next_len; /* data ptr */
242 chan->out_mbuf_cur_len -= next_len; /* data len */
245 * in case the current mbuf (of a possible chain) data
246 * has been put into the fifo, check if there is a next
247 * mbuf in the chain. If there is one, get ptr to it
248 * and update the data ptr and the length
251 if((chan->out_mbuf_cur_len <= 0) &&
252 ((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL))
254 chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
255 chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
257 if(sc->sc_trace & TRACE_B_TX)
260 hdr.unit = L0ISICUNIT(unit);
261 hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
263 hdr.count = ++sc->sc_trace_bcount;
265 i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
271 * if there is either still data in the current mbuf and/or
272 * there is a successor on the chain available issue just
273 * a XTF (transmit) command to HSCX. if ther is no more
274 * data available from the current mbuf (-chain), issue
275 * an XTF and an XME (message end) command which will then
276 * send the CRC and the closing HDLC flag sequence
279 if(chan->out_mbuf_cur && (chan->out_mbuf_cur_len > 0))
282 * more data available, send current fifo out.
283 * next xfer to HSCX tx fifo is done in the
284 * HSCX interrupt routine.
287 cmd |= HSCX_CMDR_XTF;
291 /* end of mbuf chain */
293 if(chan->bprot == BPROT_NONE)
294 cmd |= HSCX_CMDR_XTF;
296 cmd |= HSCX_CMDR_XTF | HSCX_CMDR_XME;
298 i4b_Bfreembuf(chan->out_mbuf_head); /* free mbuf chain */
300 chan->out_mbuf_head = NULL;
301 chan->out_mbuf_cur = NULL;
302 chan->out_mbuf_cur_ptr = NULL;
303 chan->out_mbuf_cur_len = 0;
306 /* call timeout handling routine */
308 if(activity == ACT_RX || activity == ACT_TX)
309 (*chan->isic_drvr_linktab->bch_activity)(chan->isic_drvr_linktab->unit, activity);
312 isic_hscx_cmd(sc, h_chan, cmd);
317 /*---------------------------------------------------------------------------*
318 * fill statistics struct
319 *---------------------------------------------------------------------------*/
321 isic_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp)
323 struct l1_softc *sc = &l1_sc[unit];
324 l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
329 bsp->outbytes = chan->txcount;
330 bsp->inbytes = chan->rxcount;
338 /*---------------------------------------------------------------------------*
339 * return the address of isic drivers linktab
340 *---------------------------------------------------------------------------*/
342 isic_ret_linktab(int unit, int channel)
344 struct l1_softc *sc = &l1_sc[unit];
345 l1_bchan_state_t *chan = &sc->sc_chan[channel];
347 return(&chan->isic_isdn_linktab);
350 /*---------------------------------------------------------------------------*
351 * set the driver linktab in the b channel softc
352 *---------------------------------------------------------------------------*/
354 isic_set_linktab(int unit, int channel, drvr_link_t *dlt)
356 struct l1_softc *sc = &l1_sc[unit];
357 l1_bchan_state_t *chan = &sc->sc_chan[channel];
359 chan->isic_drvr_linktab = dlt;
362 /*---------------------------------------------------------------------------*
363 * initialize our local linktab
364 *---------------------------------------------------------------------------*/
366 isic_init_linktab(struct l1_softc *sc)
368 l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A];
369 isdn_link_t *lt = &chan->isic_isdn_linktab;
371 /* make sure the hardware driver is known to layer 4 */
372 ctrl_types[CTRL_PASSIVE].set_linktab = i4b_l1_set_linktab;
373 ctrl_types[CTRL_PASSIVE].get_linktab = i4b_l1_ret_linktab;
376 lt->unit = sc->sc_unit;
377 lt->channel = HSCX_CH_A;
378 lt->bch_config = isic_bchannel_setup;
379 lt->bch_tx_start = isic_bchannel_start;
380 lt->bch_stat = isic_bchannel_stat;
381 lt->tx_queue = &chan->tx_queue;
383 /* used by non-HDLC data transfers, i.e. telephony drivers */
384 lt->rx_queue = &chan->rx_queue;
386 /* used by HDLC data transfers, i.e. ipr and isp drivers */
387 lt->rx_mbuf = &chan->in_mbuf;
389 chan = &sc->sc_chan[HSCX_CH_B];
390 lt = &chan->isic_isdn_linktab;
392 lt->unit = sc->sc_unit;
393 lt->channel = HSCX_CH_B;
394 lt->bch_config = isic_bchannel_setup;
395 lt->bch_tx_start = isic_bchannel_start;
396 lt->bch_stat = isic_bchannel_stat;
397 lt->tx_queue = &chan->tx_queue;
399 /* used by non-HDLC data transfers, i.e. telephony drivers */
400 lt->rx_queue = &chan->rx_queue;
402 /* used by HDLC data transfers, i.e. ipr and isp drivers */
403 lt->rx_mbuf = &chan->in_mbuf;
406 #endif /* NISIC > 0 */