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