aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/bios.c73
-rw-r--r--sys/i386/i386/bios.c73
-rw-r--r--sys/isa/pnp.c18
-rw-r--r--sys/isa/pnpparse.c199
-rw-r--r--sys/isa/pnpvar.h1
5 files changed, 281 insertions, 83 deletions
diff --git a/sys/amd64/amd64/bios.c b/sys/amd64/amd64/bios.c
index b66d87212226..63158c4686b7 100644
--- a/sys/amd64/amd64/bios.c
+++ b/sys/amd64/amd64/bios.c
@@ -31,10 +31,13 @@
* Code for dealing with the BIOS in x86 PC systems.
*/
+#include "opt_pnp.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/bus.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/md_var.h>
@@ -43,6 +46,8 @@
#include <machine/vmparam.h>
#include <machine/pc/bios.h>
#include <isa/pnpreg.h>
+#include <isa/pnpvar.h>
+#include <isa/isavar.h>
#define BIOS_START 0xe0000
#define BIOS_SIZE 0x20000
@@ -57,10 +62,6 @@ static u_int bios32_SDCI = 0;
static void bios32_init(void *junk);
SYSINIT(bios32, SI_SUB_CPU, SI_ORDER_ANY, bios32_init, NULL);
-static void pnpbios_scan(void);
-static char *pnp_eisaformat(u_int8_t *data);
-
-
/*
* bios32_init
*
@@ -127,7 +128,6 @@ bios32_init(void *junk)
printf("pnpbios: OEM ID %x\n", pt->oemdevid);
}
- pnpbios_scan();
} else {
printf("pnpbios: Bad PnP BIOS data checksum\n");
}
@@ -450,6 +450,8 @@ bios16(struct bios_args *args, char *fmt, ...)
return (i);
}
+#ifdef PNPBIOS /* remove conditional later */
+
/*
* PnP BIOS interface; enumerate devices only known to the system
* BIOS and save information about them for later use.
@@ -484,10 +486,19 @@ struct pnp_sysdevargs
};
/*
+ * This function is called after the bus has assigned resource
+ * locations for a logical device.
+ */
+static void
+pnpbios_set_config(void *arg, struct isa_config *config, int enable)
+{
+}
+
+/*
* Quiz the PnP BIOS, build a list of PNP IDs and resource data.
*/
static void
-pnpbios_scan(void)
+pnpbios_identify(driver_t *driver, device_t parent)
{
struct PnPBIOS_table *pt = PnPBIOStable;
struct bios_args args;
@@ -498,6 +509,7 @@ pnpbios_scan(void)
u_int8_t *devnodebuf, tag;
u_int32_t *devid, *compid;
int idx, left;
+ device_t dev;
/* no PnP BIOS information */
if (pt == NULL)
@@ -542,6 +554,16 @@ pnpbios_scan(void)
break;
}
+ /* Add the device and parse its resources */
+ dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1);
+ isa_set_vendorid(dev, pd->devid);
+ isa_set_logicalid(dev, pd->devid);
+ ISA_SET_CONFIG_CALLBACK(parent, dev, pnpbios_set_config, 0);
+ pnp_parse_resources(dev, &pd->devdata[0],
+ pd->size - sizeof(struct pnp_sysdev));
+ if (!device_get_desc(dev))
+ device_set_desc_copy(dev, pnp_eisaformat(pd->devid));
+
/* Find device IDs */
devid = &pd->devid;
compid = NULL;
@@ -572,29 +594,30 @@ pnpbios_scan(void)
}
if (bootverbose) {
printf("pnpbios: handle %d device ID %s (%08x)",
- pd->handle, pnp_eisaformat((u_int8_t *)devid), *devid);
+ pd->handle, pnp_eisaformat(*devid), *devid);
if (compid != NULL)
printf(" compat ID %s (%08x)",
- pnp_eisaformat((u_int8_t *)compid), *compid);
+ pnp_eisaformat(*compid), *compid);
printf("\n");
}
}
}
-/* XXX should be somewhere else */
-static char *
-pnp_eisaformat(u_int8_t *data)
-{
- static char idbuf[8];
- const char hextoascii[] = "0123456789abcdef";
-
- idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
- idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
- idbuf[2] = '@' + (data[1] & 0x1f);
- idbuf[3] = hextoascii[(data[2] >> 4)];
- idbuf[4] = hextoascii[(data[2] & 0xf)];
- idbuf[5] = hextoascii[(data[3] >> 4)];
- idbuf[6] = hextoascii[(data[3] & 0xf)];
- idbuf[7] = 0;
- return(idbuf);
-}
+static device_method_t pnpbios_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, pnpbios_identify),
+
+ { 0, 0 }
+};
+
+static driver_t pnpbios_driver = {
+ "pnpbios",
+ pnpbios_methods,
+ 1, /* no softc */
+};
+
+static devclass_t pnpbios_devclass;
+
+DRIVER_MODULE(pnpbios, isa, pnpbios_driver, pnpbios_devclass, 0, 0);
+
+#endif /* PNPBIOS */
diff --git a/sys/i386/i386/bios.c b/sys/i386/i386/bios.c
index b66d87212226..63158c4686b7 100644
--- a/sys/i386/i386/bios.c
+++ b/sys/i386/i386/bios.c
@@ -31,10 +31,13 @@
* Code for dealing with the BIOS in x86 PC systems.
*/
+#include "opt_pnp.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/bus.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/md_var.h>
@@ -43,6 +46,8 @@
#include <machine/vmparam.h>
#include <machine/pc/bios.h>
#include <isa/pnpreg.h>
+#include <isa/pnpvar.h>
+#include <isa/isavar.h>
#define BIOS_START 0xe0000
#define BIOS_SIZE 0x20000
@@ -57,10 +62,6 @@ static u_int bios32_SDCI = 0;
static void bios32_init(void *junk);
SYSINIT(bios32, SI_SUB_CPU, SI_ORDER_ANY, bios32_init, NULL);
-static void pnpbios_scan(void);
-static char *pnp_eisaformat(u_int8_t *data);
-
-
/*
* bios32_init
*
@@ -127,7 +128,6 @@ bios32_init(void *junk)
printf("pnpbios: OEM ID %x\n", pt->oemdevid);
}
- pnpbios_scan();
} else {
printf("pnpbios: Bad PnP BIOS data checksum\n");
}
@@ -450,6 +450,8 @@ bios16(struct bios_args *args, char *fmt, ...)
return (i);
}
+#ifdef PNPBIOS /* remove conditional later */
+
/*
* PnP BIOS interface; enumerate devices only known to the system
* BIOS and save information about them for later use.
@@ -484,10 +486,19 @@ struct pnp_sysdevargs
};
/*
+ * This function is called after the bus has assigned resource
+ * locations for a logical device.
+ */
+static void
+pnpbios_set_config(void *arg, struct isa_config *config, int enable)
+{
+}
+
+/*
* Quiz the PnP BIOS, build a list of PNP IDs and resource data.
*/
static void
-pnpbios_scan(void)
+pnpbios_identify(driver_t *driver, device_t parent)
{
struct PnPBIOS_table *pt = PnPBIOStable;
struct bios_args args;
@@ -498,6 +509,7 @@ pnpbios_scan(void)
u_int8_t *devnodebuf, tag;
u_int32_t *devid, *compid;
int idx, left;
+ device_t dev;
/* no PnP BIOS information */
if (pt == NULL)
@@ -542,6 +554,16 @@ pnpbios_scan(void)
break;
}
+ /* Add the device and parse its resources */
+ dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1);
+ isa_set_vendorid(dev, pd->devid);
+ isa_set_logicalid(dev, pd->devid);
+ ISA_SET_CONFIG_CALLBACK(parent, dev, pnpbios_set_config, 0);
+ pnp_parse_resources(dev, &pd->devdata[0],
+ pd->size - sizeof(struct pnp_sysdev));
+ if (!device_get_desc(dev))
+ device_set_desc_copy(dev, pnp_eisaformat(pd->devid));
+
/* Find device IDs */
devid = &pd->devid;
compid = NULL;
@@ -572,29 +594,30 @@ pnpbios_scan(void)
}
if (bootverbose) {
printf("pnpbios: handle %d device ID %s (%08x)",
- pd->handle, pnp_eisaformat((u_int8_t *)devid), *devid);
+ pd->handle, pnp_eisaformat(*devid), *devid);
if (compid != NULL)
printf(" compat ID %s (%08x)",
- pnp_eisaformat((u_int8_t *)compid), *compid);
+ pnp_eisaformat(*compid), *compid);
printf("\n");
}
}
}
-/* XXX should be somewhere else */
-static char *
-pnp_eisaformat(u_int8_t *data)
-{
- static char idbuf[8];
- const char hextoascii[] = "0123456789abcdef";
-
- idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
- idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
- idbuf[2] = '@' + (data[1] & 0x1f);
- idbuf[3] = hextoascii[(data[2] >> 4)];
- idbuf[4] = hextoascii[(data[2] & 0xf)];
- idbuf[5] = hextoascii[(data[3] >> 4)];
- idbuf[6] = hextoascii[(data[3] & 0xf)];
- idbuf[7] = 0;
- return(idbuf);
-}
+static device_method_t pnpbios_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, pnpbios_identify),
+
+ { 0, 0 }
+};
+
+static driver_t pnpbios_driver = {
+ "pnpbios",
+ pnpbios_methods,
+ 1, /* no softc */
+};
+
+static devclass_t pnpbios_devclass;
+
+DRIVER_MODULE(pnpbios, isa, pnpbios_driver, pnpbios_devclass, 0, 0);
+
+#endif /* PNPBIOS */
diff --git a/sys/isa/pnp.c b/sys/isa/pnp.c
index abd79f4affbb..12b5dabf1fe3 100644
--- a/sys/isa/pnp.c
+++ b/sys/isa/pnp.c
@@ -90,6 +90,24 @@ static void pnp_send_initiation_key(void);
static int pnp_get_serial(pnp_id *p);
static int pnp_isolation_protocol(device_t parent);
+char *
+pnp_eisaformat(u_int32_t id)
+{
+ u_int8_t *data = (u_int8_t *) &id;
+ static char idbuf[8];
+ const char hextoascii[] = "0123456789abcdef";
+
+ idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
+ idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
+ idbuf[2] = '@' + (data[1] & 0x1f);
+ idbuf[3] = hextoascii[(data[2] >> 4)];
+ idbuf[4] = hextoascii[(data[2] & 0xf)];
+ idbuf[5] = hextoascii[(data[3] >> 4)];
+ idbuf[6] = hextoascii[(data[3] & 0xf)];
+ idbuf[7] = 0;
+ return(idbuf);
+}
+
static void
pnp_write(int d, u_char r)
{
diff --git a/sys/isa/pnpparse.c b/sys/isa/pnpparse.c
index 766869dff9e0..e513662524eb 100644
--- a/sys/isa/pnpparse.c
+++ b/sys/isa/pnpparse.c
@@ -35,6 +35,9 @@
#include <isa/pnpreg.h>
#include <isa/pnpvar.h>
+#define I16(p) ((p)[0] + ((p)[1] << 8))
+#define I32(p) (I16(p) + (I16(p+2) << 16))
+
/*
* Parse resource data for Logical Devices.
*
@@ -48,13 +51,14 @@ pnp_parse_resources(device_t dev, u_char *resources, int len)
device_t parent = device_get_parent(dev);
u_char tag, *resp, *resinfo;
int large_len, scanning = len;
- u_int32_t compat_id;
+ u_int32_t id, compat_id;
struct isa_config logdev, alt;
struct isa_config *config;
int priority = 0;
int seenalt = 0;
char buf[100];
+ id = isa_get_logicalid(dev);
bzero(&logdev, sizeof logdev);
bzero(&alt, sizeof alt);
config = &logdev;
@@ -84,17 +88,27 @@ pnp_parse_resources(device_t dev, u_char *resources, int len)
break;
case PNP_TAG_IRQ_FORMAT:
+ if (bootverbose) {
+ printf("%s: adding irq mask %#04x\n",
+ pnp_eisaformat(id),
+ I16(resinfo));
+ }
if (config->ic_nirq == ISA_NIRQ) {
device_printf(parent, "too many irqs");
scanning = 0;
break;
}
config->ic_irqmask[config->ic_nirq] =
- resinfo[0] + (resinfo[1]<<8);
+ I16(resinfo);
config->ic_nirq++;
break;
case PNP_TAG_DMA_FORMAT:
+ if (bootverbose) {
+ printf("%s: adding dma mask %#02x\n",
+ pnp_eisaformat(id),
+ resinfo[0]);
+ }
if (config->ic_ndrq == ISA_NDRQ) {
device_printf(parent, "too many drqs");
scanning = 0;
@@ -106,6 +120,10 @@ pnp_parse_resources(device_t dev, u_char *resources, int len)
break;
case PNP_TAG_START_DEPENDANT:
+ if (bootverbose) {
+ printf("%s: start dependant\n",
+ pnp_eisaformat(id));
+ }
if (config == &alt) {
ISA_ADD_CONFIG(parent, dev,
priority, config);
@@ -128,47 +146,80 @@ pnp_parse_resources(device_t dev, u_char *resources, int len)
break;
case PNP_TAG_END_DEPENDANT:
+ if (bootverbose) {
+ printf("%s: end dependant\n",
+ pnp_eisaformat(id));
+ }
ISA_ADD_CONFIG(parent, dev, priority, config);
config = &logdev;
seenalt = 1;
break;
case PNP_TAG_IO_RANGE:
+ if (bootverbose) {
+ printf("%s: adding io range "
+ "%#x-%#x, size=%#x, "
+ "align=%#x\n",
+ pnp_eisaformat(id),
+ I16(resinfo + 1),
+ I16(resinfo + 3) + resinfo[6]-1,
+ resinfo[6],
+ resinfo[5]);
+ }
if (config->ic_nport == ISA_NPORT) {
device_printf(parent, "too many ports");
scanning = 0;
break;
}
config->ic_port[config->ic_nport].ir_start =
- resinfo[1] + (resinfo[2]<<8);
+ I16(resinfo + 1);
config->ic_port[config->ic_nport].ir_end =
- resinfo[3] + (resinfo[4]<<8)
- + resinfo[6] - 1;
- config->ic_port[config->ic_nport].ir_size
- =
+ I16(resinfo + 3) + resinfo[6] - 1;
+ config->ic_port[config->ic_nport].ir_size =
resinfo[6];
+ if (resinfo[5] == 0) {
+ /* Make sure align is at least one */
+ resinfo[5] = 1;
+ }
config->ic_port[config->ic_nport].ir_align =
resinfo[5];
config->ic_nport++;
break;
case PNP_TAG_IO_FIXED:
+ if (bootverbose) {
+ printf("%s: adding io range "
+ "%#x-%#x, size=%#x, "
+ "align=%#x\n",
+ pnp_eisaformat(id),
+ I16(resinfo),
+ I16(resinfo) + resinfo[2] - 1,
+ resinfo[2],
+ 1);
+ }
if (config->ic_nport == ISA_NPORT) {
device_printf(parent, "too many ports");
scanning = 0;
break;
}
config->ic_port[config->ic_nport].ir_start =
- resinfo[0] + (resinfo[1]<<8);
+ I16(resinfo);
config->ic_port[config->ic_nport].ir_end =
- resinfo[0] + (resinfo[1]<<8)
- + resinfo[2] - 1;
+ I16(resinfo) + 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:
+ if (bootverbose) {
+ printf("%s: start dependant\n",
+ pnp_eisaformat(id));
+ }
+ scanning = 0;
+ break;
+
default:
/* Skip this resource */
device_printf(parent, "unexpected tag %d\n",
@@ -181,7 +232,7 @@ pnp_parse_resources(device_t dev, u_char *resources, int len)
scanning = 0;
continue;
}
- large_len = resp[0] + (resp[1] << 8);
+ large_len = I16(resp);
resp += 2;
scanning -= 2;
@@ -193,7 +244,8 @@ pnp_parse_resources(device_t dev, u_char *resources, int len)
resp += large_len;
scanning -= large_len;
- if (PNP_LRES_NUM(tag) == PNP_TAG_ID_ANSI) {
+ switch (PNP_LRES_NUM(tag)) {
+ case PNP_TAG_ID_ANSI:
if (large_len > sizeof(buf) - 1)
large_len = sizeof(buf) - 1;
bcopy(resinfo, buf, large_len);
@@ -205,32 +257,113 @@ pnp_parse_resources(device_t dev, u_char *resources, int len)
large_len--;
buf[large_len] = '\0';
device_set_desc_copy(dev, buf);
- continue;
- }
+ break;
+
+ case PNP_TAG_MEMORY_RANGE:
+ if (bootverbose) {
+ printf("%s: adding memory range "
+ "%#x-%#x, size=%#x, "
+ "align=%#x\n",
+ pnp_eisaformat(id),
+ I16(resinfo + 1)<<8,
+ (I16(resinfo + 3)<<8)
+ + I16(resinfo + 7) - 1,
+ I16(resinfo + 7),
+ I16(resinfo + 5));
+ }
- if (PNP_LRES_NUM(tag) != PNP_TAG_MEMORY_RANGE) {
- /* skip */
- continue;
- }
+ if (config->ic_nmem == ISA_NMEM) {
+ device_printf(parent, "too many memory ranges");
+ scanning = 0;
+ break;
+ }
- if (config->ic_nmem == ISA_NMEM) {
- device_printf(parent, "too many memory ranges");
- scanning = 0;
+ config->ic_mem[config->ic_nmem].ir_start =
+ I16(resinfo + 1)<<8;
+ config->ic_mem[config->ic_nmem].ir_end =
+ (I16(resinfo + 3)<<8)
+ + I16(resinfo + 7) - 1;
+ config->ic_mem[config->ic_nmem].ir_size =
+ I16(resinfo + 7);
+ config->ic_mem[config->ic_nmem].ir_align =
+ I16(resinfo + 5);
+ if (!config->ic_mem[config->ic_nmem].ir_align)
+ config->ic_mem[config->ic_nmem]
+ .ir_align = 0x10000;
+ config->ic_nmem++;
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)
+ case PNP_TAG_MEMORY32_RANGE:
+ if (bootverbose) {
+ printf("%s: adding memory range "
+ "%#x-%#x, size=%#x, "
+ "align=%#x\n",
+ pnp_eisaformat(id),
+ I32(resinfo + 1),
+ I32(resinfo + 5)
+ + I32(resinfo + 13) - 1,
+ I32(resinfo + 13),
+ I32(resinfo + 9));
+ }
+
+ if (config->ic_nmem == ISA_NMEM) {
+ device_printf(parent, "too many memory ranges");
+ scanning = 0;
+ break;
+ }
+
+ config->ic_mem[config->ic_nmem].ir_start =
+ I32(resinfo + 1);
+ config->ic_mem[config->ic_nmem].ir_end =
+ I32(resinfo + 5)
+ + I32(resinfo + 13) - 1;
+ config->ic_mem[config->ic_nmem].ir_size =
+ I32(resinfo + 13);
config->ic_mem[config->ic_nmem].ir_align =
- 0x10000;
- config->ic_nmem++;
+ I32(resinfo + 9);
+ config->ic_nmem++;
+ break;
+
+ case PNP_TAG_MEMORY32_FIXED:
+ if (I32(resinfo + 5) == 0) {
+ if (bootverbose) {
+ printf("%s: skipping empty range\n",
+ pnp_eisaformat(id));
+ }
+ continue;
+ }
+ if (bootverbose) {
+ printf("%s: adding memory range "
+ "%#x-%#x, size=%#x\n",
+ pnp_eisaformat(id),
+ I32(resinfo + 1),
+ I32(resinfo + 1)
+ + I32(resinfo + 5) - 1,
+ I32(resinfo + 5));
+ }
+
+ if (config->ic_nmem == ISA_NMEM) {
+ device_printf(parent, "too many memory ranges");
+ scanning = 0;
+ break;
+ }
+
+ config->ic_mem[config->ic_nmem].ir_start =
+ I32(resinfo + 1);
+ config->ic_mem[config->ic_nmem].ir_end =
+ I32(resinfo + 1)
+ + I32(resinfo + 5) - 1;
+ config->ic_mem[config->ic_nmem].ir_size =
+ I32(resinfo + 5);
+ config->ic_mem[config->ic_nmem].ir_align = 1;
+ config->ic_nmem++;
+ break;
+
+ default:
+ /* Skip this resource */
+ device_printf(parent, "unexpected tag %d\n",
+ PNP_SRES_NUM(tag));
+ }
}
}
diff --git a/sys/isa/pnpvar.h b/sys/isa/pnpvar.h
index bfd26dab2650..5f1a6dcdb234 100644
--- a/sys/isa/pnpvar.h
+++ b/sys/isa/pnpvar.h
@@ -52,6 +52,7 @@ u_char pnp_read(int d); /* currently unused, but who knows... */
| (PNP_HEXTONUM(s[6]) << 24) \
| (PNP_HEXTONUM(s[5]) << 28))
+char *pnp_eisaformat(u_int32_t id);
void pnp_parse_resources(device_t dev, u_char *resources, int len);
#endif /* KERNEL */