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