acpi_status acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, union acpi_operand_object *obj_desc, union acpi_operand_object **ret_buffer_desc) { acpi_status status; union acpi_operand_object *buffer_desc; acpi_size length; void *buffer; u32 function; u16 accessor_type; ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); /* Parameter validation */ if (!obj_desc) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } if (!ret_buffer_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { /* * If the buffer_field arguments have not been previously evaluated, * evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold * the data and then directly access the region handler. * * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function */ if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_READ | (obj_desc->field.attribute << 16); } else if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) { accessor_type = obj_desc->field.attribute; length = acpi_ex_get_serial_access_length(accessor_type, obj_desc-> field. access_length); /* * Add additional 2 bytes for the generic_serial_bus data buffer: * * Status; (Byte 0 of the data buffer) * Length; (Byte 1 of the data buffer) * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) */ length += 2; function = ACPI_READ | (accessor_type << 16); } else { /* IPMI */ length = ACPI_IPMI_BUFFER_SIZE; function = ACPI_READ; } buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Call the region handler for the read */ status = acpi_ex_access_region(obj_desc, 0, ACPI_CAST_PTR(u64, buffer_desc-> buffer.pointer), function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); goto exit; } /* * Allocate a buffer for the contents of the field. * * If the field is larger than the current integer width, create * a BUFFER to hold it. Otherwise, use an INTEGER. This allows * the use of arithmetic operators on the returned value if the * field size is equal or smaller than an Integer. * * Note: Field.length is in bits. */ length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); if (length > acpi_gbl_integer_byte_width) { /* Field is too large for an Integer, create a Buffer instead */ buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; } else { /* Field will fit within an Integer (normal case) */ buffer_desc = acpi_ut_create_integer_object((u64) 0); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } length = acpi_gbl_integer_byte_width; buffer = &buffer_desc->integer.value; } if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) { /* * For GPIO (general_purpose_io), the Address will be the bit offset * from the previous Connection() operator, making it effectively a * pin number index. The bit_length is the length of the field, which * is thus the number of pins. */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "GPIO FieldRead [FROM]: Pin %u Bits %u\n", obj_desc->field.pin_number_index, obj_desc->field.bit_length)); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Perform the write */ status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_READ); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(buffer_desc); } else { *ret_buffer_desc = buffer_desc; } return_ACPI_STATUS(status); } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, obj_desc->common.type, buffer, (u32) length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Read from the field */ status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); exit: if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(buffer_desc); } else { *ret_buffer_desc = buffer_desc; } return_ACPI_STATUS(status); }
acpi_status acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, union acpi_operand_object *obj_desc, union acpi_operand_object **result_desc) { acpi_status status; u32 length; void *buffer; union acpi_operand_object *buffer_desc; u32 function; u16 accessor_type; ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); /* Parameter validation */ if (!source_desc || !obj_desc) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { /* * If the buffer_field arguments have not been previously evaluated, * evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* * This is an SMBus, GSBus or IPMI write. We will bypass the entire field * mechanism and handoff the buffer directly to the handler. For * these address spaces, the buffer is bi-directional; on a write, * return data is returned in the same buffer. * * Source must be a buffer of sufficient size: * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. * * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function */ if (source_desc->common.type != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", acpi_ut_get_object_type_name(source_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_WRITE | (obj_desc->field.attribute << 16); } else if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) { accessor_type = obj_desc->field.attribute; length = acpi_ex_get_serial_access_length(accessor_type, obj_desc-> field. access_length); /* * Add additional 2 bytes for the generic_serial_bus data buffer: * * Status; (Byte 0 of the data buffer) * Length; (Byte 1 of the data buffer) * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) */ length += 2; function = ACPI_WRITE | (accessor_type << 16); } else { /* IPMI */ length = ACPI_IPMI_BUFFER_SIZE; function = ACPI_WRITE; } if (source_desc->buffer.length < length) { ACPI_ERROR((AE_INFO, "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", length, source_desc->buffer.length)); return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); } /* Create the bi-directional buffer */ buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* * Perform the write (returns status and perhaps data in the * same buffer) */ status = acpi_ex_access_region(obj_desc, 0, (u64 *) buffer, function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); *result_desc = buffer_desc; return_ACPI_STATUS(status); } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) { /* * For GPIO (general_purpose_io), we will bypass the entire field * mechanism and handoff the bit address and bit width directly to * the handler. The Address will be the bit offset * from the previous Connection() operator, making it effectively a * pin number index. The bit_length is the length of the field, which * is thus the number of pins. */ if (source_desc->common.type != ACPI_TYPE_INTEGER) { return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", acpi_ut_get_type_name(source_desc->common. type), source_desc->common.type, (u32)source_desc->integer.value, obj_desc->field.pin_number_index, obj_desc->field.bit_length)); buffer = &source_desc->integer.value; /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Perform the write */ status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_WRITE); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); return_ACPI_STATUS(status); } /* Get a pointer to the data to be written */ switch (source_desc->common.type) { case ACPI_TYPE_INTEGER: buffer = &source_desc->integer.value; length = sizeof(source_desc->integer.value); break; case ACPI_TYPE_BUFFER: buffer = source_desc->buffer.pointer; length = source_desc->buffer.length; break; case ACPI_TYPE_STRING: buffer = source_desc->string.pointer; length = source_desc->string.length; break; default: return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", source_desc, acpi_ut_get_type_name(source_desc->common.type), source_desc->common.type, buffer, length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", obj_desc, acpi_ut_get_type_name(obj_desc->common.type), obj_desc->common.type, obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Write to the field */ status = acpi_ex_insert_into_field(obj_desc, buffer, length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); return_ACPI_STATUS(status); }
acpi_status acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, union acpi_operand_object *obj_desc, union acpi_operand_object **ret_buffer_desc) { acpi_status status; union acpi_operand_object *buffer_desc; acpi_size length; void *buffer; u32 function; ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); if (!obj_desc) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } if (!ret_buffer_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_READ | (obj_desc->field.attribute << 16); } else if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) { length = ACPI_GSBUS_BUFFER_SIZE; function = ACPI_READ | (obj_desc->field.attribute << 16); } else { length = ACPI_IPMI_BUFFER_SIZE; function = ACPI_READ; } buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); status = acpi_ex_access_region(obj_desc, 0, ACPI_CAST_PTR(u64, buffer_desc-> buffer.pointer), function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); goto exit; } length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); if (length > acpi_gbl_integer_byte_width) { buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; } else { buffer_desc = acpi_ut_create_integer_object((u64) 0); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } length = acpi_gbl_integer_byte_width; buffer = &buffer_desc->integer.value; } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, obj_desc->common.type, buffer, (u32) length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); exit: if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(buffer_desc); } else { *ret_buffer_desc = buffer_desc; } return_ACPI_STATUS(status); }
static acpi_status acpi_ns_init_one_object(acpi_handle obj_handle, u32 level, void *context, void **return_value) { acpi_object_type type; acpi_status status = AE_OK; struct acpi_init_walk_info *info = (struct acpi_init_walk_info *)context; struct acpi_namespace_node *node = (struct acpi_namespace_node *)obj_handle; union acpi_operand_object *obj_desc; ACPI_FUNCTION_NAME(ns_init_one_object); info->object_count++; /* And even then, we are only interested in a few object types */ type = acpi_ns_get_type(obj_handle); obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { return (AE_OK); } /* Increment counters for object types we are looking for */ switch (type) { case ACPI_TYPE_REGION: info->op_region_count++; break; case ACPI_TYPE_BUFFER_FIELD: info->field_count++; break; case ACPI_TYPE_LOCAL_BANK_FIELD: info->field_count++; break; case ACPI_TYPE_BUFFER: info->buffer_count++; break; case ACPI_TYPE_PACKAGE: info->package_count++; break; default: /* No init required, just exit now */ return (AE_OK); } /* If the object is already initialized, nothing else to do */ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { return (AE_OK); } /* Must lock the interpreter before executing AML code */ acpi_ex_enter_interpreter(); /* * Each of these types can contain executable AML code within the * declaration. */ switch (type) { case ACPI_TYPE_REGION: info->op_region_init++; status = acpi_ds_get_region_arguments(obj_desc); break; case ACPI_TYPE_BUFFER_FIELD: info->field_init++; status = acpi_ds_get_buffer_field_arguments(obj_desc); break; case ACPI_TYPE_LOCAL_BANK_FIELD: info->field_init++; status = acpi_ds_get_bank_field_arguments(obj_desc); break; case ACPI_TYPE_BUFFER: info->buffer_init++; status = acpi_ds_get_buffer_arguments(obj_desc); break; case ACPI_TYPE_PACKAGE: info->package_init++; status = acpi_ds_get_package_arguments(obj_desc); break; default: /* No other types can get here */ break; } if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not execute arguments for [%4.4s] (%s)", acpi_ut_get_node_name(node), acpi_ut_get_type_name(type))); } /* * We ignore errors from above, and always return OK, since we don't want * to abort the walk on any single error. */ acpi_ex_exit_interpreter(); return (AE_OK); }
static acpi_status acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, u32 field_datum_byte_offset, u64 *value, u32 read_write) { acpi_status status; u64 local_value; ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset); if (read_write == ACPI_READ) { if (!value) { local_value = 0; /* To support reads without saving return value */ value = &local_value; } /* Clear the entire return buffer first, [Very Important!] */ *value = 0; } /* * The four types of fields are: * * buffer_field - Read/write from/to a Buffer * region_field - Read/write from/to a Operation Region. * bank_field - Write to a Bank Register, then read/write from/to an * operation_region * index_field - Write to an Index Register, then read/write from/to a * Data Register */ switch (obj_desc->common.type) { case ACPI_TYPE_BUFFER_FIELD: /* * If the buffer_field arguments have not been previously evaluated, * evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } if (read_write == ACPI_READ) { /* * Copy the data from the source buffer. * Length is the field width in bytes. */ ACPI_MEMCPY(value, (obj_desc->buffer_field.buffer_obj)->buffer. pointer + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset, obj_desc->common_field.access_byte_width); } else { /* * Copy the data to the target buffer. * Length is the field width in bytes. */ ACPI_MEMCPY((obj_desc->buffer_field.buffer_obj)->buffer. pointer + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset, value, obj_desc->common_field.access_byte_width); } status = AE_OK; break; case ACPI_TYPE_LOCAL_BANK_FIELD: /* * Ensure that the bank_value is not beyond the capacity of * the register */ if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj, (u64) obj_desc->bank_field. value)) { return_ACPI_STATUS(AE_AML_REGISTER_LIMIT); } /* * For bank_fields, we must write the bank_value to the bank_register * (itself a region_field) before we can access the data. */ status = acpi_ex_insert_into_field(obj_desc->bank_field.bank_obj, &obj_desc->bank_field.value, sizeof(obj_desc->bank_field. value)); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Now that the Bank has been selected, fall through to the * region_field case and write the datum to the Operation Region */ /*lint -fallthrough */ case ACPI_TYPE_LOCAL_REGION_FIELD: /* * For simple region_fields, we just directly access the owning * Operation Region. */ status = acpi_ex_access_region(obj_desc, field_datum_byte_offset, value, read_write); break; case ACPI_TYPE_LOCAL_INDEX_FIELD: /* * Ensure that the index_value is not beyond the capacity of * the register */ if (acpi_ex_register_overflow(obj_desc->index_field.index_obj, (u64) obj_desc->index_field. value)) { return_ACPI_STATUS(AE_AML_REGISTER_LIMIT); } /* Write the index value to the index_register (itself a region_field) */ field_datum_byte_offset += obj_desc->index_field.value; ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Write to Index Register: Value %8.8X\n", field_datum_byte_offset)); status = acpi_ex_insert_into_field(obj_desc->index_field.index_obj, &field_datum_byte_offset, sizeof(field_datum_byte_offset)); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (read_write == ACPI_READ) { /* Read the datum from the data_register */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Read from Data Register\n")); status = acpi_ex_extract_from_field(obj_desc->index_field. data_obj, value, sizeof(u64)); } else { /* Write the datum to the data_register */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Write to Data Register: Value %8.8X%8.8X\n", ACPI_FORMAT_UINT64(*value))); status = acpi_ex_insert_into_field(obj_desc->index_field. data_obj, value, sizeof(u64)); } break; default: ACPI_ERROR((AE_INFO, "Wrong object type in field I/O %u", obj_desc->common.type)); status = AE_AML_INTERNAL; break; } if (ACPI_SUCCESS(status)) { if (read_write == ACPI_READ) { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %u\n", ACPI_FORMAT_UINT64(*value), obj_desc->common_field. access_byte_width)); } else { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %u\n", ACPI_FORMAT_UINT64(*value), obj_desc->common_field. access_byte_width)); } } return_ACPI_STATUS(status); }
acpi_status acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, union acpi_operand_object *obj_desc, union acpi_operand_object **result_desc) { acpi_status status; u32 length; void *buffer; union acpi_operand_object *buffer_desc; u32 function; ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); if (!source_desc || !obj_desc) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { if (source_desc->common.type != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", acpi_ut_get_object_type_name(source_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_WRITE | (obj_desc->field.attribute << 16); } else if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) { length = ACPI_GSBUS_BUFFER_SIZE; function = ACPI_WRITE | (obj_desc->field.attribute << 16); } else { length = ACPI_IPMI_BUFFER_SIZE; function = ACPI_WRITE; } if (source_desc->buffer.length < length) { ACPI_ERROR((AE_INFO, "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", length, source_desc->buffer.length)); return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); } buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length); acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); status = acpi_ex_access_region(obj_desc, 0, (u64 *) buffer, function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); *result_desc = buffer_desc; return_ACPI_STATUS(status); } /* Get a pointer to the data to be written */ switch (source_desc->common.type) { case ACPI_TYPE_INTEGER: buffer = &source_desc->integer.value; length = sizeof(source_desc->integer.value); break; case ACPI_TYPE_BUFFER: buffer = source_desc->buffer.pointer; length = source_desc->buffer.length; break; case ACPI_TYPE_STRING: buffer = source_desc->string.pointer; length = source_desc->string.length; break; default: return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", source_desc, acpi_ut_get_type_name(source_desc->common.type), source_desc->common.type, buffer, length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", obj_desc, acpi_ut_get_type_name(obj_desc->common.type), obj_desc->common.type, obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); status = acpi_ex_insert_into_field(obj_desc, buffer, length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); return_ACPI_STATUS(status); }
acpi_status acpi_ns_init_one_object ( acpi_handle obj_handle, u32 level, void *context, void **return_value) { acpi_object_type8 type; acpi_status status; acpi_init_walk_info *info = (acpi_init_walk_info *) context; acpi_namespace_node *node = (acpi_namespace_node *) obj_handle; acpi_operand_object *obj_desc; PROC_NAME ("Ns_init_one_object"); info->object_count++; /* And even then, we are only interested in a few object types */ type = acpi_ns_get_type (obj_handle); obj_desc = node->object; if (!obj_desc) { return (AE_OK); } if ((type != ACPI_TYPE_REGION) && (type != ACPI_TYPE_BUFFER_FIELD)) { return (AE_OK); } /* * Must lock the interpreter before executing AML code */ status = acpi_ex_enter_interpreter (); if (ACPI_FAILURE (status)) { return (status); } switch (type) { case ACPI_TYPE_REGION: info->op_region_count++; if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { break; } info->op_region_init++; status = acpi_ds_get_region_arguments (obj_desc); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n")); ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s while getting region arguments [%4.4s]\n", acpi_format_exception (status), (char*)&node->name)); } if (!(acpi_dbg_level & ACPI_LV_INIT)) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, ".")); } break; case ACPI_TYPE_BUFFER_FIELD: info->field_count++; if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { break; } info->field_init++; status = acpi_ds_get_buffer_field_arguments (obj_desc); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n")); ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s while getting buffer field arguments [%4.4s]\n", acpi_format_exception (status), (char*)&node->name)); } if (!(acpi_dbg_level & ACPI_LV_INIT)) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, ".")); } break; default: break; } /* * We ignore errors from above, and always return OK, since * we don't want to abort the walk on a single error. */ acpi_ex_exit_interpreter (); return (AE_OK); }
/******************************************************************************* * * FUNCTION: acpi_ex_read_data_from_field * * PARAMETERS: walk_state - Current execution state * obj_desc - The named field * ret_buffer_desc - Where the return data object is stored * * RETURN: Status * * DESCRIPTION: Read from a named field. Returns either an Integer or a * Buffer, depending on the size of the field. * ******************************************************************************/ acpi_status acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, union acpi_operand_object *obj_desc, union acpi_operand_object **ret_buffer_desc) { acpi_status status; union acpi_operand_object *buffer_desc; acpi_size length; void *buffer; ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); /* Parameter validation */ if (!obj_desc) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } if (!ret_buffer_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_BUFFER_FIELD) { /* * If the buffer_field arguments have not been previously evaluated, * evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } } else if ((ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) { /* * This is an SMBus read. We must create a buffer to hold the data * and directly access the region handler. */ buffer_desc = acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* * Perform the read. * Note: Smbus protocol value is passed in upper 16-bits of Function */ status = acpi_ex_access_region(obj_desc, 0, ACPI_CAST_PTR(acpi_integer, buffer_desc-> buffer.pointer), ACPI_READ | (obj_desc->field. attribute << 16)); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); goto exit; } /* * Allocate a buffer for the contents of the field. * * If the field is larger than the size of an acpi_integer, create * a BUFFER to hold it. Otherwise, use an INTEGER. This allows * the use of arithmetic operators on the returned value if the * field size is equal or smaller than an Integer. * * Note: Field.length is in bits. */ length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); if (length > acpi_gbl_integer_byte_width) { /* Field is too large for an Integer, create a Buffer instead */ buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; } else { /* Field will fit within an Integer (normal case) */ buffer_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } length = acpi_gbl_integer_byte_width; buffer_desc->integer.value = 0; buffer = &buffer_desc->integer.value; } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, ACPI_GET_OBJECT_TYPE(obj_desc), buffer, (u32) length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Read from the field */ status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); exit: if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(buffer_desc); } else { *ret_buffer_desc = buffer_desc; } return_ACPI_STATUS(status); }
acpi_status acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, union acpi_operand_object *obj_desc, union acpi_operand_object **result_desc) { acpi_status status; u32 length; void *buffer; union acpi_operand_object *buffer_desc; ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); /* Parameter validation */ if (!source_desc || !obj_desc) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_BUFFER_FIELD) { /* * If the buffer_field arguments have not been previously evaluated, * evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } } else if ((ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) { /* * This is an SMBus write. We will bypass the entire field mechanism * and handoff the buffer directly to the handler. * * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE). */ if (ACPI_GET_OBJECT_TYPE(source_desc) != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, "SMBus write requires Buffer, found type %s", acpi_ut_get_object_type_name(source_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) { ACPI_ERROR((AE_INFO, "SMBus write requires Buffer of length %X, found length %X", ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length)); return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); } buffer_desc = acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; ACPI_MEMCPY(buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* * Perform the write (returns status and perhaps data in the * same buffer) * Note: SMBus protocol type is passed in upper 16-bits of Function. */ status = acpi_ex_access_region(obj_desc, 0, (acpi_integer *) buffer, ACPI_WRITE | (obj_desc->field. attribute << 16)); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); *result_desc = buffer_desc; return_ACPI_STATUS(status); } /* Get a pointer to the data to be written */ switch (ACPI_GET_OBJECT_TYPE(source_desc)) { case ACPI_TYPE_INTEGER: buffer = &source_desc->integer.value; length = sizeof(source_desc->integer.value); break; case ACPI_TYPE_BUFFER: buffer = source_desc->buffer.pointer; length = source_desc->buffer.length; break; case ACPI_TYPE_STRING: buffer = source_desc->string.pointer; length = source_desc->string.length; break; default: return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", source_desc, acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE (source_desc)), ACPI_GET_OBJECT_TYPE(source_desc), buffer, length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", obj_desc, acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE(obj_desc)), ACPI_GET_OBJECT_TYPE(obj_desc), obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Write to the field */ status = acpi_ex_insert_into_field(obj_desc, buffer, length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); return_ACPI_STATUS(status); }
static acpi_status acpi_ns_init_one_object(acpi_handle obj_handle, u32 level, void *context, void **return_value) { acpi_object_type type; acpi_status status = AE_OK; struct acpi_init_walk_info *info = (struct acpi_init_walk_info *)context; struct acpi_namespace_node *node = (struct acpi_namespace_node *)obj_handle; union acpi_operand_object *obj_desc; ACPI_FUNCTION_NAME(ns_init_one_object); info->object_count++; type = acpi_ns_get_type(obj_handle); obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { return (AE_OK); } switch (type) { case ACPI_TYPE_REGION: info->op_region_count++; break; case ACPI_TYPE_BUFFER_FIELD: info->field_count++; break; case ACPI_TYPE_LOCAL_BANK_FIELD: info->field_count++; break; case ACPI_TYPE_BUFFER: info->buffer_count++; break; case ACPI_TYPE_PACKAGE: info->package_count++; break; default: return (AE_OK); } if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { return (AE_OK); } acpi_ex_enter_interpreter(); switch (type) { case ACPI_TYPE_REGION: info->op_region_init++; status = acpi_ds_get_region_arguments(obj_desc); break; case ACPI_TYPE_BUFFER_FIELD: info->field_init++; status = acpi_ds_get_buffer_field_arguments(obj_desc); break; case ACPI_TYPE_LOCAL_BANK_FIELD: info->field_init++; status = acpi_ds_get_bank_field_arguments(obj_desc); break; case ACPI_TYPE_BUFFER: info->buffer_init++; status = acpi_ds_get_buffer_arguments(obj_desc); break; case ACPI_TYPE_PACKAGE: info->package_init++; status = acpi_ds_get_package_arguments(obj_desc); break; default: break; } if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not execute arguments for [%4.4s] (%s)", acpi_ut_get_node_name(node), acpi_ut_get_type_name(type))); } if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, ".")); } acpi_ex_exit_interpreter(); return (AE_OK); }
acpi_status acpi_ex_write_data_to_field ( union acpi_operand_object *source_desc, union acpi_operand_object *obj_desc, union acpi_operand_object **result_desc) { acpi_status status; u32 length; u32 required_length; void *buffer; void *new_buffer; u8 locked; union acpi_operand_object *buffer_desc; ACPI_FUNCTION_TRACE_PTR ("ex_write_data_to_field", obj_desc); /* Parameter validation */ if (!source_desc || !obj_desc) { return_ACPI_STATUS (AE_AML_NO_OPERAND); } if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_BUFFER_FIELD) { /* * If the buffer_field arguments have not been previously evaluated, * evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments (obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } } else if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) { /* * This is an SMBus write. We will bypass the entire field mechanism * and handoff the buffer directly to the handler. * * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE). */ if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) { ACPI_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n", acpi_ut_get_object_type_name (source_desc))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) { ACPI_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n", ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length)); return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); } buffer_desc = acpi_ut_create_buffer_object (ACPI_SMBUS_BUFFER_SIZE); if (!buffer_desc) { return_ACPI_STATUS (AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; ACPI_MEMCPY (buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE); /* Lock entire transaction if requested */ locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); /* * Perform the write (returns status and perhaps data in the same buffer) * Note: SMBus protocol type is passed in upper 16-bits of Function. */ status = acpi_ex_access_region (obj_desc, 0, (acpi_integer *) buffer, ACPI_WRITE | (obj_desc->field.attribute << 16)); acpi_ex_release_global_lock (locked); *result_desc = buffer_desc; return_ACPI_STATUS (status); } /* * Get a pointer to the data to be written */ switch (ACPI_GET_OBJECT_TYPE (source_desc)) { case ACPI_TYPE_INTEGER: buffer = &source_desc->integer.value; length = sizeof (source_desc->integer.value); break; case ACPI_TYPE_BUFFER: buffer = source_desc->buffer.pointer; length = source_desc->buffer.length; break; case ACPI_TYPE_STRING: buffer = source_desc->string.pointer; length = source_desc->string.length; break; default: return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } /* * We must have a buffer that is at least as long as the field * we are writing to. This is because individual fields are * indivisible and partial writes are not supported -- as per * the ACPI specification. */ new_buffer = NULL; required_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); if (length < required_length) { /* We need to create a new buffer */ new_buffer = ACPI_MEM_CALLOCATE (required_length); if (!new_buffer) { return_ACPI_STATUS (AE_NO_MEMORY); } /* * Copy the original data to the new buffer, starting * at Byte zero. All unused (upper) bytes of the * buffer will be 0. */ ACPI_MEMCPY ((char *) new_buffer, (char *) buffer, length); buffer = new_buffer; length = required_length; } ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n", source_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (source_desc)), ACPI_GET_OBJECT_TYPE (source_desc), buffer, length)); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n", obj_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)), ACPI_GET_OBJECT_TYPE (obj_desc), obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); /* Lock entire transaction if requested */ locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); /* Write to the field */ status = acpi_ex_insert_into_field (obj_desc, buffer, length); acpi_ex_release_global_lock (locked); /* Free temporary buffer if we used one */ if (new_buffer) { ACPI_MEM_FREE (new_buffer); } return_ACPI_STATUS (status); }