2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 *---------------------------------------------------------------------------
27 * i4b - Siemens HSCX chip (B-channel) handling
28 * --------------------------------------------
30 * $Id: hscx.c,v 1.14 2008/04/08 12:07:26 cegger Exp $
32 * last edit-date: [Fri Jan 5 11:36:10 2001]
34 *---------------------------------------------------------------------------*/
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: hscx.c,v 1.13 2007/10/19 11:59:52 ad Exp $");
39 #include <sys/param.h>
40 #if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
41 #include <sys/ioccom.h>
43 #include <sys/ioctl.h>
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
48 #include <machine/stdarg.h>
51 #include <machine/clock.h>
52 #include <i386/isa/isa_device.h>
57 #include <sys/device.h>
60 #include <sys/socket.h>
63 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
64 #include <sys/callout.h>
68 #include <machine/i4b_debug.h>
69 #include <machine/i4b_ioctl.h>
70 #include <machine/i4b_trace.h>
72 #include <netisdn/i4b_debug.h>
73 #include <netisdn/i4b_ioctl.h>
74 #include <netisdn/i4b_trace.h>
77 #include <netisdn/i4b_l2.h>
78 #include <netisdn/i4b_l1l2.h>
79 #include <netisdn/i4b_global.h>
80 #include <netisdn/i4b_mbuf.h>
82 #include <dev/ic/isic_l1.h>
83 #include <dev/ic/isac.h>
84 #include <dev/ic/hscx.h>
86 /*---------------------------------------------------------------------------*
88 *---------------------------------------------------------------------------*/
90 isic_hscx_irq(register struct isic_softc
*sc
, u_char ista
, int h_chan
, u_char ex_irq
)
92 register l1_bchan_state_t
*chan
= &sc
->sc_chan
[h_chan
];
97 NDBGL1(L1_H_IRQ
, "%#x", ista
);
101 /* get channel extended irq reg */
103 exir
= HSCX_READ(h_chan
, H_EXIR
);
105 if(exir
& HSCX_EXIR_RFO
)
108 NDBGL1(L1_H_XFRERR
, "ex_irq: receive data overflow");
111 if((exir
& HSCX_EXIR_XDU
) && (chan
->bprot
!= BPROT_NONE
))/* xmit data underrun */
114 NDBGL1(L1_H_XFRERR
, "ex_irq: xmit data underrun");
115 isic_hscx_cmd(sc
, h_chan
, HSCX_CMDR_XRES
);
117 if (chan
->out_mbuf_head
!= NULL
) /* don't continue to transmit this buffer */
119 i4b_Bfreembuf(chan
->out_mbuf_head
);
120 chan
->out_mbuf_cur
= chan
->out_mbuf_head
= NULL
;
126 /* rx message end, end of frame */
128 if(ista
& HSCX_ISTA_RME
)
130 register int fifo_data_len
;
134 rsta
= HSCX_READ(h_chan
, H_RSTA
);
136 if((rsta
& 0xf0) != 0xa0)
138 if((rsta
& HSCX_RSTA_VFR
) == 0)
141 cmd
|= (HSCX_CMDR_RHR
);
142 NDBGL1(L1_H_XFRERR
, "received invalid Frame");
146 if(rsta
& HSCX_RSTA_RDO
)
149 NDBGL1(L1_H_XFRERR
, "receive data overflow");
153 if((rsta
& HSCX_RSTA_CRC
) == 0)
156 cmd
|= (HSCX_CMDR_RHR
);
157 NDBGL1(L1_H_XFRERR
, "CRC check failed");
161 if(rsta
& HSCX_RSTA_RAB
)
164 NDBGL1(L1_H_XFRERR
, "Receive message aborted");
169 fifo_data_len
= ((HSCX_READ(h_chan
, H_RBCL
)) &
170 ((sc
->sc_bfifolen
)-1));
172 if(fifo_data_len
== 0)
173 fifo_data_len
= sc
->sc_bfifolen
;
175 /* all error conditions checked, now decide and take action */
179 if(chan
->in_mbuf
== NULL
)
181 if((chan
->in_mbuf
= i4b_Bgetmbuf(BCH_MAX_DATALEN
)) == NULL
)
182 panic("L1 isic_hscx_irq: RME, cannot allocate mbuf!");
183 chan
->in_cbptr
= chan
->in_mbuf
->m_data
;
187 fifo_data_len
-= 1; /* last byte in fifo is RSTA ! */
189 if((chan
->in_len
+ fifo_data_len
) <= BCH_MAX_DATALEN
)
191 /* read data from HSCX fifo */
193 HSCX_RDFIFO(h_chan
, chan
->in_cbptr
, fifo_data_len
);
195 cmd
|= (HSCX_CMDR_RMC
);
196 isic_hscx_cmd(sc
, h_chan
, cmd
);
199 chan
->in_len
+= fifo_data_len
;
200 chan
->rxcount
+= fifo_data_len
;
202 /* setup mbuf data length */
204 chan
->in_mbuf
->m_len
= chan
->in_len
;
205 chan
->in_mbuf
->m_pkthdr
.len
= chan
->in_len
;
207 if(sc
->sc_trace
& TRACE_B_RX
)
210 hdr
.type
= (h_chan
== HSCX_CH_A
? TRC_CH_B1
: TRC_CH_B2
);
212 hdr
.count
= ++sc
->sc_trace_bcount
;
213 isdn_layer2_trace_ind(&sc
->sc_l2
, sc
->sc_l3token
, &hdr
, chan
->in_mbuf
->m_len
, chan
->in_mbuf
->m_data
);
216 (*chan
->l4_driver
->bch_rx_data_ready
)(chan
->l4_driver_softc
);
220 /* mark buffer ptr as unused */
222 chan
->in_mbuf
= NULL
;
223 chan
->in_cbptr
= NULL
;
228 NDBGL1(L1_H_XFRERR
, "RAWHDLC rx buffer overflow in RME, in_len=%d, fifolen=%d", chan
->in_len
, fifo_data_len
);
229 chan
->in_cbptr
= chan
->in_mbuf
->m_data
;
231 cmd
|= (HSCX_CMDR_RHR
| HSCX_CMDR_RMC
);
236 if (chan
->in_mbuf
!= NULL
)
238 i4b_Bfreembuf(chan
->in_mbuf
);
239 chan
->in_mbuf
= NULL
;
240 chan
->in_cbptr
= NULL
;
243 cmd
|= (HSCX_CMDR_RMC
);
249 if(ista
& HSCX_ISTA_RPF
)
251 if(chan
->in_mbuf
== NULL
)
253 if((chan
->in_mbuf
= i4b_Bgetmbuf(BCH_MAX_DATALEN
)) == NULL
)
254 panic("L1 isic_hscx_irq: RPF, cannot allocate mbuf!");
255 chan
->in_cbptr
= chan
->in_mbuf
->m_data
;
259 chan
->rxcount
+= sc
->sc_bfifolen
;
261 if((chan
->in_len
+ sc
->sc_bfifolen
) <= BCH_MAX_DATALEN
)
263 /* read data from HSCX fifo */
265 HSCX_RDFIFO(h_chan
, chan
->in_cbptr
, sc
->sc_bfifolen
);
267 chan
->in_cbptr
+= sc
->sc_bfifolen
;
268 chan
->in_len
+= sc
->sc_bfifolen
;
272 if(chan
->bprot
== BPROT_NONE
)
274 /* setup mbuf data length */
276 chan
->in_mbuf
->m_len
= chan
->in_len
;
277 chan
->in_mbuf
->m_pkthdr
.len
= chan
->in_len
;
279 if(sc
->sc_trace
& TRACE_B_RX
)
282 hdr
.type
= (h_chan
== HSCX_CH_A
? TRC_CH_B1
: TRC_CH_B2
);
284 hdr
.count
= ++sc
->sc_trace_bcount
;
285 isdn_layer2_trace_ind(&sc
->sc_l2
, sc
->sc_l3token
, &hdr
,chan
->in_mbuf
->m_len
, chan
->in_mbuf
->m_data
);
288 /* silence detection */
290 if(!(isdn_bchan_silence(chan
->in_mbuf
->m_data
, chan
->in_mbuf
->m_len
)))
293 if(!(IF_QFULL(&chan
->rx_queue
)))
295 IF_ENQUEUE(&chan
->rx_queue
, chan
->in_mbuf
);
299 i4b_Bfreembuf(chan
->in_mbuf
);
302 /* signal upper driver that data is available */
304 (*chan
->l4_driver
->bch_rx_data_ready
)(chan
->l4_driver_softc
);
306 /* alloc new buffer */
308 if((chan
->in_mbuf
= i4b_Bgetmbuf(BCH_MAX_DATALEN
)) == NULL
)
309 panic("L1 isic_hscx_irq: RPF, cannot allocate new mbuf!");
311 /* setup new data ptr */
313 chan
->in_cbptr
= chan
->in_mbuf
->m_data
;
315 /* read data from HSCX fifo */
317 HSCX_RDFIFO(h_chan
, chan
->in_cbptr
, sc
->sc_bfifolen
);
319 chan
->in_cbptr
+= sc
->sc_bfifolen
;
320 chan
->in_len
= sc
->sc_bfifolen
;
322 chan
->rxcount
+= sc
->sc_bfifolen
;
326 NDBGL1(L1_H_XFRERR
, "RAWHDLC rx buffer overflow in RPF, in_len=%d", chan
->in_len
);
327 chan
->in_cbptr
= chan
->in_mbuf
->m_data
;
329 cmd
|= (HSCX_CMDR_RHR
);
333 /* command to release fifo space */
335 cmd
|= HSCX_CMDR_RMC
;
338 /* transmit fifo empty, new data can be written to fifo */
340 if(ista
& HSCX_ISTA_XPR
)
343 * for a description what is going on here, please have
344 * a look at isic_bchannel_start() in i4b_bchan.c !
350 NDBGL1(L1_H_IRQ
, "%s, chan %d - XPR, Tx Fifo Empty!", device_xname(&sc
->sc_dev
), h_chan
);
352 if(chan
->out_mbuf_cur
== NULL
) /* last frame is transmitted */
354 IF_DEQUEUE(&chan
->tx_queue
, chan
->out_mbuf_head
);
356 if(chan
->out_mbuf_head
== NULL
)
358 chan
->state
&= ~HSCX_TX_ACTIVE
;
359 (*chan
->l4_driver
->bch_tx_queue_empty
)(chan
->l4_driver_softc
);
363 chan
->state
|= HSCX_TX_ACTIVE
;
364 chan
->out_mbuf_cur
= chan
->out_mbuf_head
;
365 chan
->out_mbuf_cur_ptr
= chan
->out_mbuf_cur
->m_data
;
366 chan
->out_mbuf_cur_len
= chan
->out_mbuf_cur
->m_len
;
368 if(sc
->sc_trace
& TRACE_B_TX
)
371 hdr
.type
= (h_chan
== HSCX_CH_A
? TRC_CH_B1
: TRC_CH_B2
);
373 hdr
.count
= ++sc
->sc_trace_bcount
;
374 isdn_layer2_trace_ind(&sc
->sc_l2
, sc
->sc_l3token
, &hdr
, chan
->out_mbuf_cur
->m_len
, chan
->out_mbuf_cur
->m_data
);
377 if(chan
->bprot
== BPROT_NONE
)
379 if(!(isdn_bchan_silence(chan
->out_mbuf_cur
->m_data
, chan
->out_mbuf_cur
->m_len
)))
391 while(chan
->out_mbuf_cur
&& len
!= sc
->sc_bfifolen
)
393 nextlen
= min(chan
->out_mbuf_cur_len
, sc
->sc_bfifolen
- len
);
396 printf("i:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ",
399 chan
->out_mbuf_cur_ptr
,
400 chan
->out_mbuf_cur_len
,
405 isic_hscx_waitxfw(sc
, h_chan
); /* necessary !!! */
407 HSCX_WRFIFO(h_chan
, chan
->out_mbuf_cur_ptr
, nextlen
);
408 cmd
|= HSCX_CMDR_XTF
;
411 chan
->txcount
+= nextlen
;
413 chan
->out_mbuf_cur_ptr
+= nextlen
;
414 chan
->out_mbuf_cur_len
-= nextlen
;
416 if(chan
->out_mbuf_cur_len
== 0)
418 if((chan
->out_mbuf_cur
= chan
->out_mbuf_cur
->m_next
) != NULL
)
420 chan
->out_mbuf_cur_ptr
= chan
->out_mbuf_cur
->m_data
;
421 chan
->out_mbuf_cur_len
= chan
->out_mbuf_cur
->m_len
;
423 if(sc
->sc_trace
& TRACE_B_TX
)
426 hdr
.type
= (h_chan
== HSCX_CH_A
? TRC_CH_B1
: TRC_CH_B2
);
428 hdr
.count
= ++sc
->sc_trace_bcount
;
429 isdn_layer2_trace_ind(&sc
->sc_l2
, sc
->sc_l3token
, &hdr
, chan
->out_mbuf_cur
->m_len
, chan
->out_mbuf_cur
->m_data
);
434 if (chan
->bprot
!= BPROT_NONE
)
435 cmd
|= HSCX_CMDR_XME
;
436 i4b_Bfreembuf(chan
->out_mbuf_head
);
437 chan
->out_mbuf_head
= NULL
;
444 if(cmd
) /* is there a command for the HSCX ? */
446 isic_hscx_cmd(sc
, h_chan
, cmd
); /* yes, to HSCX */
449 /* call timeout handling routine */
451 if(activity
== ACT_RX
|| activity
== ACT_TX
)
452 (*chan
->l4_driver
->bch_activity
)(chan
->l4_driver_softc
, activity
);
455 /*---------------------------------------------------------------------------*
456 * HSCX initialization
458 * for telephony: extended transparent mode 1
459 * for raw hdlc: transparent mode 0
460 *---------------------------------------------------------------------------*/
462 isic_hscx_init(struct isic_softc
*sc
, int h_chan
, int activate
)
464 l1_bchan_state_t
*chan
= &sc
->sc_chan
[h_chan
];
466 HSCX_WRITE(h_chan
, H_MASK
, 0xff); /* mask irq's */
470 /* CCR1: Power Up, Clock Mode 5 */
471 HSCX_WRITE(h_chan
, H_CCR1
, HSCX_CCR1_PU
| /* power up */
472 HSCX_CCR1_CM1
); /* IPAC clock mode 5 */
476 /* CCR1: Power Up, Clock Mode 5 */
477 HSCX_WRITE(h_chan
, H_CCR1
, HSCX_CCR1_PU
| /* power up */
478 HSCX_CCR1_CM2
| /* HSCX clock mode 5 */
482 /* XAD1: Transmit Address Byte 1 */
483 HSCX_WRITE(h_chan
, H_XAD1
, 0xff);
485 /* XAD2: Transmit Address Byte 2 */
486 HSCX_WRITE(h_chan
, H_XAD2
, 0xff);
488 /* RAH2: Receive Address Byte High Reg. 2 */
489 HSCX_WRITE(h_chan
, H_RAH2
, 0xff);
491 /* XBCH: reset Transmit Byte Count High */
492 HSCX_WRITE(h_chan
, H_XBCH
, 0x00);
494 /* RLCR: reset Receive Length Check Register */
495 HSCX_WRITE(h_chan
, H_RLCR
, 0x00);
497 /* CCR2: set tx/rx clock shift bit 0 */
498 /* disable CTS irq, disable RIE irq*/
499 HSCX_WRITE(h_chan
, H_CCR2
, HSCX_CCR2_XCS0
|HSCX_CCR2_RCS0
);
501 /* XCCR: tx bit count per time slot */
502 HSCX_WRITE(h_chan
, H_XCCR
, 0x07);
504 /* RCCR: rx bit count per time slot */
505 HSCX_WRITE(h_chan
, H_RCCR
, 0x07);
507 if(sc
->sc_bustyp
== BUS_TYPE_IOM2
)
511 case HSCX_CH_A
: /* Prepare HSCX channel A */
512 /* TSAX: tx clock shift bits 1 & 2 */
513 /* tx time slot number */
514 HSCX_WRITE(h_chan
, H_TSAX
, 0x2f);
516 /* TSAR: rx clock shift bits 1 & 2 */
517 /* rx time slot number */
518 HSCX_WRITE(h_chan
, H_TSAR
, 0x2f);
521 case HSCX_CH_B
: /* Prepare HSCX channel B */
522 /* TSAX: tx clock shift bits 1 & 2 */
523 /* tx time slot number */
524 HSCX_WRITE(h_chan
, H_TSAX
, 0x03);
526 /* TSAR: rx clock shift bits 1 & 2 */
527 /* rx time slot number */
528 HSCX_WRITE(h_chan
, H_TSAR
, 0x03);
532 else /* IOM 1 setup */
534 /* TSAX: tx clock shift bits 1 & 2 */
535 /* tx time slot number */
536 HSCX_WRITE(h_chan
, H_TSAX
, 0x07);
538 /* TSAR: rx clock shift bits 1 & 2 */
539 /* rx time slot number */
540 HSCX_WRITE(h_chan
, H_TSAR
, 0x07);
545 if(chan
->bprot
== BPROT_RHDLC
)
547 /* HDLC Frames, transparent mode 0 */
548 HSCX_WRITE(h_chan
, H_MODE
,
549 HSCX_MODE_MDS1
|HSCX_MODE_RAC
|HSCX_MODE_RTS
);
553 /* Raw Telephony, extended transparent mode 1 */
554 HSCX_WRITE(h_chan
, H_MODE
,
555 HSCX_MODE_MDS1
|HSCX_MODE_MDS0
|HSCX_MODE_ADM
|HSCX_MODE_RTS
);
558 isic_hscx_cmd(sc
, h_chan
, HSCX_CMDR_RHR
|HSCX_CMDR_XRES
);
562 /* TSAX: tx time slot */
563 HSCX_WRITE(h_chan
, H_TSAX
, 0xff);
565 /* TSAR: rx time slot */
566 HSCX_WRITE(h_chan
, H_TSAR
, 0xff);
568 /* Raw Telephony, extended transparent mode 1 */
569 HSCX_WRITE(h_chan
, H_MODE
,
570 HSCX_MODE_MDS1
|HSCX_MODE_MDS0
|HSCX_MODE_ADM
|HSCX_MODE_RTS
);
573 /* don't touch ICA, EXA and EXB bits, this could be HSCX_CH_B */
574 /* always disable RSC and TIN */
576 chan
->hscx_mask
|= HSCX_MASK_RSC
| HSCX_MASK_TIN
;
581 chan
->hscx_mask
&= ~(HSCX_MASK_RME
| HSCX_MASK_RPF
| HSCX_MASK_XPR
);
586 chan
->hscx_mask
|= HSCX_MASK_RME
| HSCX_MASK_RPF
| HSCX_MASK_XPR
;
589 /* handle ICA, EXA, and EXB via interrupt mask of channel b */
591 if (h_chan
== HSCX_CH_A
)
594 HSCX_B_IMASK
&= ~(HSCX_MASK_EXA
| HSCX_MASK_ICA
);
596 HSCX_B_IMASK
|= HSCX_MASK_EXA
| HSCX_MASK_ICA
;
597 HSCX_WRITE(HSCX_CH_A
, H_MASK
, HSCX_A_IMASK
);
598 HSCX_WRITE(HSCX_CH_B
, H_MASK
, HSCX_B_IMASK
);
603 HSCX_B_IMASK
&= ~HSCX_MASK_EXB
;
605 HSCX_B_IMASK
|= HSCX_MASK_EXB
;
606 HSCX_WRITE(HSCX_CH_B
, H_MASK
, HSCX_B_IMASK
);
609 /* clear spurious interrupts left over */
611 if(h_chan
== HSCX_CH_A
)
613 HSCX_READ(h_chan
, H_EXIR
);
614 HSCX_READ(h_chan
, H_ISTA
);
616 else /* mask ICA, because it must not be cleared by reading ISTA */
618 HSCX_WRITE(HSCX_CH_B
, H_MASK
, HSCX_B_IMASK
| HSCX_MASK_ICA
);
619 HSCX_READ(h_chan
, H_EXIR
);
620 HSCX_READ(h_chan
, H_ISTA
);
621 HSCX_WRITE(HSCX_CH_B
, H_MASK
, HSCX_B_IMASK
);
625 /*---------------------------------------------------------------------------*
626 * write command to HSCX command register
627 *---------------------------------------------------------------------------*/
629 isic_hscx_cmd(struct isic_softc
*sc
, int h_chan
, unsigned char cmd
)
633 while(((HSCX_READ(h_chan
, H_STAR
)) & HSCX_STAR_CEC
) && timeout
)
641 NDBGL1(L1_H_ERR
, "HSCX wait for CEC timeout!");
644 HSCX_WRITE(h_chan
, H_CMDR
, cmd
);
647 /*---------------------------------------------------------------------------*
648 * wait for HSCX transmit FIFO write enable
649 *---------------------------------------------------------------------------*/
651 isic_hscx_waitxfw(struct isic_softc
*sc
, int h_chan
)
656 int timeout
= WAITTO
;
658 while((!(((HSCX_READ(h_chan
, H_STAR
)) &
659 (HSCX_STAR_CEC
| HSCX_STAR_XFW
)) == HSCX_STAR_XFW
)) && timeout
)
667 NDBGL1(L1_H_ERR
, "HSCX wait for XFW timeout!");
669 else if (timeout
!= WAITTO
)
671 NDBGL1(L1_H_XFRERR
, "HSCX wait for XFW time: %d uS", (WAITTO
-timeout
)*50);