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