--- /dev/null Fri Jun 26 08:09:33 2009 +++ new/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_scope.c Fri Jun 26 08:09:32 2009 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2009, Intel Corporation. + * All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static ACPI_STATUS acpidev_scope_probe(acpidev_walk_info_t *infop); +static acpidev_filter_result_t acpidev_scope_filter(acpidev_walk_info_t *infop, + char *devname, int maxlen); +static ACPI_STATUS acpidev_scope_init(acpidev_walk_info_t *infop); + +/* + * Default class driver for ACPI scope object. + * This class dirver is used to handle predefined ACPI SCOPE object + * under ACPI root object, such as _PR_, _SB_ and _TZ_ etc. + * Default policy for ACPI SCOPE object is SKIP. + */ +acpidev_class_t acpidev_class_scope = { + 0, /* adc_refcnt */ + ACPIDEV_CLASS_REV1, /* adc_version */ + ACPIDEV_CLASS_ID_SCOPE, /* adc_class_id */ + "ACPI Scope", /* adc_class_name */ + ACPIDEV_TYPE_SCOPE, /* adc_dev_type */ + NULL, /* adc_private */ + NULL, /* adc_pre_probe */ + NULL, /* adc_post_probe */ + acpidev_scope_probe, /* adc_probe */ + acpidev_scope_filter, /* adc_filter */ + acpidev_scope_init, /* adc_init */ + NULL, /* adc_fini */ +}; + +acpidev_class_list_t *acpidev_class_list_scope = NULL; + +/* + * All SCOPE objects share a global pseudo unit address space across system. + */ +static uint32_t acpidev_scope_unitaddr = 0; + +/* Filter rule table for ACPI SCOPE object. */ +static acpidev_filter_rule_t acpidev_scope_filters[] = { + { /* For safety, though _SB_ is hardcoded as DEVICE by acpica */ + NULL, + 0, + ACPIDEV_FILTER_SCAN, + &acpidev_class_list_device, + 1, + 1, + ACPIDEV_OBJECT_NAME_SB, + "", + }, + { /* Handle _PR_ object. */ + NULL, + 0, + ACPIDEV_FILTER_SCAN, + &acpidev_class_list_scope, + 1, + 1, + ACPIDEV_OBJECT_NAME_PR, + ACPIDEV_NODE_NAME_PROCESSOR, + }, + { /* Ignore all other scope objects. */ + NULL, + 0, + ACPIDEV_FILTER_SKIP, + NULL, + 1, + INT_MAX, + NULL, + NULL, + } +}; + +static ACPI_STATUS +acpidev_scope_probe(acpidev_walk_info_t *infop) +{ + ACPI_STATUS rc; + int flags; + + ASSERT(infop != NULL); + ASSERT(infop->awi_hdl != NULL); + ASSERT(infop->awi_info != NULL); + if (infop->awi_info->Type != ACPI_TYPE_LOCAL_SCOPE) { + return (AE_OK); + } + + if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) { + flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE; + rc = acpidev_process_object(infop, flags); + } else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) { + flags = ACPIDEV_PROCESS_FLAG_SCAN; + rc = acpidev_process_object(infop, flags); + } else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) { + flags = ACPIDEV_PROCESS_FLAG_SCAN; + rc = acpidev_process_object(infop, flags); + } else { + ACPIDEV_DEBUG(CE_WARN, + "acpidev: unknown operation type %u in scope_probe().", + infop->awi_op_type); + rc = AE_BAD_PARAMETER; + } + if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) { + cmn_err(CE_CONT, + "?acpidev: failed to process scope object %s.\n", + infop->awi_name); + } else { + rc = AE_OK; + } + + return (rc); +} + +static acpidev_filter_result_t +acpidev_scope_filter(acpidev_walk_info_t *infop, char *devname, int maxlen) +{ + acpidev_filter_result_t res; + + ASSERT(infop != NULL); + if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE || + infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE || + infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) { + res = acpidev_filter_device(infop, infop->awi_hdl, + ACPIDEV_ARRAY_PARAM(acpidev_scope_filters), + devname, maxlen); + } else { + ACPIDEV_DEBUG(CE_WARN, + "acpidev: unknown operation type %u in scope_filter().", + infop->awi_op_type); + res = ACPIDEV_FILTER_FAILED; + } + + return (res); +} + +/*ARGSUSED*/ +static ACPI_STATUS +acpidev_scope_init(acpidev_walk_info_t *infop) +{ + char unitaddr[32]; + char *compatibles[] = { + ACPIDEV_HID_SCOPE, + ACPIDEV_TYPE_SCOPE, + ACPIDEV_HID_VIRTNEX, + ACPIDEV_TYPE_VIRTNEX, + }; + + ASSERT(infop != NULL); + ASSERT(infop->awi_hdl != NULL); + ASSERT(infop->awi_dip != NULL); + if (ACPI_FAILURE(acpidev_set_compatibles(infop, + ACPIDEV_ARRAY_PARAM(compatibles)))) { + return (AE_ERROR); + } + (void) snprintf(unitaddr, sizeof (unitaddr), "%u", + atomic_inc_32_nv(&acpidev_scope_unitaddr) - 1); + if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) { + return (AE_ERROR); + } + + return (AE_OK); +}