diff options
author | jhb <jhb@FreeBSD.org> | 2008-11-18 21:01:54 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-11-18 21:01:54 +0000 |
commit | c2251260be90b098d300f1452cc5cb46c5032282 (patch) | |
tree | 9f64d56b3288179bc04a3f77b610240093f70345 /sys/dev | |
parent | 7a676b30d156207340caf73e0c93ff42db650ffb (diff) | |
download | FreeBSD-src-c2251260be90b098d300f1452cc5cb46c5032282.zip FreeBSD-src-c2251260be90b098d300f1452cc5cb46c5032282.tar.gz |
Allow device hints to wire the unit numbers of devices.
- An "at" hint now reserves a device name.
- A new BUS_HINT_DEVICE_UNIT method is added to the bus interface. When
determining the unit number of a device, this method is invoked to
let the bus driver specify the unit of a device given a specific
devclass. This is the only way a device can be given a name reserved
via an "at" hint.
- Implement BUS_HINT_DEVICE_UNIT() for the acpi(4) and isa(4) bus drivers.
Both of these busses implement this by comparing the resources for a
given hint device with the resources enumerated by ACPI/PnPBIOS and
wire a unit if the hint resources are a subset of the "real" resources.
- Use bus_hinted_children() for adding hinted devices on isa(4) busses
now instead of doing it by hand.
- Remove the unit kludging from sio(4) as it is no longer necessary.
Prodding from: peter, imp
OK'd by: marcel
MFC after: 1 month
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpica/acpi.c | 86 | ||||
-rw-r--r-- | sys/dev/sio/sio_pci.c | 31 | ||||
-rw-r--r-- | sys/dev/sio/sio_puc.c | 29 |
3 files changed, 86 insertions, 60 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index a345f29..8271917 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -158,6 +158,8 @@ static int acpi_child_pnpinfo_str_method(device_t acdev, device_t child, #if defined(__i386__) || defined(__amd64__) static void acpi_enable_pcie(void); #endif +static void acpi_hint_device_unit(device_t acdev, device_t child, + const char *name, int *unitp); static device_method_t acpi_methods[] = { /* Device interface */ @@ -187,6 +189,7 @@ static device_method_t acpi_methods[] = { DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_hint_device_unit, acpi_hint_device_unit), /* ACPI bus */ DEVMETHOD(acpi_id_probe, acpi_device_id_probe), @@ -949,6 +952,89 @@ acpi_get_rlist(device_t dev, device_t child) return (&ad->ad_rl); } +static int +acpi_match_resource_hint(device_t dev, int type, long value) +{ + struct acpi_device *ad = device_get_ivars(dev); + struct resource_list *rl = &ad->ad_rl; + struct resource_list_entry *rle; + + STAILQ_FOREACH(rle, rl, link) { + if (rle->type != type) + continue; + if (rle->start <= value && rle->end >= value) + return (1); + } + return (0); +} + +/* + * Wire device unit numbers based on resource matches in hints. + */ +static void +acpi_hint_device_unit(device_t acdev, device_t child, const char *name, + int *unitp) +{ + const char *s; + long value; + int line, matches, unit; + + /* + * Iterate over all the hints for the devices with the specified + * name to see if one's resources are a subset of this device. + */ + line = 0; + for (;;) { + if (resource_find_dev(&line, name, &unit, "at", NULL) != 0) + break; + + /* Must have an "at" for acpi or isa. */ + resource_string_value(name, unit, "at", &s); + if (!(strcmp(s, "acpi0") == 0 || strcmp(s, "acpi") == 0 || + strcmp(s, "isa0") == 0 || strcmp(s, "isa") == 0)) + continue; + + /* + * Check for matching resources. We must have at least one, + * and all resources specified have to match. + * + * XXX: We may want to revisit this to be more lenient and wire + * as long as it gets one match. + */ + matches = 0; + if (resource_long_value(name, unit, "port", &value) == 0) { + if (acpi_match_resource_hint(child, SYS_RES_IOPORT, value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "maddr", &value) == 0) { + if (acpi_match_resource_hint(child, SYS_RES_MEMORY, value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "irq", &value) == 0) { + if (acpi_match_resource_hint(child, SYS_RES_IRQ, value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "drq", &value) == 0) { + if (acpi_match_resource_hint(child, SYS_RES_DRQ, value)) + matches++; + else + continue; + } + + if (matches > 0) { + /* We have a winner! */ + *unitp = unit; + break; + } + } +} + /* * Pre-allocate/manage all memory and IO resources. Since rman can't handle * duplicates, we merge any in the sysresource attach routine. diff --git a/sys/dev/sio/sio_pci.c b/sys/dev/sio/sio_pci.c index 459baa1..dc9b004 100644 --- a/sys/dev/sio/sio_pci.c +++ b/sys/dev/sio/sio_pci.c @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcivar.h> static int sio_pci_attach(device_t dev); -static void sio_pci_kludge_unit(device_t dev); static int sio_pci_probe(device_t dev); static device_method_t sio_pci_methods[] = { @@ -101,39 +100,9 @@ sio_pci_attach(dev) id++; if (id->desc == NULL) return (ENXIO); - sio_pci_kludge_unit(dev); return (sioattach(dev, id->rid, 0UL)); } -/* - * Don't cut and paste this to other drivers. It is a horrible kludge - * which will fail to work and also be unnecessary in future versions. - */ -static void -sio_pci_kludge_unit(dev) - device_t dev; -{ - devclass_t dc; - int err; - int start; - int unit; - - unit = 0; - start = 0; - while (resource_int_value("sio", unit, "port", &start) == 0 && - start > 0) - unit++; - if (device_get_unit(dev) < unit) { - dc = device_get_devclass(dev); - while (devclass_get_device(dc, unit)) - unit++; - device_printf(dev, "moving to sio%d\n", unit); - err = device_set_unit(dev, unit); /* EVIL DO NOT COPY */ - if (err) - device_printf(dev, "error moving device %d\n", err); - } -} - static int sio_pci_probe(dev) device_t dev; diff --git a/sys/dev/sio/sio_puc.c b/sys/dev/sio/sio_puc.c index 37691f7..0ae0e7d 100644 --- a/sys/dev/sio/sio_puc.c +++ b/sys/dev/sio/sio_puc.c @@ -62,34 +62,6 @@ static driver_t sio_puc_driver = { 0, }; -/* - * Don't cut and paste this to other drivers. It is a horrible kludge - * which will fail to work and also be unnecessary in future versions. - */ -static void -sio_puc_kludge_unit(device_t dev) -{ - devclass_t dc; - int err; - int start; - int unit; - - unit = 0; - start = 0; - while (resource_int_value("sio", unit, "port", &start) == 0 && - start > 0) - unit++; - if (device_get_unit(dev) < unit) { - dc = device_get_devclass(dev); - while (devclass_get_device(dc, unit)) - unit++; - device_printf(dev, "moving to sio%d\n", unit); - err = device_set_unit(dev, unit); /* EVIL DO NOT COPY */ - if (err) - device_printf(dev, "error moving device %d\n", err); - } -} - static int sio_puc_attach(device_t dev) { @@ -98,7 +70,6 @@ sio_puc_attach(device_t dev) if (BUS_READ_IVAR(device_get_parent(dev), dev, PUC_IVAR_CLOCK, &rclk) != 0) rclk = DEFAULT_RCLK; - sio_puc_kludge_unit(dev); return (sioattach(dev, 0, rclk)); } |