1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /******************************************************************************* 3 * 4 * Module Name: nsobject - Utilities for objects attached to namespace 5 * table entries 6 * 7 ******************************************************************************/ 8 9 #include <acpi/acpi.h> 10 #include "accommon.h" 11 #include "acnamesp.h" 12 13 #define _COMPONENT ACPI_NAMESPACE 14 ACPI_MODULE_NAME("nsobject") 15 16 /******************************************************************************* 17 * 18 * FUNCTION: acpi_ns_attach_object 19 * 20 * PARAMETERS: node - Parent Node 21 * object - Object to be attached 22 * type - Type of object, or ACPI_TYPE_ANY if not 23 * known 24 * 25 * RETURN: Status 26 * 27 * DESCRIPTION: Record the given object as the value associated with the 28 * name whose acpi_handle is passed. If Object is NULL 29 * and Type is ACPI_TYPE_ANY, set the name as having no value. 30 * Note: Future may require that the Node->Flags field be passed 31 * as a parameter. 32 * 33 * MUTEX: Assumes namespace is locked 34 * 35 ******************************************************************************/ 36 acpi_status 37 acpi_ns_attach_object(struct acpi_namespace_node *node, 38 union acpi_operand_object *object, acpi_object_type type) 39 { 40 union acpi_operand_object *obj_desc; 41 union acpi_operand_object *last_obj_desc; 42 acpi_object_type object_type = ACPI_TYPE_ANY; 43 44 ACPI_FUNCTION_TRACE(ns_attach_object); 45 46 /* 47 * Parameter validation 48 */ 49 if (!node) { 50 51 /* Invalid handle */ 52 53 ACPI_ERROR((AE_INFO, "Null NamedObj handle")); 54 return_ACPI_STATUS(AE_BAD_PARAMETER); 55 } 56 57 if (!object && (ACPI_TYPE_ANY != type)) { 58 59 /* Null object */ 60 61 ACPI_ERROR((AE_INFO, 62 "Null object, but type not ACPI_TYPE_ANY")); 63 return_ACPI_STATUS(AE_BAD_PARAMETER); 64 } 65 66 if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { 67 68 /* Not a name handle */ 69 70 ACPI_ERROR((AE_INFO, "Invalid handle %p [%s]", 71 node, acpi_ut_get_descriptor_name(node))); 72 return_ACPI_STATUS(AE_BAD_PARAMETER); 73 } 74 75 /* Check if this object is already attached */ 76 77 if (node->object == object) { 78 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 79 "Obj %p already installed in NameObj %p\n", 80 object, node)); 81 82 return_ACPI_STATUS(AE_OK); 83 } 84 85 /* If null object, we will just install it */ 86 87 if (!object) { 88 obj_desc = NULL; 89 object_type = ACPI_TYPE_ANY; 90 } 91 92 /* 93 * If the source object is a namespace Node with an attached object, 94 * we will use that (attached) object 95 */ 96 else if ((ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) && 97 ((struct acpi_namespace_node *)object)->object) { 98 /* 99 * Value passed is a name handle and that name has a 100 * non-null value. Use that name's value and type. 101 */ 102 obj_desc = ((struct acpi_namespace_node *)object)->object; 103 object_type = ((struct acpi_namespace_node *)object)->type; 104 } 105 106 /* 107 * Otherwise, we will use the parameter object, but we must type 108 * it first 109 */ 110 else { 111 obj_desc = (union acpi_operand_object *)object; 112 113 /* Use the given type */ 114 115 object_type = type; 116 } 117 118 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Installing %p into Node %p [%4.4s]\n", 119 obj_desc, node, acpi_ut_get_node_name(node))); 120 121 /* Detach an existing attached object if present */ 122 123 if (node->object) { 124 acpi_ns_detach_object(node); 125 } 126 127 if (obj_desc) { 128 /* 129 * Must increment the new value's reference count 130 * (if it is an internal object) 131 */ 132 acpi_ut_add_reference(obj_desc); 133 134 /* 135 * Handle objects with multiple descriptors - walk 136 * to the end of the descriptor list 137 */ 138 last_obj_desc = obj_desc; 139 while (last_obj_desc->common.next_object) { 140 last_obj_desc = last_obj_desc->common.next_object; 141 } 142 143 /* Install the object at the front of the object list */ 144 145 last_obj_desc->common.next_object = node->object; 146 } 147 148 node->type = (u8) object_type; 149 node->object = obj_desc; 150 151 return_ACPI_STATUS(AE_OK); 152 } 153 154 /******************************************************************************* 155 * 156 * FUNCTION: acpi_ns_detach_object 157 * 158 * PARAMETERS: node - A Namespace node whose object will be detached 159 * 160 * RETURN: None. 161 * 162 * DESCRIPTION: Detach/delete an object associated with a namespace node. 163 * if the object is an allocated object, it is freed. 164 * Otherwise, the field is simply cleared. 165 * 166 ******************************************************************************/ 167 168 void acpi_ns_detach_object(struct acpi_namespace_node *node) 169 { 170 union acpi_operand_object *obj_desc; 171 172 ACPI_FUNCTION_TRACE(ns_detach_object); 173 174 obj_desc = node->object; 175 176 if (!obj_desc || (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { 177 return_VOID; 178 } 179 180 if (node->flags & ANOBJ_ALLOCATED_BUFFER) { 181 182 /* Free the dynamic aml buffer */ 183 184 if (obj_desc->common.type == ACPI_TYPE_METHOD) { 185 ACPI_FREE(obj_desc->method.aml_start); 186 } 187 } 188 189 if (obj_desc->common.type == ACPI_TYPE_REGION) { 190 acpi_ut_remove_address_range(obj_desc->region.space_id, node); 191 } 192 193 /* Clear the Node entry in all cases */ 194 195 node->object = NULL; 196 if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) { 197 198 /* Unlink object from front of possible object list */ 199 200 node->object = obj_desc->common.next_object; 201 202 /* Handle possible 2-descriptor object */ 203 204 if (node->object && 205 (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) { 206 node->object = node->object->common.next_object; 207 } 208 209 /* 210 * Detach the object from any data objects (which are still held by 211 * the namespace node) 212 */ 213 if (obj_desc->common.next_object && 214 ((obj_desc->common.next_object)->common.type == 215 ACPI_TYPE_LOCAL_DATA)) { 216 obj_desc->common.next_object = NULL; 217 } 218 } 219 220 /* Reset the node type to untyped */ 221 222 node->type = ACPI_TYPE_ANY; 223 224 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n", 225 node, acpi_ut_get_node_name(node), obj_desc)); 226 227 /* Remove one reference on the object (and all subobjects) */ 228 229 acpi_ut_remove_reference(obj_desc); 230 return_VOID; 231 } 232 233 /******************************************************************************* 234 * 235 * FUNCTION: acpi_ns_get_attached_object 236 * 237 * PARAMETERS: node - Namespace node 238 * 239 * RETURN: Current value of the object field from the Node whose 240 * handle is passed 241 * 242 * DESCRIPTION: Obtain the object attached to a namespace node. 243 * 244 ******************************************************************************/ 245 246 union acpi_operand_object *acpi_ns_get_attached_object(struct 247 acpi_namespace_node 248 *node) 249 { 250 ACPI_FUNCTION_TRACE_PTR(ns_get_attached_object, node); 251 252 if (!node) { 253 ACPI_WARNING((AE_INFO, "Null Node ptr")); 254 return_PTR(NULL); 255 } 256 257 if (!node->object || 258 ((ACPI_GET_DESCRIPTOR_TYPE(node->object) != ACPI_DESC_TYPE_OPERAND) 259 && (ACPI_GET_DESCRIPTOR_TYPE(node->object) != 260 ACPI_DESC_TYPE_NAMED)) 261 || ((node->object)->common.type == ACPI_TYPE_LOCAL_DATA)) { 262 return_PTR(NULL); 263 } 264 265 return_PTR(node->object); 266 } 267 268 /******************************************************************************* 269 * 270 * FUNCTION: acpi_ns_get_secondary_object 271 * 272 * PARAMETERS: node - Namespace node 273 * 274 * RETURN: Current value of the object field from the Node whose 275 * handle is passed. 276 * 277 * DESCRIPTION: Obtain a secondary object associated with a namespace node. 278 * 279 ******************************************************************************/ 280 281 union acpi_operand_object *acpi_ns_get_secondary_object(union 282 acpi_operand_object 283 *obj_desc) 284 { 285 ACPI_FUNCTION_TRACE_PTR(ns_get_secondary_object, obj_desc); 286 287 if ((!obj_desc) || 288 (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) || 289 (!obj_desc->common.next_object) || 290 ((obj_desc->common.next_object)->common.type == 291 ACPI_TYPE_LOCAL_DATA)) { 292 return_PTR(NULL); 293 } 294 295 return_PTR(obj_desc->common.next_object); 296 } 297 298 /******************************************************************************* 299 * 300 * FUNCTION: acpi_ns_attach_data 301 * 302 * PARAMETERS: node - Namespace node 303 * handler - Handler to be associated with the data 304 * data - Data to be attached 305 * 306 * RETURN: Status 307 * 308 * DESCRIPTION: Low-level attach data. Create and attach a Data object. 309 * 310 ******************************************************************************/ 311 312 acpi_status 313 acpi_ns_attach_data(struct acpi_namespace_node *node, 314 acpi_object_handler handler, void *data) 315 { 316 union acpi_operand_object *prev_obj_desc; 317 union acpi_operand_object *obj_desc; 318 union acpi_operand_object *data_desc; 319 320 /* We only allow one attachment per handler */ 321 322 prev_obj_desc = NULL; 323 obj_desc = node->object; 324 while (obj_desc) { 325 if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && 326 (obj_desc->data.handler == handler)) { 327 return (AE_ALREADY_EXISTS); 328 } 329 330 prev_obj_desc = obj_desc; 331 obj_desc = obj_desc->common.next_object; 332 } 333 334 /* Create an internal object for the data */ 335 336 data_desc = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_DATA); 337 if (!data_desc) { 338 return (AE_NO_MEMORY); 339 } 340 341 data_desc->data.handler = handler; 342 data_desc->data.pointer = data; 343 344 /* Install the data object */ 345 346 if (prev_obj_desc) { 347 prev_obj_desc->common.next_object = data_desc; 348 } else { 349 node->object = data_desc; 350 } 351 352 return (AE_OK); 353 } 354 355 /******************************************************************************* 356 * 357 * FUNCTION: acpi_ns_detach_data 358 * 359 * PARAMETERS: node - Namespace node 360 * handler - Handler associated with the data 361 * 362 * RETURN: Status 363 * 364 * DESCRIPTION: Low-level detach data. Delete the data node, but the caller 365 * is responsible for the actual data. 366 * 367 ******************************************************************************/ 368 369 acpi_status 370 acpi_ns_detach_data(struct acpi_namespace_node *node, 371 acpi_object_handler handler) 372 { 373 union acpi_operand_object *obj_desc; 374 union acpi_operand_object *prev_obj_desc; 375 376 prev_obj_desc = NULL; 377 obj_desc = node->object; 378 while (obj_desc) { 379 if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && 380 (obj_desc->data.handler == handler)) { 381 if (prev_obj_desc) { 382 prev_obj_desc->common.next_object = 383 obj_desc->common.next_object; 384 } else { 385 node->object = obj_desc->common.next_object; 386 } 387 388 acpi_ut_remove_reference(obj_desc); 389 return (AE_OK); 390 } 391 392 prev_obj_desc = obj_desc; 393 obj_desc = obj_desc->common.next_object; 394 } 395 396 return (AE_NOT_FOUND); 397 } 398 399 /******************************************************************************* 400 * 401 * FUNCTION: acpi_ns_get_attached_data 402 * 403 * PARAMETERS: node - Namespace node 404 * handler - Handler associated with the data 405 * data - Where the data is returned 406 * 407 * RETURN: Status 408 * 409 * DESCRIPTION: Low level interface to obtain data previously associated with 410 * a namespace node. 411 * 412 ******************************************************************************/ 413 414 acpi_status 415 acpi_ns_get_attached_data(struct acpi_namespace_node *node, 416 acpi_object_handler handler, void **data) 417 { 418 union acpi_operand_object *obj_desc; 419 420 obj_desc = node->object; 421 while (obj_desc) { 422 if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && 423 (obj_desc->data.handler == handler)) { 424 *data = obj_desc->data.pointer; 425 return (AE_OK); 426 } 427 428 obj_desc = obj_desc->common.next_object; 429 } 430 431 return (AE_NOT_FOUND); 432 } 433