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 <acpica/include/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 }