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