exfldio.c
来自「linux 内核源代码」· C语言 代码 · 共 929 行 · 第 1/2 页
C
929 行
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, (acpi_integer) 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); } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "I/O to Data Register: ValuePtr %p\n", value)); if (read_write == ACPI_READ) { /* Read the datum from the data_register */ status = acpi_ex_extract_from_field(obj_desc->index_field. data_obj, value, sizeof(acpi_integer)); } else { /* Write the datum to the data_register */ status = acpi_ex_insert_into_field(obj_desc->index_field. data_obj, value, sizeof(acpi_integer)); } break; default: ACPI_ERROR((AE_INFO, "Wrong object type in field I/O %X", ACPI_GET_OBJECT_TYPE(obj_desc))); 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 %d\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 %d\n", ACPI_FORMAT_UINT64(*value), obj_desc->common_field. access_byte_width)); } } return_ACPI_STATUS(status);}/******************************************************************************* * * FUNCTION: acpi_ex_write_with_update_rule * * PARAMETERS: obj_desc - Field to be written * Mask - bitmask within field datum * field_value - Value to write * field_datum_byte_offset - Offset of datum within field * * RETURN: Status * * DESCRIPTION: Apply the field update rule to a field write * ******************************************************************************/acpi_statusacpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, acpi_integer mask, acpi_integer field_value, u32 field_datum_byte_offset){ acpi_status status = AE_OK; acpi_integer merged_value; acpi_integer current_value; ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask); /* Start with the new bits */ merged_value = field_value; /* If the mask is all ones, we don't need to worry about the update rule */ if (mask != ACPI_INTEGER_MAX) { /* Decode the update rule */ switch (obj_desc->common_field. field_flags & AML_FIELD_UPDATE_RULE_MASK) { case AML_FIELD_UPDATE_PRESERVE: /* * Check if update rule needs to be applied (not if mask is all * ones) The left shift drops the bits we want to ignore. */ if ((~mask << (ACPI_MUL_8(sizeof(mask)) - ACPI_MUL_8(obj_desc->common_field. access_byte_width))) != 0) { /* * Read the current contents of the byte/word/dword containing * the field, and merge with the new field value. */ status = acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset, ¤t_value, ACPI_READ); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } merged_value |= (current_value & ~mask); } break; case AML_FIELD_UPDATE_WRITE_AS_ONES: /* Set positions outside the field to all ones */ merged_value |= ~mask; break; case AML_FIELD_UPDATE_WRITE_AS_ZEROS: /* Set positions outside the field to all zeros */ merged_value &= mask; break; default: ACPI_ERROR((AE_INFO, "Unknown UpdateRule value: %X", (obj_desc->common_field. field_flags & AML_FIELD_UPDATE_RULE_MASK))); return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", ACPI_FORMAT_UINT64(mask), field_datum_byte_offset, obj_desc->common_field.access_byte_width, ACPI_FORMAT_UINT64(field_value), ACPI_FORMAT_UINT64(merged_value))); /* Write the merged value */ status = acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset, &merged_value, ACPI_WRITE); return_ACPI_STATUS(status);}/******************************************************************************* * * FUNCTION: acpi_ex_extract_from_field * * PARAMETERS: obj_desc - Field to be read * Buffer - Where to store the field data * buffer_length - Length of Buffer * * RETURN: Status * * DESCRIPTION: Retrieve the current value of the given field * ******************************************************************************/acpi_statusacpi_ex_extract_from_field(union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length){ acpi_status status; acpi_integer raw_datum; acpi_integer merged_datum; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; u32 datum_count; u32 field_datum_count; u32 i; ACPI_FUNCTION_TRACE(ex_extract_from_field); /* Validate target buffer and clear it */ if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) { ACPI_ERROR((AE_INFO, "Field size %X (bits) is too large for buffer (%X)", obj_desc->common_field.bit_length, buffer_length)); return_ACPI_STATUS(AE_BUFFER_OVERFLOW); } ACPI_MEMSET(buffer, 0, buffer_length); /* Compute the number of datums (access width data items) */ datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, obj_desc->common_field.access_bit_width); field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + obj_desc->common_field. start_field_bit_offset, obj_desc->common_field. access_bit_width); /* Priming read from the field */ status = acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum, ACPI_READ); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; /* Read the rest of the field */ for (i = 1; i < field_datum_count; i++) { /* Get next input datum from the field */ field_offset += obj_desc->common_field.access_byte_width; status = acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum, ACPI_READ); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Merge with previous datum if necessary. * * Note: Before the shift, check if the shift value will be larger than * the integer size. If so, there is no need to perform the operation. * This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ if ((obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset) < ACPI_INTEGER_BIT_SIZE) { merged_datum |= raw_datum << (obj_desc->common_field. access_bit_width - obj_desc->common_field. start_field_bit_offset); } if (i == datum_count) { break; } /* Write merged datum to target buffer */ ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); buffer_offset += obj_desc->common_field.access_byte_width; merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; } /* Mask off any extra bits in the last datum */ buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width; if (buffer_tail_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits); } /* Write the last datum to the buffer */ ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); return_ACPI_STATUS(AE_OK);}/******************************************************************************* * * FUNCTION: acpi_ex_insert_into_field * * PARAMETERS: obj_desc - Field to be written * Buffer - Data to be written * buffer_length - Length of Buffer * * RETURN: Status * * DESCRIPTION: Store the Buffer contents into the given field * ******************************************************************************/acpi_statusacpi_ex_insert_into_field(union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length){ acpi_status status; acpi_integer mask; acpi_integer width_mask; acpi_integer merged_datum; acpi_integer raw_datum = 0; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; u32 datum_count; u32 field_datum_count; u32 i; ACPI_FUNCTION_TRACE(ex_insert_into_field); /* Validate input buffer */ if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) { ACPI_ERROR((AE_INFO, "Field size %X (bits) is too large for buffer (%X)", obj_desc->common_field.bit_length, buffer_length)); return_ACPI_STATUS(AE_BUFFER_OVERFLOW); } /* * Create the bitmasks used for bit insertion. * Note: This if/else is used to bypass compiler differences with the * shift operator */ if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) { width_mask = ACPI_INTEGER_MAX; } else { width_mask = ACPI_MASK_BITS_ABOVE(obj_desc->common_field. access_bit_width); } mask = width_mask & ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset); /* Compute the number of datums (access width data items) */ datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, obj_desc->common_field.access_bit_width); field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + obj_desc->common_field. start_field_bit_offset, obj_desc->common_field. access_bit_width); /* Get initial Datum from the input buffer */ ACPI_MEMCPY(&raw_datum, buffer, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset; /* Write the entire field */ for (i = 1; i < field_datum_count; i++) { /* Write merged datum to the target field */ merged_datum &= mask; status = acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum, field_offset); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } field_offset += obj_desc->common_field.access_byte_width; /* * Start new output datum by merging with previous input datum * if necessary. * * Note: Before the shift, check if the shift value will be larger than * the integer size. If so, there is no need to perform the operation. * This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ if ((obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset) < ACPI_INTEGER_BIT_SIZE) { merged_datum = raw_datum >> (obj_desc->common_field. access_bit_width - obj_desc->common_field. start_field_bit_offset); } else { merged_datum = 0; } mask = width_mask; if (i == datum_count) { break; } /* Get the next input datum from the buffer */ buffer_offset += obj_desc->common_field.access_byte_width; ACPI_MEMCPY(&raw_datum, ((char *)buffer) + buffer_offset, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); merged_datum |= raw_datum << obj_desc->common_field.start_field_bit_offset; } /* Mask off any extra bits in the last datum */ buffer_tail_bits = (obj_desc->common_field.bit_length + obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width; if (buffer_tail_bits) { mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits); } /* Write the last datum to the field */ merged_datum &= mask; status = acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum, field_offset); return_ACPI_STATUS(status);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?