brintos

brintos / linux-shallow public Read only

0
0
Text · 16.0 KiB · 5d5bcf1 Raw
608 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: nsxfname - Public interfaces to the ACPI subsystem5 *                         ACPI Namespace oriented interfaces6 *7 * Copyright (C) 2000 - 2023, Intel Corp.8 *9 *****************************************************************************/10 11#define EXPORT_ACPI_INTERFACES12 13#include <acpi/acpi.h>14#include "accommon.h"15#include "acnamesp.h"16#include "acparser.h"17#include "amlcode.h"18 19#define _COMPONENT          ACPI_NAMESPACE20ACPI_MODULE_NAME("nsxfname")21 22/* Local prototypes */23static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,24				    struct acpi_pnp_device_id *source,25				    char *string_area);26 27/******************************************************************************28 *29 * FUNCTION:    acpi_get_handle30 *31 * PARAMETERS:  parent          - Object to search under (search scope).32 *              pathname        - Pointer to an asciiz string containing the33 *                                name34 *              ret_handle      - Where the return handle is returned35 *36 * RETURN:      Status37 *38 * DESCRIPTION: This routine will search for a caller specified name in the39 *              name space. The caller can restrict the search region by40 *              specifying a non NULL parent. The parent value is itself a41 *              namespace handle.42 *43 ******************************************************************************/44 45acpi_status46acpi_get_handle(acpi_handle parent,47		const char *pathname, acpi_handle *ret_handle)48{49	acpi_status status;50	struct acpi_namespace_node *node = NULL;51	struct acpi_namespace_node *prefix_node = NULL;52 53	ACPI_FUNCTION_ENTRY();54 55	/* Parameter Validation */56 57	if (!ret_handle || !pathname) {58		return (AE_BAD_PARAMETER);59	}60 61	/* Convert a parent handle to a prefix node */62 63	if (parent) {64		prefix_node = acpi_ns_validate_handle(parent);65		if (!prefix_node) {66			return (AE_BAD_PARAMETER);67		}68	}69 70	/*71	 * Valid cases are:72	 * 1) Fully qualified pathname73	 * 2) Parent + Relative pathname74	 *75	 * Error for <null Parent + relative path>76	 */77	if (ACPI_IS_ROOT_PREFIX(pathname[0])) {78 79		/* Pathname is fully qualified (starts with '\') */80 81		/* Special case for root-only, since we can't search for it */82 83		if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) {84			*ret_handle =85			    ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node);86			return (AE_OK);87		}88	} else if (!prefix_node) {89 90		/* Relative path with null prefix is disallowed */91 92		return (AE_BAD_PARAMETER);93	}94 95	/* Find the Node and convert to a handle */96 97	status =98	    acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);99	if (ACPI_SUCCESS(status)) {100		*ret_handle = ACPI_CAST_PTR(acpi_handle, node);101	}102 103	return (status);104}105 106ACPI_EXPORT_SYMBOL(acpi_get_handle)107 108/******************************************************************************109 *110 * FUNCTION:    acpi_get_name111 *112 * PARAMETERS:  handle          - Handle to be converted to a pathname113 *              name_type       - Full pathname or single segment114 *              buffer          - Buffer for returned path115 *116 * RETURN:      Pointer to a string containing the fully qualified Name.117 *118 * DESCRIPTION: This routine returns the fully qualified name associated with119 *              the Handle parameter. This and the acpi_pathname_to_handle are120 *              complementary functions.121 *122 ******************************************************************************/123acpi_status124acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer)125{126	acpi_status status;127 128	/* Parameter validation */129 130	if (name_type > ACPI_NAME_TYPE_MAX) {131		return (AE_BAD_PARAMETER);132	}133 134	status = acpi_ut_validate_buffer(buffer);135	if (ACPI_FAILURE(status)) {136		return (status);137	}138 139	/*140	 * Wants the single segment ACPI name.141	 * Validate handle and convert to a namespace Node142	 */143	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);144	if (ACPI_FAILURE(status)) {145		return (status);146	}147 148	if (name_type == ACPI_FULL_PATHNAME ||149	    name_type == ACPI_FULL_PATHNAME_NO_TRAILING) {150 151		/* Get the full pathname (From the namespace root) */152 153		status = acpi_ns_handle_to_pathname(handle, buffer,154						    name_type ==155						    ACPI_FULL_PATHNAME ? FALSE :156						    TRUE);157	} else {158		/* Get the single name */159 160		status = acpi_ns_handle_to_name(handle, buffer);161	}162 163	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);164	return (status);165}166 167ACPI_EXPORT_SYMBOL(acpi_get_name)168 169/******************************************************************************170 *171 * FUNCTION:    acpi_ns_copy_device_id172 *173 * PARAMETERS:  dest                - Pointer to the destination PNP_DEVICE_ID174 *              source              - Pointer to the source PNP_DEVICE_ID175 *              string_area         - Pointer to where to copy the dest string176 *177 * RETURN:      Pointer to the next string area178 *179 * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data.180 *181 ******************************************************************************/182static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,183				    struct acpi_pnp_device_id *source,184				    char *string_area)185{186	/* Create the destination PNP_DEVICE_ID */187 188	dest->string = string_area;189	dest->length = source->length;190 191	/* Copy actual string and return a pointer to the next string area */192 193	memcpy(string_area, source->string, source->length);194	return (string_area + source->length);195}196 197/******************************************************************************198 *199 * FUNCTION:    acpi_get_object_info200 *201 * PARAMETERS:  handle              - Object Handle202 *              return_buffer       - Where the info is returned203 *204 * RETURN:      Status205 *206 * DESCRIPTION: Returns information about an object as gleaned from the207 *              namespace node and possibly by running several standard208 *              control methods (Such as in the case of a device.)209 *210 * For Device and Processor objects, run the Device _HID, _UID, _CID,211 * _CLS, _ADR, _sx_w, and _sx_d methods.212 *213 * Note: Allocates the return buffer, must be freed by the caller.214 *215 * Note: This interface is intended to be used during the initial device216 * discovery namespace traversal. Therefore, no complex methods can be217 * executed, especially those that access operation regions. Therefore, do218 * not add any additional methods that could cause problems in this area.219 * Because of this reason support for the following methods has been removed:220 * 1) _SUB method was removed (11/2015)221 * 2) _STA method was removed (02/2018)222 *223 ******************************************************************************/224 225acpi_status226acpi_get_object_info(acpi_handle handle,227		     struct acpi_device_info **return_buffer)228{229	struct acpi_namespace_node *node;230	struct acpi_device_info *info;231	struct acpi_pnp_device_id_list *cid_list = NULL;232	struct acpi_pnp_device_id *hid = NULL;233	struct acpi_pnp_device_id *uid = NULL;234	struct acpi_pnp_device_id *cls = NULL;235	char *next_id_string;236	acpi_object_type type;237	acpi_name name;238	u8 param_count = 0;239	u16 valid = 0;240	u32 info_size;241	u32 i;242	acpi_status status;243 244	/* Parameter validation */245 246	if (!handle || !return_buffer) {247		return (AE_BAD_PARAMETER);248	}249 250	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);251	if (ACPI_FAILURE(status)) {252		return (status);253	}254 255	node = acpi_ns_validate_handle(handle);256	if (!node) {257		(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);258		return (AE_BAD_PARAMETER);259	}260 261	/* Get the namespace node data while the namespace is locked */262 263	info_size = sizeof(struct acpi_device_info);264	type = node->type;265	name = node->name.integer;266 267	if (node->type == ACPI_TYPE_METHOD) {268		param_count = node->object->method.param_count;269	}270 271	status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);272	if (ACPI_FAILURE(status)) {273		return (status);274	}275 276	if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {277		/*278		 * Get extra info for ACPI Device/Processor objects only:279		 * Run the Device _HID, _UID, _CLS, and _CID methods.280		 *281		 * Note: none of these methods are required, so they may or may282		 * not be present for this device. The Info->Valid bitfield is used283		 * to indicate which methods were found and run successfully.284		 */285 286		/* Execute the Device._HID method */287 288		status = acpi_ut_execute_HID(node, &hid);289		if (ACPI_SUCCESS(status)) {290			info_size += hid->length;291			valid |= ACPI_VALID_HID;292		}293 294		/* Execute the Device._UID method */295 296		status = acpi_ut_execute_UID(node, &uid);297		if (ACPI_SUCCESS(status)) {298			info_size += uid->length;299			valid |= ACPI_VALID_UID;300		}301 302		/* Execute the Device._CID method */303 304		status = acpi_ut_execute_CID(node, &cid_list);305		if (ACPI_SUCCESS(status)) {306 307			/* Add size of CID strings and CID pointer array */308 309			info_size +=310			    (cid_list->list_size -311			     sizeof(struct acpi_pnp_device_id_list));312			valid |= ACPI_VALID_CID;313		}314 315		/* Execute the Device._CLS method */316 317		status = acpi_ut_execute_CLS(node, &cls);318		if (ACPI_SUCCESS(status)) {319			info_size += cls->length;320			valid |= ACPI_VALID_CLS;321		}322	}323 324	/*325	 * Now that we have the variable-length data, we can allocate the326	 * return buffer327	 */328	info = ACPI_ALLOCATE_ZEROED(info_size);329	if (!info) {330		status = AE_NO_MEMORY;331		goto cleanup;332	}333 334	/* Get the fixed-length data */335 336	if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {337		/*338		 * Get extra info for ACPI Device/Processor objects only:339		 * Run the _ADR and, sx_w, and _sx_d methods.340		 *341		 * Notes: none of these methods are required, so they may or may342		 * not be present for this device. The Info->Valid bitfield is used343		 * to indicate which methods were found and run successfully.344		 */345 346		/* Execute the Device._ADR method */347 348		status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node,349							 &info->address);350		if (ACPI_SUCCESS(status)) {351			valid |= ACPI_VALID_ADR;352		}353 354		/* Execute the Device._sx_w methods */355 356		status = acpi_ut_execute_power_methods(node,357						       acpi_gbl_lowest_dstate_names,358						       ACPI_NUM_sx_w_METHODS,359						       info->lowest_dstates);360		if (ACPI_SUCCESS(status)) {361			valid |= ACPI_VALID_SXWS;362		}363 364		/* Execute the Device._sx_d methods */365 366		status = acpi_ut_execute_power_methods(node,367						       acpi_gbl_highest_dstate_names,368						       ACPI_NUM_sx_d_METHODS,369						       info->highest_dstates);370		if (ACPI_SUCCESS(status)) {371			valid |= ACPI_VALID_SXDS;372		}373	}374 375	/*376	 * Create a pointer to the string area of the return buffer.377	 * Point to the end of the base struct acpi_device_info structure.378	 */379	next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids);380	if (cid_list) {381 382		/* Point past the CID PNP_DEVICE_ID array */383 384		next_id_string +=385		    ((acpi_size)cid_list->count *386		     sizeof(struct acpi_pnp_device_id));387	}388 389	/*390	 * Copy the HID, UID, and CIDs to the return buffer. The variable-length391	 * strings are copied to the reserved area at the end of the buffer.392	 *393	 * For HID and CID, check if the ID is a PCI Root Bridge.394	 */395	if (hid) {396		next_id_string = acpi_ns_copy_device_id(&info->hardware_id,397							hid, next_id_string);398 399		if (acpi_ut_is_pci_root_bridge(hid->string)) {400			info->flags |= ACPI_PCI_ROOT_BRIDGE;401		}402	}403 404	if (uid) {405		next_id_string = acpi_ns_copy_device_id(&info->unique_id,406							uid, next_id_string);407	}408 409	if (cid_list) {410		info->compatible_id_list.count = cid_list->count;411		info->compatible_id_list.list_size = cid_list->list_size;412 413		/* Copy each CID */414 415		for (i = 0; i < cid_list->count; i++) {416			next_id_string =417			    acpi_ns_copy_device_id(&info->compatible_id_list.418						   ids[i], &cid_list->ids[i],419						   next_id_string);420 421			if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) {422				info->flags |= ACPI_PCI_ROOT_BRIDGE;423			}424		}425	}426 427	if (cls) {428		(void)acpi_ns_copy_device_id(&info->class_code,429					     cls, next_id_string);430	}431 432	/* Copy the fixed-length data */433 434	info->info_size = info_size;435	info->type = type;436	info->name = name;437	info->param_count = param_count;438	info->valid = valid;439 440	*return_buffer = info;441	status = AE_OK;442 443cleanup:444	if (hid) {445		ACPI_FREE(hid);446	}447	if (uid) {448		ACPI_FREE(uid);449	}450	if (cid_list) {451		ACPI_FREE(cid_list);452	}453	if (cls) {454		ACPI_FREE(cls);455	}456	return (status);457}458 459ACPI_EXPORT_SYMBOL(acpi_get_object_info)460 461/******************************************************************************462 *463 * FUNCTION:    acpi_install_method464 *465 * PARAMETERS:  buffer         - An ACPI table containing one control method466 *467 * RETURN:      Status468 *469 * DESCRIPTION: Install a control method into the namespace. If the method470 *              name already exists in the namespace, it is overwritten. The471 *              input buffer must contain a valid DSDT or SSDT containing a472 *              single control method.473 *474 ******************************************************************************/475acpi_status acpi_install_method(u8 *buffer)476{477	struct acpi_table_header *table =478	    ACPI_CAST_PTR(struct acpi_table_header, buffer);479	u8 *aml_buffer;480	u8 *aml_start;481	char *path;482	struct acpi_namespace_node *node;483	union acpi_operand_object *method_obj;484	struct acpi_parse_state parser_state;485	u32 aml_length;486	u16 opcode;487	u8 method_flags;488	acpi_status status;489 490	/* Parameter validation */491 492	if (!buffer) {493		return (AE_BAD_PARAMETER);494	}495 496	/* Table must be a DSDT or SSDT */497 498	if (!ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT) &&499	    !ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_SSDT)) {500		return (AE_BAD_HEADER);501	}502 503	/* First AML opcode in the table must be a control method */504 505	parser_state.aml = buffer + sizeof(struct acpi_table_header);506	opcode = acpi_ps_peek_opcode(&parser_state);507	if (opcode != AML_METHOD_OP) {508		return (AE_BAD_PARAMETER);509	}510 511	/* Extract method information from the raw AML */512 513	parser_state.aml += acpi_ps_get_opcode_size(opcode);514	parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);515	path = acpi_ps_get_next_namestring(&parser_state);516 517	method_flags = *parser_state.aml++;518	aml_start = parser_state.aml;519	aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);520 521	/*522	 * Allocate resources up-front. We don't want to have to delete a new523	 * node from the namespace if we cannot allocate memory.524	 */525	aml_buffer = ACPI_ALLOCATE(aml_length);526	if (!aml_buffer) {527		return (AE_NO_MEMORY);528	}529 530	method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);531	if (!method_obj) {532		ACPI_FREE(aml_buffer);533		return (AE_NO_MEMORY);534	}535 536	/* Lock namespace for acpi_ns_lookup, we may be creating a new node */537 538	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);539	if (ACPI_FAILURE(status)) {540		goto error_exit;541	}542 543	/* The lookup either returns an existing node or creates a new one */544 545	status =546	    acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1,547			   ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,548			   NULL, &node);549 550	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);551 552	if (ACPI_FAILURE(status)) {	/* ns_lookup */553		if (status != AE_ALREADY_EXISTS) {554			goto error_exit;555		}556 557		/* Node existed previously, make sure it is a method node */558 559		if (node->type != ACPI_TYPE_METHOD) {560			status = AE_TYPE;561			goto error_exit;562		}563	}564 565	/* Copy the method AML to the local buffer */566 567	memcpy(aml_buffer, aml_start, aml_length);568 569	/* Initialize the method object with the new method's information */570 571	method_obj->method.aml_start = aml_buffer;572	method_obj->method.aml_length = aml_length;573 574	method_obj->method.param_count = (u8)575	    (method_flags & AML_METHOD_ARG_COUNT);576 577	if (method_flags & AML_METHOD_SERIALIZED) {578		method_obj->method.info_flags = ACPI_METHOD_SERIALIZED;579 580		method_obj->method.sync_level = (u8)581		    ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);582	}583 584	/*585	 * Now that it is complete, we can attach the new method object to586	 * the method Node (detaches/deletes any existing object)587	 */588	status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD);589 590	/*591	 * Flag indicates AML buffer is dynamic, must be deleted later.592	 * Must be set only after attach above.593	 */594	node->flags |= ANOBJ_ALLOCATED_BUFFER;595 596	/* Remove local reference to the method object */597 598	acpi_ut_remove_reference(method_obj);599	return (status);600 601error_exit:602 603	ACPI_FREE(aml_buffer);604	ACPI_FREE(method_obj);605	return (status);606}607ACPI_EXPORT_SYMBOL(acpi_install_method)608