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        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
 246union 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
 281union 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
 312acpi_status
 313acpi_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
 369acpi_status
 370acpi_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
 414acpi_status
 415acpi_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