linux/drivers/acpi/acpica/nsobject.c
<<
>>
Prefs
   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
  14ACPI_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 ******************************************************************************/
  36acpi_status
  37acpi_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
 168void 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
 242union 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
 277union 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
 308acpi_status
 309acpi_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
 365acpi_status
 366acpi_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
 410acpi_status
 411acpi_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