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 #include <sys/types.h>
  27 #include <sys/atomic.h>
  28 #include <sys/sunddi.h>
  29 #include <sys/sunndi.h>
  30 #include <sys/acpi/acpi.h>
  31 #include <sys/acpica.h>
  32 #include <sys/acpidev.h>
  33 #include <sys/acpidev_impl.h>
  34 
  35 static ACPI_STATUS acpidev_device_probe(acpidev_walk_info_t *infop);
  36 static acpidev_filter_result_t acpidev_device_filter(acpidev_walk_info_t *infop,
  37     char *devname, int maxlen);
  38 static ACPI_STATUS acpidev_device_init(acpidev_walk_info_t *infop);
  39 
  40 static uint32_t acpidev_device_unitaddr = 0;
  41 
  42 /*
  43  * Default class driver for ACPI DEVICE objects.
  44  * The default policy for DEVICE objects is to scan child objects without
  45  * creating device nodes. But some special DEVICE objects will have device
  46  * nodes created for them.
  47  */
  48 acpidev_class_t acpidev_class_device = {
  49         0,                              /* adc_refcnt */
  50         ACPIDEV_CLASS_REV1,             /* adc_version */
  51         ACPIDEV_CLASS_ID_DEVICE,        /* adc_class_id */
  52         "ACPI Device",                  /* adc_class_name */
  53         ACPIDEV_TYPE_DEVICE,            /* adc_dev_type */
  54         NULL,                           /* adc_private */
  55         NULL,                           /* adc_pre_probe */
  56         NULL,                           /* adc_post_probe */
  57         acpidev_device_probe,           /* adc_probe */
  58         acpidev_device_filter,          /* adc_filter */
  59         acpidev_device_init,            /* adc_init */
  60         NULL,                           /* adc_fini */
  61 };
  62 
  63 /*
  64  * List of class drivers which will be called in order when handling
  65  * children of ACPI DEVICE objects.
  66  */
  67 acpidev_class_list_t *acpidev_class_list_device = NULL;
  68 
  69 /* Filter rule table for boot. */
  70 static acpidev_filter_rule_t acpidev_device_filters[] = {
  71         {       /* _SB_ object type is hardcoded to DEVICE by acpica */
  72                 NULL,
  73                 0,
  74                 ACPIDEV_FILTER_DEFAULT,
  75                 &acpidev_class_list_device,
  76                 1,
  77                 1,
  78                 ACPIDEV_OBJECT_NAME_SB,
  79                 ACPIDEV_NODE_NAME_MODULE_SBD,
  80         },
  81         {       /* Ignore other device objects under ACPI root object */
  82                 NULL,
  83                 0,
  84                 ACPIDEV_FILTER_SKIP,
  85                 NULL,
  86                 1,
  87                 1,
  88                 NULL,
  89                 NULL,
  90         },
  91         {       /* Scan other device objects not directly under ACPI root */
  92                 NULL,
  93                 0,
  94                 ACPIDEV_FILTER_SKIP,
  95                 &acpidev_class_list_device,
  96                 2,
  97                 INT_MAX,
  98                 NULL,
  99                 NULL,
 100         }
 101 };
 102 
 103 static ACPI_STATUS
 104 acpidev_device_probe(acpidev_walk_info_t *infop)
 105 {
 106         ACPI_STATUS rc = AE_OK;
 107         int flags;
 108 
 109         ASSERT(infop != NULL);
 110         ASSERT(infop->awi_hdl != NULL);
 111         ASSERT(infop->awi_info != NULL);
 112 
 113         if (infop->awi_info->Type != ACPI_TYPE_DEVICE) {
 114                 return (AE_OK);
 115         }
 116 
 117         flags = ACPIDEV_PROCESS_FLAG_SCAN;
 118         switch (infop->awi_op_type) {
 119         case ACPIDEV_OP_BOOT_PROBE:
 120                 flags |= ACPIDEV_PROCESS_FLAG_CREATE;
 121                 break;
 122 
 123         case ACPIDEV_OP_BOOT_REPROBE:
 124                 break;
 125 
 126         case ACPIDEV_OP_HOTPLUG_PROBE:
 127                 flags |= ACPIDEV_PROCESS_FLAG_CREATE |
 128                     ACPIDEV_PROCESS_FLAG_SYNCSTATUS |
 129                     ACPIDEV_PROCESS_FLAG_HOLDBRANCH;
 130                 break;
 131 
 132         default:
 133                 ACPIDEV_DEBUG(CE_WARN,
 134                     "!acpidev: unknown operation type %u in "
 135                     "acpi_device_probe().", infop->awi_op_type);
 136                 rc = AE_BAD_PARAMETER;
 137                 break;
 138         }
 139 
 140         if (rc == AE_OK) {
 141                 rc = acpidev_process_object(infop, flags);
 142         }
 143         if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
 144                 cmn_err(CE_WARN,
 145                     "!acpidev: failed to process device object %s.",
 146                     infop->awi_name);
 147         } else {
 148                 rc = AE_OK;
 149         }
 150 
 151         return (rc);
 152 }
 153 
 154 static acpidev_filter_result_t
 155 acpidev_device_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
 156 {
 157         acpidev_filter_result_t res;
 158 
 159         ASSERT(infop != NULL);
 160         if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
 161             infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
 162             infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
 163                 res = acpidev_filter_device(infop, infop->awi_hdl,
 164                     ACPIDEV_ARRAY_PARAM(acpidev_device_filters),
 165                     devname, maxlen);
 166         } else {
 167                 ACPIDEV_DEBUG(CE_WARN, "!acpidev: unknown operation type %u "
 168                     "in acpidev_device_filter().", infop->awi_op_type);
 169                 res = ACPIDEV_FILTER_FAILED;
 170         }
 171 
 172         return (res);
 173 }
 174 
 175 static ACPI_STATUS
 176 acpidev_device_init(acpidev_walk_info_t *infop)
 177 {
 178         char unitaddr[32];
 179         char *compatible[] = {
 180                 ACPIDEV_TYPE_DEVICE,
 181                 ACPIDEV_HID_VIRTNEX,
 182                 ACPIDEV_TYPE_VIRTNEX,
 183         };
 184 
 185         if (ACPI_FAILURE(acpidev_set_compatible(infop,
 186             ACPIDEV_ARRAY_PARAM(compatible)))) {
 187                 return (AE_ERROR);
 188         }
 189         (void) snprintf(unitaddr, sizeof (unitaddr), "%u",
 190             atomic_inc_32_nv(&acpidev_device_unitaddr) - 1);
 191         if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
 192                 return (AE_ERROR);
 193         }
 194 
 195         return (AE_OK);
 196 }