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