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 /* Clear the Node entry in all cases */ 190 191 node->object = NULL; 192 if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) { 193 194 /* Unlink object from front of possible object list */ 195 196 node->object = obj_desc->common.next_object; 197 198 /* Handle possible 2-descriptor object */ 199 200 if (node->object && 201 (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) { 202 node->object = node->object->common.next_object; 203 } 204 205 /* 206 * Detach the object from any data objects (which are still held by 207 * the namespace node) 208 */ 209 if (obj_desc->common.next_object && 210 ((obj_desc->common.next_object)->common.type == 211 ACPI_TYPE_LOCAL_DATA)) { 212 obj_desc->common.next_object = NULL; 213 } 214 } 215 216 /* Reset the node type to untyped */ 217 218 node->type = ACPI_TYPE_ANY; 219 220 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n", 221 node, acpi_ut_get_node_name(node), obj_desc)); 222 223 /* Remove one reference on the object (and all subobjects) */ 224 225 acpi_ut_remove_reference(obj_desc); 226 return_VOID; 227 } 228 229 /******************************************************************************* 230 * 231 * FUNCTION: acpi_ns_get_attached_object 232 * 233 * PARAMETERS: node - Namespace node 234 * 235 * RETURN: Current value of the object field from the Node whose 236 * handle is passed 237 * 238 * DESCRIPTION: Obtain the object attached to a namespace node. 239 * 240 ******************************************************************************/ 241 242 union acpi_operand_object *acpi_ns_get_attached_object(struct 243 acpi_namespace_node 244 *node) 245 { 246 ACPI_FUNCTION_TRACE_PTR(ns_get_attached_object, node); 247 248 if (!node) { 249 ACPI_WARNING((AE_INFO, "Null Node ptr")); 250 return_PTR(NULL); 251 } 252 253 if (!node->object || 254 ((ACPI_GET_DESCRIPTOR_TYPE(node->object) != ACPI_DESC_TYPE_OPERAND) 255 && (ACPI_GET_DESCRIPTOR_TYPE(node->object) != 256 ACPI_DESC_TYPE_NAMED)) 257 || ((node->object)->common.type == ACPI_TYPE_LOCAL_DATA)) { 258 return_PTR(NULL); 259 } 260 261 return_PTR(node->object); 262 } 263 264 /******************************************************************************* 265 * 266 * FUNCTION: acpi_ns_get_secondary_object 267 * 268 * PARAMETERS: node - Namespace node 269 * 270 * RETURN: Current value of the object field from the Node whose 271 * handle is passed. 272 * 273 * DESCRIPTION: Obtain a secondary object associated with a namespace node. 274 * 275 ******************************************************************************/ 276 277 union acpi_operand_object *acpi_ns_get_secondary_object(union 278 acpi_operand_object 279 *obj_desc) 280 { 281 ACPI_FUNCTION_TRACE_PTR(ns_get_secondary_object, obj_desc); 282 283 if ((!obj_desc) || 284 (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) || 285 (!obj_desc->common.next_object) || 286 ((obj_desc->common.next_object)->common.type == 287 ACPI_TYPE_LOCAL_DATA)) { 288 return_PTR(NULL); 289 } 290 291 return_PTR(obj_desc->common.next_object); 292 } 293 294 /******************************************************************************* 295 * 296 * FUNCTION: acpi_ns_attach_data 297 * 298 * PARAMETERS: node - Namespace node 299 * handler - Handler to be associated with the data 300 * data - Data to be attached 301 * 302 * RETURN: Status 303 * 304 * DESCRIPTION: Low-level attach data. Create and attach a Data object. 305 * 306 ******************************************************************************/ 307 308 acpi_status 309 acpi_ns_attach_data(struct acpi_namespace_node *node, 310 acpi_object_handler handler, void *data) 311 { 312 union acpi_operand_object *prev_obj_desc; 313 union acpi_operand_object *obj_desc; 314 union acpi_operand_object *data_desc; 315 316 /* We only allow one attachment per handler */ 317 318 prev_obj_desc = NULL; 319 obj_desc = node->object; 320 while (obj_desc) { 321 if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && 322 (obj_desc->data.handler == handler)) { 323 return (AE_ALREADY_EXISTS); 324 } 325 326 prev_obj_desc = obj_desc; 327 obj_desc = obj_desc->common.next_object; 328 } 329 330 /* Create an internal object for the data */ 331 332 data_desc = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_DATA); 333 if (!data_desc) { 334 return (AE_NO_MEMORY); 335 } 336 337 data_desc->data.handler = handler; 338 data_desc->data.pointer = data; 339 340 /* Install the data object */ 341 342 if (prev_obj_desc) { 343 prev_obj_desc->common.next_object = data_desc; 344 } else { 345 node->object = data_desc; 346 } 347 348 return (AE_OK); 349 } 350 351 /******************************************************************************* 352 * 353 * FUNCTION: acpi_ns_detach_data 354 * 355 * PARAMETERS: node - Namespace node 356 * handler - Handler associated with the data 357 * 358 * RETURN: Status 359 * 360 * DESCRIPTION: Low-level detach data. Delete the data node, but the caller 361 * is responsible for the actual data. 362 * 363 ******************************************************************************/ 364 365 acpi_status 366 acpi_ns_detach_data(struct acpi_namespace_node *node, 367 acpi_object_handler handler) 368 { 369 union acpi_operand_object *obj_desc; 370 union acpi_operand_object *prev_obj_desc; 371 372 prev_obj_desc = NULL; 373 obj_desc = node->object; 374 while (obj_desc) { 375 if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && 376 (obj_desc->data.handler == handler)) { 377 if (prev_obj_desc) { 378 prev_obj_desc->common.next_object = 379 obj_desc->common.next_object; 380 } else { 381 node->object = obj_desc->common.next_object; 382 } 383 384 acpi_ut_remove_reference(obj_desc); 385 return (AE_OK); 386 } 387 388 prev_obj_desc = obj_desc; 389 obj_desc = obj_desc->common.next_object; 390 } 391 392 return (AE_NOT_FOUND); 393 } 394 395 /******************************************************************************* 396 * 397 * FUNCTION: acpi_ns_get_attached_data 398 * 399 * PARAMETERS: node - Namespace node 400 * handler - Handler associated with the data 401 * data - Where the data is returned 402 * 403 * RETURN: Status 404 * 405 * DESCRIPTION: Low level interface to obtain data previously associated with 406 * a namespace node. 407 * 408 ******************************************************************************/ 409 410 acpi_status 411 acpi_ns_get_attached_data(struct acpi_namespace_node *node, 412 acpi_object_handler handler, void **data) 413 { 414 union acpi_operand_object *obj_desc; 415 416 obj_desc = node->object; 417 while (obj_desc) { 418 if ((obj_desc->common.type == ACPI_TYPE_LOCAL_DATA) && 419 (obj_desc->data.handler == handler)) { 420 *data = obj_desc->data.pointer; 421 return (AE_OK); 422 } 423 424 obj_desc = obj_desc->common.next_object; 425 } 426 427 return (AE_NOT_FOUND); 428 } 429