Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / net / i4b / layer1 / iwic / i4b_iwic_bchan.c
1 /*
2  * Copyright (c) 1999, 2000 Dave Boyce. All rights reserved.
3  *
4  * Copyright (c) 2000, 2001 Hellmuth Michaelis. All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *---------------------------------------------------------------------------
28  *
29  *      i4b_iwic - isdn4bsd Winbond W6692 driver
30  *      ----------------------------------------
31  *
32  * $FreeBSD: src/sys/i4b/layer1/iwic/i4b_iwic_bchan.c,v 1.7.2.1 2001/08/10 14:08:40 obrien Exp $
33  * $DragonFly: src/sys/net/i4b/layer1/iwic/i4b_iwic_bchan.c,v 1.2 2003/06/17 04:28:40 dillon Exp $
34  *
35  *      last edit-date: [Tue Jan 16 13:21:24 2001]
36  *
37  *---------------------------------------------------------------------------*/
38
39 #include "iwic.h"
40 #include "opt_i4b.h"
41 #include "pci.h"
42
43 #if (NIWIC > 0) && (NPCI > 0)
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/mbuf.h>
48 #include <sys/socket.h>
49
50 #include <net/if.h>
51
52
53 #include <machine/i4b_debug.h>
54 #include <machine/i4b_ioctl.h>
55 #include <machine/i4b_trace.h>
56
57 #include <i4b/layer1/i4b_l1.h>
58
59 #include <i4b/layer1/iwic/i4b_iwic.h>
60 #include <i4b/layer1/iwic/i4b_w6692.h>
61
62 #include <i4b/include/i4b_global.h>
63 #include <i4b/include/i4b_mbuf.h>
64
65 static void iwic_bchan_init(struct iwic_softc *sc, int chan_no, int activate);
66
67 /*---------------------------------------------------------------------------*
68  *      B-channel interrupt handler
69  *---------------------------------------------------------------------------*/
70 void
71 iwic_bchan_xirq(struct iwic_softc *sc, int chan_no)
72 {
73         int irq_stat;
74         struct iwic_bchan *chan;
75         int cmd = 0;
76         int activity = 0;
77
78         chan = &sc->sc_bchan[chan_no];
79
80         irq_stat = IWIC_READ(sc, chan->offset + B_EXIR);
81
82         NDBGL1(L1_H_IRQ, "irq_stat = 0x%x", irq_stat);
83         
84         if((irq_stat & (B_EXIR_RMR | B_EXIR_RME | B_EXIR_RDOV | B_EXIR_XFR | B_EXIR_XDUN)) == 0)
85         {
86                 NDBGL1(L1_H_XFRERR, "spurious IRQ!");
87                 return;
88         }
89
90         if (irq_stat & B_EXIR_RDOV)
91         {
92                 NDBGL1(L1_H_XFRERR, "iwic%d: EXIR B-channel Receive Data Overflow", sc->sc_unit);
93         }
94
95         if (irq_stat & B_EXIR_XDUN)
96         {
97                 NDBGL1(L1_H_XFRERR, "iwic%d: EXIR B-channel Transmit Data Underrun", sc->sc_unit);
98                 cmd |= (B_CMDR_XRST);   /*XXX must retransmit frame ! */
99         }
100
101 /* RX message end interrupt */
102         
103         if(irq_stat & B_EXIR_RME)
104         {
105                 int error;
106
107                 NDBGL1(L1_H_IRQ, "B_EXIR_RME");
108
109                 error = (IWIC_READ(sc,chan->offset+B_STAR) &
110                          (B_STAR_RDOV | B_STAR_CRCE | B_STAR_RMB));
111
112                 if(error)
113                 {
114                         if(error & B_STAR_RDOV)
115                                 NDBGL1(L1_H_XFRERR, "iwic%d: B-channel Receive Data Overflow", sc->sc_unit);
116                         if(error & B_STAR_CRCE)
117                                 NDBGL1(L1_H_XFRERR, "iwic%d: B-channel CRC Error", sc->sc_unit);
118                         if(error & B_STAR_RMB)
119                                 NDBGL1(L1_H_XFRERR, "iwic%d: B-channel Receive Message Aborted", sc->sc_unit);
120                 }
121
122                 /* all error conditions checked, now decide and take action */
123                 
124                 if(error == 0)
125                 {
126                         register int fifo_data_len;
127                         fifo_data_len = ((IWIC_READ(sc,chan->offset+B_RBCL)) &
128                                         ((IWIC_BCHAN_FIFO_LEN)-1));
129                 
130                         if(fifo_data_len == 0)
131                                 fifo_data_len = IWIC_BCHAN_FIFO_LEN;
132
133
134                         if(chan->in_mbuf == NULL)
135                         {
136                                 if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
137                                         panic("L1 iwic_bchan_irq: RME, cannot allocate mbuf!\n");
138                                 chan->in_cbptr = chan->in_mbuf->m_data;
139                                 chan->in_len = 0;
140                         }
141
142                         if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN)
143                         {
144                                 /* read data from fifo */
145         
146                                 NDBGL1(L1_H_IRQ, "B_EXIR_RME, rd fifo, len = %d", fifo_data_len);
147
148                                 IWIC_RDBFIFO(sc, chan, chan->in_cbptr, fifo_data_len);
149
150                                 cmd |= (B_CMDR_RACK | B_CMDR_RACT);
151                                 IWIC_WRITE(sc, chan->offset + B_CMDR, cmd);
152                                 cmd = 0;
153                                 
154                                 chan->in_len += fifo_data_len;
155                                 chan->rxcount += fifo_data_len;
156
157                                 /* setup mbuf data length */
158                                         
159                                 chan->in_mbuf->m_len = chan->in_len;
160                                 chan->in_mbuf->m_pkthdr.len = chan->in_len;
161
162                                 if(sc->sc_trace & TRACE_B_RX)
163                                 {
164                                         i4b_trace_hdr_t hdr;
165                                         hdr.unit = L0IWICUNIT(sc->sc_unit);
166                                         hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
167                                         hdr.dir = FROM_NT;
168                                         hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
169                                         MICROTIME(hdr.time);
170                                         i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
171                                 }
172
173                                 (*chan->iwic_drvr_linktab->bch_rx_data_ready)(chan->iwic_drvr_linktab->unit);
174
175                                 activity = ACT_RX;
176                                 
177                                 /* mark buffer ptr as unused */
178                                         
179                                 chan->in_mbuf = NULL;
180                                 chan->in_cbptr = NULL;
181                                 chan->in_len = 0;
182                         }
183                         else
184                         {
185                                 NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RME, in_len=%d, fifolen=%d", chan->in_len, fifo_data_len);
186                                 chan->in_cbptr = chan->in_mbuf->m_data;
187                                 chan->in_len = 0;
188                                 cmd |= (B_CMDR_RRST | B_CMDR_RACK);
189                         }
190                 }
191                 else
192                 {
193                         if (chan->in_mbuf != NULL)
194                         {
195                                 i4b_Bfreembuf(chan->in_mbuf);
196                                 chan->in_mbuf = NULL;
197                                 chan->in_cbptr = NULL;
198                                 chan->in_len = 0;
199                         }
200                         cmd |= (B_CMDR_RRST | B_CMDR_RACK);
201                 }
202         }
203
204 /* RX fifo full interrupt */
205
206         if(irq_stat & B_EXIR_RMR)
207         {
208                 NDBGL1(L1_H_IRQ, "B_EXIR_RMR");
209
210                 if(chan->in_mbuf == NULL)
211                 {
212                         if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
213                                 panic("L1 iwic_bchan_irq: RMR, cannot allocate mbuf!\n");
214                         chan->in_cbptr = chan->in_mbuf->m_data;
215                         chan->in_len = 0;
216                 }
217
218                 chan->rxcount += IWIC_BCHAN_FIFO_LEN;
219                 
220                 if((chan->in_len + IWIC_BCHAN_FIFO_LEN) <= BCH_MAX_DATALEN)
221                 {
222                         /* read data from fifo */
223
224                         NDBGL1(L1_H_IRQ, "B_EXIR_RMR, rd fifo, len = max (64)");
225                         
226                         IWIC_RDBFIFO(sc, chan, chan->in_cbptr, IWIC_BCHAN_FIFO_LEN);
227
228                         chan->in_cbptr += IWIC_BCHAN_FIFO_LEN;
229                         chan->in_len += IWIC_BCHAN_FIFO_LEN;
230                 }
231                 else
232                 {
233                         if(chan->bprot == BPROT_NONE)
234                         {
235                                 /* setup mbuf data length */
236                                 
237                                 chan->in_mbuf->m_len = chan->in_len;
238                                 chan->in_mbuf->m_pkthdr.len = chan->in_len;
239
240                                 if(sc->sc_trace & TRACE_B_RX)
241                                 {
242                                         i4b_trace_hdr_t hdr;
243                                         hdr.unit = L0IWICUNIT(sc->sc_unit);
244                                         hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
245                                         hdr.dir = FROM_NT;
246                                         hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
247                                         MICROTIME(hdr.time);
248                                         i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
249                                 }
250
251                                 /* silence detection */
252                                 
253                                 if(!(i4b_l1_bchan_tel_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len)))
254                                         activity = ACT_RX;
255
256 #if defined (__FreeBSD__) && __FreeBSD__ > 4
257                                 (void) IF_HANDOFF(&chan->rx_queue, chan->in_mbuf, NULL);
258 #else
259                                 if(!(IF_QFULL(&chan->rx_queue)))
260                                 {
261                                         IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf);
262                                 }
263                                 else
264                                 {
265                                         i4b_Bfreembuf(chan->in_mbuf);
266                                 }
267 #endif
268                                 /* signal upper driver that data is available */
269
270                                 (*chan->iwic_drvr_linktab->bch_rx_data_ready)(chan->iwic_drvr_linktab->unit);
271                                 
272                                 /* alloc new buffer */
273                                 
274                                 if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
275                                         panic("L1 iwic_bchan_irq: RMR, cannot allocate new mbuf!\n");
276         
277                                 /* setup new data ptr */
278                                 
279                                 chan->in_cbptr = chan->in_mbuf->m_data;
280         
281                                 /* read data from fifo */
282         
283                                 NDBGL1(L1_H_IRQ, "B_EXIR_RMR, rd fifo1, len = max (64)");
284                                 
285                                 IWIC_RDBFIFO(sc, chan, chan->in_cbptr, IWIC_BCHAN_FIFO_LEN);
286
287                                 chan->in_cbptr += IWIC_BCHAN_FIFO_LEN;
288                                 chan->in_len = IWIC_BCHAN_FIFO_LEN;
289
290                                 chan->rxcount += IWIC_BCHAN_FIFO_LEN;
291                         }
292                         else
293                         {
294                                 NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RPF, in_len=%d", chan->in_len);
295                                 chan->in_cbptr = chan->in_mbuf->m_data;
296                                 chan->in_len = 0;
297                                 cmd |= (B_CMDR_RRST | B_CMDR_RACK);
298                         }
299                 }
300                 
301                 /* command to release fifo space */
302                 
303                 cmd |= B_CMDR_RACK;
304         }
305
306 /* TX interrupt */
307         
308         if (irq_stat & B_EXIR_XFR)
309         {                       
310                 /* transmit fifo empty, new data can be written to fifo */
311
312                 int activity = -1;
313                 int len;
314                 int nextlen;
315
316                 NDBGL1(L1_H_IRQ, "B_EXIR_XFR");
317                 
318                 if(chan->out_mbuf_cur == NULL)  /* last frame is transmitted */
319                 {
320                         IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
321
322                         if(chan->out_mbuf_head == NULL)
323                         {
324                                 chan->state &= ~ST_TX_ACTIVE;
325                                 (*chan->iwic_drvr_linktab->bch_tx_queue_empty)(chan->iwic_drvr_linktab->unit);
326                         }
327                         else
328                         {
329                                 chan->state |= ST_TX_ACTIVE;
330                                 chan->out_mbuf_cur = chan->out_mbuf_head;
331                                 chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
332                                 chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
333
334                                 if(sc->sc_trace & TRACE_B_TX)
335                                 {
336                                         i4b_trace_hdr_t hdr;
337                                         hdr.unit = L0IWICUNIT(sc->sc_unit);
338                                         hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
339                                         hdr.dir = FROM_TE;
340                                         hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
341                                         MICROTIME(hdr.time);
342                                         i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
343                                 }
344
345                                 if(chan->bprot == BPROT_NONE)
346                                 {
347                                         if(!(i4b_l1_bchan_tel_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
348                                                 activity = ACT_TX;
349                                 }
350                                 else
351                                 {
352                                         activity = ACT_TX;
353                                 }
354                         }
355                 }
356                         
357                 len = 0;
358
359                 while(chan->out_mbuf_cur && len != IWIC_BCHAN_FIFO_LEN)
360                 {
361                         nextlen = min(chan->out_mbuf_cur_len, IWIC_BCHAN_FIFO_LEN - len);
362
363                         NDBGL1(L1_H_IRQ, "B_EXIR_XFR, wr fifo, len = %d", nextlen);
364                         
365                         IWIC_WRBFIFO(sc, chan, chan->out_mbuf_cur_ptr, nextlen);
366
367                         cmd |= B_CMDR_XMS;
368         
369                         len += nextlen;
370                         chan->txcount += nextlen;
371         
372                         chan->out_mbuf_cur_ptr += nextlen;
373                         chan->out_mbuf_cur_len -= nextlen;
374                         
375                         if(chan->out_mbuf_cur_len == 0) 
376                         {
377                                 if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)
378                                 {
379                                         chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
380                                         chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
381
382                                         if(sc->sc_trace & TRACE_B_TX)
383                                         {
384                                                 i4b_trace_hdr_t hdr;
385                                                 hdr.unit = L0IWICUNIT(sc->sc_unit);
386                                                 hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
387                                                 hdr.dir = FROM_TE;
388                                                 hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
389                                                 MICROTIME(hdr.time);
390                                                 i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
391                                         }
392                                 }
393                                 else
394                                 {
395                                         if (chan->bprot != BPROT_NONE)
396                                                 cmd |= B_CMDR_XME;
397                                         i4b_Bfreembuf(chan->out_mbuf_head);
398                                         chan->out_mbuf_head = NULL;
399                                 }
400                         }
401                 }
402         }
403         if(cmd)
404         {
405                 cmd |= B_CMDR_RACT;
406                 IWIC_WRITE(sc, chan->offset + B_CMDR, cmd);
407         }
408 }
409
410 /*---------------------------------------------------------------------------*
411  *      initialize one B channels rx/tx data structures
412  *---------------------------------------------------------------------------*/
413 void
414 iwic_bchannel_setup(int unit, int chan_no, int bprot, int activate)
415 {
416         struct iwic_softc *sc = &iwic_sc[unit];
417         struct iwic_bchan *chan = &sc->sc_bchan[chan_no];
418
419         int s = SPLI4B();
420         
421         NDBGL1(L1_BCHAN, "unit %d, chan %d, bprot %d, activate %d", unit, chan_no, bprot, activate);
422
423         /* general part */
424
425         chan->bprot = bprot;            /* B channel protocol */
426         chan->state = ST_IDLE;          /* B channel state */
427
428         if(activate == 0)
429         {
430                 /* deactivation */
431                 iwic_bchan_init(sc, chan_no, activate);
432         }
433                 
434         /* receiver part */
435
436         chan->rx_queue.ifq_maxlen = IFQ_MAXLEN;
437
438 #if defined (__FreeBSD__) && __FreeBSD__ > 4
439         mtx_init(&chan->rx_queue.ifq_mtx, "i4b_iwic_rx", MTX_DEF);
440 #endif
441
442         i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */
443
444         chan->rxcount = 0;              /* reset rx counter */
445         
446         i4b_Bfreembuf(chan->in_mbuf);   /* clean rx mbuf */
447
448         chan->in_mbuf = NULL;           /* reset mbuf ptr */
449         chan->in_cbptr = NULL;          /* reset mbuf curr ptr */
450         chan->in_len = 0;               /* reset mbuf data len */
451         
452         /* transmitter part */
453
454         chan->tx_queue.ifq_maxlen = IFQ_MAXLEN;
455
456 #if defined (__FreeBSD__) && __FreeBSD__ > 4    
457         mtx_init(&chan->tx_queue.ifq_mtx, "i4b_iwic_tx", MTX_DEF);
458 #endif
459
460         i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */
461         
462         chan->txcount = 0;              /* reset tx counter */
463         
464         i4b_Bfreembuf(chan->out_mbuf_head);     /* clean tx mbuf */
465
466         chan->out_mbuf_head = NULL;     /* reset head mbuf ptr */
467         chan->out_mbuf_cur = NULL;      /* reset current mbuf ptr */    
468         chan->out_mbuf_cur_ptr = NULL;  /* reset current mbuf data ptr */
469         chan->out_mbuf_cur_len = 0;     /* reset current mbuf data cnt */
470         
471         if(activate != 0)
472         {
473                 /* activation */
474                 iwic_bchan_init(sc, chan_no, activate);
475         }
476
477         splx(s);
478 }
479
480 /*---------------------------------------------------------------------------*
481  *      initalize / deinitialize B-channel hardware
482  *---------------------------------------------------------------------------*/
483 static void
484 iwic_bchan_init(struct iwic_softc *sc, int chan_no, int activate)
485 {
486         struct iwic_bchan *bchan = &sc->sc_bchan[chan_no];
487
488         NDBGL1(L1_BCHAN, "chan %d, activate %d", chan_no, activate);
489
490         if(activate)
491         {
492                 if(bchan->bprot == BPROT_NONE)
493                 {
494                         /* Extended transparent mode */
495                         IWIC_WRITE(sc, bchan->offset + B_MODE, B_MODE_MMS);
496                 }
497                 else
498                 {
499                         /* Transparent mode */
500                         IWIC_WRITE(sc, bchan->offset + B_MODE, 0);
501                         /* disable address comparation */
502                         IWIC_WRITE (sc, bchan->offset+B_ADM1, 0xff);
503                         IWIC_WRITE (sc, bchan->offset+B_ADM2, 0xff);
504                 }
505
506                 /* reset & start receiver */
507                 IWIC_WRITE(sc, bchan->offset + B_CMDR, B_CMDR_RRST|B_CMDR_RACT);
508
509                 /* clear irq mask */
510                 IWIC_WRITE(sc, bchan->offset + B_EXIM, 0);
511         }
512         else
513         {
514                 /* mask all irqs */             
515                 IWIC_WRITE(sc, bchan->offset + B_EXIM, 0xff);
516
517                 /* reset mode */
518                 IWIC_WRITE(sc, bchan->offset + B_MODE, 0);
519                 
520                 /* Bring interface down */
521                 IWIC_WRITE(sc, bchan->offset + B_CMDR, B_CMDR_RRST | B_CMDR_XRST);
522
523                 /* Flush pending interrupts */
524                 IWIC_READ(sc, bchan->offset + B_EXIR);
525         }
526 }
527
528 /*---------------------------------------------------------------------------*
529  *      start transmission on a b channel
530  *---------------------------------------------------------------------------*/
531 static void
532 iwic_bchannel_start(int unit, int chan_no)
533 {
534         struct iwic_softc *sc = &iwic_sc[unit];
535         register struct iwic_bchan *chan = &sc->sc_bchan[chan_no];
536         register int next_len;
537         register int len;
538
539         int s;
540         int activity = -1;
541         int cmd = 0;
542
543         s = SPLI4B();                           /* enter critical section */
544
545         NDBGL1(L1_BCHAN, "unit %d, channel %d", unit, chan_no);
546
547         if(chan->state & ST_TX_ACTIVE)          /* already running ? */
548         {
549                 splx(s);
550                 return;                         /* yes, leave */
551         }
552
553         /* get next mbuf from queue */
554         
555         IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
556         
557         if(chan->out_mbuf_head == NULL)         /* queue empty ? */
558         {
559                 splx(s);                        /* leave critical section */
560                 return;                         /* yes, exit */
561         }
562
563         /* init current mbuf values */
564         
565         chan->out_mbuf_cur = chan->out_mbuf_head;
566         chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
567         chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;    
568         
569         /* activity indicator for timeout handling */
570
571         if(chan->bprot == BPROT_NONE)
572         {
573                 if(!(i4b_l1_bchan_tel_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
574                         activity = ACT_TX;
575         }
576         else
577         {
578                 activity = ACT_TX;
579         }
580
581         chan->state |= ST_TX_ACTIVE;            /* we start transmitting */
582
583         if(sc->sc_trace & TRACE_B_TX)   /* if trace, send mbuf to trace dev */
584         {
585                 i4b_trace_hdr_t hdr;
586                 hdr.unit = L0IWICUNIT(unit);
587                 hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
588                 hdr.dir = FROM_TE;
589                 hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
590                 MICROTIME(hdr.time);
591                 i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
592         }                       
593
594         len = 0;        /* # of chars put into tx fifo this time */
595
596         /*
597          * fill the tx fifo with data from the current mbuf. if
598          * current mbuf holds less data than fifo length, try to
599          * get the next mbuf from (a possible) mbuf chain. if there is
600          * not enough data in a single mbuf or in a chain, then this
601          * is the last mbuf and we tell the chip that it has to send
602          * CRC and closing flag
603          */
604          
605         while((len < IWIC_BCHAN_FIFO_LEN) && chan->out_mbuf_cur)
606         {
607                 /*
608                  * put as much data into the fifo as is
609                  * available from the current mbuf
610                  */
611                  
612                 if((len + chan->out_mbuf_cur_len) >= IWIC_BCHAN_FIFO_LEN)
613                         next_len = IWIC_BCHAN_FIFO_LEN - len;
614                 else
615                         next_len = chan->out_mbuf_cur_len;
616
617                 /* write what we have from current mbuf to fifo */
618
619                 IWIC_WRBFIFO(sc, chan, chan->out_mbuf_cur_ptr, next_len);
620                 
621                 len += next_len;                /* update # of bytes written */
622                 chan->txcount += next_len;      /* statistics */
623                 chan->out_mbuf_cur_ptr += next_len;     /* data ptr */
624                 chan->out_mbuf_cur_len -= next_len;     /* data len */
625
626                 /*
627                  * in case the current mbuf (of a possible chain) data
628                  * has been put into the fifo, check if there is a next
629                  * mbuf in the chain. If there is one, get ptr to it
630                  * and update the data ptr and the length
631                  */
632                  
633                 if((chan->out_mbuf_cur_len <= 0)        &&
634                   ((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL))
635                 {
636                         chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
637                         chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
638
639                         if(sc->sc_trace & TRACE_B_TX)
640                         {
641                                 i4b_trace_hdr_t hdr;
642                                 hdr.unit = L0IWICUNIT(unit);
643                                 hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
644                                 hdr.dir = FROM_TE;
645                                 hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
646                                 MICROTIME(hdr.time);
647                                 i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
648                         }
649                 }
650         }
651
652         /*
653          * if there is either still data in the current mbuf and/or
654          * there is a successor on the chain available issue just
655          * a XTF (transmit) command to the chip. if there is no more
656          * data available from the current mbuf (-chain), issue
657          * an XTF and an XME (message end) command which will then
658          * send the CRC and the closing HDLC flag sequence
659          */
660          
661         if(chan->out_mbuf_cur && (chan->out_mbuf_cur_len > 0))
662         {
663                 /*
664                  * more data available, send current fifo out.
665                  * next xfer to tx fifo is done in the
666                  * interrupt routine.
667                  */
668                  
669                 cmd |= B_CMDR_XMS;
670         }
671         else
672         {
673                 /* end of mbuf chain */
674         
675                 if(chan->bprot == BPROT_NONE)
676                         cmd |= B_CMDR_XMS;
677                 else
678                         cmd |= (B_CMDR_XMS | B_CMDR_XME);
679                 
680                 i4b_Bfreembuf(chan->out_mbuf_head);     /* free mbuf chain */
681                 
682                 chan->out_mbuf_head = NULL;
683                 chan->out_mbuf_cur = NULL;                      
684                 chan->out_mbuf_cur_ptr = NULL;
685                 chan->out_mbuf_cur_len = 0;
686         }
687
688         /* call timeout handling routine */
689         
690         if(activity == ACT_RX || activity == ACT_TX)
691                 (*chan->iwic_drvr_linktab->bch_activity)(chan->iwic_drvr_linktab->unit, activity);
692
693         if(cmd)
694         {
695                 cmd |= B_CMDR_RACT;
696                 IWIC_WRITE(sc, chan->offset + B_CMDR, cmd);
697         }
698                 
699         splx(s);        
700 }
701
702 /*---------------------------------------------------------------------------*
703  *      return B-channel statistics
704  *---------------------------------------------------------------------------*/
705 static void
706 iwic_bchannel_stat(int unit, int chan_no, bchan_statistics_t *bsp)
707 {
708         struct iwic_softc *sc = iwic_find_sc(unit);
709         struct iwic_bchan *bchan = &sc->sc_bchan[chan_no];
710
711         int s = SPLI4B();
712
713         bsp->outbytes = bchan->txcount;
714         bsp->inbytes = bchan->rxcount;
715
716         bchan->txcount = 0;
717         bchan->rxcount = 0;
718
719         splx(s);
720 }
721
722 /*---------------------------------------------------------------------------*
723  *      initialize our local linktab
724  *---------------------------------------------------------------------------*/
725 void
726 iwic_init_linktab(struct iwic_softc *sc)
727 {
728         struct iwic_bchan *chan;
729         isdn_link_t *lt;
730
731         /* make sure the hardware driver is known to layer 4 */
732         ctrl_types[CTRL_PASSIVE].set_linktab = i4b_l1_set_linktab;
733         ctrl_types[CTRL_PASSIVE].get_linktab = i4b_l1_ret_linktab;
734
735         /* channel A */
736         
737         chan = &sc->sc_bchan[IWIC_BCH_A];
738         lt = &chan->iwic_isdn_linktab;
739         
740         lt->unit = sc->sc_unit;
741         lt->channel = IWIC_BCH_A;
742         lt->bch_config = iwic_bchannel_setup;
743         lt->bch_tx_start = iwic_bchannel_start;
744         lt->bch_stat = iwic_bchannel_stat;
745         lt->tx_queue = &chan->tx_queue;
746
747         /* used by non-HDLC data transfers, i.e. telephony drivers */
748         lt->rx_queue = &chan->rx_queue;
749
750         /* used by HDLC data transfers, i.e. ipr and isp drivers */     
751         lt->rx_mbuf = &chan->in_mbuf;   
752                                                 
753         /* channel B */
754         
755         chan = &sc->sc_bchan[IWIC_BCH_B];
756         lt = &chan->iwic_isdn_linktab;
757         
758         lt->unit = sc->sc_unit;
759         lt->channel = IWIC_BCH_B;
760         lt->bch_config = iwic_bchannel_setup;
761         lt->bch_tx_start = iwic_bchannel_start;
762         lt->bch_stat = iwic_bchannel_stat;
763         lt->tx_queue = &chan->tx_queue;
764
765         /* used by non-HDLC data transfers, i.e. telephony drivers */
766         lt->rx_queue = &chan->rx_queue;
767
768         /* used by HDLC data transfers, i.e. ipr and isp drivers */     
769         lt->rx_mbuf = &chan->in_mbuf;   
770 }
771  
772 #endif /* NIWIC > 0 */