Update the interface for child drivers. Add acpi_scan_children, which

allows a bus to re-enumerate its child handles and optionally replace
them with new children, arranged to the bus's liking.  (The current device
space is flat with all devices immediately under acpi0).  Add comments
for each interface.
This commit is contained in:
njl 2004-07-15 16:29:08 +00:00
parent b5d57460e7
commit 7c3c611f34
2 changed files with 146 additions and 21 deletions

View File

@ -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_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_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_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

View File

@ -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".
#
METHOD ACPI_STATUS walk_namespace {
# 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 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;
};