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 }
/*---------------------------------------------------------------------------* * 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; }
/*---------------------------------------------------------------------------* * 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 - 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); } }