Exemple #1
0
static acpi_status
acpi_ds_create_external_region(acpi_status lookup_status,
			       union acpi_parse_object *op,
			       char *path,
			       struct acpi_walk_state *walk_state,
			       struct acpi_namespace_node **node)
{
	acpi_status status;
	union acpi_operand_object *obj_desc;

	if (lookup_status != AE_NOT_FOUND) {
		return (lookup_status);
	}

	/*
	 * Table disassembly:
	 * operation_region not found. Generate an External for it, and
	 * insert the name into the namespace.
	 */
	acpi_dm_add_to_external_list(op, path, ACPI_TYPE_REGION, 0);
	status = acpi_ns_lookup(walk_state->scope_info, path, ACPI_TYPE_REGION,
				ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT,
				walk_state, node);
	if (ACPI_FAILURE(status)) {
		return (status);
	}

	/* Must create and install a region object for the new node */

	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION);
	if (!obj_desc) {
		return (AE_NO_MEMORY);
	}

	obj_desc->region.node = *node;
	status = acpi_ns_attach_object(*node, obj_desc, ACPI_TYPE_REGION);
	return (status);
}
/*******************************************************************************
 *
 * FUNCTION:    acpi_install_notify_handler
 *
 * PARAMETERS:  Device          - The device for which notifies will be handled
 *              handler_type    - The type of handler:
 *                                  ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
 *                                  ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
 *                                  ACPI_ALL_NOTIFY:  both system and device
 *              Handler         - Address of the handler
 *              Context         - Value passed to the handler on each GPE
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Install a handler for notifies on an ACPI device
 *
 ******************************************************************************/
