1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2009-2010, Intel Corporation.
  23  * All rights reserved.
  24  */
  25 
  26 /*
  27  * Platform specific device enumerator for ACPI specific devices.
  28  * "x86 system devices" refers to the suite of hardware components which are
  29  * common to the x86 platform and play important roles in the system
  30  * architecture but can't be enumerated/discovered through industry-standard
  31  * bus specifications. Examples of these x86 system devices include:
  32  *   * Logical processor/CPU
  33  *   * Memory device
  34  *   * Non-PCI discoverable IOMMU or DMA Remapping Engine
  35  *   * Non-PCI discoverable IOxAPIC
  36  *   * Non-PCI discoverable HPET (High Precision Event Timer)
  37  *   * ACPI defined devices, including power button, sleep button, battery etc.
  38  *
  39  * X86 system devices may be discovered through BIOS/Firmware interfaces, such
  40  * as SMBIOS tables, MPS tables and ACPI tables since their discovery isn't
  41  * covered by any industry-standard bus specifications.
  42  *
  43  * In order to aid Solaris in flexibly managing x86 system devices,
  44  * x86 system devices are placed into a specific firmware device
  45  * subtree whose device path is '/devices/fw'.
  46  *
  47  * This driver populates the firmware device subtree with ACPI-discoverable
  48  * system devices if possible. To achieve that, the ACPI object
  49  * namespace is abstracted as ACPI virtual buses which host system devices.
  50  * Another nexus driver for the ACPI virtual bus will manage all devices
  51  * connected to it.
  52  *
  53  * For more detailed information, please refer to PSARC/2009/104.
  54  */
  55 
  56 #include <sys/types.h>
  57 #include <sys/bitmap.h>
  58 #include <sys/cmn_err.h>
  59 #include <sys/ddi_subrdefs.h>
  60 #include <sys/errno.h>
  61 #include <sys/modctl.h>
  62 #include <sys/mutex.h>
  63 #include <sys/note.h>
  64 #include <sys/obpdefs.h>
  65 #include <sys/sunddi.h>
  66 #include <sys/sunndi.h>
  67 #include <sys/acpi/acpi.h>
  68 #include <sys/acpica.h>
  69 #include <sys/acpidev.h>
  70 #include <sys/acpidev_dr.h>
  71 #include <sys/acpidev_impl.h>
  72 
  73 /* Patchable through /etc/system */
  74 int acpidev_options = 0;
  75 int acpidev_debug = 0;
  76 
  77 krwlock_t acpidev_class_lock;
  78 acpidev_class_list_t *acpidev_class_list_root = NULL;
  79 ulong_t acpidev_object_type_mask[BT_BITOUL(ACPI_TYPE_NS_NODE_MAX + 1)];
  80 
  81 /* ACPI device autoconfig global status */
  82 typedef enum acpidev_status {
  83         ACPIDEV_STATUS_FAILED = -2,     /* ACPI device autoconfig failed */
  84         ACPIDEV_STATUS_DISABLED = -1,   /* ACPI device autoconfig disabled */
  85         ACPIDEV_STATUS_UNKNOWN = 0,     /* initial status */
  86         ACPIDEV_STATUS_INITIALIZED,     /* ACPI device autoconfig initialized */
  87         ACPIDEV_STATUS_FIRST_PASS,      /* first probing finished */
  88         ACPIDEV_STATUS_READY            /* second probing finished */
  89 } acpidev_status_t;
  90 
  91 static acpidev_status_t acpidev_status = ACPIDEV_STATUS_UNKNOWN;
  92 static kmutex_t acpidev_drv_lock;
  93 static dev_info_t *acpidev_root_dip = NULL;
  94 
  95 /* Boot time ACPI device enumerator. */
  96 static void acpidev_boot_probe(int type);
  97 
  98 /* DDI module auto configuration interface */
  99 extern struct mod_ops mod_miscops;
 100 
 101 static struct modlmisc modlmisc = {
 102         &mod_miscops,
 103         "ACPI device enumerator"
 104 };
 105 
 106 static struct modlinkage modlinkage = {
 107         MODREV_1,
 108         { (void *)&modlmisc, NULL }
 109 };
 110 
 111 int
 112 _init(void)
 113 {
 114         int err;
 115 
 116         if ((err = mod_install(&modlinkage)) == 0) {
 117                 bzero(acpidev_object_type_mask,
 118                     sizeof (acpidev_object_type_mask));
 119                 mutex_init(&acpidev_drv_lock, NULL, MUTEX_DRIVER, NULL);
 120                 rw_init(&acpidev_class_lock, NULL, RW_DEFAULT, NULL);
 121                 acpidev_dr_init();
 122                 impl_bus_add_probe(acpidev_boot_probe);
 123         } else {
 124                 cmn_err(CE_WARN, "!acpidev: failed to install driver.");
 125         }
 126 
 127         return (err);
 128 }
 129 
 130 int
 131 _fini(void)
 132 {
 133         /* No support for module unload. */
 134         return (EBUSY);
 135 }
 136 
 137 int
 138 _info(struct modinfo *modinfop)
 139 {
 140         return (mod_info(&modlinkage, modinfop));
 141 }
 142 
 143 /* Check blacklists and load platform specific driver modules. */
 144 static ACPI_STATUS
 145 acpidev_load_plat_modules(void)
 146 {
 147         return (AE_OK);
 148 }
 149 
 150 /* Unload platform specific driver modules. */
 151 static void
 152 acpidev_unload_plat_modules(void)
 153 {
 154 }
 155 
 156 /* Unregister all device class drivers from the device driver lists. */
 157 static void
 158 acpidev_class_list_fini(void)
 159 {
 160         acpidev_unload_plat_modules();
 161 
 162         if ((acpidev_options & ACPIDEV_OUSER_NO_PCI) == 0) {
 163                 (void) acpidev_unregister_class(&acpidev_class_list_scope,
 164                     &acpidev_class_pci);
 165                 (void) acpidev_unregister_class(&acpidev_class_list_device,
 166                     &acpidev_class_pci);
 167         }
 168 
 169         if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
 170                 (void) acpidev_unregister_class(&acpidev_class_list_device,
 171                     &acpidev_class_memory);
 172         }
 173 
 174         if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
 175                 (void) acpidev_unregister_class(&acpidev_class_list_device,
 176                     &acpidev_class_cpu);
 177                 (void) acpidev_unregister_class(&acpidev_class_list_scope,
 178                     &acpidev_class_cpu);
 179                 (void) acpidev_unregister_class(&acpidev_class_list_root,
 180                     &acpidev_class_cpu);
 181         }
 182 
 183         if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
 184                 (void) acpidev_unregister_class(&acpidev_class_list_device,
 185                     &acpidev_class_container);
 186         }
 187 
 188         (void) acpidev_unregister_class(&acpidev_class_list_device,
 189             &acpidev_class_device);
 190         (void) acpidev_unregister_class(&acpidev_class_list_root,
 191             &acpidev_class_device);
 192 
 193         (void) acpidev_unregister_class(&acpidev_class_list_root,
 194             &acpidev_class_scope);
 195 }
 196 
 197 /* Register all device class drivers onto the driver lists. */
 198 static ACPI_STATUS
 199 acpidev_class_list_init(uint64_t *fp)
 200 {
 201         ACPI_STATUS rc = AE_OK;
 202 
 203         /* Set bit in mask for supported object types. */
 204         BT_SET(acpidev_object_type_mask, ACPI_TYPE_LOCAL_SCOPE);
 205         BT_SET(acpidev_object_type_mask, ACPI_TYPE_DEVICE);
 206 
 207         /*
 208          * Register the ACPI scope class driver onto the class driver lists.
 209          * Currently only ACPI scope objects under ACPI root node, such as _PR,
 210          * _SB, _TZ etc, need to be handled, so only register the scope class
 211          * driver onto the root list.
 212          */
 213         if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_root,
 214             &acpidev_class_scope, B_FALSE))) {
 215                 goto error_out;
 216         }
 217 
 218         /*
 219          * Register the ACPI device class driver onto the class driver lists.
 220          * The ACPI device class driver should be registered at the tail to
 221          * handle all device objects which haven't been handled by other
 222          * HID/CID specific device class drivers.
 223          */
 224         if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_root,
 225             &acpidev_class_device, B_TRUE))) {
 226                 goto error_root_device;
 227         }
 228         if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_device,
 229             &acpidev_class_device, B_TRUE))) {
 230                 goto error_device_device;
 231         }
 232 
 233         /* Check and register support for ACPI container device. */
 234         if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
 235                 if (ACPI_FAILURE(acpidev_register_class(
 236                     &acpidev_class_list_device, &acpidev_class_container,
 237                     B_FALSE))) {
 238                         goto error_device_container;
 239                 }
 240                 *fp |= ACPI_DEVCFG_CONTAINER;
 241         }
 242 
 243         /* Check and register support for ACPI CPU device. */
 244         if ((acpidev_options & ACPIDEV_OUSER_NO_CPU) == 0) {
 245                 /* Handle ACPI CPU Device */
 246                 if (ACPI_FAILURE(acpidev_register_class(
 247                     &acpidev_class_list_device, &acpidev_class_cpu, B_FALSE))) {
 248                         goto error_device_cpu;
 249                 }
 250                 /* Handle ACPI Processor under _PR */
 251                 if (ACPI_FAILURE(acpidev_register_class(
 252                     &acpidev_class_list_scope, &acpidev_class_cpu, B_FALSE))) {
 253                         goto error_scope_cpu;
 254                 }
 255                 /* House-keeping for CPU scan */
 256                 if (ACPI_FAILURE(acpidev_register_class(
 257                     &acpidev_class_list_root, &acpidev_class_cpu, B_FALSE))) {
 258                         goto error_root_cpu;
 259                 }
 260                 BT_SET(acpidev_object_type_mask, ACPI_TYPE_PROCESSOR);
 261                 *fp |= ACPI_DEVCFG_CPU;
 262         }
 263 
 264         /* Check support of ACPI memory devices. */
 265         if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
 266                 /*
 267                  * Register the ACPI memory class driver onto the
 268                  * acpidev_class_list_device list because ACPI module
 269                  * class driver uses that list.
 270                  */
 271                 if (ACPI_FAILURE(acpidev_register_class(
 272                     &acpidev_class_list_device, &acpidev_class_memory,
 273                     B_FALSE))) {
 274                         goto error_device_memory;
 275                 }
 276                 *fp |= ACPI_DEVCFG_MEMORY;
 277         }
 278 
 279         /* Check support of PCI/PCIex Host Bridge devices. */
 280         if ((acpidev_options & ACPIDEV_OUSER_NO_PCI) == 0) {
 281                 /*
 282                  * Register pci/pciex class drivers onto
 283                  * the acpidev_class_list_device class list because ACPI
 284                  * module class driver uses that list.
 285                  */
 286                 if (ACPI_FAILURE(acpidev_register_class(
 287                     &acpidev_class_list_device, &acpidev_class_pci,
 288                     B_FALSE))) {
 289                         goto error_device_pci;
 290                 }
 291 
 292                 /*
 293                  * Register pci/pciex class drivers onto the
 294                  * acpidev_class_list_scope class list.
 295                  */
 296                 if (ACPI_FAILURE(acpidev_register_class(
 297                     &acpidev_class_list_scope, &acpidev_class_pci,
 298                     B_FALSE))) {
 299                         goto error_scope_pci;
 300                 }
 301 
 302                 *fp |= ACPI_DEVCFG_PCI;
 303         }
 304 
 305         /* Check blacklist and load platform specific modules. */
 306         rc = acpidev_load_plat_modules();
 307         if (ACPI_FAILURE(rc)) {
 308                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to check blacklist "
 309                     "or load pratform modules.");
 310                 goto error_plat;
 311         }
 312 
 313         return (AE_OK);
 314 
 315 error_plat:
 316         if ((acpidev_options & ACPIDEV_OUSER_NO_PCI) == 0) {
 317                 (void) acpidev_unregister_class(&acpidev_class_list_scope,
 318                     &acpidev_class_pci);
 319         }
 320 error_scope_pci:
 321         if ((acpidev_options & ACPIDEV_OUSER_NO_PCI) == 0) {
 322                 (void) acpidev_unregister_class(&acpidev_class_list_device,
 323                     &acpidev_class_pci);
 324         }
 325 error_device_pci:
 326         if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
 327                 (void) acpidev_unregister_class(&acpidev_class_list_device,
 328                     &acpidev_class_memory);
 329         }
 330 error_device_memory:
 331         if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
 332                 (void) acpidev_unregister_class(&acpidev_class_list_root,
 333                     &acpidev_class_cpu);
 334         }
 335 error_root_cpu:
 336         if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
 337                 (void) acpidev_unregister_class(&acpidev_class_list_scope,
 338                     &acpidev_class_cpu);
 339         }
 340 error_scope_cpu:
 341         if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
 342                 (void) acpidev_unregister_class(&acpidev_class_list_device,
 343                     &acpidev_class_cpu);
 344         }
 345 error_device_cpu:
 346         if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
 347                 (void) acpidev_unregister_class(&acpidev_class_list_device,
 348                     &acpidev_class_container);
 349         }
 350 error_device_container:
 351         (void) acpidev_unregister_class(&acpidev_class_list_device,
 352             &acpidev_class_device);
 353 error_device_device:
 354         (void) acpidev_unregister_class(&acpidev_class_list_root,
 355             &acpidev_class_device);
 356 error_root_device:
 357         (void) acpidev_unregister_class(&acpidev_class_list_root,
 358             &acpidev_class_scope);
 359 error_out:
 360         ACPIDEV_DEBUG(CE_WARN,
 361             "!acpidev: failed to register built-in class drivers.");
 362         *fp = 0;
 363 
 364         return (AE_ERROR);
 365 }
 366 
 367 /*
 368  * Called in single threaded context during boot, no protection for
 369  * reentrance.
 370  */
 371 static ACPI_STATUS
 372 acpidev_create_root_node(void)
 373 {
 374         int circ, rv = AE_OK;
 375         dev_info_t *dip = NULL;
 376         acpidev_data_handle_t objhdl;
 377         char *compatibles[] = {
 378                 ACPIDEV_HID_ROOTNEX,
 379                 ACPIDEV_TYPE_ROOTNEX,
 380                 ACPIDEV_HID_VIRTNEX,
 381                 ACPIDEV_TYPE_VIRTNEX,
 382         };
 383 
 384         ndi_devi_enter(ddi_root_node(), &circ);
 385         ASSERT(acpidev_root_dip == NULL);
 386 
 387         /* Query whether device node already exists. */
 388         dip = ddi_find_devinfo(ACPIDEV_NODE_NAME_ROOT, -1, 0);
 389         if (dip != NULL && ddi_get_parent(dip) == ddi_root_node()) {
 390                 ndi_devi_exit(ddi_root_node(), circ);
 391                 cmn_err(CE_WARN, "!acpidev: node /devices/%s already exists, "
 392                     "disable driver.", ACPIDEV_NODE_NAME_ROOT);
 393                 return (AE_ALREADY_EXISTS);
 394         }
 395 
 396         /* Create the device node if it doesn't exist. */
 397         rv = ndi_devi_alloc(ddi_root_node(), ACPIDEV_NODE_NAME_ROOT,
 398             (pnode_t)DEVI_SID_NODEID, &dip);
 399         if (rv != NDI_SUCCESS) {
 400                 ndi_devi_exit(ddi_root_node(), circ);
 401                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to create device node "
 402                     "for ACPI root with errcode %d.", rv);
 403                 return (AE_ERROR);
 404         }
 405 
 406         /* Build cross reference between dip and ACPI object. */
 407         if (ACPI_FAILURE(acpica_tag_devinfo(dip, ACPI_ROOT_OBJECT))) {
 408                 (void) ddi_remove_child(dip, 0);
 409                 ndi_devi_exit(ddi_root_node(), circ);
 410                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to tag object %s.",
 411                     ACPIDEV_OBJECT_NAME_SB);
 412                 return (AE_ERROR);
 413         }
 414 
 415         /* Set device properties. */
 416         rv = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
 417             OBP_COMPATIBLE, ACPIDEV_ARRAY_PARAM(compatibles));
 418         if (rv == NDI_SUCCESS) {
 419                 rv = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
 420                     OBP_DEVICETYPE, ACPIDEV_TYPE_ROOTNEX);
 421         }
 422         if (rv != DDI_SUCCESS) {
 423                 ACPIDEV_DEBUG(CE_WARN,
 424                     "!acpidev: failed to set device property for /devices/%s.",
 425                     ACPIDEV_NODE_NAME_ROOT);
 426                 goto error_out;
 427         }
 428 
 429         /* Manually create an object handle for the root node */
 430         objhdl = acpidev_data_create_handle(ACPI_ROOT_OBJECT);
 431         if (objhdl == NULL) {
 432                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to create object "
 433                     "handle for the root node.");
 434                 goto error_out;
 435         }
 436         objhdl->aod_level = 0;
 437         objhdl->aod_hdl = ACPI_ROOT_OBJECT;
 438         objhdl->aod_dip = dip;
 439         objhdl->aod_class = &acpidev_class_scope;
 440         objhdl->aod_status = acpidev_query_device_status(ACPI_ROOT_OBJECT);
 441         objhdl->aod_iflag = ACPIDEV_ODF_STATUS_VALID |
 442             ACPIDEV_ODF_DEVINFO_CREATED | ACPIDEV_ODF_DEVINFO_TAGGED;
 443 
 444         /* Bind device driver. */
 445         (void) ndi_devi_bind_driver(dip, 0);
 446 
 447         acpidev_root_dip = dip;
 448         ndi_devi_exit(ddi_root_node(), circ);
 449 
 450         return (AE_OK);
 451 
 452 error_out:
 453         (void) acpica_untag_devinfo(dip, ACPI_ROOT_OBJECT);
 454         (void) ddi_remove_child(dip, 0);
 455         ndi_devi_exit(ddi_root_node(), circ);
 456         return (AE_ERROR);
 457 }
 458 
 459 static void
 460 acpidev_initialize(void)
 461 {
 462         int rc;
 463         char *str = NULL;
 464         uint64_t features = 0;
 465 
 466         /* Check whether it has already been initialized. */
 467         if (acpidev_status == ACPIDEV_STATUS_DISABLED) {
 468                 cmn_err(CE_CONT, "?acpidev: ACPI device autoconfig "
 469                     "disabled by user.\n");
 470                 return;
 471         } else if (acpidev_status != ACPIDEV_STATUS_UNKNOWN) {
 472                 ACPIDEV_DEBUG(CE_NOTE,
 473                     "!acpidev: initialization called more than once.");
 474                 return;
 475         }
 476 
 477         /* Check whether ACPI device autoconfig has been disabled by user. */
 478         rc = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
 479             DDI_PROP_DONTPASS, "acpidev-autoconfig", &str);
 480         if (rc == DDI_SUCCESS) {
 481                 if (strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0) {
 482                         cmn_err(CE_CONT, "?acpidev: ACPI device autoconfig "
 483                             "disabled by user.\n");
 484                         ddi_prop_free(str);
 485                         acpidev_status = ACPIDEV_STATUS_DISABLED;
 486                         return;
 487                 }
 488                 ddi_prop_free(str);
 489         }
 490 
 491         /* Initialize acpica subsystem. */
 492         if (ACPI_FAILURE(acpica_init())) {
 493                 cmn_err(CE_WARN,
 494                     "!acpidev: failed to initialize acpica subsystem.");
 495                 acpidev_status = ACPIDEV_STATUS_FAILED;
 496                 return;
 497         }
 498 
 499         /* Check ACPICA subsystem status. */
 500         if (!acpica_get_core_feature(ACPI_FEATURE_FULL_INIT)) {
 501                 cmn_err(CE_WARN, "!acpidev: ACPICA hasn't been fully "
 502                     "initialized, ACPI device autoconfig will be disabled.");
 503                 acpidev_status = ACPIDEV_STATUS_DISABLED;
 504                 return;
 505         }
 506 
 507         /* Converts acpidev-options from type string to int, if any */
 508         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
 509             DDI_PROP_DONTPASS, "acpidev-options", &str) == DDI_PROP_SUCCESS) {
 510                 long data;
 511                 rc = ddi_strtol(str, NULL, 0, &data);
 512                 if (rc == 0) {
 513                         (void) e_ddi_prop_remove(DDI_DEV_T_NONE,
 514                             ddi_root_node(), "acpidev-options");
 515                         (void) e_ddi_prop_update_int(DDI_DEV_T_NONE,
 516                             ddi_root_node(), "acpidev-options", data);
 517                 }
 518                 ddi_prop_free(str);
 519         }
 520         /* Get acpidev_options user options. */
 521         acpidev_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
 522             DDI_PROP_DONTPASS, "acpidev-options", acpidev_options);
 523 
 524         /* Check whether ACPI based DR has been disabled by user. */
 525         rc = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
 526             DDI_PROP_DONTPASS, "acpidev-dr", &str);
 527         if (rc == DDI_SUCCESS) {
 528                 if (strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0) {
 529                         cmn_err(CE_CONT, "?acpidev: ACPI based DR has been "
 530                             "disabled by user.\n");
 531                         acpidev_dr_enable = 0;
 532                 }
 533                 ddi_prop_free(str);
 534         }
 535 
 536         /* Register all device class drivers. */
 537         if (ACPI_FAILURE(acpidev_class_list_init(&features))) {
 538                 cmn_err(CE_WARN,
 539                     "!acpidev: failed to initalize class driver lists.");
 540                 acpidev_status = ACPIDEV_STATUS_FAILED;
 541                 return;
 542         }
 543 
 544         /* Create root node for ACPI/firmware device subtree. */
 545         if (ACPI_FAILURE(acpidev_create_root_node())) {
 546                 cmn_err(CE_WARN, "!acpidev: failed to create root node "
 547                     "for acpi device tree.");
 548                 acpidev_class_list_fini();
 549                 acpidev_status = ACPIDEV_STATUS_FAILED;
 550                 return;
 551         }
 552 
 553         /* Notify acpica to enable ACPI device auto configuration. */
 554         acpica_set_core_feature(ACPI_FEATURE_DEVCFG);
 555         acpica_set_devcfg_feature(features);
 556 
 557         ACPIDEV_DEBUG(CE_NOTE, "!acpidev: ACPI device autoconfig initialized.");
 558         acpidev_status = ACPIDEV_STATUS_INITIALIZED;
 559 }
 560 
 561 /*
 562  * Probe devices in ACPI namespace which can't be enumerated by other methods
 563  * at boot time.
 564  */
 565 static ACPI_STATUS
 566 acpidev_boot_probe_device(acpidev_op_type_t op_type)
 567 {
 568         ACPI_STATUS rc = AE_OK;
 569         acpidev_walk_info_t *infop;
 570 
 571         ASSERT(acpidev_root_dip != NULL);
 572         ASSERT(op_type == ACPIDEV_OP_BOOT_PROBE ||
 573             op_type == ACPIDEV_OP_BOOT_REPROBE);
 574 
 575         infop = acpidev_alloc_walk_info(op_type, 0, ACPI_ROOT_OBJECT,
 576             &acpidev_class_list_root, NULL);
 577         if (infop == NULL) {
 578                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to allocate walk info "
 579                     "object in acpi_boot_probe_device().");
 580                 return (AE_ERROR);
 581         }
 582         /* Enumerate ACPI devices. */
 583         rc = acpidev_probe_child(infop);
 584         if (ACPI_FAILURE(rc)) {
 585                 cmn_err(CE_WARN, "!acpidev: failed to probe child object "
 586                     "under ACPI root node.");
 587         }
 588         acpidev_free_walk_info(infop);
 589 
 590         return (rc);
 591 }
 592 
 593 /*
 594  * Platform specific device prober for ACPI virtual bus.
 595  * It will be called in single-threaded environment to enumerate devices in
 596  * ACPI namespace at boot time.
 597  */
 598 static void
 599 acpidev_boot_probe(int type)
 600 {
 601         ACPI_STATUS rc;
 602 
 603         /* Initialize subsystem on first pass. */
 604         mutex_enter(&acpidev_drv_lock);
 605         if (type == 0) {
 606                 acpidev_initialize();
 607                 if (acpidev_status != ACPIDEV_STATUS_INITIALIZED &&
 608                     acpidev_status != ACPIDEV_STATUS_DISABLED) {
 609                         cmn_err(CE_WARN, "!acpidev: driver disabled due to "
 610                             "initalization failure.");
 611                 }
 612         }
 613 
 614         /* Probe ACPI devices */
 615         if (type == 0 && acpidev_status == ACPIDEV_STATUS_INITIALIZED) {
 616                 rc = acpidev_boot_probe_device(ACPIDEV_OP_BOOT_PROBE);
 617                 if (ACPI_SUCCESS(rc)) {
 618                         /*
 619                          * Support of DR operations will be disabled
 620                          * if failed to initialize DR subsystem.
 621                          */
 622                         rc = acpidev_dr_initialize(acpidev_root_dip);
 623                         if (ACPI_FAILURE(rc) && rc != AE_SUPPORT) {
 624                                 cmn_err(CE_CONT, "?acpidev: failed to "
 625                                     "initialize DR subsystem.");
 626                         }
 627                         acpidev_status = ACPIDEV_STATUS_FIRST_PASS;
 628                 } else {
 629                         ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to probe ACPI "
 630                             "devices during boot.");
 631                         acpidev_status = ACPIDEV_STATUS_FAILED;
 632                 }
 633         } else if (type != 0 && acpidev_status == ACPIDEV_STATUS_FIRST_PASS) {
 634                 rc = acpidev_boot_probe_device(ACPIDEV_OP_BOOT_REPROBE);
 635                 if (ACPI_SUCCESS(rc)) {
 636                         acpidev_status = ACPIDEV_STATUS_READY;
 637                 } else {
 638                         ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to reprobe "
 639                             "ACPI devices during boot.");
 640                         acpidev_status = ACPIDEV_STATUS_FAILED;
 641                 }
 642         } else if (acpidev_status != ACPIDEV_STATUS_FAILED &&
 643             acpidev_status != ACPIDEV_STATUS_DISABLED &&
 644             acpidev_status != ACPIDEV_STATUS_READY) {
 645                 cmn_err(CE_WARN,
 646                     "!acpidev: invalid ACPI device autoconfig global status.");
 647         }
 648         mutex_exit(&acpidev_drv_lock);
 649 }
 650 
 651 ACPI_STATUS
 652 acpidev_probe_child(acpidev_walk_info_t *infop)
 653 {
 654         int circ;
 655         dev_info_t *pdip;
 656         ACPI_STATUS res, rc = AE_OK;
 657         ACPI_HANDLE child;
 658         ACPI_OBJECT_TYPE type;
 659         acpidev_class_list_t *it;
 660         acpidev_walk_info_t *cinfop;
 661         acpidev_data_handle_t datap;
 662 
 663         /* Validate parameter first. */
 664         ASSERT(infop != NULL);
 665         if (infop == NULL) {
 666                 ACPIDEV_DEBUG(CE_WARN,
 667                     "!acpidev: infop is NULL in acpidev_probe_child().");
 668                 return (AE_BAD_PARAMETER);
 669         }
 670         ASSERT(infop->awi_level < ACPIDEV_MAX_ENUM_LEVELS - 1);
 671         if (infop->awi_level >= ACPIDEV_MAX_ENUM_LEVELS - 1) {
 672                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: recursive level is too deep "
 673                     "in acpidev_probe_child().");
 674                 return (AE_BAD_PARAMETER);
 675         }
 676         ASSERT(infop->awi_class_list != NULL);
 677         ASSERT(infop->awi_hdl != NULL);
 678         ASSERT(infop->awi_info != NULL);
 679         ASSERT(infop->awi_name != NULL);
 680         ASSERT(infop->awi_data != NULL);
 681         if (infop->awi_class_list == NULL || infop->awi_hdl == NULL ||
 682             infop->awi_info == NULL || infop->awi_name == NULL ||
 683             infop->awi_data == NULL) {
 684                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: infop has NULL fields in "
 685                     "acpidev_probe_child().");
 686                 return (AE_BAD_PARAMETER);
 687         }
 688         pdip = acpidev_walk_info_get_pdip(infop);
 689         if (pdip == NULL) {
 690                 ACPIDEV_DEBUG(CE_WARN,
 691                     "!acpidev: pdip is NULL in acpidev_probe_child().");
 692                 return (AE_BAD_PARAMETER);
 693         }
 694 
 695         ndi_devi_enter(pdip, &circ);
 696         rw_enter(&acpidev_class_lock, RW_READER);
 697 
 698         /* Call pre-probe callback functions. */
 699         for (it = *(infop->awi_class_list); it != NULL; it = it->acl_next) {
 700                 if (it->acl_class->adc_pre_probe == NULL) {
 701                         continue;
 702                 }
 703                 infop->awi_class_curr = it->acl_class;
 704                 if (ACPI_FAILURE(it->acl_class->adc_pre_probe(infop))) {
 705                         ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to pre-probe "
 706                             "device of type %s under %s.",
 707                             it->acl_class->adc_class_name, infop->awi_name);
 708                 }
 709         }
 710 
 711         /* Walk child objects. */
 712         child = NULL;
 713         while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_ANY,
 714             infop->awi_hdl, child, &child))) {
 715                 /* Skip object if we're not interested in it. */
 716                 if (ACPI_FAILURE(AcpiGetType(child, &type)) ||
 717                     type > ACPI_TYPE_NS_NODE_MAX ||
 718                     BT_TEST(acpidev_object_type_mask, type) == 0) {
 719                         continue;
 720                 }
 721 
 722                 /* It's another hotplug-capable board, skip it. */
 723                 if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE &&
 724                     acpidev_dr_device_is_board(child)) {
 725                         continue;
 726                 }
 727 
 728                 /* Allocate the walk info structure. */
 729                 cinfop = acpidev_alloc_walk_info(infop->awi_op_type,
 730                     infop->awi_level + 1, child, NULL, infop);
 731                 if (cinfop == NULL) {
 732                         ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to allocate "
 733                             "walk info child object of %s.",
 734                             infop->awi_name);
 735                         /* Mark error and continue to handle next child. */
 736                         rc = AE_ERROR;
 737                         continue;
 738                 }
 739 
 740                 /*
 741                  * Remember the class list used to handle this object.
 742                  * It should be the same list for different passes of scans.
 743                  */
 744                 ASSERT(cinfop->awi_data != NULL);
 745                 datap = cinfop->awi_data;
 746                 if (cinfop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
 747                         datap->aod_class_list = infop->awi_class_list;
 748                 }
 749 
 750                 /* Call registered process callbacks. */
 751                 for (it = *(infop->awi_class_list); it != NULL;
 752                     it = it->acl_next) {
 753                         if (it->acl_class->adc_probe == NULL) {
 754                                 continue;
 755                         }
 756                         cinfop->awi_class_curr = it->acl_class;
 757                         res = it->acl_class->adc_probe(cinfop);
 758                         if (ACPI_FAILURE(res)) {
 759                                 rc = res;
 760                                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to "
 761                                     "process object of type %s under %s.",
 762                                     it->acl_class->adc_class_name,
 763                                     infop->awi_name);
 764                         }
 765                 }
 766 
 767                 /* Free resources. */
 768                 acpidev_free_walk_info(cinfop);
 769         }
 770 
 771         /* Call post-probe callback functions. */
 772         for (it = *(infop->awi_class_list); it != NULL; it = it->acl_next) {
 773                 if (it->acl_class->adc_post_probe == NULL) {
 774                         continue;
 775                 }
 776                 infop->awi_class_curr = it->acl_class;
 777                 if (ACPI_FAILURE(it->acl_class->adc_post_probe(infop))) {
 778                         ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to post-probe "
 779                             "device of type %s under %s.",
 780                             it->acl_class->adc_class_name, infop->awi_name);
 781                 }
 782         }
 783 
 784         rw_exit(&acpidev_class_lock);
 785         ndi_devi_exit(pdip, circ);
 786 
 787         return (rc);
 788 }
 789 
 790 ACPI_STATUS
 791 acpidev_process_object(acpidev_walk_info_t *infop, int flags)
 792 {
 793         ACPI_STATUS rc = AE_OK;
 794         char *devname;
 795         dev_info_t *dip, *pdip;
 796         ACPI_HANDLE hdl;
 797         ACPI_DEVICE_INFO *adip;
 798         acpidev_class_t *clsp;
 799         acpidev_data_handle_t datap;
 800         acpidev_filter_result_t res;
 801 
 802         /* Validate parameters first. */
 803         ASSERT(infop != NULL);
 804         if (infop == NULL) {
 805                 ACPIDEV_DEBUG(CE_WARN,
 806                     "!acpidev: infop is NULL in acpidev_process_object().");
 807                 return (AE_BAD_PARAMETER);
 808         }
 809         ASSERT(infop->awi_hdl != NULL);
 810         ASSERT(infop->awi_info != NULL);
 811         ASSERT(infop->awi_data != NULL);
 812         ASSERT(infop->awi_class_curr != NULL);
 813         ASSERT(infop->awi_class_curr->adc_filter != NULL);
 814         hdl = infop->awi_hdl;
 815         adip = infop->awi_info;
 816         datap = infop->awi_data;
 817         clsp = infop->awi_class_curr;
 818         if (hdl == NULL || datap == NULL || adip == NULL || clsp == NULL ||
 819             clsp->adc_filter == NULL) {
 820                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: infop has NULL pointer in "
 821                     "acpidev_process_object().");
 822                 return (AE_BAD_PARAMETER);
 823         }
 824         pdip = acpidev_walk_info_get_pdip(infop);
 825         if (pdip == NULL) {
 826                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to get pdip for %s "
 827                     "in acpidev_process_object().", infop->awi_name);
 828                 return (AE_BAD_PARAMETER);
 829         }
 830 
 831         /*
 832          * Check whether the object has already been handled.
 833          * Tag and child dip pointer are used to indicate the object has been
 834          * handled by the ACPI auto configure driver. It has the
 835          * following usages:
 836          * 1) Prevent creating dip for objects which already have a dip
 837          *    when reloading the ACPI auto configure driver.
 838          * 2) Prevent creating multiple dips for ACPI objects with ACPI
 839          *    aliases. Currently ACPICA framework has no way to tell whether
 840          *    an object is an alias or not for some types of object. So tag
 841          *    is used to indicate that the object has been handled.
 842          * 3) Prevent multiple class drivers from creating multiple devices for
 843          *    the same ACPI object.
 844          */
 845         if ((flags & ACPIDEV_PROCESS_FLAG_CREATE) &&
 846             (flags & ACPIDEV_PROCESS_FLAG_CHECK) &&
 847             !(infop->awi_flags & ACPIDEV_WI_DISABLE_CREATE) &&
 848             (infop->awi_flags & ACPIDEV_WI_DEVICE_CREATED)) {
 849                 ASSERT(infop->awi_dip != NULL);
 850                 ACPIDEV_DEBUG(CE_NOTE,
 851                     "!acpidev: device has already been created for object %s.",
 852                     infop->awi_name);
 853                 return (AE_ALREADY_EXISTS);
 854         }
 855 
 856         /*
 857          * Determine action according to following rules based on device
 858          * status returned by _STA method. Please refer to ACPI3.0b section
 859          * 6.3.1 and 6.5.1.
 860          * present functioning enabled  Action
 861          *      0       0       x       Do nothing
 862          *      1       x       0       Do nothing
 863          *      1       x       1       Create node and scan child
 864          *      x       1       0       Do nothing
 865          *      x       1       1       Create node and scan child
 866          */
 867         if ((datap->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0 ||
 868             (flags & ACPIDEV_PROCESS_FLAG_SYNCSTATUS)) {
 869                 if (adip->Valid & ACPI_VALID_STA) {
 870                         datap->aod_status = adip->CurrentStatus;
 871                 } else {
 872                         datap->aod_status = acpidev_query_device_status(hdl);
 873                 }
 874                 datap->aod_iflag |= ACPIDEV_ODF_STATUS_VALID;
 875         }
 876         if (!acpidev_check_device_enabled(datap->aod_status)) {
 877                 ACPIDEV_DEBUG(CE_NOTE, "!acpidev: object %s doesn't exist.",
 878                     infop->awi_name);
 879                 /*
 880                  * Need to scan for hotplug-capable boards even if object
 881                  * doesn't exist or has been disabled during the first pass.
 882                  * So just disable creating device node and keep on scanning.
 883                  */
 884                 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
 885                         flags &= ~ACPIDEV_PROCESS_FLAG_CREATE;
 886                 } else {
 887                         return (AE_NOT_EXIST);
 888                 }
 889         }
 890 
 891         ASSERT(infop->awi_data != NULL);
 892         ASSERT(infop->awi_parent != NULL);
 893         ASSERT(infop->awi_parent->awi_data != NULL);
 894         if (flags & ACPIDEV_PROCESS_FLAG_CREATE) {
 895                 mutex_enter(&(DEVI(pdip)->devi_lock));
 896                 /*
 897                  * Put the device into offline state if its parent is in
 898                  * offline state.
 899                  */
 900                 if (DEVI_IS_DEVICE_OFFLINE(pdip)) {
 901                         flags |= ACPIDEV_PROCESS_FLAG_OFFLINE;
 902                 }
 903                 mutex_exit(&(DEVI(pdip)->devi_lock));
 904         }
 905 
 906         /* Evaluate filtering rules and generate device name. */
 907         devname = kmem_zalloc(ACPIDEV_MAX_NAMELEN + 1, KM_SLEEP);
 908         (void) memcpy(devname, (char *)&adip->Name, sizeof (adip->Name));
 909         if (flags & ACPIDEV_PROCESS_FLAG_CREATE) {
 910                 res = clsp->adc_filter(infop, devname, ACPIDEV_MAX_NAMELEN);
 911         } else {
 912                 res = clsp->adc_filter(infop, NULL, 0);
 913         }
 914 
 915         /* Create device if requested. */
 916         if ((flags & ACPIDEV_PROCESS_FLAG_CREATE) &&
 917             !(infop->awi_flags & ACPIDEV_WI_DISABLE_CREATE) &&
 918             !(infop->awi_flags & ACPIDEV_WI_DEVICE_CREATED) &&
 919             (res == ACPIDEV_FILTER_DEFAULT || res == ACPIDEV_FILTER_CREATE)) {
 920                 int ret;
 921 
 922                 /*
 923                  * Allocate dip and set default properties.
 924                  * Properties can be overriden in class specific init routines.
 925                  */
 926                 ASSERT(infop->awi_dip == NULL);
 927                 ndi_devi_alloc_sleep(pdip, devname, (pnode_t)DEVI_SID_NODEID,
 928                     &dip);
 929                 infop->awi_dip = dip;
 930                 ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
 931                     OBP_DEVICETYPE, clsp->adc_dev_type);
 932                 if (ret != NDI_SUCCESS) {
 933                         ACPIDEV_DEBUG(CE_WARN,
 934                             "!acpidev: failed to set device property for %s.",
 935                             infop->awi_name);
 936                         (void) ddi_remove_child(dip, 0);
 937                         infop->awi_dip = NULL;
 938                         kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
 939                         return (AE_ERROR);
 940                 }
 941 
 942                 /* Build cross reference between dip and ACPI object. */
 943                 if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0 &&
 944                     ACPI_FAILURE(acpica_tag_devinfo(dip, hdl))) {
 945                         cmn_err(CE_WARN,
 946                             "!acpidev: failed to tag object %s.",
 947                             infop->awi_name);
 948                         (void) ddi_remove_child(dip, 0);
 949                         infop->awi_dip = NULL;
 950                         kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
 951                         return (AE_ERROR);
 952                 }
 953 
 954                 /* Call class specific initialization callback. */
 955                 if (clsp->adc_init != NULL &&
 956                     ACPI_FAILURE(clsp->adc_init(infop))) {
 957                         ACPIDEV_DEBUG(CE_WARN,
 958                             "!acpidev: failed to initialize device %s.",
 959                             infop->awi_name);
 960                         if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0) {
 961                                 (void) acpica_untag_devinfo(dip, hdl);
 962                         }
 963                         (void) ddi_remove_child(dip, 0);
 964                         infop->awi_dip = NULL;
 965                         kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
 966                         return (AE_ERROR);
 967                 }
 968 
 969                 /* Set device into offline state if requested. */
 970                 if (flags & ACPIDEV_PROCESS_FLAG_OFFLINE) {
 971                         mutex_enter(&(DEVI(dip)->devi_lock));
 972                         DEVI_SET_DEVICE_OFFLINE(dip);
 973                         mutex_exit(&(DEVI(dip)->devi_lock));
 974                 }
 975 
 976                 /* Mark status */
 977                 infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED;
 978                 datap->aod_iflag |= ACPIDEV_ODF_DEVINFO_CREATED;
 979                 datap->aod_dip = dip;
 980                 datap->aod_class = clsp;
 981                 /* Hold reference count on class driver. */
 982                 atomic_inc_32(&clsp->adc_refcnt);
 983                 if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0) {
 984                         datap->aod_iflag |= ACPIDEV_ODF_DEVINFO_TAGGED;
 985                 }
 986 
 987                 /* Bind device driver. */
 988                 if ((flags & ACPIDEV_PROCESS_FLAG_NOBIND) != 0) {
 989                         mutex_enter(&(DEVI(dip)->devi_lock));
 990                         DEVI(dip)->devi_flags |= DEVI_NO_BIND;
 991                         mutex_exit(&(DEVI(dip)->devi_lock));
 992                 } else {
 993                         (void) ndi_devi_bind_driver(dip, 0);
 994                 }
 995 
 996                 /* Hold reference on branch when hot-adding devices. */
 997                 if (flags & ACPIDEV_PROCESS_FLAG_HOLDBRANCH) {
 998                         e_ddi_branch_hold(dip);
 999                 }
