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