aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/acpica
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/acpica')
-rw-r--r--sys/dev/acpica/acpi.c88
-rw-r--r--sys/dev/acpica/acpi_if.m79
2 files changed, 146 insertions, 21 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index f9295e2f0c23..e8cd3f4dcd47 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -111,15 +111,16 @@ static char *acpi_device_id_probe(device_t bus, device_t dev, char **ids);
static ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev,
ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters,
ACPI_BUFFER *ret);
-static ACPI_STATUS acpi_device_walk_ns(device_t bus, device_t dev,
- ACPI_OBJECT_TYPE type, UINT32 max_depth,
- ACPI_WALK_CALLBACK user_fn, void *context, void **ret);
+static ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level,
+ void *context, void **retval);
+static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev,
+ int max_depth, acpi_scan_cb_t user_fn, void *arg);
static int acpi_isa_pnp_probe(device_t bus, device_t child,
- struct isa_pnp_id *ids);
+ struct isa_pnp_id *ids);
static void acpi_probe_children(device_t bus);
static int acpi_probe_order(ACPI_HANDLE handle, int *order);
static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level,
- void *context, void **status);
+ void *context, void **status);
static BOOLEAN acpi_MatchHid(ACPI_HANDLE h, const char *hid);
static void acpi_shutdown_final(void *arg, int howto);
static void acpi_enable_fixed_events(struct acpi_softc *sc);
@@ -169,7 +170,7 @@ static device_method_t acpi_methods[] = {
/* ACPI bus */
DEVMETHOD(acpi_id_probe, acpi_device_id_probe),
DEVMETHOD(acpi_evaluate_object, acpi_device_eval_obj),
- DEVMETHOD(acpi_walk_namespace, acpi_device_walk_ns),
+ DEVMETHOD(acpi_scan_children, acpi_device_scan_children),
/* ISA emulation */
DEVMETHOD(isa_pnp_probe, acpi_isa_pnp_probe),
@@ -1036,20 +1037,85 @@ acpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname,
{
ACPI_HANDLE h;
- if ((h = acpi_get_handle(dev)) == NULL)
+ if (dev == NULL)
+ h = ACPI_ROOT_OBJECT;
+ else if ((h = acpi_get_handle(dev)) == NULL)
return (AE_BAD_PARAMETER);
return (AcpiEvaluateObject(h, pathname, parameters, ret));
}
+/* Callback arg for our implementation of walking the namespace. */
+struct acpi_device_scan_ctx {
+ acpi_scan_cb_t user_fn;
+ void *arg;
+ ACPI_HANDLE parent;
+};
+
+static ACPI_STATUS
+acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level, void *arg, void **retval)
+{
+ struct acpi_device_scan_ctx *ctx;
+ device_t dev, old_dev;
+ ACPI_STATUS status;
+ ACPI_OBJECT_TYPE type;
+
+ /*
+ * Skip this device if we think we'll have trouble with it or it is
+ * the parent where the scan began.
+ */
+ ctx = (struct acpi_device_scan_ctx *)arg;
+ if (acpi_avoid(h) || h == ctx->parent)
+ return (AE_OK);
+
+ /* If this is not a valid device type (e.g., a method), skip it. */
+ if (ACPI_FAILURE(AcpiGetType(h, &type)))
+ return (AE_OK);
+ if (type != ACPI_TYPE_DEVICE && type != ACPI_TYPE_PROCESSOR &&
+ type != ACPI_TYPE_THERMAL && type != ACPI_TYPE_POWER)
+ return (AE_OK);
+
+ /*
+ * Call the user function with the current device. If it is unchanged
+ * afterwards, return. Otherwise, we update the handle to the new dev.
+ */
+ old_dev = acpi_get_device(h);
+ dev = old_dev;
+ status = ctx->user_fn(h, &dev, level, ctx->arg);
+ if (ACPI_FAILURE(status) || old_dev == dev)
+ return (status);
+
+ /* Remove the old child and its connection to the handle. */
+ if (old_dev != NULL) {
+ device_delete_child(device_get_parent(old_dev), old_dev);
+ AcpiDetachData(h, acpi_fake_objhandler);
+ }
+
+ /* Recreate the handle association if the user created a device. */
+ if (dev != NULL)
+ AcpiAttachData(h, acpi_fake_objhandler, dev);
+
+ return (AE_OK);
+}
+
static ACPI_STATUS
-acpi_device_walk_ns(device_t bus, device_t dev, ACPI_OBJECT_TYPE type,
- UINT32 max_depth, ACPI_WALK_CALLBACK user_fn, void *context, void **ret)
+acpi_device_scan_children(device_t bus, device_t dev, int max_depth,
+ acpi_scan_cb_t user_fn, void *arg)
{
ACPI_HANDLE h;
+ struct acpi_device_scan_ctx ctx;
- if ((h = acpi_get_handle(dev)) == NULL)
+ if (acpi_disabled("children"))
+ return (AE_OK);
+
+ if (dev == NULL)
+ h = ACPI_ROOT_OBJECT;
+ else if ((h = acpi_get_handle(dev)) == NULL)
return (AE_BAD_PARAMETER);
- return (AcpiWalkNamespace(type, h, max_depth, user_fn, context, ret));
+ ctx.user_fn = user_fn;
+ ctx.arg = arg;
+ ctx.parent = h;
+ return (AcpiWalkNamespace(ACPI_TYPE_ANY, h, max_depth,
+ acpi_device_scan_cb, &ctx, NULL));
}
static int
diff --git a/sys/dev/acpica/acpi_if.m b/sys/dev/acpica/acpi_if.m
index c2cdc1121e18..7365d9ce3c80 100644
--- a/sys/dev/acpica/acpi_if.m
+++ b/sys/dev/acpica/acpi_if.m
@@ -33,7 +33,28 @@
INTERFACE acpi;
#
-# Default implementation for the probe method.
+# Callback function for each child handle traversed in acpi_scan_children().
+#
+# ACPI_HANDLE h: current child device being considered
+#
+# device_t *dev: pointer to the child's original device_t or NULL if there
+# was none. The callback should store a new device in *dev if it has
+# created one. The method implementation will automatically clean up the
+# previous device and properly associate the current ACPI_HANDLE with it.
+#
+# level: current level being scanned
+#
+# void *arg: argument passed in original call to acpi_scan_children()
+#
+# Returns: AE_OK if the scan should continue, otherwise an error
+#
+HEADER {
+ typedef ACPI_STATUS (*acpi_scan_cb_t)(ACPI_HANDLE h, device_t *dev,
+ int level, void *arg);
+};
+
+#
+# Default implementation for acpi_id_probe().
#
CODE {
static char *
@@ -44,7 +65,16 @@ CODE {
};
#
-# Probe
+# Check a device for a match in a list of ID strings. The strings can be
+# EISA PNP IDs or ACPI _HID/_CID values.
+#
+# device_t bus: parent bus for the device
+#
+# device_t dev: device being considered
+#
+# char **ids: array of ID strings to consider
+#
+# Returns: ID string matched or NULL if no match
#
METHOD char * id_probe {
device_t bus;
@@ -53,7 +83,22 @@ METHOD char * id_probe {
} DEFAULT acpi_generic_id_probe;
#
-# AcpiEvaluateObject
+# Evaluate an ACPI method or object, given its path.
+#
+# device_t bus: parent bus for the device
+#
+# device_t dev: evaluate the object relative to this device's handle.
+# Specify NULL to begin the search at the ACPI root.
+#
+# ACPI_STRING pathname: absolute or relative path to this object
+#
+# ACPI_OBJECT_LIST *parameters: array of arguments to pass to the object.
+# Specify NULL if there are none.
+#
+# ACPI_BUFFER *ret: the result (if any) of the evaluation
+# Specify NULL if there is none.
+#
+# Returns: AE_OK or an error value
#
METHOD ACPI_STATUS evaluate_object {
device_t bus;
@@ -64,14 +109,28 @@ METHOD ACPI_STATUS evaluate_object {
};
#
-# AcpiWalkNamespace
+# Rescan a subtree and optionally reattach devices to handles. Users
+# specify a callback that is called for each ACPI_HANDLE of type Device
+# that is a child of "dev".
+#
+# device_t bus: parent bus for the device
+#
+# device_t dev: begin the scan starting with this device's handle.
+# Specify NULL to begin the scan at the ACPI root.
+#
+# int max_depth: number of levels to traverse (i.e., 1 means just the
+# immediate children.
+#
+# acpi_scan_cb_t user_fn: called for each child handle
+#
+# void *arg: argument to pass to the callback function
+#
+# Returns: AE_OK or an error value, based on the callback return value
#
-METHOD ACPI_STATUS walk_namespace {
+METHOD ACPI_STATUS scan_children {
device_t bus;
device_t dev;
- ACPI_OBJECT_TYPE type;
- UINT32 max_depth;
- ACPI_WALK_CALLBACK user_fn;
- void *context;
- void **ret;
+ int max_depth;
+ acpi_scan_cb_t user_fn;
+ void *arg;
};