1000         }
1001 
1002         /* Free resources */
1003         kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
1004         rc = AE_OK;
1005 
1006         /* Recursively scan child objects if requested. */
1007         switch (res) {
1008         case ACPIDEV_FILTER_DEFAULT:
1009                 /* FALLTHROUGH */
1010         case ACPIDEV_FILTER_SCAN:
1011                 /* Check if we need to scan child. */
1012                 if ((flags & ACPIDEV_PROCESS_FLAG_SCAN) &&
1013                     !(infop->awi_flags & ACPIDEV_WI_DISABLE_SCAN) &&
1014                     !(infop->awi_flags & ACPIDEV_WI_CHILD_SCANNED)) {
1015                         /* probe child object. */
1016                         rc = acpidev_probe_child(infop);
1017                         if (ACPI_FAILURE(rc)) {
1018                                 ACPIDEV_DEBUG(CE_WARN,
1019                                     "!acpidev: failed to probe subtree of %s.",
1020                                     infop->awi_name);
1021                                 rc = AE_ERROR;
1022                         }
1023                         /* Mark object as scanned. */
1024                         infop->awi_flags |= ACPIDEV_WI_CHILD_SCANNED;
1025                 }
1026                 break;
1027 
1028         case ACPIDEV_FILTER_CREATE:
1029                 /* FALLTHROUGH */
1030         case ACPIDEV_FILTER_CONTINUE:
1031                 /* FALLTHROUGH */
1032         case ACPIDEV_FILTER_SKIP:
1033                 break;
1034 
1035         case ACPIDEV_FILTER_FAILED:
1036                 ACPIDEV_DEBUG(CE_WARN,
1037                     "!acpidev: failed to probe device for %s.",
1038                     infop->awi_name);
1039                 rc = AE_ERROR;
1040                 break;
1041 
1042         default:
1043                 cmn_err(CE_WARN,
1044                     "!acpidev: unknown filter result code %d.", res);
1045                 rc = AE_ERROR;
1046                 break;
1047         }
1048 
1049         return (rc);
1050 }
1051 
1052 acpidev_filter_result_t
1053 acpidev_filter_default(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
1054     acpidev_filter_rule_t *afrp, char *devname, int len)
1055 {
1056         _NOTE(ARGUNUSED(hdl));
1057 
1058         ASSERT(afrp != NULL);
1059         ASSERT(devname == NULL || len >= ACPIDEV_MAX_NAMELEN);
1060         if (infop->awi_level < afrp->adf_minlvl ||
1061             infop->awi_level > afrp->adf_maxlvl) {
1062                 return (ACPIDEV_FILTER_CONTINUE);
1063         } else if (afrp->adf_pattern != NULL &&
1064             strncmp(afrp->adf_pattern,
1065             (char *)&infop->awi_info->Name,
1066             sizeof (infop->awi_info->Name))) {
1067                 return (ACPIDEV_FILTER_CONTINUE);
1068         }
1069         if (afrp->adf_replace != NULL && devname != NULL) {
1070                 (void) strlcpy(devname, afrp->adf_replace, len);
1071         }
1072 
1073         return (afrp->adf_retcode);
1074 }
1075 
1076 acpidev_filter_result_t
1077 acpidev_filter_device(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
1078     acpidev_filter_rule_t *afrp, int entries, char *devname, int len)
1079 {
1080         acpidev_filter_result_t res;
1081 
1082         /* Evaluate filtering rules. */
1083         for (; entries > 0; entries--, afrp++) {
1084                 if (afrp->adf_filter_func != NULL) {
1085                         res = afrp->adf_filter_func(infop, hdl, afrp,
1086                             devname, len);
1087                 } else {
1088                         res = acpidev_filter_default(infop, hdl, afrp,
1089                             devname, len);
1090                 }
1091                 if (res == ACPIDEV_FILTER_DEFAULT ||
1092                     res == ACPIDEV_FILTER_SCAN) {
1093                         infop->awi_class_list = afrp->adf_class_list;
1094                         break;
1095                 }
1096         }
1097 
1098         return (res);
1099 }
1100 
1101 dev_info_t *
1102 acpidev_root_node(void)
1103 {
1104         return (acpidev_root_dip);
1105 }
1106 
1107 ACPI_STATUS
1108 acpidev_register_class(acpidev_class_list_t **listpp, acpidev_class_t *clsp,
1109     boolean_t tail)
1110 {
1111         ACPI_STATUS rc;
1112         acpidev_class_list_t *item;
1113         acpidev_class_list_t *temp;
1114 
1115         ASSERT(clsp != NULL);
1116         ASSERT(listpp != NULL);
1117         if (listpp == NULL || clsp == NULL) {
1118                 ACPIDEV_DEBUG(CE_WARN,
1119                     "!acpidev: invalid parameter in acpidev_register_class().");
1120                 return (AE_BAD_PARAMETER);
1121         } else if (clsp->adc_version != ACPIDEV_CLASS_REV) {
1122                 cmn_err(CE_WARN,
1123                     "!acpidev: class driver %s version mismatch.",
1124                     clsp->adc_class_name);
1125                 return (AE_BAD_DATA);
1126         }
1127 
1128         rc = AE_OK;
1129         item = kmem_zalloc(sizeof (*item), KM_SLEEP);
1130         item->acl_class = clsp;
1131         rw_enter(&acpidev_class_lock, RW_WRITER);
1132         /* Check for duplicated item. */
1133         for (temp = *listpp; temp != NULL; temp = temp->acl_next) {
1134                 if (temp->acl_class == clsp) {
1135                         cmn_err(CE_WARN,
1136                             "!acpidev: register duplicate class driver %s.",
1137                             clsp->adc_class_name);
1138                         rc = AE_ALREADY_EXISTS;
1139                         break;
1140                 }
1141         }
1142         if (ACPI_SUCCESS(rc)) {
1143                 if (tail) {
1144                         while (*listpp) {
1145                                 listpp = &(*listpp)->acl_next;
1146                         }
1147                 }
1148                 item->acl_next = *listpp;
1149                 *listpp = item;
1150         }
1151         rw_exit(&acpidev_class_lock);
1152         if (ACPI_FAILURE(rc)) {
1153                 kmem_free(item, sizeof (*item));
1154         }
1155 
1156         return (rc);
1157 }
1158 
1159 ACPI_STATUS
1160 acpidev_unregister_class(acpidev_class_list_t **listpp,
1161     acpidev_class_t *clsp)
1162 {
1163         ACPI_STATUS rc = AE_NOT_FOUND;
1164         acpidev_class_list_t *temp;
1165 
1166         ASSERT(clsp != NULL);
1167         ASSERT(listpp != NULL);
1168         if (listpp == NULL || clsp == NULL) {
1169                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameter "
1170                     "in acpidev_unregister_class().");
1171                 return (AE_BAD_PARAMETER);
1172         }
1173 
1174         rw_enter(&acpidev_class_lock, RW_WRITER);
1175         for (temp = NULL; *listpp; listpp = &(*listpp)->acl_next) {
1176                 if ((*listpp)->acl_class == clsp) {
1177                         temp = *listpp;
1178                         *listpp = (*listpp)->acl_next;
1179                         break;
1180                 }
1181         }
1182         if (temp == NULL) {
1183                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: class %p(%s) doesn't exist "
1184                     "in acpidev_unregister_class().",
1185                     (void *)clsp, clsp->adc_class_name);
1186                 rc = AE_NOT_FOUND;
1187         } else if (temp->acl_class->adc_refcnt != 0) {
1188                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: class %p(%s) is still in use "
1189                     "in acpidev_unregister_class()..",
1190                     (void *)clsp, clsp->adc_class_name);
1191                 rc = AE_ERROR;
1192         } else {
1193                 kmem_free(temp, sizeof (*temp));
1194                 rc = AE_OK;
1195         }
1196         rw_exit(&acpidev_class_lock);
1197 
1198         return (rc);
1199 }