kernel tree reorganization stage 1: Major cvs repository work (not logged as
[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.4 2003/08/07 21:17:26 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 <net/if.h>
46
47 #include <net/i4b/include/machine/i4b_debug.h>
48 #include <net/i4b/include/machine/i4b_ioctl.h>
49 #include <net/i4b/include/machine/i4b_trace.h>
50
51 #include "../i4b_l1.h"
52
53 #include "i4b_isic.h"
54 #include "i4b_hscx.h"
55
56 #include "../../include/i4b_mbuf.h"
57 #include "../../include/i4b_global.h"
58
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);
61
62 /*---------------------------------------------------------------------------*
63  *      initialize one B channels rx/tx data structures and init/deinit HSCX
64  *---------------------------------------------------------------------------*/
65 void
66 isic_bchannel_setup(int unit, int h_chan, int bprot, int activate)
67 {
68         struct l1_softc *sc = &l1_sc[unit];
69         l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
70
71         int s = SPLI4B();
72         
73         if(activate == 0)
74         {
75                 /* deactivation */
76                 isic_hscx_init(sc, h_chan, activate);
77         }
78                 
79         NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s",
80                 sc->sc_unit, h_chan, activate ? "activate" : "deactivate");
81
82         /* general part */
83
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 */
88
89         /* receiver part */
90
91         chan->rx_queue.ifq_maxlen = IFQ_MAXLEN;
92
93 #if defined (__FreeBSD__) && __FreeBSD__ > 4    
94         mtx_init(&chan->rx_queue.ifq_mtx, "i4b_isic_rx", MTX_DEF);
95 #endif
96
97         i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */
98
99         chan->rxcount = 0;              /* reset rx counter */
100         
101         i4b_Bfreembuf(chan->in_mbuf);   /* clean rx mbuf */
102
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 */
106         
107         /* transmitter part */
108
109         chan->tx_queue.ifq_maxlen = IFQ_MAXLEN;
110
111 #if defined (__FreeBSD__) && __FreeBSD__ > 4    
112         mtx_init(&chan->tx_queue.ifq_mtx, "i4b_isic_tx", MTX_DEF);
113 #endif
114         
115         i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */
116
117         chan->txcount = 0;              /* reset tx counter */
118         
119         i4b_Bfreembuf(chan->out_mbuf_head);     /* clean tx mbuf */
120
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 */
125         
126         if(activate != 0)
127         {
128                 /* activation */
129                 isic_hscx_init(sc, h_chan, activate);
130         }
131
132         splx(s);
133 }
134
135 /*---------------------------------------------------------------------------*
136  *      start transmission on a b channel
137  *---------------------------------------------------------------------------*/
138 static void
139 isic_bchannel_start(int unit, int h_chan)
140 {
141         struct l1_softc *sc = &l1_sc[unit];
142         l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
143         int next_len;
144         int len;
145
146         int s;
147         int activity = -1;
148         int cmd = 0;
149
150         s = SPLI4B();                           /* enter critical section */
151         if(chan->state & HSCX_TX_ACTIVE)        /* already running ? */
152         {
153                 splx(s);
154                 return;                         /* yes, leave */
155         }
156
157         /* get next mbuf from queue */
158         
159         IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
160         
161         if(chan->out_mbuf_head == NULL)         /* queue empty ? */
162         {
163                 splx(s);                        /* leave critical section */
164                 return;                         /* yes, exit */
165         }
166
167         /* init current mbuf values */
168         
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;    
172         
173         /* activity indicator for timeout handling */
174
175         if(chan->bprot == BPROT_NONE)
176         {
177                 if(!(i4b_l1_bchan_tel_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
178                         activity = ACT_TX;
179         }
180         else
181         {
182                 activity = ACT_TX;
183         }
184
185         chan->state |= HSCX_TX_ACTIVE;          /* we start transmitting */
186         
187         if(sc->sc_trace & TRACE_B_TX)   /* if trace, send mbuf to trace dev */
188         {
189                 i4b_trace_hdr_t hdr;
190                 hdr.unit = L0ISICUNIT(unit);
191                 hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
192                 hdr.dir = FROM_TE;
193                 hdr.count = ++sc->sc_trace_bcount;
194                 MICROTIME(hdr.time);
195                 i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
196         }                       
197
198         len = 0;        /* # of chars put into HSCX tx fifo this time */
199
200         /*
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
207          */
208          
209         while((len < sc->sc_bfifolen) && chan->out_mbuf_cur)
210         {
211                 /*
212                  * put as much data into the HSCX fifo as is
213                  * available from the current mbuf
214                  */
215                  
216                 if((len + chan->out_mbuf_cur_len) >= sc->sc_bfifolen)
217                         next_len = sc->sc_bfifolen - len;
218                 else
219                         next_len = chan->out_mbuf_cur_len;
220
221 #ifdef NOTDEF           
222                 printf("b:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ",
223                         chan->out_mbuf_head,
224                         chan->out_mbuf_cur,                     
225                         chan->out_mbuf_cur_ptr,
226                         chan->out_mbuf_cur_len,
227                         len,
228                         next_len);
229 #endif
230
231                 /* wait for tx fifo write enabled */
232
233                 isic_hscx_waitxfw(sc, h_chan);
234
235                 /* write what we have from current mbuf to HSCX fifo */
236
237                 HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, next_len);
238
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 */
243
244                 /*
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
249                  */
250                  
251                 if((chan->out_mbuf_cur_len <= 0)        &&
252                   ((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL))
253                 {
254                         chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
255                         chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
256
257                         if(sc->sc_trace & TRACE_B_TX)
258                         {
259                                 i4b_trace_hdr_t hdr;
260                                 hdr.unit = L0ISICUNIT(unit);
261                                 hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
262                                 hdr.dir = FROM_TE;
263                                 hdr.count = ++sc->sc_trace_bcount;
264                                 MICROTIME(hdr.time);
265                                 i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
266                         }                       
267                 }
268         }
269
270         /*
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
277          */
278          
279         if(chan->out_mbuf_cur && (chan->out_mbuf_cur_len > 0))
280         {
281                 /*
282                  * more data available, send current fifo out.
283                  * next xfer to HSCX tx fifo is done in the
284                  * HSCX interrupt routine.
285                  */
286                  
287                 cmd |= HSCX_CMDR_XTF;
288         }
289         else
290         {
291                 /* end of mbuf chain */
292         
293                 if(chan->bprot == BPROT_NONE)
294                         cmd |= HSCX_CMDR_XTF;
295                 else
296                         cmd |= HSCX_CMDR_XTF | HSCX_CMDR_XME;
297                 
298                 i4b_Bfreembuf(chan->out_mbuf_head);     /* free mbuf chain */
299                 
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;
304         }
305
306         /* call timeout handling routine */
307         
308         if(activity == ACT_RX || activity == ACT_TX)
309                 (*chan->isic_drvr_linktab->bch_activity)(chan->isic_drvr_linktab->unit, activity);
310
311         if(cmd)
312                 isic_hscx_cmd(sc, h_chan, cmd);
313                 
314         splx(s);        
315 }
316
317 /*---------------------------------------------------------------------------*
318  *      fill statistics struct
319  *---------------------------------------------------------------------------*/
320 static void
321 isic_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp)
322 {
323         struct l1_softc *sc = &l1_sc[unit];
324         l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
325         int s;
326
327         s = SPLI4B();
328         
329         bsp->outbytes = chan->txcount;
330         bsp->inbytes = chan->rxcount;
331
332         chan->txcount = 0;
333         chan->rxcount = 0;
334
335         splx(s);
336 }
337
338 /*---------------------------------------------------------------------------*
339  *      return the address of isic drivers linktab      
340  *---------------------------------------------------------------------------*/
341 isdn_link_t *
342 isic_ret_linktab(int unit, int channel)
343 {
344         struct l1_softc *sc = &l1_sc[unit];
345         l1_bchan_state_t *chan = &sc->sc_chan[channel];
346
347         return(&chan->isic_isdn_linktab);
348 }
349  
350 /*---------------------------------------------------------------------------*
351  *      set the driver linktab in the b channel softc
352  *---------------------------------------------------------------------------*/
353 void
354 isic_set_linktab(int unit, int channel, drvr_link_t *dlt)
355 {
356         struct l1_softc *sc = &l1_sc[unit];
357         l1_bchan_state_t *chan = &sc->sc_chan[channel];
358
359         chan->isic_drvr_linktab = dlt;
360 }
361
362 /*---------------------------------------------------------------------------*
363  *      initialize our local linktab
364  *---------------------------------------------------------------------------*/
365 void
366 isic_init_linktab(struct l1_softc *sc)
367 {
368         l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A];
369         isdn_link_t *lt = &chan->isic_isdn_linktab;
370
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;
374
375         /* local setup */
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;
382
383         /* used by non-HDLC data transfers, i.e. telephony drivers */
384         lt->rx_queue = &chan->rx_queue;
385
386         /* used by HDLC data transfers, i.e. ipr and isp drivers */     
387         lt->rx_mbuf = &chan->in_mbuf;   
388                                                 
389         chan = &sc->sc_chan[HSCX_CH_B];
390         lt = &chan->isic_isdn_linktab;
391
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;
398
399         /* used by non-HDLC data transfers, i.e. telephony drivers */
400         lt->rx_queue = &chan->rx_queue;
401
402         /* used by HDLC data transfers, i.e. ipr and isp drivers */     
403         lt->rx_mbuf = &chan->in_mbuf;   
404 }
405  
406 #endif /* NISIC > 0 */