summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/alpha/alpha/autoconf.c11
-rw-r--r--sys/amd64/amd64/autoconf.c17
-rw-r--r--sys/conf/files13
-rw-r--r--sys/conf/files.i3867
-rw-r--r--sys/dev/ata/ata-all.c13
-rw-r--r--sys/dev/pcm/isa/mss.c4
-rw-r--r--sys/dev/sio/sio.c21
-rw-r--r--sys/dev/sound/isa/mss.c4
-rw-r--r--sys/i386/conf/files.i3867
-rw-r--r--sys/i386/i386/autoconf.c17
-rw-r--r--sys/i386/i386/userconfig.c3
-rw-r--r--sys/i386/isa/isa_compat.h4
-rw-r--r--sys/isa/isa_common.c554
-rw-r--r--sys/isa/isa_common.h13
-rw-r--r--sys/isa/isa_if.m44
-rw-r--r--sys/isa/isavar.h68
-rw-r--r--sys/isa/pnp.c761
-rw-r--r--sys/isa/pnpreg.h (renamed from sys/isa/pnp.h)159
-rw-r--r--sys/isa/pnpvar.h57
-rw-r--r--sys/isa/sio.c21
20 files changed, 1597 insertions, 201 deletions
diff --git a/sys/alpha/alpha/autoconf.c b/sys/alpha/alpha/autoconf.c
index 4eafc4f..b0aa687 100644
--- a/sys/alpha/alpha/autoconf.c
+++ b/sys/alpha/alpha/autoconf.c
@@ -63,7 +63,12 @@ SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL)
static void configure_finish __P((void));
static void configure_start __P((void));
-device_t isa_bus_device = 0;
+#include "isa.h"
+#if NISA > 0
+#include <isa/isavar.h>
+device_t isa_bus_device = 0;
+#endif
+
struct cam_sim *boot_sim = 0;
extern int nfs_diskless_valid;
@@ -194,8 +199,10 @@ configure(void *dummy)
/*
* Probe ISA devices after everything.
*/
+#if NISA > 0
if (isa_bus_device)
- bus_generic_attach(isa_bus_device);
+ isa_probe_children(isa_bus_device);
+#endif
}
configure_finish();
diff --git a/sys/amd64/amd64/autoconf.c b/sys/amd64/amd64/autoconf.c
index 630bd05..5dbbedd 100644
--- a/sys/amd64/amd64/autoconf.c
+++ b/sys/amd64/amd64/autoconf.c
@@ -74,12 +74,8 @@
#include <i386/isa/icu.h>
#endif /* APIC_IO */
-#include "pnp.h"
-#if NPNP > 0
-#include <i386/isa/isa_device.h>
-#include <i386/isa/pnp.h>
-#endif
-
+#include "isa.h"
+#include <isa/isavar.h>
device_t isa_bus_device = 0;
static void configure_first __P((void *));
@@ -223,17 +219,14 @@ configure(dummy)
/* initialize new bus architecture */
root_bus_configure();
-#if NPNP > 0
- /* Activate PNP. If no drivers are found, let ISA probe them.. */
- pnp_configure();
-#endif
-
+#if NISA > 0
/*
* Explicitly probe and attach ISA last. The isa bus saves
* it's device node at attach time for us here.
*/
if (isa_bus_device)
- bus_generic_attach(isa_bus_device);
+ isa_probe_children(isa_bus_device);
+#endif
/*
* Now we're ready to handle (pending) interrupts.
diff --git a/sys/conf/files b/sys/conf/files
index 27bfc80..8aab83c 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -766,4 +766,17 @@ isa_if.h optional isa \
clean "isa_if.h"
isa/isa_common.c optional isa
isa/isahint.c optional isa
+isa/pnp.c optional pnp
isa/bt_isa.c optional bt isa
+dev/pcm/sound.c optional pcm
+dev/pcm/ac97.c optional pcm
+dev/pcm/dsp.c optional pcm
+dev/pcm/channel.c optional pcm
+dev/pcm/feeder.c optional pcm
+dev/pcm/fake.c optional pcm
+dev/pcm/mixer.c optional pcm
+dev/pcm/isa/mss.c optional pcm isa
+dev/pcm/isa/sb.c optional pcm isa
+dev/pcm/pci/es1370.c optional pcm pci
+dev/pcm/pci/t4dwave.c optional pcm pci
+dev/pcm/pci/aureal.c optional pcm pci
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index f55ae9e..1ec918c 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -234,7 +234,6 @@ i386/isa/pcvt/pcvt_kbd.c optional vt
i386/isa/pcvt/pcvt_out.c optional vt
i386/isa/pcvt/pcvt_sup.c optional vt
i386/isa/pcvt/pcvt_vtf.c optional vt
-i386/isa/pnp.c optional pnp
i386/isa/ppc.c optional ppc
i386/isa/prof_machdep.c optional profiling-routine
i386/isa/random_machdep.c standard
@@ -244,11 +243,6 @@ i386/isa/scd.c optional scd
i386/isa/si.c optional si
i386/isa/si2_z280.c optional si
i386/isa/si3_t225.c optional si
-i386/isa/snd/ad1848.c optional pcm
-i386/isa/snd/clones.c optional pcm
-i386/isa/snd/dmabuf.c optional pcm
-i386/isa/snd/sb_dsp.c optional pcm
-i386/isa/snd/sound.c optional pcm
i386/isa/sound/ad1848.c optional css
i386/isa/sound/ad1848.c optional gus
i386/isa/sound/ad1848.c optional gusxvi
@@ -391,5 +385,4 @@ libkern/strncmp.c standard
libkern/strncpy.c standard
libkern/udivdi3.c standard
libkern/umoddi3.c standard
-pci/es1370.c optional pcm pci
pci/ide_pci.c optional wd pci
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index d0ef616..89213c9 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -83,6 +83,13 @@ struct ata_softc *atadevices[MAXATA];
static devclass_t ata_devclass;
#if NISA > 0
+static struct isa_pnp_id ata_ids[] = {
+ {0x0006d041, "Generic ESDI/IDE/ATA controller"}, /* PNP0600 */
+ {0x0106d041, "Plus Hardcard II"}, /* PNP0601 */
+ {0x0206d041, "Plus Hardcard IIXL/EZ"}, /* PNP0602 */
+ {0x0306d041, "Generic ATA"}, /* PNP0603 */
+ {0}
+};
static int
ata_isaprobe(device_t dev)
@@ -92,7 +99,11 @@ ata_isaprobe(device_t dev)
int32_t ctlr, res;
int32_t lun;
- /* allocate the port range */
+ /* Check isapnp ids */
+ if (ISA_PNP_PROBE(device_get_parent(dev), dev, ata_ids) == ENXIO)
+ return (ENXIO);
+
+ /* Allocate the port range */
rid = 0;
port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE);
if (!port)
diff --git a/sys/dev/pcm/isa/mss.c b/sys/dev/pcm/isa/mss.c
index cc34ddc..13645d9 100644
--- a/sys/dev/pcm/isa/mss.c
+++ b/sys/dev/pcm/isa/mss.c
@@ -511,9 +511,11 @@ mss_probe(device_t dev)
mss_probe_end:
result = mss_detect(dev, mss);
no:
+ mss_release_resources(mss, dev);
+#if 0
if (setres) ISA_DELETE_RESOURCE(device_get_parent(dev), dev,
SYS_RES_IOPORT, mss->io_rid); /* XXX ? */
- mss_release_resources(mss, dev);
+#endif
return result;
}
diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c
index 0cd84ba..503aa3e 100644
--- a/sys/dev/sio/sio.c
+++ b/sys/dev/sio/sio.c
@@ -577,6 +577,15 @@ card_intr(struct pccard_devinfo *devi)
#define SET_FLAG(dev, bit) isa_set_flags(dev, isa_get_flags(dev) | (bit))
#define CLR_FLAG(dev, bit) isa_set_flags(dev, isa_get_flags(dev) & ~(bit))
+static struct isa_pnp_id sio_ids[] = {
+ {0x0005d041, "Standard PC COM port"}, /* PNP0500 */
+ {0x0105d041, "16550A-compatible COM port"}, /* PNP0501 */
+ {0x0205d041, "Multiport serial device (non-intelligent 16550)"}, /* PNP0502 */
+ {0x1005d041, "Generic IRDA-compatible device"}, /* PNP0510 */
+ {0x1105d041, "Generic IRDA-compatible device"}, /* PNP0511 */
+ {0}
+};
+
static int
sioprobe(dev)
device_t dev;
@@ -596,10 +605,7 @@ sioprobe(dev)
struct resource *port;
/* Check isapnp ids */
- if (isa_get_vendorid(dev)
- && isa_get_compatid(dev) != PNP_EISAID("PNP0500")
- && isa_get_compatid(dev) != PNP_EISAID("PNP0501")
- && isa_get_compatid(dev) != PNP_EISAID("PNP0502"))
+ if (ISA_PNP_PROBE(device_get_parent(dev), dev, sio_ids) == ENXIO)
return (ENXIO);
rid = 0;
@@ -2628,11 +2634,12 @@ static cn_putc_t siocnputc;
#ifdef __i386__
CONS_DRIVER(sio, siocnprobe, siocninit, NULL, siocngetc, siocncheckc, siocnputc);
+#endif
+
/* To get the GDB related variables */
#if DDB > 0
#include <ddb/ddb.h>
#endif
-#endif
static void
siocntxwait(iobase)
@@ -2830,17 +2837,15 @@ siocnprobe(cp)
siocniobase = iobase;
siocnunit = unit;
}
- if (COM_DEBUGGER(flags) && !COM_LLCONSOLE(flags)) {
+ if (COM_DEBUGGER(flags)) {
printf("sio%d: gdb debugging port\n", unit);
siogdbiobase = iobase;
siogdbunit = unit;
-#ifdef __i386__
#if DDB > 0
gdbdev = makedev(CDEV_MAJOR, unit);
gdb_getc = siocngetc;
gdb_putc = siocnputc;
#endif
-#endif
}
}
}
diff --git a/sys/dev/sound/isa/mss.c b/sys/dev/sound/isa/mss.c
index cc34ddc..13645d9 100644
--- a/sys/dev/sound/isa/mss.c
+++ b/sys/dev/sound/isa/mss.c
@@ -511,9 +511,11 @@ mss_probe(device_t dev)
mss_probe_end:
result = mss_detect(dev, mss);
no:
+ mss_release_resources(mss, dev);
+#if 0
if (setres) ISA_DELETE_RESOURCE(device_get_parent(dev), dev,
SYS_RES_IOPORT, mss->io_rid); /* XXX ? */
- mss_release_resources(mss, dev);
+#endif
return result;
}
diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386
index f55ae9e..1ec918c 100644
--- a/sys/i386/conf/files.i386
+++ b/sys/i386/conf/files.i386
@@ -234,7 +234,6 @@ i386/isa/pcvt/pcvt_kbd.c optional vt
i386/isa/pcvt/pcvt_out.c optional vt
i386/isa/pcvt/pcvt_sup.c optional vt
i386/isa/pcvt/pcvt_vtf.c optional vt
-i386/isa/pnp.c optional pnp
i386/isa/ppc.c optional ppc
i386/isa/prof_machdep.c optional profiling-routine
i386/isa/random_machdep.c standard
@@ -244,11 +243,6 @@ i386/isa/scd.c optional scd
i386/isa/si.c optional si
i386/isa/si2_z280.c optional si
i386/isa/si3_t225.c optional si
-i386/isa/snd/ad1848.c optional pcm
-i386/isa/snd/clones.c optional pcm
-i386/isa/snd/dmabuf.c optional pcm
-i386/isa/snd/sb_dsp.c optional pcm
-i386/isa/snd/sound.c optional pcm
i386/isa/sound/ad1848.c optional css
i386/isa/sound/ad1848.c optional gus
i386/isa/sound/ad1848.c optional gusxvi
@@ -391,5 +385,4 @@ libkern/strncmp.c standard
libkern/strncpy.c standard
libkern/udivdi3.c standard
libkern/umoddi3.c standard
-pci/es1370.c optional pcm pci
pci/ide_pci.c optional wd pci
diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c
index 630bd05..5dbbedd 100644
--- a/sys/i386/i386/autoconf.c
+++ b/sys/i386/i386/autoconf.c
@@ -74,12 +74,8 @@
#include <i386/isa/icu.h>
#endif /* APIC_IO */
-#include "pnp.h"
-#if NPNP > 0
-#include <i386/isa/isa_device.h>
-#include <i386/isa/pnp.h>
-#endif
-
+#include "isa.h"
+#include <isa/isavar.h>
device_t isa_bus_device = 0;
static void configure_first __P((void *));
@@ -223,17 +219,14 @@ configure(dummy)
/* initialize new bus architecture */
root_bus_configure();
-#if NPNP > 0
- /* Activate PNP. If no drivers are found, let ISA probe them.. */
- pnp_configure();
-#endif
-
+#if NISA > 0
/*
* Explicitly probe and attach ISA last. The isa bus saves
* it's device node at attach time for us here.
*/
if (isa_bus_device)
- bus_generic_attach(isa_bus_device);
+ isa_probe_children(isa_bus_device);
+#endif
/*
* Now we're ready to handle (pending) interrupts.
diff --git a/sys/i386/i386/userconfig.c b/sys/i386/i386/userconfig.c
index 65b40aa..7ca8b25 100644
--- a/sys/i386/i386/userconfig.c
+++ b/sys/i386/i386/userconfig.c
@@ -125,6 +125,9 @@
#include <i386/isa/isa_device.h>
#include "pnp.h"
+#undef NPNP
+#define NPNP 0
+
#if NPNP > 0
#include <i386/isa/pnp.h>
#endif
diff --git a/sys/i386/isa/isa_compat.h b/sys/i386/isa/isa_compat.h
index e6f57f6..913d967 100644
--- a/sys/i386/isa/isa_compat.h
+++ b/sys/i386/isa/isa_compat.h
@@ -120,7 +120,6 @@ extern struct isa_driver wldriver;
extern struct isa_driver zedriver;
extern struct isa_driver zpdriver;
extern struct isa_driver oltrdriver;
-extern struct isa_driver pcmdriver;
extern struct isa_driver pasdriver;
extern struct isa_driver sbdriver;
extern struct isa_driver sbxvidriver;
@@ -334,9 +333,6 @@ static struct old_isa_driver old_drivers[] = {
#if NOLTR > 0
{ INTR_TYPE_MISC, &oltrdriver },
#endif
-#if NPCM > 0
- { INTR_TYPE_MISC, &pcmdriver },
-#endif
#if NPAS > 0
{ INTR_TYPE_MISC, &pasdriver },
#endif
diff --git a/sys/isa/isa_common.c b/sys/isa/isa_common.c
index c16b663..8d597fe 100644
--- a/sys/isa/isa_common.c
+++ b/sys/isa/isa_common.c
@@ -99,13 +99,391 @@ static int
isa_attach(device_t dev)
{
/*
- * Arrange for bus_generic_attach(dev) to be called later.
+ * Arrange for isa_probe_children(dev) to be called later. XXX
*/
isa_bus_device = dev;
return 0;
}
/*
+ * Find a working set of memory regions for a child using the ranges
+ * in *config and return the regions in *result. Returns non-zero if
+ * a set of ranges was found.
+ */
+static int
+isa_find_memory(device_t child,
+ struct isa_config *config,
+ struct isa_config *result)
+{
+ device_t dev = device_get_parent(child);
+ int success, i;
+ struct resource *res[ISA_NMEM];
+
+ /*
+ * First clear out any existing resource definitions.
+ */
+ for (i = 0; i < ISA_NMEM; i++) {
+ ISA_DELETE_RESOURCE(dev, child, SYS_RES_MEMORY, i);
+ res[i] = NULL;
+ }
+
+ success = 1;
+ result->ic_nmem = config->ic_nmem;
+ for (i = 0; i < config->ic_nmem; i++) {
+ u_int32_t start, end, size, align;
+ for (start = config->ic_mem[i].ir_start,
+ end = config->ic_mem[i].ir_end,
+ size = config->ic_mem[i].ir_size,
+ align = config->ic_mem[i].ir_align;
+ start + size - 1 <= end;
+ start += align) {
+ ISA_SET_RESOURCE(dev, child, SYS_RES_MEMORY, i,
+ start, size);
+ res[i] = bus_alloc_resource(child,
+ SYS_RES_MEMORY, &i,
+ 0, ~0, 1, RF_ACTIVE);
+ if (res[i]) {
+ result->ic_mem[i].ir_start = start;
+ result->ic_mem[i].ir_end = start + size - 1;
+ result->ic_mem[i].ir_size = size;
+ result->ic_mem[i].ir_align = align;
+ break;
+ }
+ }
+
+ /*
+ * If we didn't find a place for memory range i, then
+ * give up now.
+ */
+ if (!res[i]) {
+ success = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < ISA_NMEM; i++) {
+ if (res[i])
+ bus_release_resource(child, SYS_RES_MEMORY,
+ i, res[i]);
+ }
+
+ return success;
+}
+
+/*
+ * Find a working set of port regions for a child using the ranges
+ * in *config and return the regions in *result. Returns non-zero if
+ * a set of ranges was found.
+ */
+static int
+isa_find_port(device_t child,
+ struct isa_config *config,
+ struct isa_config *result)
+{
+ device_t dev = device_get_parent(child);
+ int success, i;
+ struct resource *res[ISA_NPORT];
+
+ /*
+ * First clear out any existing resource definitions.
+ */
+ for (i = 0; i < ISA_NPORT; i++) {
+ ISA_DELETE_RESOURCE(dev, child, SYS_RES_IOPORT, i);
+ res[i] = NULL;
+ }
+
+ success = 1;
+ result->ic_nport = config->ic_nport;
+ for (i = 0; i < config->ic_nport; i++) {
+ u_int32_t start, end, size, align;
+ for (start = config->ic_port[i].ir_start,
+ end = config->ic_port[i].ir_end,
+ size = config->ic_port[i].ir_size,
+ align = config->ic_port[i].ir_align;
+ start + size - 1 <= end;
+ start += align) {
+ ISA_SET_RESOURCE(dev, child, SYS_RES_IOPORT, i,
+ start, size);
+ res[i] = bus_alloc_resource(child,
+ SYS_RES_IOPORT, &i,
+ 0, ~0, 1, RF_ACTIVE);
+ if (res[i]) {
+ result->ic_port[i].ir_start = start;
+ result->ic_port[i].ir_end = start + size - 1;
+ result->ic_port[i].ir_size = size;
+ result->ic_port[i].ir_align = align;
+ break;
+ }
+ }
+
+ /*
+ * If we didn't find a place for port range i, then
+ * give up now.
+ */
+ if (!res[i]) {
+ success = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < ISA_NPORT; i++) {
+ if (res[i])
+ bus_release_resource(child, SYS_RES_IOPORT,
+ i, res[i]);
+ }
+
+ return success;
+}
+
+/*
+ * Return the index of the first bit in the mask (or -1 if mask is empty.
+ */
+static int
+find_first_bit(u_int32_t mask)
+{
+ return ffs(mask) - 1;
+}
+
+/*
+ * Return the index of the next bit in the mask, or -1 if there are no more.
+ */
+static int
+find_next_bit(u_int32_t mask, int bit)
+{
+ bit++;
+ while (bit < 32 && !(mask & (1 << bit)))
+ bit++;
+ if (bit != 32)
+ return bit;
+ return -1;
+}
+
+/*
+ * Find a working set of irqs for a child using the masks in *config
+ * and return the regions in *result. Returns non-zero if a set of
+ * irqs was found.
+ */
+static int
+isa_find_irq(device_t child,
+ struct isa_config *config,
+ struct isa_config *result)
+{
+ device_t dev = device_get_parent(child);
+ int success, i;
+ struct resource *res[ISA_NIRQ];
+
+ /*
+ * First clear out any existing resource definitions.
+ */
+ for (i = 0; i < ISA_NIRQ; i++) {
+ ISA_DELETE_RESOURCE(dev, child, SYS_RES_IRQ, i);
+ res[i] = NULL;
+ }
+
+ success = 1;
+ result->ic_nirq = config->ic_nirq;
+ for (i = 0; i < config->ic_nirq; i++) {
+ u_int32_t mask = config->ic_irqmask[i];
+ int irq;
+ for (irq = find_first_bit(mask);
+ irq != -1;
+ irq = find_next_bit(mask, irq)) {
+ ISA_SET_RESOURCE(dev, child, SYS_RES_IRQ, i,
+ irq, 1);
+ res[i] = bus_alloc_resource(child,
+ SYS_RES_IRQ, &i,
+ 0, ~0, 1, RF_ACTIVE);
+ if (res[i]) {
+ result->ic_irqmask[i] = (1 << irq);
+ break;
+ }
+ }
+
+ /*
+ * If we didn't find a place for irq range i, then
+ * give up now.
+ */
+ if (!res[i]) {
+ success = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < ISA_NIRQ; i++) {
+ if (res[i])
+ bus_release_resource(child, SYS_RES_IRQ,
+ i, res[i]);
+ }
+
+ return success;
+}
+
+/*
+ * Find a working set of drqs for a child using the masks in *config
+ * and return the regions in *result. Returns non-zero if a set of
+ * drqs was found.
+ */
+static int
+isa_find_drq(device_t child,
+ struct isa_config *config,
+ struct isa_config *result)
+{
+ device_t dev = device_get_parent(child);
+ int success, i;
+ struct resource *res[ISA_NDRQ];
+
+ /*
+ * First clear out any existing resource definitions.
+ */
+ for (i = 0; i < ISA_NDRQ; i++) {
+ ISA_DELETE_RESOURCE(dev, child, SYS_RES_DRQ, i);
+ res[i] = NULL;
+ }
+
+ success = 1;
+ result->ic_ndrq = config->ic_ndrq;
+ for (i = 0; i < config->ic_ndrq; i++) {
+ u_int32_t mask = config->ic_drqmask[i];
+ int drq;
+ for (drq = find_first_bit(mask);
+ drq != -1;
+ drq = find_next_bit(mask, drq)) {
+ ISA_SET_RESOURCE(dev, child, SYS_RES_DRQ, i,
+ drq, 1);
+ res[i] = bus_alloc_resource(child,
+ SYS_RES_DRQ, &i,
+ 0, ~0, 1, RF_ACTIVE);
+ if (res[i]) {
+ result->ic_drqmask[i] = (1 << drq);
+ break;
+ }
+ }
+
+ /*
+ * If we didn't find a place for drq range i, then
+ * give up now.
+ */
+ if (!res[i]) {
+ success = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < ISA_NDRQ; i++) {
+ if (res[i])
+ bus_release_resource(child, SYS_RES_DRQ,
+ i, res[i]);
+ }
+
+ return success;
+}
+
+/*
+ * Attempt to find a working set of resources for a device. Return
+ * non-zero if a working configuration is found.
+ */
+static int
+isa_assign_resources(device_t child)
+{
+ struct isa_device *idev = DEVTOISA(child);
+ struct isa_config_entry *ice;
+ struct isa_config config;
+
+ bzero(&config, sizeof config);
+ TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
+ if (!isa_find_memory(child, &ice->ice_config, &config))
+ continue;
+ if (!isa_find_port(child, &ice->ice_config, &config))
+ continue;
+ if (!isa_find_irq(child, &ice->ice_config, &config))
+ continue;
+ if (!isa_find_drq(child, &ice->ice_config, &config))
+ continue;
+
+ /*
+ * A working configuration was found enable the device
+ * with this configuration.
+ */
+ if (idev->id_config_cb) {
+ idev->id_config_cb(idev->id_config_arg,
+ &config, 1);
+ return 1;
+ }
+ }
+
+ /*
+ * Disable the device.
+ */
+ bzero(&config, sizeof config);
+ if (idev->id_config_cb)
+ idev->id_config_cb(idev->id_config_arg, &config, 0);
+ device_disable(child);
+
+ return 0;
+}
+
+/*
+ * Called after other devices have initialised to probe for isa devices.
+ */
+void
+isa_probe_children(device_t dev)
+{
+ device_t *children;
+ int nchildren, i;
+
+ if (device_get_children(dev, &children, &nchildren))
+ return;
+
+ /*
+ * First probe all non-pnp devices so that they claim their
+ * resources first.
+ */
+ for (i = 0; i < nchildren; i++) {
+ device_t child = children[i];
+ struct isa_device *idev = DEVTOISA(child);
+
+ if (TAILQ_FIRST(&idev->id_configs))
+ continue;
+
+ device_probe_and_attach(child);
+ }
+
+ /*
+ * Next assign resource to pnp devices and probe them.
+ */
+ for (i = 0; i < nchildren; i++) {
+ device_t child = children[i];
+ struct isa_device* idev = DEVTOISA(child);
+
+ if (!TAILQ_FIRST(&idev->id_configs))
+ continue;
+
+ if (isa_assign_resources(child)) {
+ struct resource_list_entry *rle;
+
+ device_probe_and_attach(child);
+
+ /*
+ * Claim any unallocated resources to keep other
+ * devices from using them.
+ */
+ SLIST_FOREACH(rle, &idev->id_resources, link) {
+ if (!rle->res) {
+ int rid = rle->rid;
+ resource_list_alloc(dev, child,
+ rle->type,
+ &rid,
+ 0, ~0, 1,
+ RF_ACTIVE);
+ }
+ }
+ }
+ }
+
+ free(children, M_TEMP);
+}
+
+/*
* Add a new child with default ivars.
*/
static device_t
@@ -120,6 +498,7 @@ isa_add_child(device_t dev, int order, const char *name, int unit)
resource_list_init(&idev->id_resources);
idev->id_flags = 0;
+ TAILQ_INIT(&idev->id_configs);
return device_add_child_ordered(dev, order, name, unit, idev);
}
@@ -128,26 +507,27 @@ static void
isa_print_resources(struct resource_list *rl, const char *name, int type,
const char *format)
{
- struct resource_list_entry *rle0 = resource_list_find(rl, type, 0);
- struct resource_list_entry *rle1 = resource_list_find(rl, type, 1);
-
- if (rle0 || rle1) {
- printf(" %s ", name);
- if (rle0) {
- printf(format, rle0->start);
- if (rle0->count > 1) {
- printf("-");
- printf(format, rle0->start + rle0->count - 1);
- }
- }
- if (rle1) {
- if (rle0)
+ struct resource_list_entry *rle;
+ int printed;
+ int i;
+
+ printed = 0;
+ for (i = 0; i < 16; i++) {
+ rle = resource_list_find(rl, type, i);
+ if (rle) {
+ if (printed == 0)
+ printf(" %s ", name);
+ else if (printed > 0)
printf(",");
- printf(format, rle1->start);
- if (rle1->count > 1) {
+ printed++;
+ printf(format, rle->start);
+ if (rle->count > 1) {
printf("-");
- printf(format, rle1->start + rle1->count - 1);
+ printf(format, rle->start + rle->count - 1);
}
+ } else if (i > 3) {
+ /* check the first few regardless */
+ break;
}
}
}
@@ -355,6 +735,25 @@ isa_write_ivar(device_t bus, device_t dev,
return (0);
}
+/*
+ * Free any resources which the driver missed or which we were holding for
+ * it (see isa_probe_children).
+ */
+static void
+isa_child_detached(device_t dev, device_t child)
+{
+ struct isa_device* idev = DEVTOISA(child);
+ struct resource_list_entry *rle;
+
+ SLIST_FOREACH(rle, &idev->id_resources, link) {
+ if (rle->res)
+ resource_list_release(dev, child,
+ rle->type,
+ rle->rid,
+ rle->res);
+ }
+}
+
static int
isa_set_resource(device_t dev, device_t child, int type, int rid,
u_long start, u_long count)
@@ -365,7 +764,15 @@ isa_set_resource(device_t dev, device_t child, int type, int rid,
if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
&& type != SYS_RES_IRQ && type != SYS_RES_DRQ)
return EINVAL;
- if (rid < 0 || rid > 1)
+ if (rid < 0)
+ return EINVAL;
+ if (type == SYS_RES_IOPORT && rid >= ISA_NPORT)
+ return EINVAL;
+ if (type == SYS_RES_MEMORY && rid >= ISA_NMEM)
+ return EINVAL;
+ if (type == SYS_RES_IRQ && rid >= ISA_NIRQ)
+ return EINVAL;
+ if (type == SYS_RES_DRQ && rid >= ISA_NDRQ)
return EINVAL;
resource_list_add(rl, type, rid, start, start + count - 1, count);
@@ -399,6 +806,65 @@ isa_delete_resource(device_t dev, device_t child, int type, int rid)
resource_list_delete(rl, type, rid);
}
+static int
+isa_add_config(device_t dev, device_t child,
+ int priority, struct isa_config *config)
+{
+ struct isa_device* idev = DEVTOISA(child);
+ struct isa_config_entry *newice, *ice;
+
+ newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT);
+ if (!newice)
+ return ENOMEM;
+
+ newice->ice_priority = priority;
+ newice->ice_config = *config;
+
+ TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
+ if (ice->ice_priority > priority)
+ break;
+ }
+ if (ice)
+ TAILQ_INSERT_BEFORE(ice, newice, ice_link);
+ else
+ TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link);
+
+ return 0;
+}
+
+static void
+isa_set_config_callback(device_t dev, device_t child,
+ isa_config_cb *fn, void *arg)
+{
+ struct isa_device* idev = DEVTOISA(child);
+
+ idev->id_config_cb = fn;
+ idev->id_config_arg = arg;
+}
+
+static int
+isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids)
+{
+ struct isa_device* idev = DEVTOISA(child);
+
+ if (!idev->id_vendorid)
+ return ENOENT;
+
+ while (ids->ip_id) {
+ /*
+ * Really ought to support >1 compat id per device.
+ */
+ if (idev->id_logicalid == ids->ip_id
+ || idev->id_compatid == ids->ip_id) {
+ device_set_desc(child, ids->ip_desc);
+ return 0;
+ }
+ ids++;
+ }
+
+ return ENXIO;
+}
+
static device_method_t isa_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, isa_probe),
@@ -413,6 +879,7 @@ static device_method_t isa_methods[] = {
DEVMETHOD(bus_print_child, isa_print_child),
DEVMETHOD(bus_read_ivar, isa_read_ivar),
DEVMETHOD(bus_write_ivar, isa_write_ivar),
+ DEVMETHOD(bus_child_detached, isa_child_detached),
DEVMETHOD(bus_alloc_resource, isa_alloc_resource),
DEVMETHOD(bus_release_resource, isa_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
@@ -424,6 +891,9 @@ static device_method_t isa_methods[] = {
DEVMETHOD(isa_set_resource, isa_set_resource),
DEVMETHOD(isa_get_resource, isa_get_resource),
DEVMETHOD(isa_delete_resource, isa_delete_resource),
+ DEVMETHOD(isa_add_config, isa_add_config),
+ DEVMETHOD(isa_set_config_callback, isa_set_config_callback),
+ DEVMETHOD(isa_pnp_probe, isa_pnp_probe),
{ 0, 0 }
};
@@ -441,3 +911,49 @@ DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0);
#ifdef __i386__
DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0);
#endif
+
+/*
+ * A fallback driver for reporting un-matched pnp devices.
+ */
+
+static int
+unknown_probe(device_t dev)
+{
+ /*
+ * Only match pnp devices.
+ */
+ if (isa_get_vendorid(dev) != 0)
+ return -100;
+ return ENXIO;
+}
+
+static int
+unknown_attach(device_t dev)
+{
+ return 0;
+}
+
+static int
+unknown_detach(device_t dev)
+{
+ return 0;
+}
+
+static device_method_t unknown_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, unknown_probe),
+ DEVMETHOD(device_attach, unknown_attach),
+ DEVMETHOD(device_detach, unknown_detach),
+
+ { 0, 0 }
+};
+
+static driver_t unknown_driver = {
+ "unknown",
+ unknown_methods,
+ 1, /* no softc */
+};
+
+static devclass_t unknown_devclass;
+
+DRIVER_MODULE(unknown, isa, unknown_driver, unknown_devclass, 0, 0);
diff --git a/sys/isa/isa_common.h b/sys/isa/isa_common.h
index c63f1ef..4a104fe 100644
--- a/sys/isa/isa_common.h
+++ b/sys/isa/isa_common.h
@@ -36,6 +36,16 @@
MALLOC_DECLARE(M_ISADEV);
/*
+ * PNP configurations are kept in a tailq.
+ */
+TAILQ_HEAD(isa_config_list, isa_config_entry);
+struct isa_config_entry {
+ TAILQ_ENTRY(isa_config_entry) ice_link;
+ int ice_priority;
+ struct isa_config ice_config;
+};
+
+/*
* The structure used to attach devices to the isa bus.
*/
struct isa_device {
@@ -45,6 +55,9 @@ struct isa_device {
u_int32_t id_serial; /* pnp serial */
u_int32_t id_logicalid; /* pnp logical device id */
u_int32_t id_compatid; /* pnp compat device id */
+ struct isa_config_list id_configs; /* pnp config alternatives */
+ isa_config_cb *id_config_cb; /* callback function */
+ void *id_config_arg; /* callback argument */
};
#define DEVTOISA(dev) ((struct isa_device *) device_get_ivars(dev))
diff --git a/sys/isa/isa_if.m b/sys/isa/isa_if.m
index 051b0de..2c3ab0f 100644
--- a/sys/isa/isa_if.m
+++ b/sys/isa/isa_if.m
@@ -26,6 +26,10 @@
# $FreeBSD$
#
+CODE {
+#include <isa/isavar.h>
+};
+
INTERFACE isa;
#
@@ -63,3 +67,43 @@ METHOD void delete_resource {
int type;
int rid;
};
+
+#
+# Add a Plug-and-play configuration to the device. Configurations with
+# a lower priority are preferred.
+#
+METHOD int add_config {
+ device_t dev;
+ device_t child;
+ int priority;
+ struct isa_config *config;
+};
+
+#
+# Register a function which can be called to configure a device with
+# a given set of resources. The function will be called with a struct
+# isa_config representing the desired configuration and a flag to
+# state whether the device should be enabled.
+#
+METHOD void set_config_callback {
+ device_t dev;
+ device_t child;
+ isa_config_cb *fn;
+ void *arg;
+};
+
+#
+# A helper method for implementing probe methods for PnP compatible
+# drivers. The driver calls this method with a list of PnP ids and
+# descriptions and it returns zero if one of the ids matches or ENXIO
+# otherwise.
+#
+# If the device is not plug-and-play compatible, this method returns
+# ENOENT, allowing the caller to fall back to heuristic probing
+# techniques.
+#
+METHOD int pnp_probe {
+ device_t dev;
+ device_t child;
+ struct isa_pnp_id *ids;
+};
diff --git a/sys/isa/isavar.h b/sys/isa/isavar.h
index a0a9b88..7f912e5 100644
--- a/sys/isa/isavar.h
+++ b/sys/isa/isavar.h
@@ -29,8 +29,12 @@
#ifndef _ISA_ISAVAR_H_
#define _ISA_ISAVAR_H_
+struct isa_config;
+struct isa_pnp_id;
+typedef void isa_config_cb(void *arg, struct isa_config *config, int enable);
+
#include "isa_if.h"
-#include <isa/pnp.h>
+#include <isa/pnpvar.h>
#ifdef KERNEL
@@ -50,6 +54,39 @@
#define ISA_NIRQ 2
#define ISA_NDRQ 2
+/*
+ * Plug and play cards can support a range of resource
+ * configurations. This structure is used by the isapnp parser to
+ * inform the isa bus about the resource possibilities of the
+ * device. Each different alternative should be supplied by calling
+ * ISA_ADD_CONFIG().
+ */
+struct isa_range {
+ u_int32_t ir_start;
+ u_int32_t ir_end;
+ u_int32_t ir_size;
+ u_int32_t ir_align;
+};
+
+struct isa_config {
+ struct isa_range ic_mem[ISA_NMEM];
+ struct isa_range ic_port[ISA_NPORT];
+ u_int32_t ic_irqmask[ISA_NIRQ];
+ u_int32_t ic_drqmask[ISA_NDRQ];
+ int ic_nmem;
+ int ic_nport;
+ int ic_nirq;
+ int ic_ndrq;
+};
+
+/*
+ * Used to build lists of IDs and description strings for PnP drivers.
+ */
+struct isa_pnp_id {
+ u_int32_t ip_id;
+ const char *ip_desc;
+};
+
enum isa_device_ivars {
ISA_IVAR_PORT,
ISA_IVAR_PORT_0 = ISA_IVAR_PORT,
@@ -76,12 +113,6 @@ enum isa_device_ivars {
ISA_IVAR_COMPATID
};
-extern intrmask_t isa_irq_pending(void);
-extern intrmask_t isa_irq_mask(void);
-#ifdef __i386__
-extern void isa_wrap_old_drivers(void);
-#endif
-
/*
* Simplified accessors for isa devices
*/
@@ -112,14 +143,21 @@ ISA_ACCESSOR(serial, SERIAL, int)
ISA_ACCESSOR(logicalid, LOGICALID, int)
ISA_ACCESSOR(compatid, COMPATID, int)
-void isa_dmacascade __P((int chan));
-void isa_dmadone __P((int flags, caddr_t addr, int nbytes, int chan));
-void isa_dmainit __P((int chan, u_int bouncebufsize));
-void isa_dmastart __P((int flags, caddr_t addr, u_int nbytes, int chan));
-int isa_dma_acquire __P((int chan));
-void isa_dma_release __P((int chan));
-int isa_dmastatus __P((int chan));
-int isa_dmastop __P((int chan));
+extern intrmask_t isa_irq_pending(void);
+extern intrmask_t isa_irq_mask(void);
+#ifdef __i386__
+extern void isa_wrap_old_drivers(void);
+#endif
+extern void isa_probe_children(device_t dev);
+
+extern void isa_dmacascade __P((int chan));
+extern void isa_dmadone __P((int flags, caddr_t addr, int nbytes, int chan));
+extern void isa_dmainit __P((int chan, u_int bouncebufsize));
+extern void isa_dmastart __P((int flags, caddr_t addr, u_int nbytes, int chan));
+extern int isa_dma_acquire __P((int chan));
+extern void isa_dma_release __P((int chan));
+extern int isa_dmastatus __P((int chan));
+extern int isa_dmastop __P((int chan));
#endif /* KERNEL */
diff --git a/sys/isa/pnp.c b/sys/isa/pnp.c
new file mode 100644
index 0000000..6409818
--- /dev/null
+++ b/sys/isa/pnp.c
@@ -0,0 +1,761 @@
+/*
+ * Copyright (c) 1996, Sujal M. Patel
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ * from: pnp.c,v 1.11 1999/05/06 22:11:19 peter Exp
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <isa/isavar.h>
+#include <isa/pnpreg.h>
+#include <isa/pnpvar.h>
+#include <machine/resource.h>
+#include <machine/clock.h>
+
+typedef struct _pnp_id {
+ u_int32_t vendor_id;
+ u_int32_t serial;
+ u_char checksum;
+} pnp_id;
+
+struct pnp_set_config_arg {
+ int csn; /* Card number to configure */
+ int ldn; /* Logical device on card */
+};
+
+struct pnp_quirk {
+ u_int32_t vendor_id; /* Vendor of the card */
+ u_int32_t logical_id; /* ID of the device with quirk */
+ int type;
+#define PNP_QUIRK_WRITE_REG 1 /* Need to write a pnp register */
+ int arg1;
+ int arg2;
+};
+
+struct pnp_quirk pnp_quirks[] = {
+ /*
+ * The Gravis UltraSound needs register 0xf2 to be set to 0xff
+ * to enable power.
+ * XXX need to know the logical device id.
+ */
+ { 0x0100561e /* GRV0001 */, 0,
+ PNP_QUIRK_WRITE_REG, 0xf2, 0xff },
+
+ { 0 }
+};
+
+#if 0
+/*
+ * these entries are initialized using the autoconfig menu
+ * The struct is invalid (and must be initialized) if the first
+ * CSN is zero. The init code fills invalid entries with CSN 255
+ * which is not a supported value.
+ */
+
+struct pnp_cinfo pnp_ldn_overrides[MAX_PNP_LDN] = {
+ { 0 }
+};
+#endif
+
+/* The READ_DATA port that we are using currently */
+static int pnp_rd_port;
+
+static void pnp_send_initiation_key(void);
+static int pnp_get_serial(pnp_id *p);
+static int pnp_isolation_protocol(device_t parent);
+
+static void
+pnp_write(int d, u_char r)
+{
+ outb (_PNP_ADDRESS, d);
+ outb (_PNP_WRITE_DATA, r);
+}
+
+#if 0
+
+static u_char
+pnp_read(int d)
+{
+ outb (_PNP_ADDRESS, d);
+ return (inb(3 | (pnp_rd_port <<2)));
+}
+
+#endif
+
+/*
+ * Send Initiation LFSR as described in "Plug and Play ISA Specification",
+ * Intel May 94.
+ */
+static void
+pnp_send_initiation_key()
+{
+ int cur, i;
+
+ /* Reset the LSFR */
+ outb(_PNP_ADDRESS, 0);
+ outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
+
+ cur = 0x6a;
+ outb(_PNP_ADDRESS, cur);
+
+ for (i = 1; i < 32; i++) {
+ cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
+ outb(_PNP_ADDRESS, cur);
+ }
+}
+
+
+/*
+ * Get the device's serial number. Returns 1 if the serial is valid.
+ */
+static int
+pnp_get_serial(pnp_id *p)
+{
+ int i, bit, valid = 0, sum = 0x6a;
+ u_char *data = (u_char *)p;
+
+ bzero(data, sizeof(char) * 9);
+ outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
+ for (i = 0; i < 72; i++) {
+ bit = inb((pnp_rd_port << 2) | 0x3) == 0x55;
+ DELAY(250); /* Delay 250 usec */
+
+ /* Can't Short Circuit the next evaluation, so 'and' is last */
+ bit = (inb((pnp_rd_port << 2) | 0x3) == 0xaa) && bit;
+ DELAY(250); /* Delay 250 usec */
+
+ valid = valid || bit;
+
+ if (i < 64)
+ sum = (sum >> 1) |
+ (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
+
+ data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
+ }
+
+ valid = valid && (data[8] == sum);
+
+ return valid;
+}
+
+/*
+ * Fill's the buffer with resource info from the device.
+ * Returns 0 if the device fails to report
+ */
+static int
+pnp_get_resource_info(u_char *buffer, int len)
+{
+ int i, j;
+ u_char temp;
+
+ for (i = 0; i < len; i++) {
+ outb(_PNP_ADDRESS, PNP_STATUS);
+ for (j = 0; j < 100; j++) {
+ if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1)
+ break;
+ DELAY(1);
+ }
+ if (j == 100) {
+ printf("PnP device failed to report resource data\n");
+ return 0;
+ }
+ outb(_PNP_ADDRESS, PNP_RESOURCE_DATA);
+ temp = inb((pnp_rd_port << 2) | 0x3);
+ if (buffer != NULL)
+ buffer[i] = temp;
+ }
+ return 1;
+}
+
+#if 0
+/*
+ * write_pnp_parms initializes a logical device with the parms
+ * in d, and then activates the board if the last parameter is 1.
+ */
+
+static int
+write_pnp_parms(struct pnp_cinfo *d, pnp_id *p, int ldn)
+{
+ int i, empty = -1 ;
+
+ pnp_write (SET_LDN, ldn );
+ i = pnp_read(SET_LDN) ;
+ if (i != ldn) {
+ printf("Warning: LDN %d does not exist\n", ldn);
+ }
+ for (i = 0; i < 8; i++) {
+ pnp_write(IO_CONFIG_BASE + i * 2, d->ic_port[i] >> 8 );
+ pnp_write(IO_CONFIG_BASE + i * 2 + 1, d->ic_port[i] & 0xff );
+ }
+ for (i = 0; i < 4; i++) {
+ pnp_write(MEM_CONFIG + i*8, (d->ic_mem[i].base >> 16) & 0xff );
+ pnp_write(MEM_CONFIG + i*8+1, (d->ic_mem[i].base >> 8) & 0xff );
+ pnp_write(MEM_CONFIG + i*8+2, d->ic_mem[i].control & 0xff );
+ pnp_write(MEM_CONFIG + i*8+3, (d->ic_mem[i].range >> 16) & 0xff );
+ pnp_write(MEM_CONFIG + i*8+4, (d->ic_mem[i].range >> 8) & 0xff );
+ }
+ for (i = 0; i < 2; i++) {
+ pnp_write(IRQ_CONFIG + i*2 , d->irq[i] );
+ pnp_write(IRQ_CONFIG + i*2 + 1, d->irq_type[i] );
+ pnp_write(DRQ_CONFIG + i, d->drq[i] );
+ }
+ /*
+ * store parameters read into the current kernel
+ * so manual editing next time is easier
+ */
+ for (i = 0 ; i < MAX_PNP_LDN; i++) {
+ if (pnp_ldn_overrides[i].csn == d->csn &&
+ pnp_ldn_overrides[i].ldn == ldn) {
+ d->flags = pnp_ldn_overrides[i].flags ;
+ pnp_ldn_overrides[i] = *d ;
+ break ;
+ } else if (pnp_ldn_overrides[i].csn < 1 ||
+ pnp_ldn_overrides[i].csn == 255)
+ empty = i ;
+ }
+ if (i== MAX_PNP_LDN && empty != -1)
+ pnp_ldn_overrides[empty] = *d;
+
+ /*
+ * Here should really perform the range check, and
+ * return a failure if not successful.
+ */
+ pnp_write (IO_RANGE_CHECK, 0);
+ DELAY(1000); /* XXX is it really necessary ? */
+ pnp_write (ACTIVATE, d->enable ? 1 : 0);
+ DELAY(1000); /* XXX is it really necessary ? */
+ return 1 ;
+}
+#endif
+
+/*
+ * This function is called after the bus has assigned resource
+ * locations for a logical device.
+ */
+static void
+pnp_set_config(void *arg, struct isa_config *config, int enable)
+{
+ int csn = ((struct pnp_set_config_arg *) arg)->csn;
+ int ldn = ((struct pnp_set_config_arg *) arg)->ldn;
+ int i;
+
+ /*
+ * First put all cards into Sleep state with the initiation
+ * key, then put our card into Config state.
+ */
+ pnp_send_initiation_key();
+ pnp_write(PNP_WAKE, csn);
+
+ /*
+ * Select our logical device so that we can program it.
+ */
+ pnp_write(PNP_SET_LDN, ldn);
+
+ /*
+ * Now program the resources.
+ */
+ for (i = 0; i < config->ic_nmem; i++) {
+ u_int32_t start = config->ic_mem[i].ir_start;
+ u_int32_t size = config->ic_mem[i].ir_size;
+ if (start & 0xff)
+ panic("pnp_set_config: bogus memory assignment");
+ pnp_write(PNP_MEM_BASE_HIGH(i), (start >> 16) & 0xff);
+ pnp_write(PNP_MEM_BASE_LOW(i), (start >> 8) & 0xff);
+ pnp_write(PNP_MEM_RANGE_HIGH(i), (size >> 16) & 0xff);
+ pnp_write(PNP_MEM_RANGE_LOW(i), (size >> 8) & 0xff);
+ }
+ for (; i < ISA_NMEM; i++) {
+ pnp_write(PNP_MEM_BASE_HIGH(i), 0);
+ pnp_write(PNP_MEM_BASE_LOW(i), 0);
+ pnp_write(PNP_MEM_RANGE_HIGH(i), 0);
+ pnp_write(PNP_MEM_RANGE_LOW(i), 0);
+ }
+
+ for (i = 0; i < config->ic_nport; i++) {
+ u_int32_t start = config->ic_port[i].ir_start;
+ pnp_write(PNP_IO_BASE_HIGH(i), (start >> 8) & 0xff);
+ pnp_write(PNP_IO_BASE_LOW(i), (start >> 0) & 0xff);
+ }
+ for (; i < ISA_NPORT; i++) {
+ pnp_write(PNP_IO_BASE_HIGH(i), 0);
+ pnp_write(PNP_IO_BASE_LOW(i), 0);
+ }
+
+ for (i = 0; i < config->ic_nirq; i++) {
+ int irq = ffs(config->ic_irqmask[i]) - 1;
+ pnp_write(PNP_IRQ_LEVEL(i), irq);
+ pnp_write(PNP_IRQ_TYPE(i), 2); /* XXX */
+ }
+ for (; i < ISA_NIRQ; i++) {
+ /*
+ * IRQ 0 is not a valid interrupt selection and
+ * represents no interrupt selection.
+ */
+ pnp_write(PNP_IRQ_LEVEL(i), 0);
+ }
+
+ for (i = 0; i < config->ic_ndrq; i++) {
+ int drq = ffs(config->ic_drqmask[i]) - 1;
+ pnp_write(PNP_DMA_CHANNEL(i), drq);
+ }
+ for (; i < ISA_NDRQ; i++) {
+ /*
+ * DMA channel 4, the cascade channel is used to
+ * indicate no DMA channel is active.
+ */
+ pnp_write(PNP_DMA_CHANNEL(i), 4);
+ }
+
+ pnp_write(PNP_ACTIVATE, enable ? 1 : 0);
+
+ /*
+ * Wake everyone up again, we are finished.
+ */
+ pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY);
+}
+
+/*
+ * Process quirks for a logical device.. The card must be in Config state.
+ */
+static void
+pnp_check_quirks(u_int32_t vendor_id, u_int32_t logical_id, int ldn)
+{
+ struct pnp_quirk *qp;
+
+ for (qp = &pnp_quirks[0]; qp->vendor_id; qp++) {
+ if (qp->vendor_id == vendor_id
+ && (qp->logical_id == 0
+ || qp->logical_id == logical_id)) {
+ switch (qp->type) {
+ case PNP_QUIRK_WRITE_REG:
+ pnp_write(PNP_SET_LDN, ldn);
+ pnp_write(qp->arg1, qp->arg2);
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Scan Resource Data for Logical Devices.
+ *
+ * This function exits as soon as it gets an error reading *ANY*
+ * Resource Data or ir reaches the end of Resource Data. In the first
+ * case the return value will be TRUE, FALSE otherwise.
+ */
+static int
+pnp_scan_resdata(device_t parent, pnp_id *p, int csn)
+{
+ u_char tag, resinfo[16];
+ int large_len, scanning = 1024, retval = FALSE;
+ u_int32_t logical_id;
+ u_int32_t compat_id;
+ device_t dev = 0;
+ int ldn = 0;
+ struct isa_config card, logdev, alt;
+ struct isa_config *config;
+ struct pnp_set_config_arg *csnldn;
+ int priority = 0;
+ char *desc = 0;
+
+ bzero(&card, sizeof card);
+ bzero(&logdev, sizeof logdev);
+ bzero(&alt, sizeof alt);
+ config = &card;
+ while (scanning-- > 0 && pnp_get_resource_info(&tag, 1)) {
+ if (PNP_RES_TYPE(tag) == 0) {
+ /* Small resource */
+ if (pnp_get_resource_info(resinfo,
+ PNP_SRES_LEN(tag)) == 0) {
+ scanning = 0;
+ continue;
+ }
+
+ switch (PNP_SRES_NUM(tag)) {
+ case PNP_TAG_LOGIGAL_DEVICE:
+ /*
+ * A new logical device. Scan
+ * resourcea and add device.
+ */
+ bcopy(resinfo, &logical_id, 4);
+ pnp_check_quirks(p->vendor_id,
+ logical_id,
+ ldn);
+ compat_id = 0;
+ logdev = card;
+ config = &logdev;
+ dev = BUS_ADD_CHILD(parent,
+ ISA_ORDER_PNP, NULL, -1);
+ if (desc)
+ device_set_desc_copy(dev, desc);
+ isa_set_vendorid(dev, p->vendor_id);
+ isa_set_serial(dev, p->serial);
+ isa_set_logicalid(dev, logical_id);
+ csnldn = malloc(sizeof *csnldn,
+ M_DEVBUF, M_NOWAIT);
+ if (!csnldn) {
+ device_printf(parent,
+ "out of memory\n");
+ scanning = 0;
+ break;
+ }
+ csnldn->csn = csn;
+ csnldn->ldn = ldn;
+ ISA_SET_CONFIG_CALLBACK(parent, dev,
+ pnp_set_config,
+ csnldn);
+ ldn++;
+ break;
+
+ case PNP_TAG_COMPAT_DEVICE:
+ /*
+ * Got a compatible device id
+ * resource. Should keep a list of
+ * compat ids in the device.
+ */
+ bcopy(resinfo, &compat_id, 4);
+ if (dev)
+ isa_set_compatid(dev, compat_id);
+ break;
+
+ case PNP_TAG_IRQ_FORMAT:
+ if (config->ic_nirq == ISA_NIRQ) {
+ device_printf(parent,
+ "CSN %d too many irqs",
+ csn);
+ scanning = 0;
+ break;
+ }
+ config->ic_irqmask[config->ic_nirq] =
+ resinfo[0] + (resinfo[1]<<8);
+ config->ic_nirq++;
+ break;
+
+ case PNP_TAG_DMA_FORMAT:
+ if (config->ic_ndrq == ISA_NDRQ) {
+ device_printf(parent,
+ "CSN %d too many drqs",
+ csn);
+ scanning = 0;
+ break;
+ }
+ config->ic_drqmask[config->ic_ndrq] =
+ resinfo[0];
+ config->ic_ndrq++;
+ break;
+
+ case PNP_TAG_START_DEPENDANT:
+ if (config == &alt) {
+ ISA_ADD_CONFIG(parent, dev,
+ priority, config);
+ } else if (config != &logdev) {
+ device_printf(parent,
+ "CSN %d malformed\n",
+ csn);
+ scanning = 0;
+ break;
+ }
+ /*
+ * If the priority is not specified,
+ * then use the default of
+ * 'acceptable'
+ */
+ if (PNP_SRES_LEN(tag) > 0)
+ priority = resinfo[0];
+ else
+ priority = 1;
+ alt = logdev;
+ config = &alt;
+ break;
+
+ case PNP_TAG_END_DEPENDANT:
+ ISA_ADD_CONFIG(parent, dev, priority, config);
+ config = &logdev;
+ break;
+
+ case PNP_TAG_IO_RANGE:
+ if (config->ic_nport == ISA_NPORT) {
+ device_printf(parent,
+ "CSN %d too many ports",
+ csn);
+ scanning = 0;
+ break;
+ }
+ config->ic_port[config->ic_nport].ir_start =
+ resinfo[1] + (resinfo[2]<<8);
+ config->ic_port[config->ic_nport].ir_end =
+ resinfo[3] + (resinfo[4]<<8)
+ + resinfo[6] - 1;
+ config->ic_port[config->ic_nport].ir_size
+ =
+ resinfo[6];
+ config->ic_port[config->ic_nport].ir_align =
+ resinfo[5];
+ config->ic_nport++;
+ break;
+
+ case PNP_TAG_IO_FIXED:
+ if (config->ic_nport == ISA_NPORT) {
+ device_printf(parent,
+ "CSN %d too many ports",
+ csn);
+ scanning = 0;
+ break;
+ }
+ config->ic_port[config->ic_nport].ir_start =
+ resinfo[0] + (resinfo[1]<<8);
+ config->ic_port[config->ic_nport].ir_end =
+ resinfo[0] + (resinfo[1]<<8)
+ + resinfo[2] - 1;
+ config->ic_port[config->ic_nport].ir_size
+ = resinfo[2];
+ config->ic_port[config->ic_nport].ir_align = 1;
+ config->ic_nport++;
+ break;
+
+ case PNP_TAG_END:
+ scanning = 0;
+ break;
+
+ default:
+ /* Skip this resource */
+ break;
+ }
+ } else {
+ /* Large resource */
+ if (pnp_get_resource_info(resinfo, 2) == 0) {
+ scanning = 0;
+ continue;
+ }
+ large_len = resinfo[0] + (resinfo[1] << 8);
+
+ if (PNP_LRES_NUM(tag) == PNP_TAG_ID_ANSI) {
+ if (desc)
+ free(desc, M_TEMP);
+ desc = malloc(large_len + 1,
+ M_TEMP, M_NOWAIT);
+ /*
+ * Note: if malloc fails, this will
+ * skip the resource instead of
+ * reading it into desc.
+ */
+ if (pnp_get_resource_info(desc,
+ large_len) == 0) {
+ scanning = 0;
+ }
+ if (desc) {
+ /*
+ * Trim trailing spaces.
+ */
+ while (desc[large_len-1] == ' ')
+ large_len--;
+ desc[large_len] = '\0';
+ if (dev)
+ device_set_desc_copy
+ (dev, desc);
+ }
+ continue;
+ }
+
+ if (PNP_LRES_NUM(tag) != PNP_TAG_MEMORY_RANGE) {
+ /* skip */
+ if (pnp_get_resource_info(NULL,
+ large_len) == 0) {
+ scanning = 0;
+ }
+ continue;
+ }
+
+ if (pnp_get_resource_info(resinfo, large_len) == 0) {
+ scanning = 0;
+ continue;
+ }
+
+ if (config->ic_nmem == ISA_NMEM) {
+ device_printf(parent,
+ "CSN %d too many memory ranges",
+ csn);
+ scanning = 0;
+ break;
+ }
+
+ config->ic_mem[config->ic_nmem].ir_start =
+ (resinfo[4]<<8) + (resinfo[5]<<16);
+ config->ic_mem[config->ic_nmem].ir_end =
+ (resinfo[6]<<8) + (resinfo[7]<<16);
+ config->ic_mem[config->ic_nmem].ir_size =
+ (resinfo[10]<<8) + (resinfo[11]<<16);
+ config->ic_mem[config->ic_nmem].ir_align =
+ resinfo[8] + (resinfo[9]<<8);
+ if (!config->ic_mem[config->ic_nmem].ir_align)
+ config->ic_mem[config->ic_nmem].ir_align =
+ 0x10000;
+ config->ic_nmem++;
+ }
+ }
+
+ if (desc)
+ free(desc, M_TEMP);
+
+ return retval;
+}
+
+/*
+ * Run the isolation protocol. Use pnp_rd_port as the READ_DATA port
+ * value (caller should try multiple READ_DATA locations before giving
+ * up). Upon exiting, all cards are aware that they should use
+ * pnp_rd_port as the READ_DATA port.
+ *
+ * In the first pass, a csn is assigned to each board and pnp_id's
+ * are saved to an array, pnp_devices. In the second pass, each
+ * card is woken up and the device configuration is called.
+ */
+static int
+pnp_isolation_protocol(device_t parent)
+{
+ int csn;
+ pnp_id id;
+ int found = 0;
+
+ /*
+ * Put all cards into the Sleep state so that we can clear
+ * their CSNs.
+ */
+ pnp_send_initiation_key();
+
+ /*
+ * Clear the CSN for all cards.
+ */
+ pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_RESET_CSN);
+
+ /*
+ * Move all cards to the Isolation state.
+ */
+ pnp_write(PNP_WAKE, 0);
+
+ /*
+ * Tell them where the read point is going to be this time.
+ */
+ pnp_write(PNP_SET_RD_DATA, pnp_rd_port);
+
+ for (csn = 1; csn < PNP_MAX_CARDS; csn++) {
+ /*
+ * Start the serial isolation protocol.
+ */
+ outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
+ DELAY(1000); /* Delay 1 msec */
+
+ if (pnp_get_serial(&id)) {
+ /*
+ * We have read the id from a card
+ * successfully. The card which won the
+ * isolation protocol will be in Isolation
+ * mode and all others will be in Sleep. *
+ * Program the CSN of the isolated card
+ * (taking it to Config state) and read its
+ * resources, creating devices as we find
+ * logical devices on the card.
+ */
+ pnp_write(PNP_SET_CSN, csn);
+ pnp_scan_resdata(parent, &id, csn);
+ found++;
+ } else
+ break;
+
+ /*
+ * Put this card back to the Sleep state and
+ * simultaneously move all cards which don't have a
+ * CSN yet to Isolation state.
+ */
+ pnp_write(PNP_WAKE, 0);
+ }
+
+ /*
+ * Unless we have chosen the wrong read port, all cards will
+ * be in Sleep state. Put them back into WaitForKey for
+ * now. Their resources will be programmed later.
+ */
+ pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY);
+
+ return found;
+}
+
+
+/*
+ * pnp_identify()
+ *
+ * autoconfiguration of pnp devices. This routine just runs the
+ * isolation protocol over several ports, until one is successful.
+ *
+ * may be called more than once ?
+ *
+ */
+
+static void
+pnp_identify(driver_t *driver, device_t parent)
+{
+ int num_pnp_devs;
+
+#if 0
+ if (pnp_ldn_overrides[0].csn == 0) {
+ if (bootverbose)
+ printf("Initializing PnP override table\n");
+ bzero (pnp_ldn_overrides, sizeof(pnp_ldn_overrides));
+ pnp_ldn_overrides[0].csn = 255 ;
+ }
+#endif
+
+ /* Try various READ_DATA ports from 0x203-0x3ff */
+ for (pnp_rd_port = 0x80; (pnp_rd_port < 0xff); pnp_rd_port += 0x10) {
+ if (bootverbose)
+ printf("Trying Read_Port at %x\n", (pnp_rd_port << 2) | 0x3);
+
+ num_pnp_devs = pnp_isolation_protocol(parent);
+ if (num_pnp_devs)
+ break;
+ }
+}
+
+static device_method_t pnp_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, pnp_identify),
+
+ { 0, 0 }
+};
+
+static driver_t pnp_driver = {
+ "pnp",
+ pnp_methods,
+ 1, /* no softc */
+};
+
+static devclass_t pnp_devclass;
+
+DRIVER_MODULE(pnp, isa, pnp_driver, pnp_devclass, 0, 0);
diff --git a/sys/isa/pnp.h b/sys/isa/pnpreg.h
index cc50a1a..fed7a4c 100644
--- a/sys/isa/pnp.h
+++ b/sys/isa/pnpreg.h
@@ -29,20 +29,23 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD$
* from: pnp.h,v 1.7 1998/09/13 22:15:44 eivind Exp
*/
-#ifndef _ISA_PNP_H_
-#define _ISA_PNP_H_
+#ifndef _ISA_PNPREG_H_
+#define _ISA_PNPREG_H_
/* Maximum Number of PnP Devices. 8 should be plenty */
-#define MAX_PNP_CARDS 8
+#define PNP_MAX_CARDS 8
+
+#if 0
/*
* the following is the maximum number of PnP Logical devices that
* userconfig can handle.
*/
#define MAX_PNP_LDN 20
+#endif
/* Static ports to access PnP state machine */
#if defined(PC98) && defined(KERNEL)
@@ -55,21 +58,24 @@
#endif
/* PnP Registers. Write to ADDRESS and then use WRITE/READ_DATA */
-#define SET_RD_DATA 0x00
+#define PNP_SET_RD_DATA 0x00
/***
Writing to this location modifies the address of the port used for
reading from the Plug and Play ISA cards. Bits[7:0] become I/O
read port address bits[9:2]. Reads from this register are ignored.
***/
-#define SERIAL_ISOLATION 0x01
+#define PNP_SERIAL_ISOLATION 0x01
/***
A read to this register causes a Plug and Play cards in the Isolation
state to compare one bit of the boards ID.
This register is read only.
***/
-#define CONFIG_CONTROL 0x02
+#define PNP_CONFIG_CONTROL 0x02
+#define PNP_CONFIG_CONTROL_RESET_CSN 0x04
+#define PNP_CONFIG_CONTROL_WAIT_FOR_KEY 0x02
+#define PNP_CONFIG_CONTROL_RESET 0x01
/***
Bit[2] Reset CSN to 0
Bit[1] Return to the Wait for Key state
@@ -93,7 +99,7 @@
software to clear the bits.
***/
-#define WAKE 0x03
+#define PNP_WAKE 0x03
/***
A write to this port will cause all cards that have a CSN that
matches the write data[7:0] to go from the Sleep state to the either
@@ -103,20 +109,20 @@
writeonly.
***/
-#define RESOURCE_DATA 0x04
+#define PNP_RESOURCE_DATA 0x04
/***
A read from this address reads the next byte of resource information.
The Status register must be polled until bit[0] is set before this
register may be read. This register is read only.
***/
-#define STATUS 0x05
+#define PNP_STATUS 0x05
/***
Bit[0] when set indicates it is okay to read the next data byte
from the Resource Data register. This register is readonly.
***/
-#define SET_CSN 0x06
+#define PNP_SET_CSN 0x06
/***
A write to this port sets a card's CSN. The CSN is a value uniquely
assigned to each ISA card after the serial identification process
@@ -124,7 +130,7 @@
command. This register is read/write.
***/
-#define SET_LDN 0x07
+#define PNP_SET_LDN 0x07
/***
Selects the current logical device. All reads and writes of memory,
I/O, interrupt and DMA configuration information access the registers
@@ -137,7 +143,7 @@
/*** addresses 0x08 - 0x1F Card Level Reserved for future use ***/
/*** addresses 0x20 - 0x2F Card Level, Vendor Defined ***/
-#define ACTIVATE 0x30
+#define PNP_ACTIVATE 0x30
/***
For each logical device there is one activate register that controls
whether or not the logical device is active on the ISA bus. Bit[0],
@@ -146,7 +152,9 @@
logical device is activated, I/O range check must be disabled.
***/
-#define IO_RANGE_CHECK 0x31
+#define PNP_IO_RANGE_CHECK 0x31
+#define PNP_IO_RANGE_CHECK_ENABLE 0x02
+#define PNP_IO_RANGE_CHECK_READ_AS_55 0x01
/***
This register is used to perform a conflict check on the I/O port
range programmed for use by a logical device.
@@ -165,7 +173,13 @@
/*** addr 0x32 - 0x37 Logical Device Control Reserved for future use ***/
/*** addr 0x38 - 0x3F Logical Device Control Vendor Define ***/
-#define MEM_CONFIG 0x40
+#define PNP_MEM_BASE_HIGH(i) (0x40 + 8*(i))
+#define PNP_MEM_BASE_LOW(i) (0x41 + 8*(i))
+#define PNP_MEM_CONTROL(i) (0x42 * 8*(i))
+#define PNP_MEM_CONTROL_16BIT 0x2
+#define PNP_MEM_CONTROL_LIMIT 0x1
+#define PNP_MEM_RANGE_HIGH(i) (0x43 + 8*(i))
+#define PNP_MEM_RANGE_LOW(i) (0x44 + 8*(i))
/***
Four memory resource registers per range, four ranges.
Fill with 0 if no ranges are enabled.
@@ -185,14 +199,16 @@
Offset 5-Offset 7: filler, unused.
***/
-#define IO_CONFIG_BASE 0x60
+#define PNP_IO_BASE_HIGH(i) (0x60 + 2*(i))
+#define PNP_IO_BASE_LOW(i) (0x61 + 2*(i))
/***
Eight ranges, two bytes per range.
Offset 0: I/O port base address bits[15:8]
Offset 1: I/O port base address bits[7:0]
***/
-#define IRQ_CONFIG 0x70
+#define PNP_IRQ_LEVEL(i) (0x70 + 2*(i))
+#define PNP_IRQ_TYPE(i) (0x71 + 2*(i))
/***
Two entries, two bytes per entry.
Offset 0: RW interrupt level (1..15, 0=unused).
@@ -201,7 +217,7 @@
byte 1 can be readonly if 1 type of int is used.
***/
-#define DRQ_CONFIG 0x74
+#define PNP_DMA_CHANNEL(i) (0x74 + 1*(i))
/***
Two entries, one byte per entry. Bits[2:0] select
which DMA channel is in use for DMA 0. Zero selects DMA channel
@@ -218,91 +234,26 @@
#define PNP_LRES_NUM(a) (a & 0x7f)
/* Small Resource Item names */
-#define PNP_VERSION 0x1
-#define LOG_DEVICE_ID 0x2
-#define COMP_DEVICE_ID 0x3
-#define IRQ_FORMAT 0x4
-#define DMA_FORMAT 0x5
-#define START_DEPEND_FUNC 0x6
-#define END_DEPEND_FUNC 0x7
-#define IO_PORT_DESC 0x8
-#define FIXED_IO_PORT_DESC 0x9
-#define SM_RES_RESERVED 0xa-0xd
-#define SM_VENDOR_DEFINED 0xe
-#define END_TAG 0xf
+#define PNP_TAG_VERSION 0x1
+#define PNP_TAG_LOGIGAL_DEVICE 0x2
+#define PNP_TAG_COMPAT_DEVICE 0x3
+#define PNP_TAG_IRQ_FORMAT 0x4
+#define PNP_TAG_DMA_FORMAT 0x5
+#define PNP_TAG_START_DEPENDANT 0x6
+#define PNP_TAG_END_DEPENDANT 0x7
+#define PNP_TAG_IO_RANGE 0x8
+#define PNP_TAG_IO_FIXED 0x9
+#define PNP_TAG_RESERVED 0xa-0xd
+#define PNP_TAG_VENDOR 0xe
+#define PNP_TAG_END 0xf
/* Large Resource Item names */
-#define MEMORY_RANGE_DESC 0x1
-#define ID_STRING_ANSI 0x2
-#define ID_STRING_UNICODE 0x3
-#define LG_VENDOR_DEFINED 0x4
-#define _32BIT_MEM_RANGE_DESC 0x5
-#define _32BIT_FIXED_LOC_DESC 0x6
-#define LG_RES_RESERVED 0x7-0x7f
-
-/*
- * pnp_cinfo contains Configuration Information. They are used
- * to communicate to the device driver the actual configuration
- * of the device, and also by the userconfig menu to let the
- * operating system override any configuration set by the bios.
- *
- */
-struct pnp_cinfo {
- u_int vendor_id; /* board id */
- u_int serial; /* Board's Serial Number */
- u_long flags; /* OS-reserved flags */
- u_char csn; /* assigned Card Select Number */
- u_char ldn; /* Logical Device Number */
- u_char enable; /* pnp enable */
- u_char override; /* override bios parms (in userconfig) */
- u_char irq[2]; /* IRQ Number */
- u_char irq_type[2]; /* IRQ Type */
- u_char drq[2];
- u_short port[8]; /* The Base Address of the Port */
- struct {
- u_int32_t base; /* Memory Base Address */
- int control; /* Memory Control Register */
- u_int32_t range; /* Memory Range *OR* Upper Limit */
- } mem[4];
-};
-
-#ifdef KERNEL
-
-/*
- * Used by userconfig
- */
-extern struct pnp_cinfo pnp_ldn_overrides[MAX_PNP_LDN];
-
-/*
- * The following definitions are for use in drivers
- */
-extern struct linker_set pnpdevice_set;
-
-typedef struct _pnpid_t {
- u_int32_t vend_id; /* Not anly a Vendor ID, also a Compatible Device ID */
- char *id_str;
-} pnpid_t;
-
-void pnp_write(int d, u_char r); /* used by Luigi's sound driver */
-u_char pnp_read(int d); /* currently unused, but who knows... */
-int enable_pnp_card(void);
-
-#define PNP_HEXTONUM(c) ((c) >= 'a' \
- ? (c) - 'a' + 10 \
- : ((c) >= 'A' \
- ? (c) - 'A' + 10 \
- : (c) - '0'))
-
-#define PNP_EISAID(s) \
- ((((s[0] - '@') & 0x1f) << 2) \
- | (((s[1] - '@') & 0x18) >> 3) \
- | (((s[1] - '@') & 0x07) << 13) \
- | (((s[2] - '@') & 0x1f) << 8) \
- | (PNP_HEXTONUM(s[4]) << 16) \
- | (PNP_HEXTONUM(s[3]) << 20) \
- | (PNP_HEXTONUM(s[6]) << 24) \
- | (PNP_HEXTONUM(s[5]) << 28))
-
-#endif /* KERNEL */
-
-#endif /* !_ISA_PNP_H_ */
+#define PNP_TAG_MEMORY_RANGE 0x1
+#define PNP_TAG_ID_ANSI 0x2
+#define PNP_TAG_ID_UNICODE 0x3
+#define PNP_TAG_LARGE_VENDOR 0x4
+#define PNP_TAG_MEMORY32_RANGE 0x5
+#define PNP_TAG_MEMORY32_FIXED 0x6
+#define PNP_TAG_LARGE_RESERVED 0x7-0x7f
+
+#endif /* !_ISA_PNPREG_H_ */
diff --git a/sys/isa/pnpvar.h b/sys/isa/pnpvar.h
new file mode 100644
index 0000000..063663d
--- /dev/null
+++ b/sys/isa/pnpvar.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1999 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ISA_PNPVAR_H_
+#define _ISA_PNPVAR_H_
+
+#ifdef KERNEL
+
+#if 0
+void pnp_write(int d, u_char r); /* used by Luigi's sound driver */
+u_char pnp_read(int d); /* currently unused, but who knows... */
+#endif
+
+#define PNP_HEXTONUM(c) ((c) >= 'a' \
+ ? (c) - 'a' + 10 \
+ : ((c) >= 'A' \
+ ? (c) - 'A' + 10 \
+ : (c) - '0'))
+
+#define PNP_EISAID(s) \
+ ((((s[0] - '@') & 0x1f) << 2) \
+ | (((s[1] - '@') & 0x18) >> 3) \
+ | (((s[1] - '@') & 0x07) << 13) \
+ | (((s[2] - '@') & 0x1f) << 8) \
+ | (PNP_HEXTONUM(s[4]) << 16) \
+ | (PNP_HEXTONUM(s[3]) << 20) \
+ | (PNP_HEXTONUM(s[6]) << 24) \
+ | (PNP_HEXTONUM(s[5]) << 28))
+
+#endif /* KERNEL */
+
+#endif /* !_ISA_PNPVAR_H_ */
diff --git a/sys/isa/sio.c b/sys/isa/sio.c
index 0cd84ba..503aa3e 100644
--- a/sys/isa/sio.c
+++ b/sys/isa/sio.c
@@ -577,6 +577,15 @@ card_intr(struct pccard_devinfo *devi)
#define SET_FLAG(dev, bit) isa_set_flags(dev, isa_get_flags(dev) | (bit))
#define CLR_FLAG(dev, bit) isa_set_flags(dev, isa_get_flags(dev) & ~(bit))
+static struct isa_pnp_id sio_ids[] = {
+ {0x0005d041, "Standard PC COM port"}, /* PNP0500 */
+ {0x0105d041, "16550A-compatible COM port"}, /* PNP0501 */
+ {0x0205d041, "Multiport serial device (non-intelligent 16550)"}, /* PNP0502 */
+ {0x1005d041, "Generic IRDA-compatible device"}, /* PNP0510 */
+ {0x1105d041, "Generic IRDA-compatible device"}, /* PNP0511 */
+ {0}
+};
+
static int
sioprobe(dev)
device_t dev;
@@ -596,10 +605,7 @@ sioprobe(dev)
struct resource *port;
/* Check isapnp ids */
- if (isa_get_vendorid(dev)
- && isa_get_compatid(dev) != PNP_EISAID("PNP0500")
- && isa_get_compatid(dev) != PNP_EISAID("PNP0501")
- && isa_get_compatid(dev) != PNP_EISAID("PNP0502"))
+ if (ISA_PNP_PROBE(device_get_parent(dev), dev, sio_ids) == ENXIO)
return (ENXIO);
rid = 0;
@@ -2628,11 +2634,12 @@ static cn_putc_t siocnputc;
#ifdef __i386__
CONS_DRIVER(sio, siocnprobe, siocninit, NULL, siocngetc, siocncheckc, siocnputc);
+#endif
+
/* To get the GDB related variables */
#if DDB > 0
#include <ddb/ddb.h>
#endif
-#endif
static void
siocntxwait(iobase)
@@ -2830,17 +2837,15 @@ siocnprobe(cp)
siocniobase = iobase;
siocnunit = unit;
}
- if (COM_DEBUGGER(flags) && !COM_LLCONSOLE(flags)) {
+ if (COM_DEBUGGER(flags)) {
printf("sio%d: gdb debugging port\n", unit);
siogdbiobase = iobase;
siogdbunit = unit;
-#ifdef __i386__
#if DDB > 0
gdbdev = makedev(CDEV_MAJOR, unit);
gdb_getc = siocngetc;
gdb_putc = siocnputc;
#endif
-#endif
}
}
}
OpenPOWER on IntegriCloud