diff options
-rw-r--r-- | sys/alpha/alpha/autoconf.c | 11 | ||||
-rw-r--r-- | sys/amd64/amd64/autoconf.c | 17 | ||||
-rw-r--r-- | sys/conf/files | 13 | ||||
-rw-r--r-- | sys/conf/files.i386 | 7 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.c | 13 | ||||
-rw-r--r-- | sys/dev/pcm/isa/mss.c | 4 | ||||
-rw-r--r-- | sys/dev/sio/sio.c | 21 | ||||
-rw-r--r-- | sys/dev/sound/isa/mss.c | 4 | ||||
-rw-r--r-- | sys/i386/conf/files.i386 | 7 | ||||
-rw-r--r-- | sys/i386/i386/autoconf.c | 17 | ||||
-rw-r--r-- | sys/i386/i386/userconfig.c | 3 | ||||
-rw-r--r-- | sys/i386/isa/isa_compat.h | 4 | ||||
-rw-r--r-- | sys/isa/isa_common.c | 554 | ||||
-rw-r--r-- | sys/isa/isa_common.h | 13 | ||||
-rw-r--r-- | sys/isa/isa_if.m | 44 | ||||
-rw-r--r-- | sys/isa/isavar.h | 68 | ||||
-rw-r--r-- | sys/isa/pnp.c | 761 | ||||
-rw-r--r-- | sys/isa/pnpreg.h (renamed from sys/isa/pnp.h) | 159 | ||||
-rw-r--r-- | sys/isa/pnpvar.h | 57 | ||||
-rw-r--r-- | sys/isa/sio.c | 21 |
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 } } } |