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, 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; 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 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) { 118 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE; 119 rc = acpidev_process_object(infop, flags); 120 } else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) { 121 flags = ACPIDEV_PROCESS_FLAG_SCAN; 122 rc = acpidev_process_object(infop, flags); 123 } else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) { 124 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE; 125 rc = acpidev_process_object(infop, flags); 126 } else { 127 ACPIDEV_DEBUG(CE_WARN, 128 "acpidev: unknown operation type %u in " 129 "acpi_device_probe().", infop->awi_op_type); 130 rc = AE_BAD_PARAMETER; 131 } 132 if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) { 133 cmn_err(CE_WARN, 134 "!acpidev: failed to process device object %s.", 135 infop->awi_name); 136 } else { 137 rc = AE_OK; 138 } 139 140 return (rc); 141 } 142 143 static acpidev_filter_result_t 144 acpidev_device_filter(acpidev_walk_info_t *infop, char *devname, int maxlen) 145 { 146 acpidev_filter_result_t res; 147 148 ASSERT(infop != NULL); 149 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE || 150 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE || 151 infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) { 152 res = acpidev_filter_device(infop, infop->awi_hdl, 153 ACPIDEV_ARRAY_PARAM(acpidev_device_filters), 154 devname, maxlen); 155 } else { 156 ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u " 157 "in acpidev_device_filter().", infop->awi_op_type); 158 res = ACPIDEV_FILTER_FAILED; 159 } 160 161 return (res); 162 } 163 164 /*ARGSUSED*/ 165 static ACPI_STATUS 166 acpidev_device_init(acpidev_walk_info_t *infop) 167 { 168 char unitaddr[32]; 169 char *compatible[] = { 170 ACPIDEV_TYPE_DEVICE, 171 ACPIDEV_HID_VIRTNEX, 172 ACPIDEV_TYPE_VIRTNEX, 173 }; 174 175 if (ACPI_FAILURE(acpidev_set_compatible(infop, 176 ACPIDEV_ARRAY_PARAM(compatible)))) { 177 return (AE_ERROR); 178 } 179 (void) snprintf(unitaddr, sizeof (unitaddr), "%u", 180 atomic_inc_32_nv(&acpidev_device_unitaddr) - 1); 181 if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) { 182 return (AE_ERROR); 183 } 184 185 return (AE_OK); 186 } 187