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
acpi_ns_attach_object(struct acpi_namespace_node * node,union acpi_operand_object * object,acpi_object_type type)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  
acpi_ns_detach_object(struct acpi_namespace_node * node)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  
acpi_ns_get_attached_object(struct acpi_namespace_node * node)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  
acpi_ns_get_secondary_object(union acpi_operand_object * obj_desc)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
acpi_ns_attach_data(struct acpi_namespace_node * node,acpi_object_handler handler,void * data)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
acpi_ns_detach_data(struct acpi_namespace_node * node,acpi_object_handler handler)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
acpi_ns_get_attached_data(struct acpi_namespace_node * node,acpi_object_handler handler,void ** data)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