1 /* $NetBSD: isacsx.c,v 1.5 2007/10/19 11:59:54 ad Exp $ */
3 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
4 * Copyright (c) 2001 Gary Jennejohn. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 *---------------------------------------------------------------------------
29 * i4b_ifpi2_isac.c - i4b Fritz PCI Version 2 ISACSX handler
30 * --------------------------------------------
32 * $Id: isacsx.c,v 1.6 2008/04/08 12:07:26 cegger Exp $
34 * $FreeBSD: src/sys/i4b/layer1/ifpi2/i4b_ifpi2_isacsx.c,v 1.3 2002/09/02 00:52:07 brooks Exp $
37 *---------------------------------------------------------------------------*/
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: isacsx.c,v 1.5 2007/10/19 11:59:54 ad Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
45 #include <sys/socket.h>
46 #include <sys/device.h>
50 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
51 #include <sys/callout.h>
55 #include <machine/i4b_debug.h>
56 #include <machine/i4b_ioctl.h>
57 #include <machine/i4b_trace.h>
59 #include <i4b/layer1/i4b_l1.h>
61 #include <i4b/layer1/isic/i4b_isic.h>
62 #include <i4b/layer1/isic/i4b_hscx.h>
64 #include <i4b/layer1/ifpi2/i4b_ifpi2_ext.h>
65 #include <i4b/layer1/ifpi2/i4b_ifpi2_isacsx.h>
67 #include <i4b/include/i4b_global.h>
68 #include <i4b/include/i4b_mbuf.h>
72 #include <netisdn/i4b_debug.h>
73 #include <netisdn/i4b_ioctl.h>
74 #include <netisdn/i4b_trace.h>
76 #include <netisdn/i4b_global.h>
77 #include <netisdn/i4b_l2.h>
78 #include <netisdn/i4b_l1l2.h>
79 #include <netisdn/i4b_mbuf.h>
81 #include <dev/ic/isacsx.h>
82 #include <dev/ic/isic_l1.h>
83 #include <dev/ic/hscx.h>
87 static u_char
isic_isacsx_exir_hdlr(register struct isic_softc
*sc
, u_char exir
);
88 static void isic_isacsx_ind_hdlr(register struct isic_softc
*sc
, int ind
);
90 /* the ISACSX has 2 mask registers of interest - cannot use ISAC_IMASK */
91 unsigned char isacsx_imaskd
;
92 unsigned char isacsx_imask
;
94 /*---------------------------------------------------------------------------*
95 * ISACSX interrupt service routine
96 *---------------------------------------------------------------------------*/
98 isic_isacsx_irq(struct isic_softc
*sc
, int ista
)
100 register u_char c
= 0;
101 register u_char istad
= 0;
103 NDBGL1(L1_F_MSG
, "%s: ista = 0x%02x", device_xname(&sc
->sc_dev
), ista
);
105 /* was it an HDLC interrupt ? */
106 if (ista
& ISACSX_ISTA_ICD
)
108 istad
= ISAC_READ(I_ISTAD
);
109 NDBGL1(L1_F_MSG
, "%s: istad = 0x%02x", device_xname(&sc
->sc_dev
), istad
);
111 if(istad
& (ISACSX_ISTAD_RFO
|ISACSX_ISTAD_XMR
|ISACSX_ISTAD_XDU
))
113 /* not really EXIR, but very similar */
114 c
|= isic_isacsx_exir_hdlr(sc
, istad
);
118 if(istad
& ISACSX_ISTAD_RME
) /* receive message end */
123 /* get rx status register */
125 rsta
= ISAC_READ(I_RSTAD
);
127 /* Check for Frame and CRC valid */
128 if((rsta
& ISACSX_RSTAD_MASK
) != (ISACSX_RSTAD_VFR
|ISACSX_RSTAD_CRC
))
132 if(!(rsta
& ISACSX_RSTAD_VFR
)) /* VFR error */
135 NDBGL1(L1_I_ERR
, "%s: Frame not valid error", device_xname(&sc
->sc_dev
));
138 if(!(rsta
& ISACSX_RSTAD_CRC
)) /* CRC error */
141 NDBGL1(L1_I_ERR
, "%s: CRC error", device_xname(&sc
->sc_dev
));
144 if(rsta
& ISACSX_RSTAD_RDO
) /* ReceiveDataOverflow */
147 NDBGL1(L1_I_ERR
, "%s: Data Overrun error", device_xname(&sc
->sc_dev
));
150 if(rsta
& ISACSX_RSTAD_RAB
) /* ReceiveABorted */
153 NDBGL1(L1_I_ERR
, "%s: Receive Aborted error", device_xname(&sc
->sc_dev
));
157 NDBGL1(L1_I_ERR
, "%s: RME unknown error, RSTAD = 0x%02x!", device_xname(&sc
->sc_dev
), rsta
);
159 i4b_Dfreembuf(sc
->sc_ibuf
);
161 c
|= ISACSX_CMDRD_RMC
|ISACSX_CMDRD_RRES
;
167 ISAC_WRITE(I_CMDRD
, ISACSX_CMDRD_RMC
|ISACSX_CMDRD_RRES
);
172 rest
= (ISAC_READ(I_RBCLD
) & (ISACSX_FIFO_LEN
-1));
175 rest
= ISACSX_FIFO_LEN
;
177 if(sc
->sc_ibuf
== NULL
)
179 if((sc
->sc_ibuf
= i4b_Dgetmbuf(rest
)) != NULL
)
180 sc
->sc_ib
= sc
->sc_ibuf
->m_data
;
182 panic("isic_isacsx_irq: RME, i4b_Dgetmbuf returns NULL!\n");
186 if(sc
->sc_ilen
<= (MAX_DFRAME_LEN
- rest
))
188 ISAC_RDFIFO(sc
->sc_ib
, rest
);
189 /* the last byte contains status, strip it */
190 sc
->sc_ilen
+= rest
- 1;
192 sc
->sc_ibuf
->m_pkthdr
.len
=
193 sc
->sc_ibuf
->m_len
= sc
->sc_ilen
;
195 if(sc
->sc_trace
& TRACE_D_RX
)
199 memset(&hdr
, 0, sizeof hdr
);
202 hdr
.count
= ++sc
->sc_trace_dcount
;
203 isdn_layer2_trace_ind(&sc
->sc_l2
, sc
->sc_l3token
, &hdr
, sc
->sc_ibuf
->m_len
, sc
->sc_ibuf
->m_data
);
206 c
|= ISACSX_CMDRD_RMC
;
208 if(sc
->sc_intr_valid
== ISIC_INTR_VALID
&&
209 (((struct isdn_l3_driver
*)sc
->sc_l3token
)->protocol
!= PROTOCOL_D64S
))
211 isdn_layer2_data_ind(&sc
->sc_l2
, sc
->sc_l3token
, sc
->sc_ibuf
);
215 i4b_Dfreembuf(sc
->sc_ibuf
);
220 NDBGL1(L1_I_ERR
, "RME, input buffer overflow!");
221 i4b_Dfreembuf(sc
->sc_ibuf
);
222 c
|= ISACSX_CMDRD_RMC
|ISACSX_CMDRD_RRES
;
230 if(istad
& ISACSX_ISTAD_RPF
) /* receive fifo full */
232 if(sc
->sc_ibuf
== NULL
)
234 if((sc
->sc_ibuf
= i4b_Dgetmbuf(MAX_DFRAME_LEN
)) != NULL
)
235 sc
->sc_ib
= sc
->sc_ibuf
->m_data
;
237 panic("isic_isacsx_irq: RPF, i4b_Dgetmbuf returns NULL!\n");
241 if(sc
->sc_ilen
<= (MAX_DFRAME_LEN
- ISACSX_FIFO_LEN
))
243 ISAC_RDFIFO(sc
->sc_ib
, ISACSX_FIFO_LEN
);
244 sc
->sc_ilen
+= ISACSX_FIFO_LEN
;
245 sc
->sc_ib
+= ISACSX_FIFO_LEN
;
246 c
|= ISACSX_CMDRD_RMC
;
250 NDBGL1(L1_I_ERR
, "RPF, input buffer overflow!");
251 i4b_Dfreembuf(sc
->sc_ibuf
);
255 c
|= ISACSX_CMDRD_RMC
|ISACSX_CMDRD_RRES
;
259 if(istad
& ISACSX_ISTAD_XPR
) /* transmit fifo empty (XPR bit set) */
261 if((sc
->sc_obuf2
!= NULL
) && (sc
->sc_obuf
== NULL
))
263 sc
->sc_freeflag
= sc
->sc_freeflag2
;
264 sc
->sc_obuf
= sc
->sc_obuf2
;
265 sc
->sc_op
= sc
->sc_obuf
->m_data
;
266 sc
->sc_ol
= sc
->sc_obuf
->m_len
;
269 printf("ob2=%x, op=%x, ol=%d, f=%d #",
279 printf("ob=%x, op=%x, ol=%d, f=%d #",
289 ISAC_WRFIFO(sc
->sc_op
, min(sc
->sc_ol
, ISACSX_FIFO_LEN
));
291 if(sc
->sc_ol
> ISACSX_FIFO_LEN
) /* length > 32 ? */
293 sc
->sc_op
+= ISACSX_FIFO_LEN
; /* bufferptr+32 */
294 sc
->sc_ol
-= ISACSX_FIFO_LEN
; /* length - 32 */
295 c
|= ISACSX_CMDRD_XTF
; /* set XTF bit */
301 i4b_Dfreembuf(sc
->sc_obuf
);
308 c
|= ISACSX_CMDRD_XTF
| ISACSX_CMDRD_XME
;
313 sc
->sc_state
&= ~ISAC_TX_ACTIVE
;
317 if(ista
& ISACSX_ISTA_CIC
) /* channel status change CISQ */
321 /* get command/indication rx register*/
323 ci
= ISAC_READ(I_CIR0
);
325 /* C/I code change IRQ (flag already cleared by CIR0 read) */
327 if(ci
& ISACSX_CIR0_CIC0
)
328 isic_isacsx_ind_hdlr(sc
, (ci
>> 4) & 0xf);
333 ISAC_WRITE(I_CMDRD
, c
);
337 /*---------------------------------------------------------------------------*
338 * ISACSX L1 Extended IRQ handler
339 *---------------------------------------------------------------------------*/
341 isic_isacsx_exir_hdlr(register struct isic_softc
*sc
, u_char exir
)
345 if(exir
& ISACSX_ISTAD_XMR
)
347 NDBGL1(L1_I_ERR
, "EXIRQ Tx Message Repeat");
349 c
|= ISACSX_CMDRD_XRES
;
352 if(exir
& ISACSX_ISTAD_XDU
)
354 NDBGL1(L1_I_ERR
, "EXIRQ Tx Data Underrun");
356 c
|= ISACSX_CMDRD_XRES
;
359 if(exir
& ISACSX_ISTAD_RFO
)
361 NDBGL1(L1_I_ERR
, "EXIRQ Rx Frame Overflow");
363 c
|= ISACSX_CMDRD_RMC
;
366 #if 0 /* all blocked per default */
367 if(exir
& ISACSX_EXIR_SOV
)
369 NDBGL1(L1_I_ERR
, "EXIRQ Sync Xfer Overflow");
372 if(exir
& ISACSX_EXIR_MOS
)
374 NDBGL1(L1_I_ERR
, "EXIRQ Monitor Status");
377 if(exir
& ISACSX_EXIR_SAW
)
379 /* cannot happen, STCR:TSF is set to 0 */
381 NDBGL1(L1_I_ERR
, "EXIRQ Subscriber Awake");
384 if(exir
& ISACSX_EXIR_WOV
)
386 /* cannot happen, STCR:TSF is set to 0 */
388 NDBGL1(L1_I_ERR
, "EXIRQ Watchdog Timer Overflow");
395 /*---------------------------------------------------------------------------*
396 * ISACSX L1 Indication handler
397 *---------------------------------------------------------------------------*/
399 isic_isacsx_ind_hdlr(register struct isic_softc
*sc
, int ind
)
405 case ISACSX_CIR0_IAI8
:
406 NDBGL1(L1_I_CICO
, "rx AI8 in state %s", isic_printstate(sc
));
407 if(sc
->sc_bustyp
== BUS_TYPE_IOM2
)
408 isic_isacsx_l1_cmd(sc
, CMD_AR8
);
410 isdn_layer2_status_ind(&sc
->sc_l2
, sc
->sc_l3token
, STI_L1STAT
, LAYER_ACTIVE
);
413 case ISACSX_CIR0_IAI10
:
414 NDBGL1(L1_I_CICO
, "rx AI10 in state %s", isic_printstate(sc
));
415 if(sc
->sc_bustyp
== BUS_TYPE_IOM2
)
416 isic_isacsx_l1_cmd(sc
, CMD_AR10
);
418 isdn_layer2_status_ind(&sc
->sc_l2
, sc
->sc_l3token
, STI_L1STAT
, LAYER_ACTIVE
);
421 case ISACSX_CIR0_IRSY
:
422 NDBGL1(L1_I_CICO
, "rx RSY in state %s", isic_printstate(sc
));
426 case ISACSX_CIR0_IPU
:
427 NDBGL1(L1_I_CICO
, "rx PU in state %s", isic_printstate(sc
));
431 case ISACSX_CIR0_IDR
:
432 NDBGL1(L1_I_CICO
, "rx DR in state %s", isic_printstate(sc
));
433 isic_isacsx_l1_cmd(sc
, CMD_DIU
);
437 case ISACSX_CIR0_IDID
:
438 NDBGL1(L1_I_CICO
, "rx DID in state %s", isic_printstate(sc
));
440 isdn_layer2_status_ind(&sc
->sc_l2
, sc
->sc_l3token
, STI_L1STAT
, LAYER_IDLE
);
443 case ISACSX_CIR0_IDIS
:
444 NDBGL1(L1_I_CICO
, "rx DIS in state %s", isic_printstate(sc
));
448 case ISACSX_CIR0_IEI
:
449 NDBGL1(L1_I_CICO
, "rx EI in state %s", isic_printstate(sc
));
450 isic_isacsx_l1_cmd(sc
, CMD_DIU
);
454 case ISACSX_CIR0_IARD
:
455 NDBGL1(L1_I_CICO
, "rx ARD in state %s", isic_printstate(sc
));
459 case ISACSX_CIR0_ITI
:
460 NDBGL1(L1_I_CICO
, "rx TI in state %s", isic_printstate(sc
));
464 case ISACSX_CIR0_IATI
:
465 NDBGL1(L1_I_CICO
, "rx ATI in state %s", isic_printstate(sc
));
469 case ISACSX_CIR0_ISD
:
470 NDBGL1(L1_I_CICO
, "rx SD in state %s", isic_printstate(sc
));
475 NDBGL1(L1_I_ERR
, "UNKNOWN Indication 0x%x in state %s", ind
, isic_printstate(sc
));
479 isic_next_state(sc
, event
);
482 /*---------------------------------------------------------------------------*
483 * execute a layer 1 command
484 *---------------------------------------------------------------------------*/
486 isic_isacsx_l1_cmd(struct isic_softc
*sc
, int command
)
490 #ifdef I4B_SMP_WORKAROUND
492 /* XXXXXXXXXXXXXXXXXXX */
495 * patch from Wolfgang Helbig:
497 * Here is a patch that makes i4b work on an SMP:
498 * The card (TELES 16.3) didn't interrupt on an SMP machine.
499 * This is a gross workaround, but anyway it works *and* provides
500 * some information as how to finally fix this problem.
503 HSCX_WRITE(0, H_MASK
, 0xff);
504 HSCX_WRITE(1, H_MASK
, 0xff);
505 ISAC_WRITE(I_MASKD
, 0xff);
506 ISAC_WRITE(I_MASK
, 0xff);
508 HSCX_WRITE(0, H_MASK
, HSCX_A_IMASK
);
509 HSCX_WRITE(1, H_MASK
, HSCX_B_IMASK
);
510 ISAC_WRITE(I_MASKD
, isacsx_imaskd
);
511 ISAC_WRITE(I_MASK
, isacsx_imask
);
513 /* XXXXXXXXXXXXXXXXXXX */
515 #endif /* I4B_SMP_WORKAROUND */
517 if(command
< 0 || command
> CMD_ILL
)
519 NDBGL1(L1_I_ERR
, "illegal cmd 0x%x in state %s", command
, isic_printstate(sc
));
523 cmd
= ISACSX_CIX0_LOW
;
528 NDBGL1(L1_I_CICO
, "tx TIM in state %s", isic_printstate(sc
));
529 cmd
|= (ISACSX_CIX0_CTIM
<< 4);
533 NDBGL1(L1_I_CICO
, "tx RS in state %s", isic_printstate(sc
));
534 cmd
|= (ISACSX_CIX0_CRS
<< 4);
538 NDBGL1(L1_I_CICO
, "tx AR8 in state %s", isic_printstate(sc
));
539 cmd
|= (ISACSX_CIX0_CAR8
<< 4);
543 NDBGL1(L1_I_CICO
, "tx AR10 in state %s", isic_printstate(sc
));
544 cmd
|= (ISACSX_CIX0_CAR10
<< 4);
548 NDBGL1(L1_I_CICO
, "tx DIU in state %s", isic_printstate(sc
));
549 cmd
|= (ISACSX_CIX0_CDIU
<< 4);
552 ISAC_WRITE(I_CIX0
, cmd
);
555 /*---------------------------------------------------------------------------*
556 * L1 ISACSX initialization
557 *---------------------------------------------------------------------------*/
559 isic_isacsx_init(struct isic_softc
*sc
)
561 isacsx_imaskd
= 0xff; /* disable all irqs */
562 isacsx_imask
= 0xff; /* disable all irqs */
564 ISAC_WRITE(I_MASKD
, isacsx_imaskd
);
565 ISAC_WRITE(I_MASK
, isacsx_imask
);
567 /* the ISACSX only runs in IOM-2 mode */
568 NDBGL1(L1_I_SETUP
, "configuring for IOM-2 mode");
570 /* TR_CONF0: Transceiver Configuration Register 0:
571 * DIS_TR - transceiver enabled
572 * EN_ICV - normal operation
573 * EXLP - no external loop
574 * LDD - automatic clock generation
576 ISAC_WRITE(I_WTR_CONF0
, 0);
578 /* TR_CONF2: Transceiver Configuration Register 1:
579 * DIS_TX - transmitter enabled
580 * PDS - phase deviation 2 S-bits
581 * RLP - remote line loop open
583 ISAC_WRITE(I_WTR_CONF2
, 0);
585 /* MODED: Mode Register:
586 * MDSx - transparent mode 0
587 * TMD - timer mode = external
588 * RAC - Receiver enabled
589 * DIMx - digital i/f mode
591 ISAC_WRITE(I_WMODED
, ISACSX_MODED_MDS2
|ISACSX_MODED_MDS1
|ISACSX_MODED_RAC
|ISACSX_MODED_DIM0
);
593 /* enabled interrupts:
594 * ===================
595 * RME - receive message end
596 * RPF - receive pool full
597 * RPO - receive pool overflow
598 * XPR - transmit pool ready
599 * XMR - transmit message repeat
600 * XDU - transmit data underrun
603 isacsx_imaskd
= ISACSX_MASKD_LOW
;
604 ISAC_WRITE(I_MASKD
, isacsx_imaskd
);
606 /* enabled interrupts:
607 * ===================
608 * ICD - HDLC interrupt from D-channel
609 * CIC - C/I channel change
612 isacsx_imask
= ~(ISACSX_MASK_ICD
| ISACSX_MASK_CIC
);
614 ISAC_WRITE(I_MASK
, isacsx_imask
);
619 /*---------------------------------------------------------------------------*
620 * L1 ISACSX disable interrupts
621 *---------------------------------------------------------------------------*/
623 isic_isacsx_disable_intr(struct isic_softc
*sc
)
625 ISAC_WRITE(I_WMODED
, ISACSX_MODED_MDS2
|ISACSX_MODED_MDS1
|ISACSX_MODED_DIM0
);
626 isacsx_imaskd
= 0xff; /* disable all irqs */
627 isacsx_imask
= 0xff; /* disable all irqs */
629 ISAC_WRITE(I_MASKD
, isacsx_imaskd
);
630 ISAC_WRITE(I_MASK
, isacsx_imask
);
633 /*---------------------------------------------------------------------------*
634 * ISACSX recover - try to recover from irq lockup
635 *---------------------------------------------------------------------------*/
637 isic_isacsx_recover(struct isic_softc
*sc
)
644 * Leo: Unknown if this function does anything good... At least it
645 * prints some stuff that might be helpful.
648 printf("%s: isic_isacsx_recover\n", device_xname(&sc
->sc_dev
));
649 /* get isac irq status */
651 byte
= ISAC_READ(I_ISTAD
);
653 NDBGL1(L1_ERROR
, " ISAC: ISTAD = 0x%x", byte
);
655 if(byte
& ISACSX_ISTA_ICD
) {
656 istad
= ISAC_READ(I_ISTAD
);
657 NDBGL1(L1_ERROR
, " ISACSX: istad = 0x%02x", istad
);
660 if(byte
& ISACSX_ISTA_CIC
)
662 byte
= ISAC_READ(I_CIR0
);
664 NDBGL1(L1_ERROR
, " ISACSX: CIR0 = 0x%x", byte
);
667 NDBGL1(L1_ERROR
, " ISACSX: IMASKD/IMASK = 0x%02x/%02x", isacsx_imaskd
,
670 ISAC_WRITE(I_MASKD
, 0xff);
671 ISAC_WRITE(I_MASK
, 0xff);
673 ISAC_WRITE(I_MASKD
, isacsx_imaskd
);
674 ISAC_WRITE(I_MASK
, isacsx_imask
);