diff options
author | imp <imp@FreeBSD.org> | 2001-05-19 05:21:23 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2001-05-19 05:21:23 +0000 |
commit | 19cf17e66bdb51d13bab00923578bca0d84b1767 (patch) | |
tree | c45081f7289aa2f5035db43efd349436e770e919 /sys/pccard/pcic_isa.c | |
parent | 26885aebf5fdd5705ba9e5442caf61b733234219 (diff) | |
download | FreeBSD-src-19cf17e66bdb51d13bab00923578bca0d84b1767.zip FreeBSD-src-19cf17e66bdb51d13bab00923578bca0d84b1767.tar.gz |
Move ISA specific code into pcic_isa. This is the probe routine, the
get/setb1 routines. Also expose clrb and setb as pcic_{clrb,setb} so
we can use it from the probe. pcic_probe is no longer needed.
Diffstat (limited to 'sys/pccard/pcic_isa.c')
-rw-r--r-- | sys/pccard/pcic_isa.c | 215 |
1 files changed, 214 insertions, 1 deletions
diff --git a/sys/pccard/pcic_isa.c b/sys/pccard/pcic_isa.c index 46a3cb9..130e670 100644 --- a/sys/pccard/pcic_isa.c +++ b/sys/pccard/pcic_isa.c @@ -53,9 +53,58 @@ static struct isa_pnp_id pcic_ids[] = { {0} }; +static char *bridges[] = +{ + "Intel i82365SL-A/B", + "IBM PCIC", + "VLSI 82C146", + "Cirrus logic 672x", + "Cirrus logic 6710", + "Vadem 365", + "Vadem 465", + "Vadem 468", + "Vadem 469", + "Ricoh RF5C396", + "IBM KING PCMCIA Controller", + "Intel i82365SL-DF" +}; + +/* + * Read a register from the PCIC. + */ +static unsigned char +getb1(struct pcic_slot *sp, int reg) +{ + outb(sp->index, sp->offset + reg); + return (inb(sp->data)); +} + +/* + * Write a register on the PCIC + */ +static void +putb1(struct pcic_slot *sp, int reg, unsigned char val) +{ + outb(sp->index, sp->offset + reg); + outb(sp->data, val); +} + +/* + * Look for an Intel PCIC (or compatible). + * For each available slot, allocate a PC-CARD slot. + */ static int pcic_isa_probe(device_t dev) { + int slotnum, validslots = 0; + struct pcic_slot *sp; + struct pcic_slot *sp0; + struct pcic_slot *sp1; + struct pcic_slot spsave; + unsigned char c; + struct resource *r; + int rid; + struct pcic_softc *sc; int error; /* Check isapnp ids */ @@ -63,7 +112,171 @@ pcic_isa_probe(device_t dev) if (error == ENXIO) return (ENXIO); - return (pcic_probe(dev)); + if (bus_get_resource_start(dev, SYS_RES_IOPORT, 0) == 0) + bus_set_resource(dev, SYS_RES_IOPORT, 0, PCIC_INDEX0, 2); + rid = 0; + r = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); + if (!r) { + if (bootverbose) + device_printf(dev, "Cannot get I/O range\n"); + return (ENOMEM); + } + + sc = (struct pcic_softc *) device_get_softc(dev); + sc->unit = device_get_unit(dev); + sp = &sc->slots[0]; + for (slotnum = 0; slotnum < PCIC_CARD_SLOTS; slotnum++, sp++) { + /* + * Initialise the PCIC slot table. + */ + sp->getb = getb1; + sp->putb = putb1; + sp->index = rman_get_start(r); + sp->data = sp->index + 1; + sp->offset = slotnum * PCIC_SLOT_SIZE; + sp->controller = -1; + } + + /* + * Prescan for the broken VLSI chips. + * + * According to the Linux PCMCIA code from David Hinds, + * working chipsets return 0x84 from their (correct) ID ports, + * while the broken ones would need to be probed at the new + * offset we set after we assume it's broken. + * + * Note: because of this, we may incorrectly detect a single + * slot vlsi chip as a i82365sl step D. I cannot find a + * datasheet for the affected chip, so that's the best we can + * do for now. + */ + sp0 = &sc->slots[0]; + sp1 = &sc->slots[1]; + if (sp0->getb(sp0, PCIC_ID_REV) == PCIC_VLSI82C146 && + sp1->getb(sp1, PCIC_ID_REV) != PCIC_VLSI82C146) { + spsave = *sp1; + sp1->index += 4; + sp1->data += 4; + sp1->offset = PCIC_SLOT_SIZE << 1; + if (sp1->getb(sp1, PCIC_ID_REV) != PCIC_VLSI82C146) { + *sp1 = spsave; + } else { + sp0->controller = PCIC_VLSI; + sp1->controller = PCIC_VLSI; + } + } + + /* + * Look for normal chipsets here. + */ + sp = &sc->slots[0]; + for (slotnum = 0; slotnum < PCIC_CARD_SLOTS; slotnum++, sp++) { + /* + * see if there's a PCMCIA controller here + * Intel PCMCIA controllers use 0x82 and 0x83 + * IBM clone chips use 0x88 and 0x89, apparently + */ + c = sp->getb(sp, PCIC_ID_REV); + sp->revision = -1; + switch(c) { + /* + * 82365 or clones. + */ + case PCIC_INTEL0: + case PCIC_INTEL1: + sp->controller = PCIC_I82365; + sp->revision = c & 1; + /* + * Now check for VADEM chips. + */ + outb(sp->index, 0x0E); /* Unlock VADEM's extra regs */ + outb(sp->index, 0x37); + pcic_setb(sp, PCIC_VMISC, PCIC_VADEMREV); + c = sp->getb(sp, PCIC_ID_REV); + if (c & 0x08) { + switch (sp->revision = c & 7) { + case 1: + sp->controller = PCIC_VG365; + break; + case 2: + sp->controller = PCIC_VG465; + break; + case 3: + sp->controller = PCIC_VG468; + break; + default: + sp->controller = PCIC_VG469; + break; + } + pcic_clrb(sp, PCIC_VMISC, PCIC_VADEMREV); + } + + /* + * Check for RICOH RF5C396 PCMCIA Controller + */ + c = sp->getb(sp, 0x3a); + if (c == 0xb2) { + sp->controller = PCIC_RF5C396; + } + + break; + /* + * Intel i82365D or maybe a vlsi 82c146 + * we detected the vlsi case earlier, so if the controller + * isn't set, we know it is a i82365sl step D. + */ + case PCIC_INTEL2: + if (sp->controller == -1) + sp->controller = PCIC_I82365SL_DF; + break; + case PCIC_IBM1: + case PCIC_IBM2: + sp->controller = PCIC_IBM; + sp->revision = c & 1; + break; + case PCIC_IBM3: + sp->controller = PCIC_IBM_KING; + sp->revision = c & 1; + break; + default: + continue; + } + /* + * Check for Cirrus logic chips. + */ + sp->putb(sp, PCIC_CLCHIP, 0); + c = sp->getb(sp, PCIC_CLCHIP); + if ((c & PCIC_CLC_TOGGLE) == PCIC_CLC_TOGGLE) { + c = sp->getb(sp, PCIC_CLCHIP); + if ((c & PCIC_CLC_TOGGLE) == 0) { + if (c & PCIC_CLC_DUAL) + sp->controller = PCIC_PD672X; + else + sp->controller = PCIC_PD6710; + sp->revision = 8 - ((c & 0x1F) >> 2); + } + } + device_set_desc(dev, bridges[(int) sp->controller]); + /* + * OK it seems we have a PCIC or lookalike. + * Allocate a slot and initialise the data structures. + */ + validslots++; + sp->slt = (struct slot *) 1; + /* + * Modem cards send the speaker audio (dialing noises) + * to the host's speaker. Cirrus Logic PCIC chips must + * enable this. There is also a Low Power Dynamic Mode bit + * that claims to reduce power consumption by 30%, so + * enable it and hope for the best. + */ + if (sp->controller == PCIC_PD672X) { + pcic_setb(sp, PCIC_MISC1, PCIC_MISC1_SPEAKER); + pcic_setb(sp, PCIC_MISC2, PCIC_LPDM_EN); + } + } + bus_release_resource(dev, SYS_RES_IOPORT, rid, r); + return (validslots ? 0 : ENXIO); } static int |