summaryrefslogtreecommitdiffstats
path: root/sys/pccard/pcic_isa.c
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2001-05-19 05:21:23 +0000
committerimp <imp@FreeBSD.org>2001-05-19 05:21:23 +0000
commit19cf17e66bdb51d13bab00923578bca0d84b1767 (patch)
treec45081f7289aa2f5035db43efd349436e770e919 /sys/pccard/pcic_isa.c
parent26885aebf5fdd5705ba9e5442caf61b733234219 (diff)
downloadFreeBSD-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.c215
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
OpenPOWER on IntegriCloud