acpi_status
acpi_install_notify_handler(acpi_handle device,
			    u32 handler_type,
			    acpi_notify_handler handler, void *context)
{
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *notify_obj;
	struct acpi_namespace_node *node;
	acpi_status status;

	ACPI_FUNCTION_TRACE(acpi_install_notify_handler);

	/* Parameter validation */

	if ((!device) ||
	    (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/* Convert and validate the device handle */

	node = acpi_ns_validate_handle(device);
	if (!node) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/*
	 * Root Object:
	 * Registering a notify handler on the root object indicates that the
	 * caller wishes to receive notifications for all objects. Note that
	 * only one <external> global handler can be regsitered (per notify type).
	 */
	if (device == ACPI_ROOT_OBJECT) {

		/* Make sure the handler is not already installed */

		if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
		     acpi_gbl_system_notify.handler) ||
		    ((handler_type & ACPI_DEVICE_NOTIFY) &&
		     acpi_gbl_device_notify.handler)) {
			status = AE_ALREADY_EXISTS;
			goto unlock_and_exit;
		}

		if (handler_type & ACPI_SYSTEM_NOTIFY) {
			acpi_gbl_system_notify.node = node;
			acpi_gbl_system_notify.handler = handler;
			acpi_gbl_system_notify.context = context;
		}

		if (handler_type & ACPI_DEVICE_NOTIFY) {
			acpi_gbl_device_notify.node = node;
			acpi_gbl_device_notify.handler = handler;
			acpi_gbl_device_notify.context = context;
		}

		/* Global notify handler installed */
	}

	/*
	 * All Other Objects:
	 * Caller will only receive notifications specific to the target object.
	 * Note that only certain object types can receive notifications.
	 */
	else {
		/* Notifies allowed on this object? */

		if (!acpi_ev_is_notify_object(node)) {
			status = AE_TYPE;
			goto unlock_and_exit;
		}

		/* Check for an existing internal object */

		obj_desc = acpi_ns_get_attached_object(node);
		if (obj_desc) {

			/* Object exists - make sure there's no handler */

			if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
			     obj_desc->common_notify.system_notify) ||
			    ((handler_type & ACPI_DEVICE_NOTIFY) &&
			     obj_desc->common_notify.device_notify)) {
				status = AE_ALREADY_EXISTS;
				goto unlock_and_exit;
			}
		} else {
			/* Create a new object */

			obj_desc = acpi_ut_create_internal_object(node->type);
			if (!obj_desc) {
				status = AE_NO_MEMORY;
				goto unlock_and_exit;
			}

			/* Attach new object to the Node */

			status =
			    acpi_ns_attach_object(device, obj_desc, node->type);

			/* Remove local reference to the object */

			acpi_ut_remove_reference(obj_desc);
			if (ACPI_FAILURE(status)) {
				goto unlock_and_exit;
			}
		}

		/* Install the handler */

		notify_obj =
		    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
		if (!notify_obj) {
			status = AE_NO_MEMORY;
			goto unlock_and_exit;
		}

		notify_obj->notify.node = node;
		notify_obj->notify.handler = handler;
		notify_obj->notify.context = context;

		if (handler_type & ACPI_SYSTEM_NOTIFY) {
			obj_desc->common_notify.system_notify = notify_obj;
		}

		if (handler_type & ACPI_DEVICE_NOTIFY) {
			obj_desc->common_notify.device_notify = notify_obj;
		}

		if (handler_type == ACPI_ALL_NOTIFY) {

			/* Extra ref if installed in both */

			acpi_ut_add_reference(notify_obj);
		}
	}

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS(status);
}
Exemple #3
0
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *second_desc = NULL;
	u32 type;
	acpi_status status;

	ACPI_FUNCTION_TRACE(ex_prep_field_value);

	/* Parameter validation */

	if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) {
		if (!info->region_node) {
			ACPI_ERROR((AE_INFO, "Null RegionNode"));
			return_ACPI_STATUS(AE_AML_NO_OPERAND);
		}

		type = acpi_ns_get_type(info->region_node);
		if (type != ACPI_TYPE_REGION) {
			ACPI_ERROR((AE_INFO,
				    "Needed Region, found type 0x%X (%s)",
				    type, acpi_ut_get_type_name(type)));

			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
		}
	}

	/* Allocate a new field object */

	obj_desc = acpi_ut_create_internal_object(info->field_type);
	if (!obj_desc) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	/* Initialize areas of the object that are common to all fields */

	obj_desc->common_field.node = info->field_node;
	status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags,
						  info->attribute,
						  info->field_bit_position,
						  info->field_bit_length);
	if (ACPI_FAILURE(status)) {
		acpi_ut_delete_object_desc(obj_desc);
		return_ACPI_STATUS(status);
	}

	/* Initialize areas of the object that are specific to the field type */

	switch (info->field_type) {
	case ACPI_TYPE_LOCAL_REGION_FIELD:

		obj_desc->field.region_obj =
		    acpi_ns_get_attached_object(info->region_node);

		/* An additional reference for the container */

		acpi_ut_add_reference(obj_desc->field.region_obj);

		/* allow full data read from EC address space */
		if (obj_desc->field.region_obj->region.space_id ==
			ACPI_ADR_SPACE_EC) {
			if (obj_desc->common_field.bit_length > 8) {
				unsigned width =
					ACPI_ROUND_BITS_UP_TO_BYTES(
					obj_desc->common_field.bit_length);
				// access_bit_width is u8, don't overflow it
				if (width > 8)
					width = 8;
				obj_desc->common_field.access_byte_width =
							width;
				obj_desc->common_field.access_bit_width =
							8 * width;
			}
		}

		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
				  "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
				  obj_desc->field.start_field_bit_offset,
				  obj_desc->field.base_byte_offset,
				  obj_desc->field.access_byte_width,
				  obj_desc->field.region_obj));
		break;

	case ACPI_TYPE_LOCAL_BANK_FIELD:

		obj_desc->bank_field.value = info->bank_value;
		obj_desc->bank_field.region_obj =
		    acpi_ns_get_attached_object(info->region_node);
		obj_desc->bank_field.bank_obj =
		    acpi_ns_get_attached_object(info->register_node);

		/* An additional reference for the attached objects */

		acpi_ut_add_reference(obj_desc->bank_field.region_obj);
		acpi_ut_add_reference(obj_desc->bank_field.bank_obj);

		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
				  "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n",
				  obj_desc->bank_field.start_field_bit_offset,
				  obj_desc->bank_field.base_byte_offset,
				  obj_desc->field.access_byte_width,
				  obj_desc->bank_field.region_obj,
				  obj_desc->bank_field.bank_obj));

		/*
		 * Remember location in AML stream of the field unit
		 * opcode and operands -- since the bank_value
		 * operands must be evaluated.
		 */
		second_desc = obj_desc->common.next_object;
		second_desc->extra.aml_start =
		    ACPI_CAST_PTR(union acpi_parse_object,
				  info->data_register_node)->named.data;
		second_desc->extra.aml_length =
		    ACPI_CAST_PTR(union acpi_parse_object,
				  info->data_register_node)->named.length;

		break;

	case ACPI_TYPE_LOCAL_INDEX_FIELD:

		/* Get the Index and Data registers */

		obj_desc->index_field.index_obj =
		    acpi_ns_get_attached_object(info->register_node);
		obj_desc->index_field.data_obj =
		    acpi_ns_get_attached_object(info->data_register_node);

		if (!obj_desc->index_field.data_obj
		    || !obj_desc->index_field.index_obj) {
			ACPI_ERROR((AE_INFO,
				    "Null Index Object during field prep"));
			acpi_ut_delete_object_desc(obj_desc);
			return_ACPI_STATUS(AE_AML_INTERNAL);
		}

		/* An additional reference for the attached objects */

		acpi_ut_add_reference(obj_desc->index_field.data_obj);
		acpi_ut_add_reference(obj_desc->index_field.index_obj);

		/*
		 * April 2006: Changed to match MS behavior
		 *
		 * The value written to the Index register is the byte offset of the
		 * target field in units of the granularity of the index_field
		 *
		 * Previously, the value was calculated as an index in terms of the
		 * width of the Data register, as below:
		 *
		 *      obj_desc->index_field.Value = (u32)
		 *          (Info->field_bit_position / ACPI_MUL_8 (
		 *              obj_desc->Field.access_byte_width));
		 *
		 * February 2006: Tried value as a byte offset:
		 *      obj_desc->index_field.Value = (u32)
		 *          ACPI_DIV_8 (Info->field_bit_position);
		 */
		obj_desc->index_field.value =
		    (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position),
					  obj_desc->index_field.
					  access_byte_width);

		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
				  "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
				  obj_desc->index_field.start_field_bit_offset,
				  obj_desc->index_field.base_byte_offset,
				  obj_desc->index_field.value,
				  obj_desc->field.access_byte_width,
				  obj_desc->index_field.index_obj,
				  obj_desc->index_field.data_obj));
		break;

	default:
		/* No other types should get here */
		break;
	}

	/*
	 * Store the constructed descriptor (obj_desc) into the parent Node,
	 * preserving the current type of that named_obj.
	 */
	status = acpi_ns_attach_object(info->field_node, obj_desc,
				       acpi_ns_get_type(info->field_node));

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "Set NamedObj %p [%4.4s], ObjDesc %p\n",
			  info->field_node,
			  acpi_ut_get_node_name(info->field_node), obj_desc));

	/* Remove local reference to the object */

	acpi_ut_remove_reference(obj_desc);
	return_ACPI_STATUS(status);
}
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *second_desc = NULL;
	acpi_status status;
	u32 access_byte_width;
	u32 type;

	ACPI_FUNCTION_TRACE(ex_prep_field_value);

	/*                      */

	if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) {
		if (!info->region_node) {
			ACPI_ERROR((AE_INFO, "Null RegionNode"));
			return_ACPI_STATUS(AE_AML_NO_OPERAND);
		}

		type = acpi_ns_get_type(info->region_node);
		if (type != ACPI_TYPE_REGION) {
			ACPI_ERROR((AE_INFO,
				    "Needed Region, found type 0x%X (%s)", type,
				    acpi_ut_get_type_name(type)));

			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
		}
	}

	/*                             */

	obj_desc = acpi_ut_create_internal_object(info->field_type);
	if (!obj_desc) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	/*                                                              */

	obj_desc->common_field.node = info->field_node;
	status = acpi_ex_prep_common_field_object(obj_desc,
						  info->field_flags,
						  info->attribute,
						  info->field_bit_position,
						  info->field_bit_length);
	if (ACPI_FAILURE(status)) {
		acpi_ut_delete_object_desc(obj_desc);
		return_ACPI_STATUS(status);
	}

	/*                                                                    */

	switch (info->field_type) {
	case ACPI_TYPE_LOCAL_REGION_FIELD:

		obj_desc->field.region_obj =
		    acpi_ns_get_attached_object(info->region_node);

		/*                                              */

		obj_desc->field.access_length = info->access_length;

		if (info->connection_node) {
			second_desc = info->connection_node->object;
			if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
				status =
				    acpi_ds_get_buffer_arguments(second_desc);
				if (ACPI_FAILURE(status)) {
					acpi_ut_delete_object_desc(obj_desc);
					return_ACPI_STATUS(status);
				}
			}

			obj_desc->field.resource_buffer =
			    second_desc->buffer.pointer;
			obj_desc->field.resource_length =
			    (u16)second_desc->buffer.length;
		} else if (info->resource_buffer) {
			obj_desc->field.resource_buffer = info->resource_buffer;
			obj_desc->field.resource_length = info->resource_length;
		}

		/*                                            */

		if ((obj_desc->field.region_obj->region.space_id ==
		     ACPI_ADR_SPACE_EC)
		    && (obj_desc->common_field.bit_length > 8)) {
			access_byte_width =
			    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.
							bit_length);

			/*                                     */

			if (access_byte_width < 256) {
				obj_desc->common_field.access_byte_width =
				    (u8)access_byte_width;
			}
		}
		/*                                           */

		acpi_ut_add_reference(obj_desc->field.region_obj);

		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
				  "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
				  obj_desc->field.start_field_bit_offset,
				  obj_desc->field.base_byte_offset,
				  obj_desc->field.access_byte_width,
				  obj_desc->field.region_obj));
		break;

	case ACPI_TYPE_LOCAL_BANK_FIELD:

		obj_desc->bank_field.value = info->bank_value;
		obj_desc->bank_field.region_obj =
		    acpi_ns_get_attached_object(info->region_node);
		obj_desc->bank_field.bank_obj =
		    acpi_ns_get_attached_object(info->register_node);

		/*                                                  */

		acpi_ut_add_reference(obj_desc->bank_field.region_obj);
		acpi_ut_add_reference(obj_desc->bank_field.bank_obj);

		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
				  "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n",
				  obj_desc->bank_field.start_field_bit_offset,
				  obj_desc->bank_field.base_byte_offset,
				  obj_desc->field.access_byte_width,
				  obj_desc->bank_field.region_obj,
				  obj_desc->bank_field.bank_obj));

		/*
                                                      
                                                
                                
   */
		second_desc = obj_desc->common.next_object;
		second_desc->extra.aml_start =
		    ACPI_CAST_PTR(union acpi_parse_object,
				  info->data_register_node)->named.data;
		second_desc->extra.aml_length =
		    ACPI_CAST_PTR(union acpi_parse_object,
				  info->data_register_node)->named.length;

		break;

	case ACPI_TYPE_LOCAL_INDEX_FIELD:

		/*                                  */

		obj_desc->index_field.index_obj =
		    acpi_ns_get_attached_object(info->register_node);
		obj_desc->index_field.data_obj =
		    acpi_ns_get_attached_object(info->data_register_node);

		if (!obj_desc->index_field.data_obj
		    || !obj_desc->index_field.index_obj) {
			ACPI_ERROR((AE_INFO,
				    "Null Index Object during field prep"));
			acpi_ut_delete_object_desc(obj_desc);
			return_ACPI_STATUS(AE_AML_INTERNAL);
		}

		/*                                                  */

		acpi_ut_add_reference(obj_desc->index_field.data_obj);
		acpi_ut_add_reference(obj_desc->index_field.index_obj);

		/*
                                             
    
                                                                      
                                                                
    
                                                                     
                                          
    
                                             
                                                      
                                                      
    
                                                 
                                             
                                                    
   */
		obj_desc->index_field.value =
		    (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position),
					  obj_desc->index_field.
					  access_byte_width);

		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
				  "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
				  obj_desc->index_field.start_field_bit_offset,
				  obj_desc->index_field.base_byte_offset,
				  obj_desc->index_field.value,
				  obj_desc->field.access_byte_width,
				  obj_desc->index_field.index_obj,
				  obj_desc->index_field.data_obj));
		break;

	default:
		/*                                */
		break;
	}

	/*
                                                                     
                                                  
  */
	status = acpi_ns_attach_object(info->field_node, obj_desc,
				       acpi_ns_get_type(info->field_node));

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "Set NamedObj %p [%4.4s], ObjDesc %p\n",
			  info->field_node,
			  acpi_ut_get_node_name(info->field_node), obj_desc));

	/*                                      */

	acpi_ut_remove_reference(obj_desc);
	return_ACPI_STATUS(status);
}
Exemple #5
0
acpi_status
acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
			     struct acpi_namespace_node *node,
			     struct acpi_walk_state *walk_state,
			     u8 implicit_conversion)
{
	acpi_status status = AE_OK;
	union acpi_operand_object *target_desc;
	union acpi_operand_object *new_desc;
	acpi_object_type target_type;

	ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_node, source_desc);

	/* Get current type of the node, and object attached to Node */

	target_type = acpi_ns_get_type(node);
	target_desc = acpi_ns_get_attached_object(node);

	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n",
			  source_desc,
			  acpi_ut_get_object_type_name(source_desc), node,
			  acpi_ut_get_type_name(target_type)));

	/*
	 * Resolve the source object to an actual value
	 * (If it is a reference object)
	 */
	status = acpi_ex_resolve_object(&source_desc, target_type, walk_state);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/* If no implicit conversion, drop into the default case below */

	if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) {

		/* Force execution of default (no implicit conversion) */

		target_type = ACPI_TYPE_ANY;
	}

	/* Do the actual store operation */

	switch (target_type) {
	case ACPI_TYPE_BUFFER_FIELD:
	case ACPI_TYPE_LOCAL_REGION_FIELD:
	case ACPI_TYPE_LOCAL_BANK_FIELD:
	case ACPI_TYPE_LOCAL_INDEX_FIELD:

		/* For fields, copy the source data to the target field. */

		status = acpi_ex_write_data_to_field(source_desc, target_desc,
						     &walk_state->result_obj);
		break;

	case ACPI_TYPE_INTEGER:
	case ACPI_TYPE_STRING:
	case ACPI_TYPE_BUFFER:

		/*
		 * These target types are all of type Integer/String/Buffer, and
		 * therefore support implicit conversion before the store.
		 *
		 * Copy and/or convert the source object to a new target object
		 */
		status =
		    acpi_ex_store_object_to_object(source_desc, target_desc,
						   &new_desc, walk_state);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}

		if (new_desc != target_desc) {
			/*
			 * Store the new new_desc as the new value of the Name, and set
			 * the Name's type to that of the value being stored in it.
			 * source_desc reference count is incremented by attach_object.
			 *
			 * Note: This may change the type of the node if an explicit store
			 * has been performed such that the node/object type has been
			 * changed.
			 */
			status =
			    acpi_ns_attach_object(node, new_desc,
						  new_desc->common.type);

			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
					  "Store %s into %s via Convert/Attach\n",
					  acpi_ut_get_object_type_name
					  (source_desc),
					  acpi_ut_get_object_type_name
					  (new_desc)));
		}
		break;

	default:

		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
				  "Storing %s (%p) directly into node (%p) with no implicit conversion\n",
				  acpi_ut_get_object_type_name(source_desc),
				  source_desc, node));

		/* No conversions for all other types.  Just attach the source object */

		status = acpi_ns_attach_object(node, source_desc,
					       ACPI_GET_OBJECT_TYPE
					       (source_desc));
		break;
	}

	return_ACPI_STATUS(status);
}
acpi_status
acpi_ev_install_space_handler(struct acpi_namespace_node * node,
			      acpi_adr_space_type space_id,
			      acpi_adr_space_handler handler,
			      acpi_adr_space_setup setup, void *context)
{
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *handler_obj;
	acpi_status status;
	acpi_object_type type;
	u8 flags = 0;

	ACPI_FUNCTION_TRACE(ev_install_space_handler);

	/*
	 * This registration is valid for only the types below
	 * and the root.  This is where the default handlers
	 * get placed.
	 */
	if ((node->type != ACPI_TYPE_DEVICE) &&
	    (node->type != ACPI_TYPE_PROCESSOR) &&
	    (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	if (handler == ACPI_DEFAULT_HANDLER) {
		flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;

		switch (space_id) {
		case ACPI_ADR_SPACE_SYSTEM_MEMORY:
			handler = acpi_ex_system_memory_space_handler;
			setup = acpi_ev_system_memory_region_setup;
			break;

		case ACPI_ADR_SPACE_SYSTEM_IO:
			handler = acpi_ex_system_io_space_handler;
			setup = acpi_ev_io_space_region_setup;
			break;

		case ACPI_ADR_SPACE_PCI_CONFIG:
			handler = acpi_ex_pci_config_space_handler;
			setup = acpi_ev_pci_config_region_setup;
			break;

		case ACPI_ADR_SPACE_CMOS:
			handler = acpi_ex_cmos_space_handler;
			setup = acpi_ev_cmos_region_setup;
			break;

		case ACPI_ADR_SPACE_PCI_BAR_TARGET:
			handler = acpi_ex_pci_bar_space_handler;
			setup = acpi_ev_pci_bar_region_setup;
			break;

		case ACPI_ADR_SPACE_DATA_TABLE:
			handler = acpi_ex_data_table_space_handler;
			setup = NULL;
			break;

		default:
			status = AE_BAD_PARAMETER;
			goto unlock_and_exit;
		}
	}

	/* If the caller hasn't specified a setup routine, use the default */

	if (!setup) {
		setup = acpi_ev_default_region_setup;
	}

	/* Check for an existing internal object */

	obj_desc = acpi_ns_get_attached_object(node);
	if (obj_desc) {
		/*
		 * The attached device object already exists.
		 * Make sure the handler is not already installed.
		 */
		handler_obj = obj_desc->device.handler;

		/* Walk the handler list for this device */

		while (handler_obj) {

			/* Same space_id indicates a handler already installed */

			if (handler_obj->address_space.space_id == space_id) {
				if (handler_obj->address_space.handler ==
				    handler) {
					/*
					 * It is (relatively) OK to attempt to install the SAME
					 * handler twice. This can easily happen
					 * with PCI_Config space.
					 */
					status = AE_SAME_HANDLER;
					goto unlock_and_exit;
				} else {
					/* A handler is already installed */

					status = AE_ALREADY_EXISTS;
				}
				goto unlock_and_exit;
			}

			/* Walk the linked list of handlers */

			handler_obj = handler_obj->address_space.next;
		}
	} else {
		ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
				  "Creating object on Device %p while installing handler\n",
				  node));

		/* obj_desc does not exist, create one */

		if (node->type == ACPI_TYPE_ANY) {
			type = ACPI_TYPE_DEVICE;
		} else {
			type = node->type;
		}

		obj_desc = acpi_ut_create_internal_object(type);
		if (!obj_desc) {
			status = AE_NO_MEMORY;
			goto unlock_and_exit;
		}

		/* Init new descriptor */

		obj_desc->common.type = (u8) type;

		/* Attach the new object to the Node */

		status = acpi_ns_attach_object(node, obj_desc, type);

		/* Remove local reference to the object */

		acpi_ut_remove_reference(obj_desc);

		if (ACPI_FAILURE(status)) {
			goto unlock_and_exit;
		}
	}

	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
			  acpi_ut_get_region_name(space_id), space_id,
			  acpi_ut_get_node_name(node), node, obj_desc));

	/*
	 * Install the handler
	 *
	 * At this point there is no existing handler.
	 * Just allocate the object for the handler and link it
	 * into the list.
	 */
	handler_obj =
	    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
	if (!handler_obj) {
		status = AE_NO_MEMORY;
		goto unlock_and_exit;
	}

	/* Init handler obj */

	handler_obj->address_space.space_id = (u8) space_id;
	handler_obj->address_space.handler_flags = flags;
	handler_obj->address_space.region_list = NULL;
	handler_obj->address_space.node = node;
	handler_obj->address_space.handler = handler;
	handler_obj->address_space.context = context;
	handler_obj->address_space.setup = setup;

	/* Install at head of Device.address_space list */

	handler_obj->address_space.next = obj_desc->device.handler;

	/*
	 * The Device object is the first reference on the handler_obj.
	 * Each region that uses the handler adds a reference.
	 */
	obj_desc->device.handler = handler_obj;

	/*
	 * Walk the namespace finding all of the regions this
	 * handler will manage.
	 *
	 * Start at the device and search the branch toward
	 * the leaf nodes until either the leaf is encountered or
	 * a device is detected that has an address handler of the
	 * same type.
	 *
	 * In either case, back up and search down the remainder
	 * of the branch
	 */
	status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
					ACPI_NS_WALK_UNLOCK,
					acpi_ev_install_handler, handler_obj,
					NULL);

      unlock_and_exit:
	return_ACPI_STATUS(status);
}
Exemple #7
0
acpi_status
acpi_install_notify_handler(acpi_handle device,
			    u32 handler_type,
			    acpi_notify_handler handler, void *context)
{
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *notify_obj;
	struct acpi_namespace_node *node;
	acpi_status status;

	ACPI_FUNCTION_TRACE(acpi_install_notify_handler);

	

	if ((!device) ||
	    (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	

	node = acpi_ns_map_handle_to_node(device);
	if (!node) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	
	if (device == ACPI_ROOT_OBJECT) {

		

		if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
		     acpi_gbl_system_notify.handler) ||
		    ((handler_type & ACPI_DEVICE_NOTIFY) &&
		     acpi_gbl_device_notify.handler)) {
			status = AE_ALREADY_EXISTS;
			goto unlock_and_exit;
		}

		if (handler_type & ACPI_SYSTEM_NOTIFY) {
			acpi_gbl_system_notify.node = node;
			acpi_gbl_system_notify.handler = handler;
			acpi_gbl_system_notify.context = context;
		}

		if (handler_type & ACPI_DEVICE_NOTIFY) {
			acpi_gbl_device_notify.node = node;
			acpi_gbl_device_notify.handler = handler;
			acpi_gbl_device_notify.context = context;
		}

		
	}

	
	else {
		

		if (!acpi_ev_is_notify_object(node)) {
			status = AE_TYPE;
			goto unlock_and_exit;
		}

		

		obj_desc = acpi_ns_get_attached_object(node);
		if (obj_desc) {

			

			if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
			     obj_desc->common_notify.system_notify) ||
			    ((handler_type & ACPI_DEVICE_NOTIFY) &&
			     obj_desc->common_notify.device_notify)) {
				status = AE_ALREADY_EXISTS;
				goto unlock_and_exit;
			}
		} else {
			

			obj_desc = acpi_ut_create_internal_object(node->type);
			if (!obj_desc) {
				status = AE_NO_MEMORY;
				goto unlock_and_exit;
			}

			

			status =
			    acpi_ns_attach_object(device, obj_desc, node->type);

			

			acpi_ut_remove_reference(obj_desc);
			if (ACPI_FAILURE(status)) {
				goto unlock_and_exit;
			}
		}

		

		notify_obj =
		    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
		if (!notify_obj) {
			status = AE_NO_MEMORY;
			goto unlock_and_exit;
		}

		notify_obj->notify.node = node;
		notify_obj->notify.handler = handler;
		notify_obj->notify.context = context;

		if (handler_type & ACPI_SYSTEM_NOTIFY) {
			obj_desc->common_notify.system_notify = notify_obj;
		}

		if (handler_type & ACPI_DEVICE_NOTIFY) {
			obj_desc->common_notify.device_notify = notify_obj;
		}

		if (handler_type == ACPI_ALL_NOTIFY) {

			

			acpi_ut_add_reference(notify_obj);
		}
	}

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS(status);
}
Exemple #8
0
acpi_status
acpi_install_notify_handler (
	acpi_handle             device,
	u32                     handler_type,
	acpi_notify_handler     handler,
	void                    *context)
{
	acpi_operand_object     *obj_desc;
	acpi_operand_object     *notify_obj;
	acpi_namespace_node     *device_node;
	acpi_status             status = AE_OK;


	FUNCTION_TRACE ("Acpi_install_notify_handler");


	/* Parameter validation */

	if ((!handler) ||
		(handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
		return_ACPI_STATUS (AE_BAD_PARAMETER);
	}

	acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);

	/* Convert and validate the device handle */

	device_node = acpi_ns_map_handle_to_node (device);
	if (!device_node) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/*
	 * Root Object:
	 * Registering a notify handler on the root object indicates that the
	 * caller wishes to receive notifications for all objects.  Note that
	 * only one <external> global handler can be regsitered (per notify type).
	 */
	if (device == ACPI_ROOT_OBJECT) {
		/* Make sure the handler is not already installed */

		if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
			  acpi_gbl_sys_notify.handler) ||
			((handler_type == ACPI_DEVICE_NOTIFY) &&
			  acpi_gbl_drv_notify.handler)) {
			status = AE_EXIST;
			goto unlock_and_exit;
		}

		if (handler_type == ACPI_SYSTEM_NOTIFY) {
			acpi_gbl_sys_notify.node = device_node;
			acpi_gbl_sys_notify.handler = handler;
			acpi_gbl_sys_notify.context = context;
		}
		else /* ACPI_DEVICE_NOTIFY */ {
			acpi_gbl_drv_notify.node = device_node;
			acpi_gbl_drv_notify.handler = handler;
			acpi_gbl_drv_notify.context = context;
		}

		/* Global notify handler installed */
	}

	/*
	 * All Other Objects:
	 * Caller will only receive notifications specific to the target object.
	 * Note that only certain object types can receive notifications.
	 */
	else {
		/*
		 * These are the ONLY objects that can receive ACPI notifications
		 */
		if ((device_node->type != ACPI_TYPE_DEVICE)    &&
			(device_node->type != ACPI_TYPE_PROCESSOR) &&
			(device_node->type != ACPI_TYPE_POWER)     &&
			(device_node->type != ACPI_TYPE_THERMAL)) {
			status = AE_BAD_PARAMETER;
			goto unlock_and_exit;
		}

		/* Check for an existing internal object */

		obj_desc = acpi_ns_get_attached_object (device_node);
		if (obj_desc) {

			/* Object exists - make sure there's no handler */

			if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
				  obj_desc->device.sys_handler) ||
				((handler_type == ACPI_DEVICE_NOTIFY) &&
				  obj_desc->device.drv_handler)) {
				status = AE_EXIST;
				goto unlock_and_exit;
			}
		}

		else {
			/* Create a new object */

			obj_desc = acpi_ut_create_internal_object (device_node->type);
			if (!obj_desc) {
				status = AE_NO_MEMORY;
				goto unlock_and_exit;
			}

			/* Attach new object to the Node */

			status = acpi_ns_attach_object (device, obj_desc, (u8) device_node->type);
			if (ACPI_FAILURE (status)) {
				goto unlock_and_exit;
			}
		}

		/* Install the handler */

		notify_obj = acpi_ut_create_internal_object (INTERNAL_TYPE_NOTIFY);
		if (!notify_obj) {
			status = AE_NO_MEMORY;
			goto unlock_and_exit;
		}

		notify_obj->notify_handler.node = device_node;
		notify_obj->notify_handler.handler = handler;
		notify_obj->notify_handler.context = context;


		if (handler_type == ACPI_SYSTEM_NOTIFY) {
			obj_desc->device.sys_handler = notify_obj;
		}

		else /* ACPI_DEVICE_NOTIFY */ {
			obj_desc->device.drv_handler = notify_obj;
		}
	}


