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