diff options
Diffstat (limited to 'drivers/acpi/acpica/exfield.c')
| -rw-r--r-- | drivers/acpi/acpica/exfield.c | 108 | 
1 files changed, 99 insertions, 9 deletions
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index c2a65aaf29a..12878e1982f 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@   *****************************************************************************/  /* - * Copyright (C) 2000 - 2013, Intel Corp. + * Copyright (C) 2000 - 2014, Intel Corp.   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -45,10 +45,71 @@  #include "accommon.h"  #include "acdispat.h"  #include "acinterp.h" +#include "amlcode.h"  #define _COMPONENT          ACPI_EXECUTER  ACPI_MODULE_NAME("exfield") +/* Local prototypes */ +static u32 +acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length); + +/******************************************************************************* + * + * FUNCTION:    acpi_get_serial_access_bytes + * + * PARAMETERS:  accessor_type   - The type of the protocol indicated by region + *                                field access attributes + *              access_length   - The access length of the region field + * + * RETURN:      Decoded access length + * + * DESCRIPTION: This routine returns the length of the generic_serial_bus + *              protocol bytes + * + ******************************************************************************/ + +static u32 +acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length) +{ +	u32 length; + +	switch (accessor_type) { +	case AML_FIELD_ATTRIB_QUICK: + +		length = 0; +		break; + +	case AML_FIELD_ATTRIB_SEND_RCV: +	case AML_FIELD_ATTRIB_BYTE: + +		length = 1; +		break; + +	case AML_FIELD_ATTRIB_WORD: +	case AML_FIELD_ATTRIB_WORD_CALL: + +		length = 2; +		break; + +	case AML_FIELD_ATTRIB_MULTIBYTE: +	case AML_FIELD_ATTRIB_RAW_BYTES: +	case AML_FIELD_ATTRIB_RAW_PROCESS: + +		length = access_length; +		break; + +	case AML_FIELD_ATTRIB_BLOCK: +	case AML_FIELD_ATTRIB_BLOCK_CALL: +	default: + +		length = ACPI_GSBUS_BUFFER_SIZE; +		break; +	} + +	return (length); +} +  /*******************************************************************************   *   * FUNCTION:    acpi_ex_read_data_from_field @@ -63,8 +124,9 @@ ACPI_MODULE_NAME("exfield")   *              Buffer, depending on the size of the field.   *   ******************************************************************************/ +  acpi_status -acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, +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)  { @@ -73,6 +135,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,  	acpi_size length;  	void *buffer;  	u32 function; +	u16 accessor_type;  	ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); @@ -116,9 +179,22 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,  			    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); +			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 modeled generic_serial_bus data buffer: +			 * typedef struct { +			 *     BYTEStatus; // Byte 0 of the data buffer +			 *     BYTELength; // Byte 1 of the data buffer +			 *     BYTE[x-1]Data; // Bytes 2-x of the arbitrary length data buffer, +			 * } +			 */ +			length += 2; +			function = ACPI_READ | (accessor_type << 16);  		} else {	/* IPMI */  			length = ACPI_IPMI_BUFFER_SIZE; @@ -197,7 +273,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,  	status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);  	acpi_ex_release_global_lock(obj_desc->common_field.field_flags); -      exit: +exit:  	if (ACPI_FAILURE(status)) {  		acpi_ut_remove_reference(buffer_desc);  	} else { @@ -231,6 +307,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,  	void *buffer;  	union acpi_operand_object *buffer_desc;  	u32 function; +	u16 accessor_type;  	ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); @@ -284,9 +361,22 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,  			    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); +			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 modeled generic_serial_bus data buffer: +			 * typedef struct { +			 *     BYTEStatus; // Byte 0 of the data buffer +			 *     BYTELength; // Byte 1 of the data buffer +			 *     BYTE[x-1]Data; // Bytes 2-x of the arbitrary length data buffer, +			 * } +			 */ +			length += 2; +			function = ACPI_WRITE | (accessor_type << 16);  		} else {	/* IPMI */  			length = ACPI_IPMI_BUFFER_SIZE;  | 