unlock_and_exit:
	acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS (status);
}
Exemple #9
0
ACPI_STATUS
acpi_ds_method_data_set_value (
	u32                     type,
	u32                     index,
	ACPI_OPERAND_OBJECT     *src_desc,
	ACPI_WALK_STATE         *walk_state)
{
	ACPI_STATUS             status;
	ACPI_OPERAND_OBJECT     **entry;


	/* Parameter validation */

	if (!src_desc) {
		return (AE_BAD_PARAMETER);
	}


	/* Get a pointer to the requested method stack entry */

	status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry);
	if (ACPI_FAILURE (status)) {
		goto cleanup;
	}

	if (*entry == src_desc) {
		goto cleanup;
	}


	/*
	 * If there is an object already in this slot, we either
	 * have to delete it, or if this is an argument and there
	 * is an object reference stored there, we have to do
	 * an indirect store!
	 */

	if (*entry) {
		/*
		 * Check for an indirect store if an argument
		 * contains an object reference (stored as an Node).
		 * We don't allow this automatic dereferencing for
		 * locals, since a store to a local should overwrite
		 * anything there, including an object reference.
		 *
		 * If both Arg0 and Local0 contain Ref_of (Local4):
		 *
		 * Store (1, Arg0)             - Causes indirect store to local4
		 * Store (1, Local0)           - Stores 1 in local0, overwriting
		 *                                  the reference to local4
		 * Store (1, De_refof (Local0)) - Causes indirect store to local4
		 *
		 * Weird, but true.
		 */

		if ((type == MTH_TYPE_ARG) &&
			(VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED)))
		{
			/* Detach an existing object from the Node */

			acpi_ns_detach_object ((ACPI_NAMESPACE_NODE *) *entry);

			/*
			 * Store this object into the Node
			 * (do the indirect store)
			 */

			status = acpi_ns_attach_object ((ACPI_NAMESPACE_NODE *) *entry, src_desc,
					   src_desc->common.type);
			return (status);
		}


		/*
		 * Otherwise, just delete the existing object
		 * before storing the new one
		 */

		acpi_ds_method_data_delete_value (type, index, walk_state);
	}


	/*
	 * Install the Obj_stack descriptor (*Src_desc) into
	 * the descriptor for the Arg or Local.
	 * Install the new object in the stack entry
	 * (increments the object reference count by one)
	 */

	status = acpi_ds_method_data_set_entry (type, index, src_desc, walk_state);
	if (ACPI_FAILURE (status)) {
		goto cleanup;
	}

	/* Normal exit */

	return (AE_OK);


	/* Error exit */

