📄 exfldio.c
字号:
* FUNCTION: acpi_ex_extract_from_field * * PARAMETERS: *obj_desc - Field to be read * *Value - Where to store value * * RETURN: Status * * DESCRIPTION: Retrieve the 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; u32 field_datum_byte_offset; u32 buffer_datum_offset; acpi_integer previous_raw_datum = 0; acpi_integer this_raw_datum = 0; acpi_integer merged_datum = 0; u32 byte_field_length; u32 datum_count; u32 i; ACPI_FUNCTION_TRACE ("ex_extract_from_field"); /* * The field must fit within the caller's buffer */ byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); if (byte_field_length > buffer_length) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field size %X (bytes) too large for buffer (%X)\n", byte_field_length, buffer_length)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } /* Convert field byte count to datum count, round up if necessary */ datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); /* * If the field is not aligned on a datum boundary and does not * fit within a single datum, we must read an extra datum. * * We could just split the aligned and non-aligned cases since the * aligned case is so very simple, but this would require more code. */ if ((obj_desc->common_field.end_field_valid_bits != 0) && (!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) { datum_count++; } ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "byte_len %X, datum_len %X, byte_gran %X\n", byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); /* * Clear the caller's buffer (the whole buffer length as given) * This is very important, especially in the cases where the buffer * is longer than the size of the field. */ ACPI_MEMSET (buffer, 0, buffer_length); field_datum_byte_offset = 0; buffer_datum_offset= 0; /* Read the entire field */ for (i = 0; i < datum_count; i++) { status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, &this_raw_datum, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* We might actually be done if the request fits in one datum */ if ((datum_count == 1) && (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { /* 1) Shift the valid data bits down to start at bit 0 */ merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset); /* 2) Mask off any upper unused bits (bits not part of the field) */ if (obj_desc->common_field.end_buffer_valid_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); } /* Store the datum to the caller buffer */ acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); return_ACPI_STATUS (AE_OK); } /* Special handling for the last datum to ignore extra bits */ if ((i >= (datum_count -1)) && (obj_desc->common_field.end_field_valid_bits)) { /* * This is the last iteration of the loop. We need to clear * any unused bits (bits that are not part of this field) before * we store the final merged datum into the caller buffer. */ this_raw_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); } /* * Create the (possibly) merged datum to be stored to the caller buffer */ if (obj_desc->common_field.start_field_bit_offset == 0) { /* Field is not skewed and we can just copy the datum */ acpi_ex_set_buffer_datum (this_raw_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); buffer_datum_offset++; } else { /* Not aligned -- on the first iteration, just save the datum */ if (i != 0) { /* * Put together the appropriate bits of the two raw data to make a * single complete field datum * * 1) Normalize the first datum down to bit 0 */ merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); /* 2) Insert the second datum "above" the first datum */ merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits); acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); buffer_datum_offset++; } /* * Save the raw datum that was just acquired since it may contain bits * of the *next* field datum */ previous_raw_datum = this_raw_datum; } field_datum_byte_offset += obj_desc->common_field.access_byte_width; } /* For non-aligned case, there is one last datum to insert */ if (obj_desc->common_field.start_field_bit_offset != 0) { merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset); acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); } return_ACPI_STATUS (AE_OK);}/******************************************************************************* * * FUNCTION: acpi_ex_insert_into_field * * PARAMETERS: *obj_desc - Field to be set * Buffer - Value to store * * RETURN: Status * * DESCRIPTION: Store the value into the given field * ******************************************************************************/acpi_statusacpi_ex_insert_into_field ( union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length){ acpi_status status; u32 field_datum_byte_offset; u32 datum_offset; acpi_integer mask; acpi_integer merged_datum; acpi_integer previous_raw_datum; acpi_integer this_raw_datum; u32 byte_field_length; u32 datum_count; ACPI_FUNCTION_TRACE ("ex_insert_into_field"); /* * Incoming buffer must be at least as long as the field, we do not * allow "partial" field writes. We do not care if the buffer is * larger than the field, this typically happens when an integer is * written to a field that is actually smaller than an integer. */ byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( obj_desc->common_field.bit_length); if (buffer_length < byte_field_length) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n", buffer_length, byte_field_length)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( obj_desc->common_field.start_field_bit_offset + obj_desc->common_field.bit_length); /* Convert byte count to datum count, round up if necessary */ datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Bytes %X, Datums %X, byte_gran %X\n", byte_field_length, datum_count, obj_desc->common_field.access_byte_width)); /* * Break the request into up to three parts (similar to an I/O request): * 1) non-aligned part at start * 2) aligned part in middle * 3) non-aligned part at the end */ field_datum_byte_offset = 0; datum_offset= 0; /* Get a single datum from the caller's buffer */ acpi_ex_get_buffer_datum (&previous_raw_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, datum_offset); /* * Part1: * Write a partial field datum if field does not begin on a datum boundary * Note: The code in this section also handles the aligned case * * Construct Mask with 1 bits where the field is, 0 bits elsewhere * (Only the bottom 5 bits of bit_length are valid for a shift operation) * * Mask off bits that are "below" the field (if any) */ mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset); /* If the field fits in one datum, may need to mask upper bits */ if ((obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM) && obj_desc->common_field.end_field_valid_bits) { /* There are bits above the field, mask them off also */ mask &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); } /* Shift and mask the value into the field position */ merged_datum = (previous_raw_datum << obj_desc->common_field.start_field_bit_offset); merged_datum &= mask; /* Apply the update rule (if necessary) and write the datum to the field */ status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_datum_byte_offset); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* We just wrote the first datum */ datum_offset++; /* If the entire field fits within one datum, we are done. */ if ((datum_count == 1) && (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { return_ACPI_STATUS (AE_OK); } /* * Part2: * Write the aligned data. * * We don't need to worry about the update rule for these data, because * all of the bits in each datum are part of the field. * * The last datum must be special cased because it might contain bits * that are not part of the field -- therefore the "update rule" must be * applied in Part3 below. */ while (datum_offset < datum_count) { field_datum_byte_offset += obj_desc->common_field.access_byte_width; /* * Get the next raw buffer datum. It may contain bits of the previous * field datum */ acpi_ex_get_buffer_datum (&this_raw_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, datum_offset); /* Create the field datum based on the field alignment */ if (obj_desc->common_field.start_field_bit_offset != 0) { /* * Put together appropriate bits of the two raw buffer data to make * a single complete field datum */ merged_datum = (previous_raw_datum >> obj_desc->common_field.datum_valid_bits) | (this_raw_datum << obj_desc->common_field.start_field_bit_offset); } else { /* Field began aligned on datum boundary */ merged_datum = this_raw_datum; } /* * Special handling for the last datum if the field does NOT end on * a datum boundary. Update Rule must be applied to the bits outside * the field. */ datum_offset++; if ((datum_offset == datum_count) && (obj_desc->common_field.end_field_valid_bits)) { /* * If there are dangling non-aligned bits, perform one more merged write * Else - field is aligned at the end, no need for any more writes */ /* * Part3: * This is the last datum and the field does not end on a datum boundary. * Build the partial datum and write with the update rule. * * Mask off the unused bits above (after) the end-of-field */ mask = ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); merged_datum &= mask; /* Write the last datum with the update rule */ status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_datum_byte_offset); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } else { /* Normal (aligned) case -- write the completed datum */ status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, &merged_datum, ACPI_WRITE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } /* * Save the most recent datum since it may contain bits of the *next* * field datum. Update current byte offset. */ previous_raw_datum = this_raw_datum; } return_ACPI_STATUS (status);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -