2 * Copyright (c) 1997, 2000 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 * $Id: isic_bchan.c,v 1.13 2008/04/08 12:07:26 cegger Exp $
32 * last edit-date: [Fri Jan 5 11:36:11 2001]
34 *---------------------------------------------------------------------------*/
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: isic_bchan.c,v 1.12 2007/10/19 11:59:54 ad Exp $");
39 #include <sys/param.h>
40 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
41 #include <sys/ioccom.h>
43 #include <sys/ioctl.h>
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
48 #include <machine/stdarg.h>
51 #include <machine/clock.h>
52 #include <i386/isa/isa_device.h>
57 #include <sys/device.h>
60 #include <sys/socket.h>
63 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
64 #include <sys/callout.h>
67 #include <netisdn/i4b_debug.h>
68 #include <netisdn/i4b_ioctl.h>
69 #include <netisdn/i4b_trace.h>
71 #include <netisdn/i4b_l2.h>
72 #include <netisdn/i4b_l1l2.h>
73 #include <netisdn/i4b_mbuf.h>
74 #include <netisdn/i4b_global.h>
76 #include <dev/ic/isic_l1.h>
77 #include <dev/ic/isac.h>
78 #include <dev/ic/hscx.h>
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
);
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
);
86 /*---------------------------------------------------------------------------*
87 * initialize one B channels rx/tx data structures and init/deinit HSCX
88 *---------------------------------------------------------------------------*/
90 isic_bchannel_setup(isdn_layer1token t
, int h_chan
, int bprot
, int activate
)
92 struct isic_softc
*sc
= (struct isic_softc
*)t
;
93 l1_bchan_state_t
*chan
= &sc
->sc_chan
[h_chan
];
100 isic_hscx_init(sc
, h_chan
, activate
);
103 NDBGL1(L1_BCHAN
, "%s, channel=%d, %s",
104 device_xname(&sc
->sc_dev
), h_chan
, activate
? "activate" : "deactivate");
108 chan
->channel
= h_chan
; /* B channel */
109 chan
->bprot
= bprot
; /* B channel protocol */
110 chan
->state
= HSCX_IDLE
; /* B channel state */
114 i4b_Bcleanifq(&chan
->rx_queue
); /* clean rx queue */
116 chan
->rx_queue
.ifq_maxlen
= IFQ_MAXLEN
;
118 chan
->rxcount
= 0; /* reset rx counter */
120 i4b_Bfreembuf(chan
->in_mbuf
); /* clean rx mbuf */
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 */
126 /* transmitter part */
128 i4b_Bcleanifq(&chan
->tx_queue
); /* clean tx queue */
130 chan
->tx_queue
.ifq_maxlen
= IFQ_MAXLEN
;
132 chan
->txcount
= 0; /* reset tx counter */
134 i4b_Bfreembuf(chan
->out_mbuf_head
); /* clean tx mbuf */
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 */
144 isic_hscx_init(sc
, h_chan
, activate
);
150 /*---------------------------------------------------------------------------*
151 * start transmission on a b channel
152 *---------------------------------------------------------------------------*/
154 isic_bchannel_start(isdn_layer1token t
, int h_chan
)
156 struct isic_softc
*sc
= (struct isic_softc
*)t
;
158 register l1_bchan_state_t
*chan
= &sc
->sc_chan
[h_chan
];
159 register int next_len
;
166 s
= splnet(); /* enter critical section */
167 if(chan
->state
& HSCX_TX_ACTIVE
) /* already running ? */
170 return; /* yes, leave */
173 /* get next mbuf from queue */
175 IF_DEQUEUE(&chan
->tx_queue
, chan
->out_mbuf_head
);
177 if(chan
->out_mbuf_head
== NULL
) /* queue empty ? */
179 splx(s
); /* leave critical section */
180 return; /* yes, exit */
183 /* init current mbuf values */
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
;
189 /* activity indicator for timeout handling */
191 if(chan
->bprot
== BPROT_NONE
)
193 if(!(isdn_bchan_silence(chan
->out_mbuf_cur
->m_data
,
194 chan
->out_mbuf_cur
->m_len
)))
202 chan
->state
|= HSCX_TX_ACTIVE
; /* we start transmitting */
204 if(sc
->sc_trace
& TRACE_B_TX
) /* if trace, send mbuf to trace dev */
207 hdr
.type
= (h_chan
== HSCX_CH_A
? TRC_CH_B1
: TRC_CH_B2
);
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
);
214 len
= 0; /* # of chars put into HSCX tx fifo this time */
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
225 while((len
< sc
->sc_bfifolen
) && chan
->out_mbuf_cur
)
228 * put as much data into the HSCX fifo as is
229 * available from the current mbuf
232 if((len
+ chan
->out_mbuf_cur_len
) >= sc
->sc_bfifolen
)
233 next_len
= sc
->sc_bfifolen
- len
;
235 next_len
= chan
->out_mbuf_cur_len
;
238 printf("b:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ",
241 chan
->out_mbuf_cur_ptr
,
242 chan
->out_mbuf_cur_len
,
247 /* wait for tx fifo write enabled */
249 isic_hscx_waitxfw(sc
, h_chan
);
251 /* write what we have from current mbuf to HSCX fifo */
253 HSCX_WRFIFO(h_chan
, chan
->out_mbuf_cur_ptr
, next_len
);
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 */
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
267 if((chan
->out_mbuf_cur_len
<= 0) &&
268 ((chan
->out_mbuf_cur
= chan
->out_mbuf_cur
->m_next
) != NULL
))
270 chan
->out_mbuf_cur_ptr
= chan
->out_mbuf_cur
->m_data
;
271 chan
->out_mbuf_cur_len
= chan
->out_mbuf_cur
->m_len
;
273 if(sc
->sc_trace
& TRACE_B_TX
)
276 hdr
.type
= (h_chan
== HSCX_CH_A
?
277 TRC_CH_B1
: TRC_CH_B2
);
279 hdr
.count
= ++sc
->sc_trace_bcount
;
280 isdn_layer2_trace_ind(&sc
->sc_l2
, sc
->sc_l3token
,
282 chan
->out_mbuf_cur
->m_len
,
283 chan
->out_mbuf_cur
->m_data
);
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
297 if(chan
->out_mbuf_cur
&& (chan
->out_mbuf_cur_len
> 0))
300 * more data available, send current fifo out.
301 * next xfer to HSCX tx fifo is done in the
302 * HSCX interrupt routine.
305 cmd
|= HSCX_CMDR_XTF
;
309 /* end of mbuf chain */
311 if(chan
->bprot
== BPROT_NONE
)
312 cmd
|= HSCX_CMDR_XTF
;
314 cmd
|= HSCX_CMDR_XTF
| HSCX_CMDR_XME
;
316 i4b_Bfreembuf(chan
->out_mbuf_head
); /* free mbuf chain */
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;
324 /* call timeout handling routine */
326 if(activity
== ACT_RX
|| activity
== ACT_TX
)
327 (*chan
->l4_driver
->bch_activity
)(
328 chan
->l4_driver_softc
, activity
);
331 isic_hscx_cmd(sc
, h_chan
, cmd
);
336 /*---------------------------------------------------------------------------*
337 * fill statistics struct
338 *---------------------------------------------------------------------------*/
340 isic_bchannel_stat(isdn_layer1token t
, int h_chan
, bchan_statistics_t
*bsp
)
342 struct isic_softc
*sc
= (struct isic_softc
*)t
;
343 l1_bchan_state_t
*chan
= &sc
->sc_chan
[h_chan
];
348 bsp
->outbytes
= chan
->txcount
;
349 bsp
->inbytes
= chan
->rxcount
;
357 /*---------------------------------------------------------------------------*
358 * return the address of isic drivers linktab
359 *---------------------------------------------------------------------------*/
361 isic_ret_linktab(void *token
, int channel
)
363 struct l2_softc
*l2sc
= token
;
364 struct isic_softc
*sc
= l2sc
->l1_token
;
365 l1_bchan_state_t
*chan
= &sc
->sc_chan
[channel
];
367 return(&chan
->isdn_linktab
);
370 /*---------------------------------------------------------------------------*
371 * set the driver linktab in the b channel softc
372 *---------------------------------------------------------------------------*/
374 isic_set_link(void *token
, int channel
, const struct isdn_l4_driver_functions
*l4_driver
, void *l4_driver_softc
)
376 struct l2_softc
*l2sc
= token
;
377 struct isic_softc
*sc
= l2sc
->l1_token
;
378 l1_bchan_state_t
*chan
= &sc
->sc_chan
[channel
];
380 chan
->l4_driver
= l4_driver
;
381 chan
->l4_driver_softc
= l4_driver_softc
;
384 static const struct isdn_l4_bchannel_functions
385 isic_l4_bchannel_functions
= {
391 /*---------------------------------------------------------------------------*
392 * initialize our local linktab
393 *---------------------------------------------------------------------------*/
395 isic_init_linktab(struct isic_softc
*sc
)
397 l1_bchan_state_t
*chan
= &sc
->sc_chan
[HSCX_CH_A
];
398 isdn_link_t
*lt
= &chan
->isdn_linktab
;
402 lt
->channel
= HSCX_CH_A
;
403 lt
->bchannel_driver
= &isic_l4_bchannel_functions
;
404 lt
->tx_queue
= &chan
->tx_queue
;
406 /* used by non-HDLC data transfers, i.e. telephony drivers */
407 lt
->rx_queue
= &chan
->rx_queue
;
409 /* used by HDLC data transfers, i.e. ipr and isp drivers */
410 lt
->rx_mbuf
= &chan
->in_mbuf
;
412 chan
= &sc
->sc_chan
[HSCX_CH_B
];
413 lt
= &chan
->isdn_linktab
;
416 lt
->channel
= HSCX_CH_B
;
417 lt
->bchannel_driver
= &isic_l4_bchannel_functions
;
418 lt
->tx_queue
= &chan
->tx_queue
;
420 /* used by non-HDLC data transfers, i.e. telephony drivers */
421 lt
->rx_queue
= &chan
->rx_queue
;
423 /* used by HDLC data transfers, i.e. ipr and isp drivers */
424 lt
->rx_mbuf
= &chan
->in_mbuf
;