cleanup:

	return (status);
}
Exemple #10
0
ACPI_STATUS
acpi_ns_root_initialize (void)
{
	ACPI_STATUS             status = AE_OK;
	PREDEFINED_NAMES        *init_val = NULL;
	ACPI_NAMESPACE_NODE     *new_node;
	ACPI_OPERAND_OBJECT     *obj_desc;


	acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);

	/*
	 * The global root ptr is initially NULL, so a non-NULL value indicates
	 * that Acpi_ns_root_initialize() has already been called; just return.
	 */

	if (acpi_gbl_root_node) {
		status = AE_OK;
		goto unlock_and_exit;
	}


	/*
	 * Tell the rest of the subsystem that the root is initialized
	 * (This is OK because the namespace is locked)
	 */

	acpi_gbl_root_node = &acpi_gbl_root_node_struct;


	/* Enter the pre-defined names in the name table */

	for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
		status = acpi_ns_lookup (NULL, init_val->name,
				 (OBJECT_TYPE_INTERNAL) init_val->type,
				 IMODE_LOAD_PASS2, NS_NO_UPSEARCH,
				 NULL, &new_node);


		/*
		 * Name entered successfully.
		 * If entry in Pre_defined_names[] specifies an
		 * initial value, create the initial value.
		 */

		if (init_val->val) {
			/*
			 * Entry requests an initial value, allocate a
			 * descriptor for it.
			 */

			obj_desc = acpi_cm_create_internal_object (
					  (OBJECT_TYPE_INTERNAL) init_val->type);

			if (!obj_desc) {
				status = AE_NO_MEMORY;
				goto unlock_and_exit;
			}

			/*
			 * Convert value string from table entry to
			 * internal representation. Only types actually
			 * used for initial values are implemented here.
			 */

			switch (init_val->type)
			{

			case ACPI_TYPE_NUMBER:

				obj_desc->number.value =
						(ACPI_INTEGER) STRTOUL (init_val->val, NULL, 10);
				break;


			case ACPI_TYPE_STRING:

				obj_desc->string.length =
						(u16) STRLEN (init_val->val);

				/*
				 * Allocate a buffer for the string.  All
				 * String.Pointers must be allocated buffers!
				 * (makes deletion simpler)
				 */
				obj_desc->string.pointer = acpi_cm_allocate (
						   (obj_desc->string.length + 1));
				if (!obj_desc->string.pointer) {
					acpi_cm_remove_reference (obj_desc);
					status = AE_NO_MEMORY;
					goto unlock_and_exit;
				}

				STRCPY (obj_desc->string.pointer, init_val->val);
				break;


			case ACPI_TYPE_MUTEX:

				obj_desc->mutex.sync_level =
						(u16) STRTOUL (init_val->val, NULL, 10);

				if (STRCMP (init_val->name, "_GL_") == 0) {
					/*
					 * Create a counting semaphore for the
					 * global lock
					 */
					status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT,
							 1, &obj_desc->mutex.semaphore);

					if (ACPI_FAILURE (status)) {
						goto unlock_and_exit;
					}
					/*
					 * We just created the mutex for the
					 * global lock, save it
					 */

					acpi_gbl_global_lock_semaphore = obj_desc->mutex.semaphore;
				}

				else {
					/* Create a mutex */

					status = acpi_os_create_semaphore (1, 1,
							   &obj_desc->mutex.semaphore);

					if (ACPI_FAILURE (status)) {
						goto unlock_and_exit;
					}
				}
				break;


			default:
				REPORT_ERROR (("Unsupported initial type value %X\n",
					init_val->type));
				acpi_cm_remove_reference (obj_desc);
				obj_desc = NULL;
				continue;
			}

			/* Store pointer to value descriptor in the Node */

			acpi_ns_attach_object (new_node, obj_desc,
					   obj_desc->common.type);
		}
	}


