diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -187,6 +187,8 @@ struct sbuf *sb); static int acpi_child_pnpinfo_method(device_t acdev, device_t child, struct sbuf *sb); +static int acpi_get_device_path(device_t bus, device_t child, + const char *locator, struct sbuf *sb); static void acpi_enable_pcie(void); static void acpi_hint_device_unit(device_t acdev, device_t child, const char *name, int *unitp); @@ -226,6 +228,7 @@ DEVMETHOD(bus_get_cpus, acpi_get_cpus), DEVMETHOD(bus_get_domain, acpi_get_domain), DEVMETHOD(bus_get_property, acpi_bus_get_prop), + DEVMETHOD(bus_get_device_path, acpi_get_device_path), /* ACPI bus */ DEVMETHOD(acpi_id_probe, acpi_device_id_probe), @@ -928,6 +931,37 @@ return (acpi_pnpinfo(dinfo->ad_handle, sb)); } +/* + * Note: the check for ACPI locator may be reduntant. However, this routine is + * suitable for both busses whose only locator is ACPI and as a building block + * for busses that have multiple locators to cope with. + */ +int +acpi_get_acpi_device_path(device_t bus, device_t child, const char *locator, struct sbuf *sb) +{ + if (strcmp(locator, BUS_LOCATOR_ACPI) == 0) { + ACPI_HANDLE *handle = acpi_get_handle(child); + + if (handle != NULL) + sbuf_printf(sb, "%s", acpi_name(handle)); + return (0); + } + + return (bus_generic_get_device_path(bus, child, locator, sb)); +} + +static int +acpi_get_device_path(device_t bus, device_t child, const char *locator, struct sbuf *sb) +{ + struct acpi_device *dinfo = device_get_ivars(child); + + if (strcmp(locator, BUS_LOCATOR_ACPI) == 0) + return (acpi_get_acpi_device_path(bus, child, locator, sb)); + + /* For the rest, punt to the default handler */ + return (bus_generic_get_device_path(bus, child, locator, sb)); +} + /* * Handle device deletion. */ diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c --- a/sys/dev/acpica/acpi_pci.c +++ b/sys/dev/acpica/acpi_pci.c @@ -81,6 +81,8 @@ static void acpi_pci_child_deleted(device_t dev, device_t child); static int acpi_pci_child_location_method(device_t cbdev, device_t child, struct sbuf *sb); +static int acpi_pci_get_device_path(device_t cbdev, + device_t child, const char *locator, struct sbuf *sb); static int acpi_pci_detach(device_t dev); static int acpi_pci_probe(device_t dev); static int acpi_pci_read_ivar(device_t dev, device_t child, int which, @@ -105,6 +107,7 @@ DEVMETHOD(bus_write_ivar, acpi_pci_write_ivar), DEVMETHOD(bus_child_deleted, acpi_pci_child_deleted), DEVMETHOD(bus_child_location, acpi_pci_child_location_method), + DEVMETHOD(bus_get_device_path, acpi_pci_get_device_path), DEVMETHOD(bus_get_cpus, acpi_get_cpus), DEVMETHOD(bus_get_dma_tag, acpi_pci_get_dma_tag), DEVMETHOD(bus_get_domain, acpi_get_domain), @@ -196,6 +199,17 @@ return (0); } +static int +acpi_pci_get_device_path(device_t bus, device_t child, const char *locator, struct sbuf *sb) +{ + + if (strcmp(locator, BUS_LOCATOR_ACPI) == 0) + return (acpi_get_acpi_device_path(bus, child, locator, sb)); + + /* For the rest, punt to the default handler */ + return (bus_generic_get_device_path(bus, child, locator, sb)); +} + /* * PCI power manangement */ diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -495,6 +495,8 @@ char *acpi_name(ACPI_HANDLE handle); int acpi_avoid(ACPI_HANDLE handle); int acpi_disabled(char *subsys); +int acpi_get_acpi_device_path(device_t bus, device_t child, + const char *locator, struct sbuf *sb); int acpi_machdep_init(device_t dev); void acpi_install_wakeup_handler(struct acpi_softc *sc); int acpi_sleep_machdep(struct acpi_softc *sc, int state); diff --git a/sys/dev/iicbus/acpi_iicbus.c b/sys/dev/iicbus/acpi_iicbus.c --- a/sys/dev/iicbus/acpi_iicbus.c +++ b/sys/dev/iicbus/acpi_iicbus.c @@ -764,6 +764,7 @@ DEVMETHOD(bus_write_ivar, acpi_iicbus_write_ivar), DEVMETHOD(bus_child_location, acpi_iicbus_child_location), DEVMETHOD(bus_child_pnpinfo, acpi_iicbus_child_pnpinfo), + DEVMETHOD(bus_get_device_path, acpi_get_acpi_device_path), DEVMETHOD_END, }; diff --git a/sys/dev/nvdimm/nvdimm_acpi.c b/sys/dev/nvdimm/nvdimm_acpi.c --- a/sys/dev/nvdimm/nvdimm_acpi.c +++ b/sys/dev/nvdimm/nvdimm_acpi.c @@ -265,6 +265,7 @@ DEVMETHOD(bus_read_ivar, nvdimm_root_read_ivar), DEVMETHOD(bus_write_ivar, nvdimm_root_write_ivar), DEVMETHOD(bus_child_location, nvdimm_root_child_location), + DEVMETHOD(bus_get_device_path, acpi_get_acpi_device_path), DEVMETHOD_END }; diff --git a/sys/dev/usb/usb_hub_acpi.c b/sys/dev/usb/usb_hub_acpi.c --- a/sys/dev/usb/usb_hub_acpi.c +++ b/sys/dev/usb/usb_hub_acpi.c @@ -553,11 +553,22 @@ return (0); } +static int +acpi_uhub_get_device_path(device_t bus, device_t child, const char *locator, struct sbuf *sb) +{ + if (strcmp(locator, BUS_LOCATOR_ACPI) == 0) + return (acpi_get_acpi_device_path(bus, child, locator, sb)); + + /* For the rest, punt to the default handler */ + return (bus_generic_get_device_path(bus, child, locator, sb)); +} + static device_method_t acpi_uhub_methods[] = { DEVMETHOD(device_probe, acpi_uhub_probe), DEVMETHOD(device_attach, acpi_uhub_attach), DEVMETHOD(device_detach, acpi_uhub_detach), DEVMETHOD(bus_child_location, acpi_uhub_child_location), + DEVMETHOD(bus_get_device_path, acpi_uhub_get_device_path), DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), DEVMETHOD_END @@ -569,6 +580,7 @@ DEVMETHOD(device_detach, acpi_uhub_detach), DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), DEVMETHOD(bus_child_location, acpi_uhub_child_location), + DEVMETHOD(bus_get_device_path, acpi_uhub_get_device_path), DEVMETHOD_END }; diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -4645,9 +4645,19 @@ int rv = 0; device_t parent; + /* + * We don't recurse on ACPI since either we know the handle for the + * device or we don't. And if we're in the generic routine, we don't + * have a ACPI override. All other locators build up a path by having + * their parents create a path and then adding the path element for this + * node. That's why we recurse with parent, bus rather than the typical + * parent, child: each spot in the tree is independent of what our child + * will do with this path. + */ parent = device_get_parent(bus); - if (parent != NULL) + if (parent != NULL && strcmp(locator, BUS_LOCATOR_ACPI) != 0) { rv = BUS_GET_DEVICE_PATH(parent, bus, locator, sb); + } if (strcmp(locator, BUS_LOCATOR_FREEBSD) == 0) { if (rv == 0) { sbuf_printf(sb, "/%s", device_get_nameunit(child)); diff --git a/sys/sys/bus.h b/sys/sys/bus.h --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -737,6 +737,7 @@ #define BUS_PASS_ORDER_LATE 7 #define BUS_PASS_ORDER_LAST 9 +#define BUS_LOCATOR_ACPI "ACPI" #define BUS_LOCATOR_FREEBSD "FreeBSD" extern int bus_current_pass;