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