unlock_and_exit:
	acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
	return (status);
}
acpi_status acpi_ns_root_initialize(void)
{
	acpi_status status;
	const struct acpi_predefined_names *init_val = NULL;
	struct acpi_namespace_node *new_node;
	union acpi_operand_object *obj_desc;
	acpi_string val = NULL;

	ACPI_FUNCTION_TRACE(ns_root_initialize);

	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	if (acpi_gbl_root_node) {
		status = AE_OK;
		goto unlock_and_exit;
	}

	acpi_gbl_root_node = &acpi_gbl_root_node_struct;

	

	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Entering predefined entries into namespace\n"));

	for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {

		

		if (!ACPI_STRCMP(init_val->name, "_OSI")
		    && !acpi_gbl_create_osi_method) {
			continue;
		}

		status = acpi_ns_lookup(NULL, init_val->name, init_val->type,
					ACPI_IMODE_LOAD_PASS2,
					ACPI_NS_NO_UPSEARCH, NULL, &new_node);

		if (ACPI_FAILURE(status) || (!new_node)) {	
			ACPI_EXCEPTION((AE_INFO, status,
					"Could not create predefined name %s",
					init_val->name));
		}

		if (init_val->val) {
			status = acpi_os_predefined_override(init_val, &val);
			if (ACPI_FAILURE(status)) {
				ACPI_ERROR((AE_INFO,
					    "Could not override predefined %s",
					    init_val->name));
			}

			if (!val) {
				val = init_val->val;
			}

			obj_desc =
			    acpi_ut_create_internal_object(init_val->type);
			if (!obj_desc) {
				status = AE_NO_MEMORY;
				goto unlock_and_exit;
			}

			switch (init_val->type) {
			case ACPI_TYPE_METHOD:
				obj_desc->method.param_count =
				    (u8) ACPI_TO_INTEGER(val);
				obj_desc->common.flags |= AOPOBJ_DATA_VALID;

#if defined (ACPI_ASL_COMPILER)

				

				new_node->value = obj_desc->method.param_count;
#else
				

				obj_desc->method.info_flags =
				    ACPI_METHOD_INTERNAL_ONLY;
				obj_desc->method.dispatch.implementation =
				    acpi_ut_osi_implementation;
#endif
				break;

			case ACPI_TYPE_INTEGER:

				obj_desc->integer.value = ACPI_TO_INTEGER(val);
				break;

			case ACPI_TYPE_STRING:

				

				obj_desc->string.length =
				    (u32) ACPI_STRLEN(val);
				obj_desc->string.pointer = val;
				obj_desc->common.flags |= AOPOBJ_STATIC_POINTER;
				break;

			case ACPI_TYPE_MUTEX:

				obj_desc->mutex.node = new_node;
				obj_desc->mutex.sync_level =
				    (u8) (ACPI_TO_INTEGER(val) - 1);

				

				status =
				    acpi_os_create_mutex(&obj_desc->mutex.
							 os_mutex);
				if (ACPI_FAILURE(status)) {
					acpi_ut_remove_reference(obj_desc);
					goto unlock_and_exit;
				}

				

				if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
					acpi_gbl_global_lock_mutex = obj_desc;

					

					status =
					    acpi_os_create_semaphore(1, 0,
								     &acpi_gbl_global_lock_semaphore);
					if (ACPI_FAILURE(status)) {
						acpi_ut_remove_reference
						    (obj_desc);
						goto unlock_and_exit;
					}
				}
				break;

			default:

				ACPI_ERROR((AE_INFO,
					    "Unsupported initial type value 0x%X",
					    init_val->type));
				acpi_ut_remove_reference(obj_desc);
				obj_desc = NULL;
				continue;
			}

			

			status = acpi_ns_attach_object(new_node, obj_desc,
						       obj_desc->common.type);

			

			acpi_ut_remove_reference(obj_desc);
		}
	}

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);

	

	if (ACPI_SUCCESS(status)) {
		status = acpi_ns_get_node(NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH,
					  &acpi_gbl_fadt_gpe_device);
	}

	return_ACPI_STATUS(status);
}
Exemple #12
0
acpi_status
acpi_ex_prep_field_value (
	struct acpi_create_field_info   *info)
{
	union acpi_operand_object       *obj_desc;
	u32                             type;
	acpi_status                     status;


