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