This represents essentially a complete rewrite of the ISA PnP code. The
new system is integrated with the ISA bus code more cleanly and allows the future addition of more enumerators such as PnPBIOS and ACPI. This commit also enables the new pcm driver since it is somewhat tied to the new PnP code.
This commit is contained in:
parent
5d3e37130b
commit
4249382df0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=50769
@ -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();
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,16 +2837,14 @@ 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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -99,12 +99,390 @@ 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.
|
||||
*/
|
||||
@ -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);
|
||||
struct resource_list_entry *rle;
|
||||
int printed;
|
||||
int i;
|
||||
|
||||
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)
|
||||
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);
|
||||
|
@ -35,6 +35,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.
|
||||
*/
|
||||
@ -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))
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 */
|
||||
|
||||
|
761
sys/isa/pnp.c
Normal file
761
sys/isa/pnp.c
Normal file
@ -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);
|
@ -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
|
||||
#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
|
||||
|
||||
/*
|
||||
* 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_ */
|
||||
#endif /* !_ISA_PNPREG_H_ */
|
57
sys/isa/pnpvar.h
Normal file
57
sys/isa/pnpvar.h
Normal file
@ -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_ */
|
@ -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,16 +2837,14 @@ 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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user