	ACPI_FUNCTION_TRACE ("ex_prep_field_value");


	/* Parameter validation */

	if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) {
		if (!info->region_node) {
			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null region_node\n"));
			return_ACPI_STATUS (AE_AML_NO_OPERAND);
		}

		type = acpi_ns_get_type (info->region_node);
		if (type != ACPI_TYPE_REGION) {
			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
				"Needed Region, found type %X %s\n",
				type, acpi_ut_get_type_name (type)));

			return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
		}
	}

	/* Allocate a new field object */

	obj_desc = acpi_ut_create_internal_object (info->field_type);
	if (!obj_desc) {
		return_ACPI_STATUS (AE_NO_MEMORY);
	}

	/* Initialize areas of the object that are common to all fields */

	obj_desc->common_field.node = info->field_node;
	status = acpi_ex_prep_common_field_object (obj_desc, info->field_flags,
			 info->attribute, info->field_bit_position, info->field_bit_length);
	if (ACPI_FAILURE (status)) {
		acpi_ut_delete_object_desc (obj_desc);
		return_ACPI_STATUS (status);
	}

	/* Initialize areas of the object that are specific to the field type */

	switch (info->field_type) {
	case ACPI_TYPE_LOCAL_REGION_FIELD:

		obj_desc->field.region_obj   = acpi_ns_get_attached_object (info->region_node);

		/* An additional reference for the container */

		acpi_ut_add_reference (obj_desc->field.region_obj);

		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
			"region_field: Bitoff=%X Off=%X Gran=%X Region %p\n",
			obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset,
			obj_desc->field.access_byte_width, obj_desc->field.region_obj));
		break;


	case ACPI_TYPE_LOCAL_BANK_FIELD:

		obj_desc->bank_field.value   = info->bank_value;
		obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (info->region_node);
		obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object (info->register_node);

		/* An additional reference for the attached objects */

		acpi_ut_add_reference (obj_desc->bank_field.region_obj);
		acpi_ut_add_reference (obj_desc->bank_field.bank_obj);

		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
			"Bank Field: bit_off=%X Off=%X Gran=%X Region %p bank_reg %p\n",
			obj_desc->bank_field.start_field_bit_offset,
			obj_desc->bank_field.base_byte_offset,
			obj_desc->field.access_byte_width,
			obj_desc->bank_field.region_obj,
			obj_desc->bank_field.bank_obj));
		break;


	case ACPI_TYPE_LOCAL_INDEX_FIELD:

		obj_desc->index_field.index_obj = acpi_ns_get_attached_object (info->register_node);
		obj_desc->index_field.data_obj = acpi_ns_get_attached_object (info->data_register_node);
		obj_desc->index_field.value  = (u32)
			(info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width));

		if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) {
			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Index Object\n"));
			return_ACPI_STATUS (AE_AML_INTERNAL);
		}

		/* An additional reference for the attached objects */

		acpi_ut_add_reference (obj_desc->index_field.data_obj);
		acpi_ut_add_reference (obj_desc->index_field.index_obj);

		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
			"index_field: bitoff=%X off=%X gran=%X Index %p Data %p\n",
			obj_desc->index_field.start_field_bit_offset,
			obj_desc->index_field.base_byte_offset,
			obj_desc->field.access_byte_width,
			obj_desc->index_field.index_obj,
			obj_desc->index_field.data_obj));
		break;

	default:
		/* No other types should get here */
		break;
	}

	/*
	 * Store the constructed descriptor (obj_desc) into the parent Node,
	 * preserving the current type of that named_obj.
	 */
	status = acpi_ns_attach_object (info->field_node, obj_desc,
			  acpi_ns_get_type (info->field_node));

	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "set named_obj %p (%4.4s) val = %p\n",
			info->field_node, info->field_node->name.ascii, obj_desc));

	/* Remove local reference to the object */

	acpi_ut_remove_reference (obj_desc);
	return_ACPI_STATUS (status);
}
Exemple #13
0
acpi_status
acpi_install_notify_handler(acpi_handle device,
			    u32 handler_type,
			    acpi_notify_handler handler, void *context)
{
	struct acpi_namespace_node *node =
	    ACPI_CAST_PTR(struct acpi_namespace_node, device);
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *handler_obj;
	acpi_status status;
	u32 i;

	ACPI_FUNCTION_TRACE(acpi_install_notify_handler);

	/* Parameter validation */

	if ((!device) || (!handler) || (!handler_type) ||
	    (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/*
	 * Root Object:
	 * Registering a notify handler on the root object indicates that the
	 * caller wishes to receive notifications for all objects. Note that
	 * only one global handler can be registered per notify type.
	 * Ensure that a handler is not already installed.
	 */
	if (device == ACPI_ROOT_OBJECT) {
		for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
			if (handler_type & (i + 1)) {
				if (acpi_gbl_global_notify[i].handler) {
					status = AE_ALREADY_EXISTS;
					goto unlock_and_exit;
				}

				acpi_gbl_global_notify[i].handler = handler;
				acpi_gbl_global_notify[i].context = context;
			}
		}

		goto unlock_and_exit;	/* Global notify handler installed, all done */
	}

	/*
	 * All Other Objects:
	 * Caller will only receive notifications specific to the target
	 * object. Note that only certain object types are allowed to
	 * receive notifications.
	 */

	/* Are Notifies allowed on this object? */

	if (!acpi_ev_is_notify_object(node)) {
		status = AE_TYPE;
		goto unlock_and_exit;
	}

	/* Check for an existing internal object, might not exist */

	obj_desc = acpi_ns_get_attached_object(node);
	if (!obj_desc) {

		/* Create a new object */

		obj_desc = acpi_ut_create_internal_object(node->type);
		if (!obj_desc) {
			status = AE_NO_MEMORY;
			goto unlock_and_exit;
		}

		/* Attach new object to the Node, remove local reference */

		status = acpi_ns_attach_object(device, obj_desc, node->type);
		acpi_ut_remove_reference(obj_desc);
		if (ACPI_FAILURE(status)) {
			goto unlock_and_exit;
		}
	}

	/* Ensure that the handler is not already installed in the lists */

	for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
		if (handler_type & (i + 1)) {
			handler_obj = obj_desc->common_notify.notify_list[i];
			while (handler_obj) {
				if (handler_obj->notify.handler == handler) {
					status = AE_ALREADY_EXISTS;
					goto unlock_and_exit;
				}

				handler_obj = handler_obj->notify.next[i];
			}
		}
	}

	/* Create and populate a new notify handler object */

	handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
	if (!handler_obj) {
		status = AE_NO_MEMORY;
		goto unlock_and_exit;
	}

	handler_obj->notify.node = node;
	handler_obj->notify.handler_type = handler_type;
	handler_obj->notify.handler = handler;
	handler_obj->notify.context = context;

	/* Install the handler at the list head(s) */

	for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
		if (handler_type & (i + 1)) {
			handler_obj->notify.next[i] =
			    obj_desc->common_notify.notify_list[i];

			obj_desc->common_notify.notify_list[i] = handler_obj;
		}
	}

	/* Add an extra reference if handler was installed in both lists */

	if (handler_type == ACPI_ALL_NOTIFY) {
		acpi_ut_add_reference(handler_obj);
	}

unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS(status);
}
Exemple #14
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_install_gpe_block
 *
 * PARAMETERS:  gpe_device          - Handle to the parent GPE Block Device
 *              gpe_block_address   - Address and space_iD
 *              register_count      - Number of GPE register pairs in the block
 *              interrupt_number    - H/W interrupt for the block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Create and Install a block of GPE registers
 *
 ******************************************************************************/
acpi_status
acpi_install_gpe_block(acpi_handle gpe_device,
		       struct acpi_generic_address *gpe_block_address,
		       u32 register_count, u32 interrupt_number)
{
	acpi_status status;
	union acpi_operand_object *obj_desc;
	struct acpi_namespace_node *node;
	struct acpi_gpe_block_info *gpe_block;

	ACPI_FUNCTION_TRACE(acpi_install_gpe_block);

	if ((!gpe_device) || (!gpe_block_address) || (!register_count)) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return (status);
	}

	node = acpi_ns_validate_handle(gpe_device);
	if (!node) {
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	/*
	 * For user-installed GPE Block Devices, the gpe_block_base_number
	 * is always zero
	 */
	status =
	    acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0,
				     interrupt_number, &gpe_block);
	if (ACPI_FAILURE(status)) {
		goto unlock_and_exit;
	}

	/* Install block in the device_object attached to the node */

	obj_desc = acpi_ns_get_attached_object(node);
	if (!obj_desc) {

		/*
		 * No object, create a new one (Device nodes do not always have
		 * an attached object)
		 */
		obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
		if (!obj_desc) {
			status = AE_NO_MEMORY;
			goto unlock_and_exit;
		}

		status =
		    acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE);

		/* Remove local reference to the object */

		acpi_ut_remove_reference(obj_desc);

		if (ACPI_FAILURE(status)) {
			goto unlock_and_exit;
		}
	}

	/* Now install the GPE block in the device_object */

	obj_desc->device.gpe_block = gpe_block;

	/* Enable the runtime GPEs in the new block */

	status = acpi_ev_initialize_gpe_block(node, gpe_block);

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS(status);
}
Exemple #15
0
acpi_status
acpi_ds_create_buffer_field(union acpi_parse_object *op,
			    struct acpi_walk_state *walk_state)
{
	union acpi_parse_object *arg;
	struct acpi_namespace_node *node;
	acpi_status status;
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *second_desc = NULL;
	u32 flags;

	ACPI_FUNCTION_TRACE(ds_create_buffer_field);

	/*
	 * Get the name_string argument (name of the new buffer_field)
	 */
	if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {

		/* For create_field, name is the 4th argument */

		arg = acpi_ps_get_arg(op, 3);
	} else {
		/* For all other create_XXXField operators, name is the 3rd argument */

		arg = acpi_ps_get_arg(op, 2);
	}

	if (!arg) {
		return_ACPI_STATUS(AE_AML_NO_OPERAND);
	}

	if (walk_state->deferred_node) {
		node = walk_state->deferred_node;
		status = AE_OK;
	} else {
		/* Execute flag should always be set when this function is entered */

		if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
			return_ACPI_STATUS(AE_AML_INTERNAL);
		}

		/* Creating new namespace node, should not already exist */

		flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
		    ACPI_NS_ERROR_IF_FOUND;

		/*
		 * Mark node temporary if we are executing a normal control
		 * method. (Don't mark if this is a module-level code method)
		 */
		if (walk_state->method_node &&
		    !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
			flags |= ACPI_NS_TEMPORARY;
		}

		/* Enter the name_string into the namespace */

		status =
		    acpi_ns_lookup(walk_state->scope_info,
				   arg->common.value.string, ACPI_TYPE_ANY,
				   ACPI_IMODE_LOAD_PASS1, flags, walk_state,
				   &node);
		if (ACPI_FAILURE(status)) {
			ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
			return_ACPI_STATUS(status);
		}
	}

	/*
	 * We could put the returned object (Node) on the object stack for later,
	 * but for now, we will put it in the "op" object that the parser uses,
	 * so we can get it again at the end of this scope.
	 */
	op->common.node = node;

	/*
	 * If there is no object attached to the node, this node was just created
	 * and we need to create the field object. Otherwise, this was a lookup
	 * of an existing node and we don't want to create the field object again.
	 */
	obj_desc = acpi_ns_get_attached_object(node);
	if (obj_desc) {
		return_ACPI_STATUS(AE_OK);
	}

	/*
	 * The Field definition is not fully parsed at this time.
	 * (We must save the address of the AML for the buffer and index operands)
	 */

	/* Create the buffer field object */

	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER_FIELD);
	if (!obj_desc) {
		status = AE_NO_MEMORY;
		goto cleanup;
	}

	/*
	 * Remember location in AML stream of the field unit opcode and operands --
	 * since the buffer and index operands must be evaluated.
	 */
	second_desc = obj_desc->common.next_object;
	second_desc->extra.aml_start = op->named.data;
	second_desc->extra.aml_length = op->named.length;
	obj_desc->buffer_field.node = node;

	/* Attach constructed field descriptors to parent node */

	status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_BUFFER_FIELD);
	if (ACPI_FAILURE(status)) {
		goto cleanup;
	}

      cleanup:

	/* Remove local reference to the object */

	acpi_ut_remove_reference(obj_desc);
	return_ACPI_STATUS(status);
}
Exemple #16
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_root_initialize
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Allocate and initialize the default root named objects
 *
 * MUTEX:       Locks namespace for entire execution
 *
 ******************************************************************************/
