/*---------------------------------------------------------------------------* * isic_recovery - try to recover from irq lockup *---------------------------------------------------------------------------*/ void isic_recover(struct isic_softc *sc) { u_char byte; /* get hscx irq status from hscx b ista */ byte = HSCX_READ(HSCX_CH_B, H_ISTA); NDBGL1(L1_ERROR, "HSCX B: ISTA = 0x%x", byte); if(byte & HSCX_ISTA_ICA) NDBGL1(L1_ERROR, "HSCX A: ISTA = 0x%x", (u_char)HSCX_READ(HSCX_CH_A, H_ISTA)); if(byte & HSCX_ISTA_EXB) NDBGL1(L1_ERROR, "HSCX B: EXIR = 0x%x", (u_char)HSCX_READ(HSCX_CH_B, H_EXIR)); if(byte & HSCX_ISTA_EXA) NDBGL1(L1_ERROR, "HSCX A: EXIR = 0x%x", (u_char)HSCX_READ(HSCX_CH_A, H_EXIR)); /* get isac irq status */ byte = ISAC_READ(I_ISTA); NDBGL1(L1_ERROR, " ISAC: ISTA = 0x%x", byte); if(byte & ISAC_ISTA_EXI) NDBGL1(L1_ERROR, " ISAC: EXIR = 0x%x", (u_char)ISAC_READ(I_EXIR)); if(byte & ISAC_ISTA_CISQ) { byte = ISAC_READ(I_CIRR); NDBGL1(L1_ERROR, " ISAC: CISQ = 0x%x", byte); if(byte & ISAC_CIRR_SQC) NDBGL1(L1_ERROR, " ISAC: SQRR = 0x%x", (u_char)ISAC_READ(I_SQRR)); } NDBGL1(L1_ERROR, "HSCX B: IMASK = 0x%x", HSCX_B_IMASK); NDBGL1(L1_ERROR, "HSCX A: IMASK = 0x%x", HSCX_A_IMASK); HSCX_WRITE(0, H_MASK, 0xff); HSCX_WRITE(1, H_MASK, 0xff); DELAY(100); HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); DELAY(100); NDBGL1(L1_ERROR, " ISAC: IMASK = 0x%x", ISAC_IMASK); ISAC_WRITE(I_MASK, 0xff); DELAY(100); ISAC_WRITE(I_MASK, ISAC_IMASK); }
/*---------------------------------------------------------------------------* * ISACSX recover - try to recover from irq lockup *---------------------------------------------------------------------------*/ void isic_isacsx_recover(struct isic_softc *sc) { u_char byte, istad; /* * XXX * Leo: Unknown if this function does anything good... At least it * prints some stuff that might be helpful. */ printf("%s: isic_isacsx_recover\n", device_xname(&sc->sc_dev)); /* get isac irq status */ byte = ISAC_READ(I_ISTAD); NDBGL1(L1_ERROR, " ISAC: ISTAD = 0x%x", byte); if(byte & ISACSX_ISTA_ICD) { istad = ISAC_READ(I_ISTAD); NDBGL1(L1_ERROR, " ISACSX: istad = 0x%02x", istad); } if(byte & ISACSX_ISTA_CIC) { byte = ISAC_READ(I_CIR0); NDBGL1(L1_ERROR, " ISACSX: CIR0 = 0x%x", byte); } NDBGL1(L1_ERROR, " ISACSX: IMASKD/IMASK = 0x%02x/%02x", isacsx_imaskd, isacsx_imask); ISAC_WRITE(I_MASKD, 0xff); ISAC_WRITE(I_MASK, 0xff); DELAY(100); ISAC_WRITE(I_MASKD, isacsx_imaskd); ISAC_WRITE(I_MASK, isacsx_imask); }
void avm_pnp_intr(int unit) { struct isic_softc *sc; u_char stat; register u_char isac_irq_stat; int was_isac = 0; sc = &isic_sc[unit]; for(;;) { stat = inb(sc->sc_port + STAT0_OFFSET); DBGL1(L1_H_IRQ, "avm_pnp_intr", ("stat %x\n", stat)); /* was there an interrupt from this card ? */ if ((stat & ASL_IRQ_Pending) == ASL_IRQ_Pending) break; /* no */ /* interrupts are low active */ if (!(stat & ASL_IRQ_TIMER)) DBGL1(L1_H_IRQ, "avm_pnp_intr", ("timer interrupt ???\n")); if (!(stat & ASL_IRQ_ISAC)) { DBGL1(L1_H_IRQ, "avm_pnp_intr", ("ISAC\n")); isac_irq_stat = ISAC_READ(I_ISTA); isic_isac_irq(sc, isac_irq_stat); was_isac = 1; } if (!(stat & ASL_IRQ_HSCX)) { DBGL1(L1_H_IRQ, "avm_pnp_intr", ("HSCX\n")); avm_pnp_hscx_int_handler(sc); } } if (was_isac) { ISAC_WRITE(0x20, 0xFF); ISAC_WRITE(0x20, 0x0); } }
/*---------------------------------------------------------------------------* * ISACSX interrupt service routine *---------------------------------------------------------------------------*/ void isic_isacsx_irq(struct isic_softc *sc, int ista) { register u_char c = 0; register u_char istad = 0; NDBGL1(L1_F_MSG, "%s: ista = 0x%02x", device_xname(&sc->sc_dev), ista); /* was it an HDLC interrupt ? */ if (ista & ISACSX_ISTA_ICD) { istad = ISAC_READ(I_ISTAD); NDBGL1(L1_F_MSG, "%s: istad = 0x%02x", device_xname(&sc->sc_dev), istad); if(istad & (ISACSX_ISTAD_RFO|ISACSX_ISTAD_XMR|ISACSX_ISTAD_XDU)) { /* not really EXIR, but very similar */ c |= isic_isacsx_exir_hdlr(sc, istad); } } if(istad & ISACSX_ISTAD_RME) /* receive message end */ { register int rest; u_char rsta; /* get rx status register */ rsta = ISAC_READ(I_RSTAD); /* Check for Frame and CRC valid */ if((rsta & ISACSX_RSTAD_MASK) != (ISACSX_RSTAD_VFR|ISACSX_RSTAD_CRC)) { int error = 0; if(!(rsta & ISACSX_RSTAD_VFR)) /* VFR error */ { error++; NDBGL1(L1_I_ERR, "%s: Frame not valid error", device_xname(&sc->sc_dev)); } if(!(rsta & ISACSX_RSTAD_CRC)) /* CRC error */ { error++; NDBGL1(L1_I_ERR, "%s: CRC error", device_xname(&sc->sc_dev)); } if(rsta & ISACSX_RSTAD_RDO) /* ReceiveDataOverflow */ { error++; NDBGL1(L1_I_ERR, "%s: Data Overrun error", device_xname(&sc->sc_dev)); } if(rsta & ISACSX_RSTAD_RAB) /* ReceiveABorted */ { error++; NDBGL1(L1_I_ERR, "%s: Receive Aborted error", device_xname(&sc->sc_dev)); } if(error == 0) NDBGL1(L1_I_ERR, "%s: RME unknown error, RSTAD = 0x%02x!", device_xname(&sc->sc_dev), rsta); i4b_Dfreembuf(sc->sc_ibuf); c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; ISAC_WRITE(I_CMDRD, ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES); return; } rest = (ISAC_READ(I_RBCLD) & (ISACSX_FIFO_LEN-1)); if(rest == 0) rest = ISACSX_FIFO_LEN; if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) sc->sc_ib = sc->sc_ibuf->m_data; else panic("isic_isacsx_irq: RME, i4b_Dgetmbuf returns NULL!\n"); sc->sc_ilen = 0; } if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest)) { ISAC_RDFIFO(sc->sc_ib, rest); /* the last byte contains status, strip it */ sc->sc_ilen += rest - 1; sc->sc_ibuf->m_pkthdr.len = sc->sc_ibuf->m_len = sc->sc_ilen; if(sc->sc_trace & TRACE_D_RX) { i4b_trace_hdr hdr; memset(&hdr, 0, sizeof hdr); hdr.type = TRC_CH_D; hdr.dir = FROM_NT; hdr.count = ++sc->sc_trace_dcount; isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); } c |= ISACSX_CMDRD_RMC; if(sc->sc_intr_valid == ISIC_INTR_VALID && (((struct isdn_l3_driver*)sc->sc_l3token)->protocol != PROTOCOL_D64S)) { isdn_layer2_data_ind(&sc->sc_l2, sc->sc_l3token, sc->sc_ibuf); } else { i4b_Dfreembuf(sc->sc_ibuf); } } else { NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES; } sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; } if(istad & ISACSX_ISTAD_RPF) /* receive fifo full */ { if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) sc->sc_ib= sc->sc_ibuf->m_data; else panic("isic_isacsx_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); sc->sc_ilen = 0; } if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISACSX_FIFO_LEN)) { ISAC_RDFIFO(sc->sc_ib, ISACSX_FIFO_LEN); sc->sc_ilen += ISACSX_FIFO_LEN; sc->sc_ib += ISACSX_FIFO_LEN; c |= ISACSX_CMDRD_RMC; } else { NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES; } } if(istad & ISACSX_ISTAD_XPR) /* transmit fifo empty (XPR bit set) */ { if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) { sc->sc_freeflag = sc->sc_freeflag2; sc->sc_obuf = sc->sc_obuf2; sc->sc_op = sc->sc_obuf->m_data; sc->sc_ol = sc->sc_obuf->m_len; sc->sc_obuf2 = NULL; #ifdef NOTDEF printf("ob2=%x, op=%x, ol=%d, f=%d #", sc->sc_obuf, sc->sc_op, sc->sc_ol, sc->sc_state); #endif } else { #ifdef NOTDEF printf("ob=%x, op=%x, ol=%d, f=%d #", sc->sc_obuf, sc->sc_op, sc->sc_ol, sc->sc_state); #endif } if(sc->sc_obuf) { ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISACSX_FIFO_LEN)); if(sc->sc_ol > ISACSX_FIFO_LEN) /* length > 32 ? */ { sc->sc_op += ISACSX_FIFO_LEN; /* bufferptr+32 */ sc->sc_ol -= ISACSX_FIFO_LEN; /* length - 32 */ c |= ISACSX_CMDRD_XTF; /* set XTF bit */ } else { if(sc->sc_freeflag) { i4b_Dfreembuf(sc->sc_obuf); sc->sc_freeflag = 0; } sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; c |= ISACSX_CMDRD_XTF | ISACSX_CMDRD_XME; } } else { sc->sc_state &= ~ISAC_TX_ACTIVE; } } if(ista & ISACSX_ISTA_CIC) /* channel status change CISQ */ { register u_char ci; /* get command/indication rx register*/ ci = ISAC_READ(I_CIR0); /* C/I code change IRQ (flag already cleared by CIR0 read) */ if(ci & ISACSX_CIR0_CIC0) isic_isacsx_ind_hdlr(sc, (ci >> 4) & 0xf); } if(c) { ISAC_WRITE(I_CMDRD, c); } }
static int isicattach(int flags, struct isic_softc *sc) { int ret = 0; const char *drvid; #ifdef __FreeBSD__ struct isic_softc *sc = &l1_sc[dev->id_unit]; #define PARM dev #define PARM2 dev, iobase2 #define FLAGS dev->id_flags #elif defined(__bsdi__) struct isic_softc *sc = device_private(self); #define PARM parent, self, ia #define PARM2 parent, self, ia #define FLAGS sc->sc_flags #else #define PARM sc #define PARM2 sc #define FLAGS flags #endif /* __FreeBSD__ */ static const char *ISACversion[] = { "2085 Version A1/A2 or 2086/2186 Version 1.1", "2085 Version B1", "2085 Version B2", "2085 Version V2.3 (B3)", "Unknown Version" }; static const char *HSCXversion[] = { "82525 Version A1", "Unknown (0x01)", "82525 Version A2", "Unknown (0x03)", "82525 Version A3", "82525 or 21525 Version 2.1", "Unknown Version" }; /* card dependent setup */ switch(FLAGS) { #ifdef ISICISA_DYNALINK #if defined(__bsdi__) || defined(__FreeBSD__) case FLAG_DYNALINK: ret = isic_attach_Dyn(PARM2); break; #endif #endif #ifdef ISICISA_TEL_S0_8 case FLAG_TELES_S0_8: ret = isic_attach_s08(PARM); break; #endif #ifdef ISICISA_TEL_S0_16 case FLAG_TELES_S0_16: ret = isic_attach_s016(PARM); break; #endif #ifdef ISICISA_TEL_S0_16_3 case FLAG_TELES_S0_163: ret = isic_attach_s0163(PARM); break; #endif #ifdef ISICISA_AVM_A1 case FLAG_AVM_A1: ret = isic_attach_avma1(PARM); break; #endif #ifdef ISICISA_USR_STI case FLAG_USR_ISDN_TA_INT: ret = isic_attach_usrtai(PARM); break; #endif #ifdef ISICISA_ITKIX1 case FLAG_ITK_IX1: ret = isic_attach_itkix1(PARM); break; #endif #ifdef ISICISA_ELSA_PCC16 case FLAG_ELSA_PCC16: ret = isic_attach_Eqs1pi(dev, 0); break; #endif #ifdef amiga case FLAG_BLMASTER: ret = 1; /* full detection was done in caller */ break; #endif /* ====================================================================== * Only P&P cards follow below!!! */ #ifdef __FreeBSD__ /* we've already splitted all non-ISA stuff out of this ISA specific part for the other OS */ #ifdef AVM_A1_PCMCIA case FLAG_AVM_A1_PCMCIA: ret = isic_attach_fritzpcmcia(PARM); break; #endif #ifdef TEL_S0_16_3_P case FLAG_TELES_S0_163_PnP: ret = isic_attach_s0163P(PARM2); break; #endif #ifdef CRTX_S0_P case FLAG_CREATIX_S0_PnP: ret = isic_attach_Cs0P(PARM2); break; #endif #ifdef DRN_NGO case FLAG_DRN_NGO: ret = isic_attach_drnngo(PARM2); break; #endif #ifdef SEDLBAUER case FLAG_SWS: ret = isic_attach_sws(PARM); break; #endif #ifdef ELSA_QS1ISA case FLAG_ELSA_QS1P_ISA: ret = isic_attach_Eqs1pi(PARM2); break; #endif #ifdef AVM_PNP case FLAG_AVM_PNP: ret = isic_attach_avm_pnp(PARM2); ret = 0; break; #endif #ifdef SIEMENS_ISURF2 case FLAG_SIEMENS_ISURF2: ret = isic_attach_siemens_isurf(PARM2); break; #endif #ifdef ASUSCOM_IPAC case FLAG_ASUSCOM_IPAC: ret = isic_attach_asi(PARM2); break; #endif #endif /* __FreeBSD__ / P&P specific part */ default: break; } if(ret == 0) return(0); if(sc->sc_ipac) { sc->sc_ipac_version = IPAC_READ(IPAC_ID); switch(sc->sc_ipac_version) { case IPAC_V11: case IPAC_V12: break; default: aprint_error_dev(sc->sc_dev, "Error, IPAC version %d unknown!\n", ret); return(0); break; } } else { sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; switch(sc->sc_isac_version) { case ISAC_VA: case ISAC_VB1: case ISAC_VB2: case ISAC_VB3: break; default: printf(ISIC_FMT "Error, ISAC version %d unknown!\n", ISIC_PARM, sc->sc_isac_version); return(0); break; } sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; switch(sc->sc_hscx_version) { case HSCX_VA1: case HSCX_VA2: case HSCX_VA3: case HSCX_V21: break; default: printf(ISIC_FMT "Error, HSCX version %d unknown!\n", ISIC_PARM, sc->sc_hscx_version); return(0); break; } } sc->sc_intr_valid = ISIC_INTR_DISABLED; /* HSCX setup */ isic_bchannel_setup(sc, HSCX_CH_A, BPROT_NONE, 0); isic_bchannel_setup(sc, HSCX_CH_B, BPROT_NONE, 0); /* setup linktab */ isic_init_linktab(sc); /* set trace level */ sc->sc_trace = TRACE_OFF; sc->sc_state = ISAC_IDLE; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; sc->sc_freeflag = 0; sc->sc_obuf2 = NULL; sc->sc_freeflag2 = 0; #if defined(__FreeBSD__) && __FreeBSD__ >=3 callout_handle_init(&sc->sc_T3_callout); callout_handle_init(&sc->sc_T4_callout); #endif #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 callout_init(&sc->sc_T3_callout, 0); callout_init(&sc->sc_T4_callout, 0); #endif /* announce manufacturer and card type */ switch(FLAGS) { case FLAG_TELES_S0_8: drvid = "Teles S0/8 or Niccy 1008"; break; case FLAG_TELES_S0_16: drvid = "Teles S0/16, Creatix ISDN S0-16 or Niccy 1016"; break; case FLAG_TELES_S0_163: drvid = "Teles S0/16.3"; break; case FLAG_AVM_A1: drvid = "AVM A1 or AVM Fritz!Card"; break; case FLAG_AVM_A1_PCMCIA: drvid = "AVM PCMCIA Fritz!Card"; break; case FLAG_TELES_S0_163_PnP: drvid = "Teles S0/PnP"; break; case FLAG_CREATIX_S0_PnP: drvid = "Creatix ISDN S0-16 P&P"; break; case FLAG_USR_ISDN_TA_INT: drvid = "USRobotics Sportster ISDN TA intern"; break; case FLAG_DRN_NGO: drvid = "Dr. Neuhaus NICCY Go@"; break; case FLAG_DYNALINK: drvid = "Dynalink IS64PH"; break; case FLAG_SWS: drvid = "Sedlbauer WinSpeed"; break; case FLAG_BLMASTER: /* board announcement was done by caller */ drvid = (char *)0; break; case FLAG_ELSA_QS1P_ISA: drvid = "ELSA QuickStep 1000pro (ISA)"; break; case FLAG_ITK_IX1: drvid = "ITK ix1 micro"; break; case FLAG_ELSA_PCC16: drvid = "ELSA PCC-16"; break; case FLAG_ASUSCOM_IPAC: drvid = "Asuscom ISDNlink 128K PnP"; break; case FLAG_SIEMENS_ISURF2: drvid = "Siemens I-Surf 2.0"; break; default: drvid = "ERROR, unknown flag used"; break; } #ifndef __FreeBSD__ printf("\n"); #endif if (drvid) printf(ISIC_FMT "%s\n", ISIC_PARM, drvid); /* announce chip versions */ if(sc->sc_ipac) { if(sc->sc_ipac_version == IPAC_V11) printf(ISIC_FMT "IPAC PSB2115 Version 1.1\n", ISIC_PARM); else printf(ISIC_FMT "IPAC PSB2115 Version 1.2\n", ISIC_PARM); } else { if(sc->sc_isac_version >= ISAC_UNKN) { printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, ISIC_PARM, sc->sc_isac_version); sc->sc_isac_version = ISAC_UNKN; } else { printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, ISIC_PARM, ISACversion[sc->sc_isac_version], sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); } #ifdef __FreeBSD__ printf("(Addr=0x%lx)\n", (u_long)ISAC_BASE); #endif if(sc->sc_hscx_version >= HSCX_UNKN) { printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, ISIC_PARM, sc->sc_hscx_version); sc->sc_hscx_version = HSCX_UNKN; } else { printf(ISIC_FMT "HSCX %s" TERMFMT, ISIC_PARM, HSCXversion[sc->sc_hscx_version]); } #ifdef __FreeBSD__ printf("(AddrA=0x%lx, AddrB=0x%lx)\n", (u_long)HSCX_A_BASE, (u_long)HSCX_B_BASE); #endif /* __FreeBSD__ */ } #ifdef __FreeBSD__ next_isic_unit++; #if defined(__FreeBSD_version) && __FreeBSD_version >= 300003 /* set the interrupt handler - no need to change isa_device.h */ dev->id_intr = (inthand2_t *)isicintr; #endif #endif /* __FreeBSD__ */ /* init higher protocol layers */ isic_attach_bri(sc, drvid, &isic_std_driver); return(1); #undef PARM #undef FLAGS }
/*---------------------------------------------------------------------------* * ISAC interrupt service routine *---------------------------------------------------------------------------*/ void isic_isac_irq(struct isic_softc *sc, int ista) { register u_char c = 0; NDBGL1(L1_F_MSG, "%s: ista = 0x%02x", device_xname(&sc->sc_dev), ista); if(ista & ISAC_ISTA_EXI) /* extended interrupt */ { u_int8_t exirstat = ISAC_READ(I_EXIR); if (sc->sc_intr_valid == ISIC_INTR_VALID) c |= isic_isac_exir_hdlr(sc, exirstat); } if(ista & ISAC_ISTA_RME) /* receive message end */ { register int rest; u_char rsta; /* get rx status register */ rsta = ISAC_READ(I_RSTA); if((rsta & ISAC_RSTA_MASK) != 0x20) { int error = 0; if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ { error++; NDBGL1(L1_I_ERR, "%s: CRC error", device_xname(&sc->sc_dev)); } if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ { error++; NDBGL1(L1_I_ERR, "%s: Data Overrun error", device_xname(&sc->sc_dev)); } if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ { error++; NDBGL1(L1_I_ERR, "%s: Receive Aborted error", device_xname(&sc->sc_dev)); } if(error == 0) { NDBGL1(L1_I_ERR, "%s: RME unknown error, RSTA = 0x%02x!", device_xname(&sc->sc_dev), rsta); } i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); ISACCMDRWRDELAY(); return; } rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); if(rest == 0) rest = ISAC_FIFO_LEN; if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) sc->sc_ib = sc->sc_ibuf->m_data; else panic("isic_isac_irq: RME, i4b_Dgetmbuf returns NULL!"); sc->sc_ilen = 0; } if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest)) { ISAC_RDFIFO(sc->sc_ib, rest); sc->sc_ilen += rest; sc->sc_ibuf->m_pkthdr.len = sc->sc_ibuf->m_len = sc->sc_ilen; if(sc->sc_trace & TRACE_D_RX) { i4b_trace_hdr hdr; memset(&hdr, 0, sizeof hdr); hdr.type = TRC_CH_D; hdr.dir = FROM_NT; hdr.count = ++sc->sc_trace_dcount; isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); } c |= ISAC_CMDR_RMC; if(sc->sc_intr_valid == ISIC_INTR_VALID && (((struct isdn_l3_driver*)sc->sc_l3token)->protocol != PROTOCOL_D64S)) { isdn_layer2_data_ind(&sc->sc_l2, sc->sc_l3token, sc->sc_ibuf); } else { i4b_Dfreembuf(sc->sc_ibuf); } } else { NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; } if(ista & ISAC_ISTA_RPF) /* receive fifo full */ { if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) sc->sc_ib= sc->sc_ibuf->m_data; else panic("isic_isac_irq: RPF, i4b_Dgetmbuf returns NULL!"); sc->sc_ilen = 0; } if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) { ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); sc->sc_ilen += ISAC_FIFO_LEN; sc->sc_ib += ISAC_FIFO_LEN; c |= ISAC_CMDR_RMC; } else { NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } } if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ { if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) { sc->sc_freeflag = sc->sc_freeflag2; sc->sc_obuf = sc->sc_obuf2; sc->sc_op = sc->sc_obuf->m_data; sc->sc_ol = sc->sc_obuf->m_len; sc->sc_obuf2 = NULL; #ifdef NOTDEF printf("ob2=%x, op=%x, ol=%d, f=%d #", sc->sc_obuf, sc->sc_op, sc->sc_ol, sc->sc_state); #endif } else { #ifdef NOTDEF printf("ob=%x, op=%x, ol=%d, f=%d #", sc->sc_obuf, sc->sc_op, sc->sc_ol, sc->sc_state); #endif } if(sc->sc_obuf) { ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN)); if(sc->sc_ol > ISAC_FIFO_LEN) /* length > 32 ? */ { sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */ sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */ c |= ISAC_CMDR_XTF; /* set XTF bit */ } else { if(sc->sc_freeflag) { i4b_Dfreembuf(sc->sc_obuf); sc->sc_freeflag = 0; } sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; c |= ISAC_CMDR_XTF | ISAC_CMDR_XME; } } else { sc->sc_state &= ~ISAC_TX_ACTIVE; } } if(ista & ISAC_ISTA_CISQ) /* channel status change CISQ */ { register u_char ci; /* get command/indication rx register*/ ci = ISAC_READ(I_CIRR); /* if S/Q IRQ, read SQC reg to clr SQC IRQ */ if(ci & ISAC_CIRR_SQC) (void) ISAC_READ(I_SQRR); /* C/I code change IRQ (flag already cleared by CIRR read) */ if(ci & ISAC_CIRR_CIC0) isic_isac_ind_hdlr(sc, (ci >> 2) & 0xf); } if(c) { ISAC_WRITE(I_CMDR, c); ISACCMDRWRDELAY(); } }
/*---------------------------------------------------------------------------* * isic_attach_avm_pnp - attach Fritz!Card PnP *---------------------------------------------------------------------------*/ int isic_attach_avm_pnp(struct isa_device *dev, unsigned int iobase2) { struct isic_softc *sc; u_int v; int unit; unit = dev->id_unit; sc = &isic_sc[unit]; /* this thing doesn't have an HSCX, so fake the base addresses */ /* put the unit number into the lower byte - HACK */ HSCX_A_BASE = (caddr_t)(HSCX0FAKE + unit); HSCX_B_BASE = (caddr_t)(HSCX1FAKE + unit); /* reset the card */ /* the Linux driver does this to clear any pending ISAC interrupts */ v = 0; v = ISAC_READ(I_STAR); v = ISAC_READ(I_MODE); v = ISAC_READ(I_ADF2); v = ISAC_READ(I_ISTA); if (v & ISAC_ISTA_EXI) { v = ISAC_READ(I_EXIR); } v = ISAC_READ(I_CIRR); ISAC_WRITE(I_MASK, 0xff); /* the Linux driver does this to clear any pending HSCX interrupts */ v = hscx_read_reg(0, HSCX_STAT, sc); v = hscx_read_reg(0, HSCX_STAT+1, sc); v = hscx_read_reg(0, HSCX_STAT+2, sc); v = hscx_read_reg(0, HSCX_STAT+3, sc); v = hscx_read_reg(1, HSCX_STAT, sc); v = hscx_read_reg(1, HSCX_STAT+1, sc); v = hscx_read_reg(1, HSCX_STAT+2, sc); v = hscx_read_reg(1, HSCX_STAT+3, sc); outb(sc->sc_port + STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE); DELAY(SEC_DELAY/100); /* 10 ms */ outb(sc->sc_port + STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE); DELAY(SEC_DELAY/100); /* 10 ms */ outb(sc->sc_port + STAT1_OFFSET, ASL1_ENABLE_IOM+(ffs(sc->sc_irq)-1)); DELAY(SEC_DELAY/100); /* 10 ms */ printf("isic%d: ISAC %s (IOM-%c)\n", unit, "2085 Version A1/A2 or 2086/2186 Version 1.1", sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); /* init the ISAC */ isic_isac_init(sc); /* init the "HSCX" */ avm_pnp_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); avm_pnp_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); /* can't use the normal B-Channel stuff */ avm_pnp_init_linktab(sc); /* set trace level */ sc->sc_trace = TRACE_OFF; sc->sc_state = ISAC_IDLE; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; sc->sc_freeflag = 0; sc->sc_obuf2 = NULL; sc->sc_freeflag2 = 0; #if defined(__FreeBSD__) && __FreeBSD__ >=3 callout_handle_init(&sc->sc_T3_callout); callout_handle_init(&sc->sc_T4_callout); #endif /* init higher protocol layers */ MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); return(0); }
int isicattach(int flags, struct isic_softc *sc) #endif /* __FreeBSD__ */ { int ret = 0; char *drvid; #ifdef __FreeBSD__ struct isic_softc *sc = &isic_sc[dev->id_unit]; #define PARM dev #define PARM2 dev, iobase2 #define FLAGS dev->id_flags #else #define PARM sc #define PARM2 sc #define FLAGS flags #endif static char *ISACversion[] = { "2085 Version A1/A2 or 2086/2186 Version 1.1", "2085 Version B1", "2085 Version B2", "2085 Version V2.3 (B3)", "Unknown Version" }; static char *HSCXversion[] = { "82525 Version A1", "Unknown (0x01)", "82525 Version A2", "Unknown (0x03)", "82525 Version A3", "82525 or 21525 Version 2.1", "Unknown Version" }; /* done in bus specific attach code for other OS */ #ifdef __FreeBSD__ if(dev->id_unit != next_isic_unit) { printf("isicattach: Error: new unit (%d) != next_isic_unit (%d)!\n", dev->id_unit, next_isic_unit); return(0); } sc->sc_unit = dev->id_unit; #else isic_sc[sc->sc_unit] = sc; #endif /* card dependent setup */ switch(FLAGS) { #ifdef DYNALINK case FLAG_DYNALINK: ret = isic_attach_Dyn(PARM2); break; #endif #ifdef TEL_S0_8 case FLAG_TELES_S0_8: ret = isic_attach_s08(PARM); break; #endif #ifdef TEL_S0_16 case FLAG_TELES_S0_16: ret = isic_attach_s016(PARM); break; #endif #ifdef TEL_S0_16_3 case FLAG_TELES_S0_163: ret = isic_attach_s0163(PARM); break; #endif #ifdef AVM_A1 case FLAG_AVM_A1: ret = isic_attach_avma1(PARM); break; #endif #ifdef USR_STI case FLAG_USR_ISDN_TA_INT: ret = isic_attach_usrtai(PARM); break; #endif #ifdef ITKIX1 case FLAG_ITK_IX1: ret = isic_attach_itkix1(PARM); break; #endif /* ====================================================================== * Only P&P cards follow below!!! */ #ifdef __FreeBSD__ /* we've already splitted all non-ISA stuff out of this ISA specific part for the other OS */ #ifdef AVM_PCMCIA case FLAG_AVM_A1_PCMCIA: ret = isic_attach_fritzpcmcia(PARM); break; #endif #ifndef __FreeBSD__ #ifdef TEL_S0_16_3_P case FLAG_TELES_S0_163_PnP: ret = isic_attach_s0163P(PARM2); break; #endif #endif #ifdef CRTX_S0_P case FLAG_CREATIX_S0_PnP: ret = isic_attach_Cs0P(PARM2); break; #endif #ifdef DRN_NGO case FLAG_DRN_NGO: ret = isic_attach_drnngo(PARM2); break; #endif #ifdef SEDLBAUER case FLAG_SWS: ret = isic_attach_sws(PARM); break; #endif #ifdef ELSA_QS1ISA case FLAG_ELSA_QS1P_ISA: ret = isic_attach_Eqs1pi(PARM2); break; #endif #endif /* __FreeBSD__ / P&P specific part */ /* --- XXX - don't know how to handle this - should be removed!!!! ---- */ #ifdef amiga case FLAG_BLMASTER: ret = 1; /* full detection was done in caller */ break; #endif /* ------------------------------------------------------------------- */ default: break; } if(ret == 0) return(0); sc->sc_isac_version = 0; sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; switch(sc->sc_isac_version) { case ISAC_VA: case ISAC_VB1: case ISAC_VB2: case ISAC_VB3: break; default: printf(ISIC_FMT "Error, ISAC version %d unknown!\n", ISIC_PARM, sc->sc_isac_version); return(0); break; } sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; switch(sc->sc_hscx_version) { case HSCX_VA1: case HSCX_VA2: case HSCX_VA3: case HSCX_V21: break; default: printf(ISIC_FMT "Error, HSCX version %d unknown!\n", ISIC_PARM, sc->sc_hscx_version); return(0); break; }; /* ISAC setup */ isic_isac_init(sc); /* HSCX setup */ isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); /* setup linktab */ isic_init_linktab(sc); /* set trace level */ sc->sc_trace = TRACE_OFF; sc->sc_state = ISAC_IDLE; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; sc->sc_freeflag = 0; sc->sc_obuf2 = NULL; sc->sc_freeflag2 = 0; #if defined(__FreeBSD__) && __FreeBSD__ >=3 callout_handle_init(&sc->sc_T3_callout); callout_handle_init(&sc->sc_T4_callout); #endif /* init higher protocol layers */ MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); /* announce manufacturer and card type */ switch(FLAGS) { case FLAG_TELES_S0_8: drvid = "Teles S0/8 or Niccy 1008"; break; case FLAG_TELES_S0_16: drvid = "Teles S0/16, Creatix ISDN S0-16 or Niccy 1016"; break; case FLAG_TELES_S0_163: drvid = "Teles S0/16.3"; break; case FLAG_AVM_A1: drvid = "AVM A1 or AVM Fritz!Card"; break; case FLAG_AVM_A1_PCMCIA: drvid = "AVM PCMCIA Fritz!Card"; break; case FLAG_TELES_S0_163_PnP: drvid = "Teles S0/PnP"; break; case FLAG_CREATIX_S0_PnP: drvid = "Creatix ISDN S0-16 P&P"; break; case FLAG_USR_ISDN_TA_INT: drvid = "USRobotics Sportster ISDN TA intern"; break; case FLAG_DRN_NGO: drvid = "Dr. Neuhaus NICCY Go@"; break; case FLAG_DYNALINK: drvid = "Dynalink IS64PH"; break; case FLAG_SWS: drvid = "Sedlbauer WinSpeed"; break; case FLAG_BLMASTER: /* board announcement was done by caller */ drvid = (char *)0; break; case FLAG_ELSA_QS1P_ISA: drvid = "ELSA QuickStep 1000pro (ISA)"; break; case FLAG_ITK_IX1: drvid = "ITK ix1 micro"; break; default: drvid = "ERROR, unknown flag used"; break; } #ifndef __FreeBSD__ printf("\n"); #endif if (drvid) printf(ISIC_FMT "%s\n", ISIC_PARM, drvid); /* announce chip versions */ if(sc->sc_isac_version >= ISAC_UNKN) { printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, ISIC_PARM, sc->sc_isac_version); sc->sc_isac_version = ISAC_UNKN; } else { printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, ISIC_PARM, ISACversion[sc->sc_isac_version], sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); } #ifdef __FreeBSD__ printf("(Addr=0x%lx)\n", (u_long)ISAC_BASE); #endif if(sc->sc_hscx_version >= HSCX_UNKN) { printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, ISIC_PARM, sc->sc_hscx_version); sc->sc_hscx_version = HSCX_UNKN; } else { printf(ISIC_FMT "HSCX %s" TERMFMT, ISIC_PARM, HSCXversion[sc->sc_hscx_version]); } #ifdef __FreeBSD__ printf("(AddrA=0x%lx, AddrB=0x%lx)\n", (u_long)HSCX_A_BASE, (u_long)HSCX_B_BASE); next_isic_unit++; #if defined(__FreeBSD_version) && __FreeBSD_version >= 300003 /* set the interrupt handler - no need to change isa_device.h */ dev->id_intr = (inthand2_t *)isicintr; #endif #endif /* __FreeBSD__ */ return(1); #undef PARM #undef FLAGS }
/*---------------------------------------------------------------------------* * isic - device driver interrupt routine *---------------------------------------------------------------------------*/ void isicintr(struct l1_softc *sc) { if(sc->sc_ipac == 0) /* HSCX/ISAC interupt routine */ { u_char was_hscx_irq = 0; u_char was_isac_irq = 0; register u_char hscx_irq_stat; register u_char isac_irq_stat; for(;;) { /* get hscx irq status from hscx b ista */ hscx_irq_stat = HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK; /* get isac irq status */ isac_irq_stat = ISAC_READ(I_ISTA); /* do as long as there are pending irqs in the chips */ if(!hscx_irq_stat && !isac_irq_stat) break; if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF | HSCX_ISTA_RSC | HSCX_ISTA_XPR | HSCX_ISTA_TIN | HSCX_ISTA_EXB)) { isic_hscx_irq(sc, hscx_irq_stat, HSCX_CH_B, hscx_irq_stat & HSCX_ISTA_EXB); was_hscx_irq = 1; } if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA)) { isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK, HSCX_CH_A, hscx_irq_stat & HSCX_ISTA_EXA); was_hscx_irq = 1; } if(isac_irq_stat) { isic_isac_irq(sc, isac_irq_stat); /* isac handler */ was_isac_irq = 1; } } HSCX_WRITE(0, H_MASK, 0xff); ISAC_WRITE(I_MASK, 0xff); HSCX_WRITE(1, H_MASK, 0xff); #ifdef ELSA_QS1ISA DELAY(80); if((sc->sc_cardtyp == CARD_TYPEP_ELSAQS1ISA) && (sc->clearirq)) { sc->clearirq(sc); } #else DELAY(100); #endif HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); ISAC_WRITE(I_MASK, ISAC_IMASK); HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); } else /* IPAC interrupt routine */ { register u_char ipac_irq_stat; register u_char was_ipac_irq = 0; for(;;) { /* get global irq status */ ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f; /* check hscx a */ if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA)) { /* HSCX A interrupt */ isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA), HSCX_CH_A, ipac_irq_stat & IPAC_ISTA_EXA); was_ipac_irq = 1; } if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB)) { /* HSCX B interrupt */ isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA), HSCX_CH_B, ipac_irq_stat & IPAC_ISTA_EXB); was_ipac_irq = 1; } if(ipac_irq_stat & IPAC_ISTA_ICD) { /* ISAC interrupt */ isic_isac_irq(sc, ISAC_READ(I_ISTA)); was_ipac_irq = 1; } if(ipac_irq_stat & IPAC_ISTA_EXD) { /* force ISAC interrupt handling */ isic_isac_irq(sc, ISAC_ISTA_EXI); was_ipac_irq = 1; } /* do as long as there are pending irqs in the chip */ if(!ipac_irq_stat) break; } IPAC_WRITE(IPAC_MASK, 0xff); DELAY(50); IPAC_WRITE(IPAC_MASK, 0xc0); } }
/*---------------------------------------------------------------------------* * isic_attach_common - common attach routine for all busses *---------------------------------------------------------------------------*/ int isic_attach_common(device_t dev) { char *drvid = NULL; int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; sc->sc_unit = unit; sc->sc_isac_version = 0; sc->sc_hscx_version = 0; if(sc->sc_ipac) { sc->sc_ipac_version = IPAC_READ(IPAC_ID); switch(sc->sc_ipac_version) { case IPAC_V11: case IPAC_V12: break; default: printf("isic%d: Error, IPAC version %d unknown!\n", unit, sc->sc_ipac_version); return(0); break; } } else { sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; switch(sc->sc_isac_version) { case ISAC_VA: case ISAC_VB1: case ISAC_VB2: case ISAC_VB3: break; default: printf("isic%d: Error, ISAC version %d unknown!\n", unit, sc->sc_isac_version); return ENXIO; break; } sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; switch(sc->sc_hscx_version) { case HSCX_VA1: case HSCX_VA2: case HSCX_VA3: case HSCX_V21: break; default: printf("isic%d: Error, HSCX version %d unknown!\n", unit, sc->sc_hscx_version); return ENXIO; break; } } isic_isac_init(sc); /* ISAC setup */ /* HSCX setup */ isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); isic_init_linktab(sc); /* setup linktab */ sc->sc_trace = TRACE_OFF; /* set trace level */ sc->sc_state = ISAC_IDLE; /* set state */ sc->sc_ibuf = NULL; /* input buffering */ sc->sc_ib = NULL; sc->sc_ilen = 0; sc->sc_obuf = NULL; /* output buffering */ sc->sc_op = NULL; sc->sc_ol = 0; sc->sc_freeflag = 0; sc->sc_obuf2 = NULL; /* second output buffer */ sc->sc_freeflag2 = 0; /* timer setup */ callout_handle_init(&sc->sc_T3_callout); callout_handle_init(&sc->sc_T4_callout); /* init higher protocol layers */ i4b_l1_mph_status_ind(L0ISICUNIT(sc->sc_unit), STI_ATTACH, sc->sc_cardtyp, &isic_l1mux_func); /* announce manufacturer and card type for ISA cards */ switch(sc->sc_cardtyp) { case CARD_TYPEP_8: drvid = "Teles S0/8 (or compatible)"; break; case CARD_TYPEP_16: drvid = "Teles S0/16 (or compatible)"; break; case CARD_TYPEP_16_3: drvid = "Teles S0/16.3"; break; case CARD_TYPEP_AVMA1: drvid = "AVM A1 or Fritz!Card Classic"; break; case CARD_TYPEP_PCFRITZ: drvid = "AVM Fritz!Card PCMCIA"; break; case CARD_TYPEP_USRTA: drvid = "USRobotics Sportster ISDN TA intern"; break; case CARD_TYPEP_ITKIX1: drvid = "ITK ix1 micro"; break; case CARD_TYPEP_PCC16: drvid = "ELSA MicroLink ISDN/PCC-16"; break; default: drvid = NULL; /* pnp/pci cards announce themselves */ break; } if(drvid) printf("isic%d: %s\n", unit, drvid); if(bootverbose) { /* announce chip versions */ if(sc->sc_ipac) { if(sc->sc_ipac_version == IPAC_V11) printf("isic%d: IPAC PSB2115 Version 1.1\n", unit); else printf("isic%d: IPAC PSB2115 Version 1.2\n", unit); } else { printf("isic%d: ISAC %s (IOM-%c)\n", unit, ISACversion[sc->sc_isac_version], sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); printf("isic%d: HSCX %s\n", unit, HSCXversion[sc->sc_hscx_version]); } } return 0; }
/*---------------------------------------------------------------------------* * ISAC interrupt service routine *---------------------------------------------------------------------------*/ void ifpnp_isac_irq(struct l1_softc *sc, int ista) { u_char c = 0; NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista); if(ista & ISAC_ISTA_EXI) /* extended interrupt */ { c |= ifpnp_isac_exir_hdlr(sc, ISAC_READ(I_EXIR)); } if(ista & ISAC_ISTA_RME) /* receive message end */ { int rest; u_char rsta; /* get rx status register */ rsta = ISAC_READ(I_RSTA); if((rsta & ISAC_RSTA_MASK) != 0x20) { int error = 0; if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ { error++; NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit); } if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ { error++; NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit); } if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ { error++; NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit); } if(error == 0) NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); ISACCMDRWRDELAY(); return; } rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); if(rest == 0) rest = ISAC_FIFO_LEN; if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) sc->sc_ib = sc->sc_ibuf->m_data; else panic("ifpnp_isac_irq: RME, i4b_Dgetmbuf returns NULL!\n"); sc->sc_ilen = 0; } if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest)) { ISAC_RDFIFO(sc->sc_ib, rest); sc->sc_ilen += rest; sc->sc_ibuf->m_pkthdr.len = sc->sc_ibuf->m_len = sc->sc_ilen; if(sc->sc_trace & TRACE_D_RX) { i4b_trace_hdr_t hdr; hdr.unit = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_D; hdr.dir = FROM_NT; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); } c |= ISAC_CMDR_RMC; if(sc->sc_enabled && (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)) { i4b_l1_ph_data_ind(L0IFPNPUNIT(sc->sc_unit), sc->sc_ibuf); } else { i4b_Dfreembuf(sc->sc_ibuf); } } else { NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; } if(ista & ISAC_ISTA_RPF) /* receive fifo full */ { if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) sc->sc_ib= sc->sc_ibuf->m_data; else panic("ifpnp_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); sc->sc_ilen = 0; } if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) { ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); sc->sc_ilen += ISAC_FIFO_LEN; sc->sc_ib += ISAC_FIFO_LEN; c |= ISAC_CMDR_RMC; } else { NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } } if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ { if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) { sc->sc_freeflag = sc->sc_freeflag2; sc->sc_obuf = sc->sc_obuf2; sc->sc_op = sc->sc_obuf->m_data; sc->sc_ol = sc->sc_obuf->m_len; sc->sc_obuf2 = NULL; #ifdef NOTDEF kprintf("ob2=%x, op=%x, ol=%d, f=%d #", sc->sc_obuf, sc->sc_op, sc->sc_ol, sc->sc_state); #endif } else { #ifdef NOTDEF kprintf("ob=%x, op=%x, ol=%d, f=%d #", sc->sc_obuf, sc->sc_op, sc->sc_ol, sc->sc_state); #endif } if(sc->sc_obuf) { ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN)); if(sc->sc_ol > ISAC_FIFO_LEN) /* length > 32 ? */ { sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */ sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */ c |= ISAC_CMDR_XTF; /* set XTF bit */ } else { if(sc->sc_freeflag) { i4b_Dfreembuf(sc->sc_obuf); sc->sc_freeflag = 0; } sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; c |= ISAC_CMDR_XTF | ISAC_CMDR_XME; } } else { sc->sc_state &= ~ISAC_TX_ACTIVE; } } if(ista & ISAC_ISTA_CISQ) /* channel status change CISQ */ { u_char ci; /* get command/indication rx register*/ ci = ISAC_READ(I_CIRR); /* if S/Q IRQ, read SQC reg to clr SQC IRQ */ if(ci & ISAC_CIRR_SQC) ISAC_READ(I_SQRR); /* C/I code change IRQ (flag already cleared by CIRR read) */ if(ci & ISAC_CIRR_CIC0) ifpnp_isac_ind_hdlr(sc, (ci >> 2) & 0xf); }
static void isic_isapnp_attach(device_t parent, device_t self, void *aux) { static const char *ISACversion[] = { "2085 Version A1/A2 or 2086/2186 Version 1.1", "2085 Version B1", "2085 Version B2", "2085 Version V2.3 (B3)", "Unknown Version" }; static const char *HSCXversion[] = { "82525 Version A1", "Unknown (0x01)", "82525 Version A2", "Unknown (0x03)", "82525 Version A3", "82525 or 21525 Version 2.1", "Unknown Version" }; struct isic_softc *sc = device_private(self); struct isapnp_attach_args *ipa = aux; const struct isic_isapnp_card_desc *desc = isic_isapnp_descriptions; int i; sc->sc_dev = self; if (isapnp_config(ipa->ipa_iot, ipa->ipa_memt, ipa)) { aprint_error_dev(sc->sc_dev, "error in region allocation\n"); return; } for (i = 0; i < NUM_DESCRIPTIONS; i++, desc++) if (strcmp(ipa->ipa_devlogic, desc->devlogic) == 0) break; if (i >= NUM_DESCRIPTIONS) panic("could not identify isic PnP device"); /* setup parameters */ sc->sc_cardtyp = desc->card_type; sc->sc_irq = ipa->ipa_irq[0].num; desc->allocmaps(ipa, sc); /* announce card name */ printf(": %s\n", desc->name); /* establish interrupt handler */ if (isa_intr_establish(ipa->ipa_ic, ipa->ipa_irq[0].num, ipa->ipa_irq[0].type, IPL_NET, isicintr, sc) == NULL) aprint_error_dev(sc->sc_dev, "couldn't establish interrupt handler\n"); /* init card */ desc->attach(sc); /* announce chip versions */ sc->sc_isac_version = 0; sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; switch (sc->sc_isac_version) { case ISAC_VA: case ISAC_VB1: case ISAC_VB2: case ISAC_VB3: break; default: aprint_error(ISIC_FMT "Error, ISAC version %d unknown!\n", ISIC_PARM, sc->sc_isac_version); return; break; } sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; switch (sc->sc_hscx_version) { case HSCX_VA1: case HSCX_VA2: case HSCX_VA3: case HSCX_V21: break; default: aprint_error(ISIC_FMT "Error, HSCX version %d unknown!\n", ISIC_PARM, sc->sc_hscx_version); return; break; }; sc->sc_intr_valid = ISIC_INTR_DISABLED; /* HSCX setup */ isic_bchannel_setup(sc, HSCX_CH_A, BPROT_NONE, 0); isic_bchannel_setup(sc, HSCX_CH_B, BPROT_NONE, 0); /* setup linktab */ isic_init_linktab(sc); /* set trace level */ sc->sc_trace = TRACE_OFF; sc->sc_state = ISAC_IDLE; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; sc->sc_freeflag = 0; sc->sc_obuf2 = NULL; sc->sc_freeflag2 = 0; #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 callout_init(&sc->sc_T3_callout, 0); callout_init(&sc->sc_T4_callout, 0); #endif /* announce chip versions */ if (sc->sc_isac_version >= ISAC_UNKN) { aprint_error(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, ISIC_PARM, sc->sc_isac_version); sc->sc_isac_version = ISAC_UNKN; } else { aprint_error(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, ISIC_PARM, ISACversion[sc->sc_isac_version], sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); } if (sc->sc_hscx_version >= HSCX_UNKN) { aprint_error(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, ISIC_PARM, sc->sc_hscx_version); sc->sc_hscx_version = HSCX_UNKN; } else { aprint_error(ISIC_FMT "HSCX %s" TERMFMT, ISIC_PARM, HSCXversion[sc->sc_hscx_version]); } /* init higher protocol layers and save l2 handle */ isic_attach_bri(sc, desc->name, &isic_std_driver); }
/*---------------------------------------------------------------------------* * isic - device driver interrupt routine *---------------------------------------------------------------------------*/ int isicintr(void *arg) { struct isic_softc *sc = arg; /* could this be an interrupt for us? */ if (sc->sc_intr_valid == ISIC_INTR_DYING) return 0; /* do not touch removed hardware */ if(sc->sc_ipac == 0) /* HSCX/ISAC interupt routine */ { u_char was_hscx_irq = 0; u_char was_isac_irq = 0; register u_char hscx_irq_stat; register u_char isac_irq_stat; for(;;) { /* get hscx irq status from hscx b ista */ hscx_irq_stat = HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK; /* get isac irq status */ isac_irq_stat = ISAC_READ(I_ISTA); /* do as long as there are pending irqs in the chips */ if(!hscx_irq_stat && !isac_irq_stat) break; if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF | HSCX_ISTA_RSC | HSCX_ISTA_XPR | HSCX_ISTA_TIN | HSCX_ISTA_EXB)) { isic_hscx_irq(sc, hscx_irq_stat, HSCX_CH_B, hscx_irq_stat & HSCX_ISTA_EXB); was_hscx_irq = 1; } if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA)) { isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK, HSCX_CH_A, hscx_irq_stat & HSCX_ISTA_EXA); was_hscx_irq = 1; } if(isac_irq_stat) { /* isac handler */ isic_isac_irq(sc, isac_irq_stat); was_isac_irq = 1; } } HSCX_WRITE(0, H_MASK, 0xff); ISAC_WRITE(I_MASK, 0xff); HSCX_WRITE(1, H_MASK, 0xff); if (sc->clearirq) { DELAY(80); sc->clearirq(sc); } else DELAY(100); HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); ISAC_WRITE(I_MASK, ISAC_IMASK); HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); return(was_hscx_irq || was_isac_irq); } else /* IPAC interrupt routine */ { register u_char ipac_irq_stat; register u_char was_ipac_irq = 0; for(;;) { /* get global irq status */ ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f; /* check hscx a */ if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA)) { /* HSCX A interrupt */ isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA), HSCX_CH_A, ipac_irq_stat & IPAC_ISTA_EXA); was_ipac_irq = 1; } if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB)) { /* HSCX B interrupt */ isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA), HSCX_CH_B, ipac_irq_stat & IPAC_ISTA_EXB); was_ipac_irq = 1; } if(ipac_irq_stat & IPAC_ISTA_ICD) { /* ISAC interrupt, Obey ISAC-IPAC differences */ u_int8_t isac_ista = ISAC_READ(I_ISTA); if (isac_ista & 0xfe) isic_isac_irq(sc, isac_ista & 0xfe); if (isac_ista & 0x01) /* unexpected */ printf("%s: unexpected ipac timer2 irq\n", sc->sc_dev.dv_xname); was_ipac_irq = 1; } if(ipac_irq_stat & IPAC_ISTA_EXD) { /* ISAC EXI interrupt */ isic_isac_irq(sc, ISAC_ISTA_EXI); was_ipac_irq = 1; } /* do as long as there are pending irqs in the chip */ if(!ipac_irq_stat) break; } #if 0 /* * This seems not to be necessary on IPACs - no idea why * it is here - but due to limit range of test cards, leave * it in for now, in case we have to resurrect it. */ IPAC_WRITE(IPAC_MASK, 0xff); DELAY(50); IPAC_WRITE(IPAC_MASK, 0xc0); #endif return(was_ipac_irq); } }