1 /*
   2  * Copyright (c) 2009, Intel Corporation.
   3  * All rights reserved.
   4  */
   5 
   6 #include <sys/types.h>
   7 #include <sys/atomic.h>
   8 #include <sys/sunddi.h>
   9 #include <sys/sunndi.h>
  10 #include <sys/acpi/acpi.h>
  11 #include <sys/acpica.h>
  12 #include <sys/acpidev.h>
  13 #include <sys/acpidev_impl.h>
  14 
  15 static ACPI_STATUS acpidev_device_probe(acpidev_walk_info_t *infop);
  16 static acpidev_filter_result_t acpidev_device_filter(acpidev_walk_info_t *infop,
  17     char *devname, int maxlen);
  18 static ACPI_STATUS acpidev_device_init(acpidev_walk_info_t *infop);
  19 
  20 /*
  21  * Default class driver for ACPI DEVICE object.
  22  * The default policy for DEVICE object is scanning child objects without
  23  * creating device node. But some special DEVICE objects will have device
  24  * node created for them.
  25  */
  26 acpidev_class_t acpidev_class_device = {
  27         0,                              /* adc_refcnt */
  28         ACPIDEV_CLASS_REV1,             /* adc_version */
  29         ACPIDEV_CLASS_ID_DEVICE,        /* adc_class_id */
  30         "ACPI Device",                  /* adc_class_name */
  31         ACPIDEV_TYPE_DEVICE,            /* adc_dev_type */
  32         NULL,                           /* adc_private */
  33         NULL,                           /* adc_pre_probe */
  34         NULL,                           /* adc_post_probe */
  35         acpidev_device_probe,           /* adc_probe */
  36         acpidev_device_filter,          /* adc_filter */
  37         acpidev_device_init,            /* adc_init */
  38         NULL,                           /* adc_fini */
  39 };
  40 
  41 /*
  42  * List head of class drivers which will be called in order when handling
  43  * children of ACPI DEVICE object.
  44  */
  45 acpidev_class_list_t *acpidev_class_list_device = NULL;
  46 
  47 /* Filter rule table for boot. */
  48 static acpidev_filter_rule_t acpidev_device_filters[] = {
  49         {       /* _SB_ object type is hardcoded to DEVICE by acpica */
  50                 NULL,
  51                 0,
  52                 ACPIDEV_FILTER_SCAN,
  53                 &acpidev_class_list_device,
  54                 1,
  55                 1,
  56                 ACPIDEV_OBJECT_NAME_SB,
  57                 NULL,
  58         },
  59         {       /* Ignore other device objects under ACPI root object */
  60                 NULL,
  61                 0,
  62                 ACPIDEV_FILTER_SKIP,
  63                 NULL,
  64                 1,
  65                 1,
  66                 NULL,
  67                 NULL,
  68         },
  69         {       /* Scan other device objects not directly under ACPI root */
  70                 NULL,
  71                 0,
  72                 ACPIDEV_FILTER_SCAN,
  73                 &acpidev_class_list_device,
  74                 2,
  75                 INT_MAX,
  76                 NULL,
  77                 NULL,
  78         }
  79 };
  80 
  81 static ACPI_STATUS
  82 acpidev_device_probe(acpidev_walk_info_t *infop)
  83 {
  84         ACPI_STATUS rc;
  85         int flags;
  86 
  87         ASSERT(infop != NULL);
  88         ASSERT(infop->awi_hdl != NULL);
  89         ASSERT(infop->awi_info != NULL);
  90 
  91         if (infop->awi_info->Type != ACPI_TYPE_DEVICE) {
  92                 return (AE_OK);
  93         }
  94 
  95         if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
  96                 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
  97                 rc = acpidev_process_object(infop, flags);
  98         } else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
  99                 flags = ACPIDEV_PROCESS_FLAG_SCAN;
 100                 rc = acpidev_process_object(infop, flags);
 101         } else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
 102                 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
 103                 rc = acpidev_process_object(infop, flags);
 104         } else {
 105                 ACPIDEV_DEBUG(CE_WARN,
 106                     "acpidev: unknown operation type %u in device_probe().",
 107                     infop->awi_op_type);
 108                 rc = AE_BAD_PARAMETER;
 109         }
 110         if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
 111                 cmn_err(CE_CONT,
 112                     "?acpidev: failed to process device object %s.\n",
 113                     infop->awi_name);
 114         } else {
 115                 rc = AE_OK;
 116         }
 117 
 118         return (rc);
 119 }
 120 
 121 static acpidev_filter_result_t
 122 acpidev_device_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
 123 {
 124         acpidev_filter_result_t res;
 125 
 126         ASSERT(infop != NULL);
 127         if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
 128             infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
 129             infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
 130                 res = acpidev_filter_device(infop, infop->awi_hdl,
 131                     ACPIDEV_ARRAY_PARAM(acpidev_device_filters),
 132                     devname, maxlen);
 133         } else {
 134                 ACPIDEV_DEBUG(CE_WARN,
 135                     "acpidev: unknown operation type %u in device_filter().",
 136                     infop->awi_op_type);
 137                 res = ACPIDEV_FILTER_FAILED;
 138         }
 139 
 140         return (res);
 141 }
 142 
 143 /*ARGSUSED*/
 144 static ACPI_STATUS
 145 acpidev_device_init(acpidev_walk_info_t *infop)
 146 {
 147         char *compatibles[] = {
 148                 ACPIDEV_TYPE_DEVICE,
 149                 ACPIDEV_HID_VIRTNEX,
 150                 ACPIDEV_TYPE_VIRTNEX,
 151         };
 152 
 153         if (ACPI_FAILURE(acpidev_set_compatibles(infop,
 154             ACPIDEV_ARRAY_PARAM(compatibles)))) {
 155                 return (AE_ERROR);
 156         }
 157         if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, NULL))) {
 158                 return (AE_ERROR);
 159         }
 160 
 161         return (AE_OK);
 162 }