acpi_status acpi_ns_root_initialize(void)
{
	acpi_status status;
	const struct acpi_predefined_names *init_val = NULL;
	struct acpi_namespace_node *new_node;
	union acpi_operand_object *obj_desc;
	acpi_string val = NULL;

	ACPI_FUNCTION_TRACE(ns_root_initialize);

	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/*
	 * The global root ptr is initially NULL, so a non-NULL value indicates
	 * that acpi_ns_root_initialize() has already been called; just return.
	 */
	if (acpi_gbl_root_node) {
		status = AE_OK;
		goto unlock_and_exit;
	}

	/*
	 * Tell the rest of the subsystem that the root is initialized
	 * (This is OK because the namespace is locked)
	 */
	acpi_gbl_root_node = &acpi_gbl_root_node_struct;

	/* Enter the pre-defined names in the name table */

	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Entering predefined entries into namespace\n"));

	for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {

		/* _OSI is optional for now, will be permanent later */

		if (!ACPI_STRCMP(init_val->name, "_OSI")
		    && !acpi_gbl_create_osi_method) {
			continue;
		}

		status = acpi_ns_lookup(NULL, init_val->name, init_val->type,
					ACPI_IMODE_LOAD_PASS2,
					ACPI_NS_NO_UPSEARCH, NULL, &new_node);

		if (ACPI_FAILURE(status) || (!new_node)) {	/* Must be on same line for code converter */
			ACPI_EXCEPTION((AE_INFO, status,
					"Could not create predefined name %s",
					init_val->name));
		}

		/*
		 * Name entered successfully.
		 * If entry in pre_defined_names[] specifies an
		 * initial value, create the initial value.
		 */
		if (init_val->val) {
			status = acpi_os_predefined_override(init_val, &val);
			if (ACPI_FAILURE(status)) {
				ACPI_ERROR((AE_INFO,
					    "Could not override predefined %s",
					    init_val->name));
			}

			if (!val) {
				val = init_val->val;
			}

			/*
			 * Entry requests an initial value, allocate a
			 * descriptor for it.
			 */
			obj_desc =
			    acpi_ut_create_internal_object(init_val->type);
			if (!obj_desc) {
				status = AE_NO_MEMORY;
				goto unlock_and_exit;
			}

			/*
			 * Convert value string from table entry to
			 * internal representation. Only types actually
			 * used for initial values are implemented here.
			 */
			switch (init_val->type) {
			case ACPI_TYPE_METHOD:
				obj_desc->method.param_count =
				    (u8) ACPI_TO_INTEGER(val);
				obj_desc->common.flags |= AOPOBJ_DATA_VALID;

#if defined (ACPI_ASL_COMPILER)

				/* Save the parameter count for the i_aSL compiler */

				new_node->value = obj_desc->method.param_count;
#else
				/* Mark this as a very SPECIAL method */

				obj_desc->method.method_flags =
				    AML_METHOD_INTERNAL_ONLY;
				obj_desc->method.implementation =
				    acpi_ut_osi_implementation;
#endif
				break;

			case ACPI_TYPE_INTEGER:

				obj_desc->integer.value = ACPI_TO_INTEGER(val);
				break;

			case ACPI_TYPE_STRING:

				/*
				 * Build an object around the static string
				 */
				obj_desc->string.length =
				    (u32) ACPI_STRLEN(val);
				obj_desc->string.pointer = val;
				obj_desc->common.flags |= AOPOBJ_STATIC_POINTER;
				break;

			case ACPI_TYPE_MUTEX:

				obj_desc->mutex.node = new_node;
				obj_desc->mutex.sync_level =
				    (u8) (ACPI_TO_INTEGER(val) - 1);

				/* Create a mutex */

				status =
				    acpi_os_create_mutex(&obj_desc->mutex.
							 os_mutex);
				if (ACPI_FAILURE(status)) {
					acpi_ut_remove_reference(obj_desc);
					goto unlock_and_exit;
				}

				/* Special case for ACPI Global Lock */

				if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
					acpi_gbl_global_lock_mutex = obj_desc;

					/* Create additional counting semaphore for global lock */

					status =
					    acpi_os_create_semaphore(1, 0,
								     &acpi_gbl_global_lock_semaphore);
					if (ACPI_FAILURE(status)) {
						acpi_ut_remove_reference
						    (obj_desc);
						goto unlock_and_exit;
					}
				}
				break;

			default:

				ACPI_ERROR((AE_INFO,
					    "Unsupported initial type value %X",
					    init_val->type));
				acpi_ut_remove_reference(obj_desc);
				obj_desc = NULL;
				continue;
			}

			/* Store pointer to value descriptor in the Node */

			status = acpi_ns_attach_object(new_node, obj_desc,
						       ACPI_GET_OBJECT_TYPE
						       (obj_desc));

			/* Remove local reference to the object */

			acpi_ut_remove_reference(obj_desc);
		}
	}

      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);

	/* Save a handle to "_GPE", it is always present */

	if (ACPI_SUCCESS(status)) {
		status = acpi_ns_get_node(NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH,
					  &acpi_gbl_fadt_gpe_device);
	}

	return_ACPI_STATUS(status);
}
Exemple #17
0
acpi_status
acpi_ds_store_object_to_local (
    u16                     opcode,
    u32                     index,
    acpi_operand_object     *src_desc,
    acpi_walk_state         *walk_state)
{
    acpi_status             status;
    acpi_operand_object     **entry;


    FUNCTION_TRACE ("Ds_method_data_set_value");
    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%d Idx=%d Obj=%p\n",
                       opcode, index, src_desc));


    /* Parameter validation */

    if (!src_desc) {
        return_ACPI_STATUS (AE_BAD_PARAMETER);
    }


    /* Get a pointer to the requested method stack entry */

    status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
    if (ACPI_FAILURE (status)) {
        goto cleanup;
    }

    if (*entry == src_desc) {
        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p already installed!\n", src_desc));
        goto cleanup;
    }


    /*
     * If there is an object already in this slot, we either
     * have to delete it, or if this is an argument and there
     * is an object reference stored there, we have to do
     * an indirect store!
     */
    if (*entry) {
        /*
         * Check for an indirect store if an argument
         * contains an object reference (stored as an Node).
         * We don't allow this automatic dereferencing for
         * locals, since a store to a local should overwrite
         * anything there, including an object reference.
         *
         * If both Arg0 and Local0 contain Ref_of (Local4):
         *
         * Store (1, Arg0)             - Causes indirect store to local4
         * Store (1, Local0)           - Stores 1 in local0, overwriting
         *                                  the reference to local4
         * Store (1, De_refof (Local0)) - Causes indirect store to local4
         *
         * Weird, but true.
         */
        if ((opcode == AML_ARG_OP) &&
                (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED))) {
            ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
                               "Arg (%p) is an Obj_ref(Node), storing in %p\n",
                               src_desc, *entry));

            /* Detach an existing object from the Node */

            acpi_ns_detach_object ((acpi_namespace_node *) *entry);

            /*
             * Store this object into the Node
             * (do the indirect store)
             */
            status = acpi_ns_attach_object ((acpi_namespace_node *) *entry, src_desc,
                                            src_desc->common.type);
            return_ACPI_STATUS (status);
        }


#ifdef ACPI_ENABLE_IMPLICIT_CONVERSION
        /*
         * Perform "Implicit conversion" of the new object to the type of the
         * existing object
         */
        status = acpi_ex_convert_to_target_type ((*entry)->common.type, &src_desc, walk_state);
        if (ACPI_FAILURE (status)) {
            goto cleanup;
        }
#endif

        /*
         * Delete the existing object
         * before storing the new one
         */
        acpi_ds_method_data_delete_value (opcode, index, walk_state);
    }


    /*
     * Install the Obj_stack descriptor (*Src_desc) into
     * the descriptor for the Arg or Local.
     * Install the new object in the stack entry
     * (increments the object reference count by one)
     */
    status = acpi_ds_method_data_set_entry (opcode, index, src_desc, walk_state);
    if (ACPI_FAILURE (status)) {
        goto cleanup;
    }

    /* Normal exit */

    return_ACPI_STATUS (AE_OK);


    /* Error exit */

cleanup:

    return_ACPI_STATUS (status);
}