summaryrefslogtreecommitdiffstats
path: root/sys/pccard
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2001-03-19 07:10:38 +0000
committerimp <imp@FreeBSD.org>2001-03-19 07:10:38 +0000
commit9083f0a44ebf5f1a671d0db189ec7624fe49d158 (patch)
treec0710dc3715f0f339526b1db802481b7c3f3cab2 /sys/pccard
parentdcd5bf93d5b1cbb72c98dae3773924bc9c19d231 (diff)
downloadFreeBSD-src-9083f0a44ebf5f1a671d0db189ec7624fe49d158.zip
FreeBSD-src-9083f0a44ebf5f1a671d0db189ec7624fe49d158.tar.gz
Lots of minor cleanup, plus a couple of interesting things.
o Attempt to disable the slot when we detect that there are problems with it in our ISR. This should make polling mode work better for more cards, but more work may be needed. This "disabling" sets the card interrupt register to 0. This worked for me for lots of tests in polling mode. o Now that I've found datasheets, fix a boatload of magic numbers in the source to make it easier to understand. o Use a table of names rather than a big case statement. o Cull a few of the "unused" controller types that we map to other times that were a vestiage of PAO code that we never merged in the same way. o Enforce legal IRQs. You are no longer allowed to try to use IRQs that will fail on all known ISA/PCI <-> PCMCIA bridges. The bridges do not have pins for these illegal interrupts, and all of them are listed as reserved and/or illegeal in the datasheets depending on which one you look at. o Add comments about how IBM-AT based computers and NEC PC-98 based computers map these interrupts and which ones are valid. o Always clear the bit that steers the management interrupt either to the value listed in the PCIC_STAT_INT register. I've seen this bit get set on suspend/resume and after windows boot, and it does't hurt to clear it. NOTE: this might mean we can share this interrupt in the future.
Diffstat (limited to 'sys/pccard')
-rw-r--r--sys/pccard/i82365.h77
-rw-r--r--sys/pccard/pcic.c152
-rw-r--r--sys/pccard/slot.h2
3 files changed, 137 insertions, 94 deletions
diff --git a/sys/pccard/i82365.h b/sys/pccard/i82365.h
index f3012ef..20b2c09 100644
--- a/sys/pccard/i82365.h
+++ b/sys/pccard/i82365.h
@@ -38,17 +38,17 @@
#define PCIC_I82365 0 /* Intel chip */
#define PCIC_IBM 1 /* IBM clone */
#define PCIC_VLSI 2 /* VLSI chip */
-#define PCIC_PD672X 3 /* Cirrus logic 627x */
+#define PCIC_PD672X 3 /* Cirrus logic 672x */
#define PCIC_PD6710 4 /* Cirrus logic 6710 */
-#define PCIC_CL6729 5 /* Cirrus logic 6729 */
-#define PCIC_VG365 6 /* Vadem 365 */
-#define PCIC_VG465 7 /* Vadem 465 */
-#define PCIC_VG468 8 /* Vadem 468 */
-#define PCIC_VG469 9 /* Vadem 469 */
-#define PCIC_RF5C396 10 /* Ricoh RF5C396 */
-#define PCIC_IBM_KING 11 /* IBM KING PCMCIA Controller */
-#define PCIC_PC98 12 /* NEC PC98 PCMCIA Controller */
-#define PCIC_TI1130 13 /* TI PCI1130 CardBus */
+#define PCIC_VG365 5 /* Vadem 365 */
+#define PCIC_VG465 6 /* Vadem 465 */
+#define PCIC_VG468 7 /* Vadem 468 */
+#define PCIC_VG469 8 /* Vadem 469 */
+#define PCIC_RF5C396 9 /* Ricoh RF5C396 */
+#define PCIC_IBM_KING 10 /* IBM KING PCMCIA Controller */
+/* These last two aren't in normal freebsd */
+#define PCIC_PC98 11 /* NEC PC98 PCMCIA Controller */
+#define PCIC_TI1130 12 /* TI PCI1130 CardBus */
/*
* Address of the controllers. Each controller can manage
@@ -84,6 +84,10 @@
#define PCIC_MISC1 0x16 /* PD672x: Misc control register 1 per slot */
#define PCIC_GLO_CTRL 0x1e /* Global Control Register */
#define PCIC_MISC2 0x1e /* PD672x: Misc control register 2 per chip */
+#define PCIC_CLCHIP 0x1f /* PD67xx: Chip I/D */
+#define PCIC_CVSR 0x2f /* Vadem: Voltage select register */
+
+#define PCIC_VMISC 0x3a /* Vadem: Misc control register */
#define PCIC_TIME_SETUP0 0x3a
#define PCIC_TIME_CMD0 0x3b
@@ -99,6 +103,7 @@
/* For Identification and Revision (PCIC_ID_REV) */
#define PCIC_INTEL0 0x82 /* Intel 82365SL Rev. 0; Both Memory and I/O */
#define PCIC_INTEL1 0x83 /* Intel 82365SL Rev. 1; Both Memory and I/O */
+#define PCIC_VLSI82C146 0x84 /* VLSI 82C146 */
#define PCIC_IBM1 0x88 /* IBM PCIC clone; Both Memory and I/O */
#define PCIC_IBM2 0x89 /* IBM PCIC clone; Both Memory and I/O */
#define PCIC_IBM3 0x8a /* IBM KING PCIC clone; Both Memory and I/O */
@@ -120,7 +125,7 @@
#define PCIC_VCC_5V 0x10 /* 5 volts */
#define PCIC_VCC_3V 0x18 /* 3 volts */
#define PCIC_VCC_5V_KING 0x14 /* 5 volts for KING PCIC */
-#define PCIC_VPP 0x0C /* Vpp control bits */
+#define PCIC_VPP 0x03 /* Vpp control bits */
#define PCIC_VPP_5V 0x01 /* 5 volts */
#define PCIC_VPP_12V 0x02 /* 12 volts */
@@ -204,24 +209,62 @@
#define PCIC_CDRES_EN 0x10 /* card detect resume enable */
#define PCIC_SW_CD_INT 0x20 /* s/w card detect interrupt */
-/* For Misc. Control Register 1 */
-#define PCIC_SPKR_EN 0x10 /* Cirrus PD672x: speaker enable */
+/* CL-PD67[12]x: For 3.3V cards, etc. (PCIC_MISC1) */
+#define PCIC_MISC1_5V_DETECT 0x01 /* PD6710 only */
+#define PCIC_MISC1_VCC_33 0x02 /* Set Vcc is 3.3V, else 5.0V */
+#define PCIC_MISC1_PMINT 0x04 /* Pulse management intr */
+#define PCIC_MISC1_PCINT 0x08 /* Pulse card interrupt */
+#define PCIC_MISC1_SPEAKER 0x10 /* Enable speaker */
+#define PCIC_MISC1_INPACK 0x80 /* INPACK throttles data */
-/* For Global Control register (PCIC_GLO_CTRL) */
+/* i82365B and newer (!PD67xx) Global Control register (PCIC_GLO_CTRL) */
#define PCIC_PWR_DOWN 0x01 /* power down */
#define PCIC_LVL_MODE 0x02 /* level mode interrupt enable */
#define PCIC_WB_CSCINT 0x04 /* explicit write-back csc intr */
+/* Rev B only */
#define PCIC_IRQ0_LEVEL 0x08 /* irq 14 pulse mode enable */
#define PCIC_IRQ1_LEVEL 0x10
-/* For Misc. Control Register 2 */
+/* CL-PD67[12]x: For Misc. Control Register 2 (PCIC_MISC2) */
#define PCIC_LPDM_EN 0x02 /* Cirrus PD672x: low power dynamic mode */
+/* CL-PD67[12]x: Chip info (PCIC_CLCHIP) */
+#define PCIC_CLC_TOGGLE 0xc0 /* These bits toggle 1 -> 0 */
+#define PCIC_CLC_DUAL 0x20 /* Single/dual socket version */
+
+/* Vadem: Card Voltage Select register (PCIC_CVSR) */
+#define PCIC_CVSR_VS 0x03 /* Voltage select */
+#define PCIC_CVSR_VS_5 0x00 /* 5.0 V */
+#define PCIC_CVSR_VS_33a 0x01 /* alt 3.3V */
+#define PCIC_CVSR_VS_XX 0x02 /* X.XV when available */
+#define PCIC_CVSR_VS_33 0x03 /* 3.3V */
+
+/* Vadem: misc register (PCIC_VMISC) */
+#define PCIC_VADEMREV 0x40
+
/*
* Mask of allowable interrupts.
- * Ints are 3,4,5,7,9,10,11,12,14,15
+ *
+ * For IBM-AT machines, irqs 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 are
+ * allowed. Nearly all IBM-AT machines with pcic cards or bridges
+ * wire these interrupts (or a subset thereof) to the corresponding
+ * pins on the ISA bus. Some older laptops are reported to not route
+ * all the interrupt pins to the bus because the designers knew that
+ * some would conflict with builtin devices.
+ *
+ * For NEC PC98 machines, irq 3, 5, 6, 9, 10, 11, 12, 13 are allowed.
+ * These correspond to the C-BUS signals INT 0, 1, 2, 3, 41, 42, 5, 6
+ * respectively. This is with the desktop C-BUS addin card. I don't
+ * know if this corresponds to laptop usage or not.
+ *
+ * I'm not sure the proper way to map these interrupts, but it looks
+ * like pc98 is a subset of ibm-at so no actual mapping is required.
*/
-#define PCIC_INT_MASK_ALLOWED 0xDEB8
+#ifdef PC98
+#define PCIC_INT_MASK_ALLOWED 0x3E68 /* PC98 */
+#else
+#define PCIC_INT_MASK_ALLOWED 0xDEB8 /* AT */
+#endif
#define PCIC_IO_WIN 2
#define PCIC_MEM_WIN 5
diff --git a/sys/pccard/pcic.c b/sys/pccard/pcic.c
index 8f1b624..3443ef6 100644
--- a/sys/pccard/pcic.c
+++ b/sys/pccard/pcic.c
@@ -55,7 +55,6 @@ static int pcic_power __P((struct slot *));
static timeout_t pcic_reset;
static void pcic_resume(struct slot *);
static void pcic_disable __P((struct slot *));
-static void pcic_mapirq __P((struct slot *, int));
static timeout_t pcictimeout;
static struct callout_handle pcictimeout_ch
= CALLOUT_HANDLE_INITIALIZER(&pcictimeout_ch);
@@ -97,6 +96,21 @@ static int validunits = 0;
#define GET_UNIT(d) *(int *)device_get_softc(d)
#define SET_UNIT(d,u) *(int *)device_get_softc(d) = (u)
+static char *bridges[] =
+{
+ "Intel i82365",
+ "IBM PCIC",
+ "VLSI 82C146",
+ "Cirrus logic 672x",
+ "Cirrus logic 6710",
+ "Vadem 365",
+ "Vadem 465",
+ "Vadem 468",
+ "Vadem 469",
+ "Ricoh RF5C396",
+ "IBM KING PCMCIA Controller"
+};
+
/*
* Internal inline functions for accessing the PCIC.
*/
@@ -281,7 +295,6 @@ pcic_probe(device_t dev)
struct slot *slt;
struct pcic_slot *sp;
unsigned char c;
- char *name;
int error;
struct resource *r;
int rid;
@@ -299,7 +312,6 @@ pcic_probe(device_t dev)
cinfo.mapio = pcic_io;
cinfo.ioctl = pcic_ioctl;
cinfo.power = pcic_power;
- cinfo.mapirq = pcic_mapirq;
cinfo.reset = pcic_reset;
cinfo.disable = pcic_disable;
cinfo.resume = pcic_resume;
@@ -333,7 +345,8 @@ pcic_probe(device_t dev)
* ones would need to be probed at the new offset we set after
* we assume it's broken.
*/
- if (slotnum == 1 && maybe_vlsi && sp->getb(sp, PCIC_ID_REV) != 0x84) {
+ if (slotnum == 1 && maybe_vlsi &&
+ sp->getb(sp, PCIC_ID_REV) != PCIC_VLSI82C146) {
sp->index += 4;
sp->data += 4;
sp->offset = PCIC_SLOT_SIZE << 1;
@@ -349,16 +362,16 @@ pcic_probe(device_t dev)
/*
* 82365 or clones.
*/
- case 0x82:
- case 0x83:
+ case PCIC_INTEL0:
+ case PCIC_INTEL1:
sp->controller = PCIC_I82365;
sp->revision = c & 1;
/*
* Now check for VADEM chips.
*/
- outb(sp->index, 0x0E);
+ outb(sp->index, 0x0E); /* Unlock VADEM's extra regs */
outb(sp->index, 0x37);
- setb(sp, 0x3A, 0x40);
+ setb(sp, PCIC_VMISC, PCIC_VADEMREV);
c = sp->getb(sp, PCIC_ID_REV);
if (c & 0x08) {
switch (sp->revision = c & 7) {
@@ -375,7 +388,7 @@ pcic_probe(device_t dev)
sp->controller = PCIC_VG469;
break;
}
- clrb(sp, 0x3A, 0x40);
+ clrb(sp, PCIC_VMISC, PCIC_VADEMREV);
}
/*
@@ -390,16 +403,16 @@ pcic_probe(device_t dev)
/*
* VLSI chips.
*/
- case 0x84:
+ case PCIC_VLSI82C146:
sp->controller = PCIC_VLSI;
maybe_vlsi = 1;
break;
- case 0x88:
- case 0x89:
+ case PCIC_IBM1:
+ case PCIC_IBM2:
sp->controller = PCIC_IBM;
sp->revision = c & 1;
break;
- case 0x8a:
+ case PCIC_IBM3:
sp->controller = PCIC_IBM_KING;
sp->revision = c & 1;
break;
@@ -409,57 +422,19 @@ pcic_probe(device_t dev)
/*
* Check for Cirrus logic chips.
*/
- sp->putb(sp, 0x1F, 0);
- c = sp->getb(sp, 0x1F);
- if ((c & 0xC0) == 0xC0) {
- c = sp->getb(sp, 0x1F);
- if ((c & 0xC0) == 0) {
- if (c & 0x20)
+ 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);
}
}
- switch(sp->controller) {
- case PCIC_I82365:
- name = "Intel i82365";
- break;
- case PCIC_IBM:
- name = "IBM PCIC";
- break;
- case PCIC_IBM_KING:
- name = "IBM KING PCMCIA Controller";
- break;
- case PCIC_PD672X:
- name = "Cirrus Logic PD672X";
- break;
- case PCIC_PD6710:
- name = "Cirrus Logic PD6710";
- break;
- case PCIC_VG365:
- name = "Vadem 365";
- break;
- case PCIC_VG465:
- name = "Vadem 465";
- break;
- case PCIC_VG468:
- name = "Vadem 468";
- break;
- case PCIC_VG469:
- name = "Vadem 469";
- break;
- case PCIC_RF5C396:
- name = "Ricoh RF5C396";
- break;
- case PCIC_VLSI:
- name = "VLSI 82C146";
- break;
- default:
- name = "Unknown!";
- break;
- }
- device_set_desc(dev, name);
+ 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.
@@ -479,7 +454,7 @@ pcic_probe(device_t dev)
* enable it and hope for the best.
*/
if (sp->controller == PCIC_PD672X) {
- setb(sp, PCIC_MISC1, PCIC_SPKR_EN);
+ setb(sp, PCIC_MISC1, PCIC_MISC1_SPEAKER);
setb(sp, PCIC_MISC2, PCIC_LPDM_EN);
}
}
@@ -487,6 +462,14 @@ pcic_probe(device_t dev)
return(validslots ? 0 : ENXIO);
}
+static void
+do_mgt_irq(struct pcic_slot *sp, int irq)
+{
+ /* Management IRQ changes */
+ clrb(sp, PCIC_INT_GEN, PCIC_INTR_ENA);
+ sp->putb(sp, PCIC_STAT_INT, (irq << 4) | 0xF);
+}
+
static int
pcic_attach(device_t dev)
{
@@ -521,9 +504,17 @@ pcic_attach(device_t dev)
}
rid = 0;
r = 0;
- if (irq >= 0) {
+ if (irq > 0) {
r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq,
- ~0, 1, RF_ACTIVE);
+ irq, 1, RF_ACTIVE);
+ }
+ if (r && ((1 << (rman_get_start(r))) & PCIC_INT_MASK_ALLOWED) == 0) {
+ device_printf(dev,
+ "Hardware does not support irq %d, trying polling.\n",
+ irq);
+ bus_release_resource(dev, SYS_RES_IRQ, rid, r);
+ r = 0;
+ irq = 0;
}
if (r) {
error = bus_setup_intr(dev, r, INTR_TYPE_MISC,
@@ -538,19 +529,20 @@ pcic_attach(device_t dev)
irq = 0;
}
if (irq == 0) {
- pcictimeout_ch = timeout(pcictimeout, (void *) GET_UNIT(dev), hz/2);
+ pcictimeout_ch = timeout(pcictimeout, (void *) GET_UNIT(dev),
+ hz/2);
device_printf(dev, "Polling mode\n");
}
sp = &pcic_slots[GET_UNIT(dev) * PCIC_CARD_SLOTS];
for (i = 0; i < PCIC_CARD_SLOTS; i++, sp++) {
- /* Assign IRQ */
- sp->putb(sp, PCIC_STAT_INT, (irq << 4) | 0xF);
+ if (sp->slt == NULL)
+ continue;
+
+ do_mgt_irq(sp, irq);
/* Check for changes */
setb(sp, PCIC_POWER, PCIC_PCPWRE| PCIC_DISRST);
- if (sp->slt == NULL)
- continue;
stat = sp->getb(sp, PCIC_STATUS);
if (bootverbose)
printf("stat is %x\n", stat);
@@ -612,6 +604,7 @@ pcic_power(struct slot *slt)
case PCIC_RF5C396:
case PCIC_VLSI:
case PCIC_IBM_KING:
+ case PCIC_I82365:
switch(slt->pwr.vpp) {
default:
return(EINVAL);
@@ -640,9 +633,9 @@ pcic_power(struct slot *slt)
(sp->controller == PCIC_VG469) ||
(sp->controller == PCIC_VG465) ||
(sp->controller == PCIC_VG365))
- setb(sp, 0x2f, 0x03) ;
+ setb(sp, PCIC_CVSR, PCIC_CVSR_VS);
else
- setb(sp, 0x16, 0x02);
+ setb(sp, PCIC_MISC1, PCIC_MISC1_VCC_33);
break;
case 50:
if (sp->controller == PCIC_IBM_KING) {
@@ -654,9 +647,9 @@ pcic_power(struct slot *slt)
(sp->controller == PCIC_VG469) ||
(sp->controller == PCIC_VG465) ||
(sp->controller == PCIC_VG365))
- clrb(sp, 0x2f, 0x03) ;
+ clrb(sp, PCIC_CVSR, PCIC_CVSR_VS);
else
- clrb(sp, 0x16, 0x02);
+ clrb(sp, PCIC_MISC1, PCIC_MISC1_VCC_33);
break;
}
break;
@@ -671,7 +664,7 @@ pcic_power(struct slot *slt)
/* Some chips are smarter than us it seems, so if we weren't
* allowed to use 5V, try 3.3 instead
*/
- if (!(sp->getb(sp, PCIC_STATUS) & 0x40) && slt->pwr.vcc == 50) {
+ if (!(sp->getb(sp, PCIC_STATUS) & PCIC_POW) && slt->pwr.vcc == 50) {
slt->pwr.vcc = 33;
slt->pwr.vpp = 0;
return (pcic_power(slt));
@@ -681,7 +674,8 @@ pcic_power(struct slot *slt)
/*
* tell the PCIC which irq we want to use. only the following are legal:
- * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15
+ * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15. We require the callers of this
+ * routine to do the check for legality.
*/
static void
pcic_mapirq(struct slot *slt, int irq)
@@ -690,7 +684,8 @@ pcic_mapirq(struct slot *slt, int irq)
if (irq == 0)
clrb(sp, PCIC_INT_GEN, 0xF);
else
- sp->putb(sp, PCIC_INT_GEN, (sp->getb(sp, PCIC_INT_GEN) & 0xF0) | irq);
+ sp->putb(sp, PCIC_INT_GEN,
+ (sp->getb(sp, PCIC_INT_GEN) & 0xF0) | irq);
}
/*
@@ -781,6 +776,7 @@ pcicintr(void *arg)
PCIC_CD) {
pccard_event(sp->slt, card_inserted);
} else {
+ pcic_disable(sp->slt);
pccard_event(sp->slt, card_removed);
}
}
@@ -797,9 +793,9 @@ pcic_resume(struct slot *slt)
{
struct pcic_slot *sp = slt->cdata;
- sp->putb(sp, PCIC_STAT_INT, (slt->irq << 4) | 0xF);
+ do_mgt_irq(sp, slt->irq);
if (sp->controller == PCIC_PD672X) {
- setb(sp, PCIC_MISC1, PCIC_SPKR_EN);
+ setb(sp, PCIC_MISC1, PCIC_MISC1_SPEAKER);
setb(sp, PCIC_MISC2, PCIC_LPDM_EN);
}
}
@@ -898,6 +894,12 @@ pcic_setup_intr(device_t dev, device_t child, struct resource *irq,
struct pccard_devinfo *devi = device_get_ivars(child);
int err;
+ if (((1 << rman_get_start(irq)) & PCIC_INT_MASK_ALLOWED) == 0) {
+ device_printf(dev, "Hardware does not support irq %ld.\n",
+ rman_get_start(irq));
+ return (EINVAL);
+ }
+
err = bus_generic_setup_intr(dev, child, irq, flags, intr, arg,
cookiep);
if (err == 0)
diff --git a/sys/pccard/slot.h b/sys/pccard/slot.h
index edd1400..f43122c 100644
--- a/sys/pccard/slot.h
+++ b/sys/pccard/slot.h
@@ -66,8 +66,6 @@ struct slot_ctrl {
/* Set power values */
int (*ioctl) __P((struct slot *, int, caddr_t));
/* ioctl to lower level */
- void (*mapirq) __P((struct slot *, int));
- /* Map interrupt number */
void (*resume) __P((struct slot *));
/* suspend/resume support */
int maxmem; /* Number of allowed memory windows */
OpenPOWER on IntegriCloud