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