Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /******************************************************************************
  2.  *
  3.  * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
  4.  *
  5.  *****************************************************************************/
  6.  
  7. /*
  8.  * Copyright (C) 2000 - 2015, Intel Corp.
  9.  * All rights reserved.
  10.  *
  11.  * Redistribution and use in source and binary forms, with or without
  12.  * modification, are permitted provided that the following conditions
  13.  * are met:
  14.  * 1. Redistributions of source code must retain the above copyright
  15.  *    notice, this list of conditions, and the following disclaimer,
  16.  *    without modification.
  17.  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18.  *    substantially similar to the "NO WARRANTY" disclaimer below
  19.  *    ("Disclaimer") and any redistribution must be conditioned upon
  20.  *    including a substantially similar Disclaimer requirement for further
  21.  *    binary redistribution.
  22.  * 3. Neither the names of the above-listed copyright holders nor the names
  23.  *    of any contributors may be used to endorse or promote products derived
  24.  *    from this software without specific prior written permission.
  25.  *
  26.  * Alternatively, this software may be distributed under the terms of the
  27.  * GNU General Public License ("GPL") version 2 as published by the Free
  28.  * Software Foundation.
  29.  *
  30.  * NO WARRANTY
  31.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  34.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35.  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  40.  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41.  * POSSIBILITY OF SUCH DAMAGES.
  42.  */
  43.  
  44. #include <acpi/acpi.h>
  45. #include "accommon.h"
  46. #include "acdispat.h"
  47. #include "acinterp.h"
  48. #include "amlcode.h"
  49.  
  50. #define _COMPONENT          ACPI_EXECUTER
  51. ACPI_MODULE_NAME("exfield")
  52.  
  53. /* Local prototypes */
  54. static u32
  55. acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length);
  56.  
  57. /*******************************************************************************
  58.  *
  59.  * FUNCTION:    acpi_ex_get_serial_access_length
  60.  *
  61.  * PARAMETERS:  accessor_type   - The type of the protocol indicated by region
  62.  *                                field access attributes
  63.  *              access_length   - The access length of the region field
  64.  *
  65.  * RETURN:      Decoded access length
  66.  *
  67.  * DESCRIPTION: This routine returns the length of the generic_serial_bus
  68.  *              protocol bytes
  69.  *
  70.  ******************************************************************************/
  71.  
  72. static u32
  73. acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length)
  74. {
  75.         u32 length;
  76.  
  77.         switch (accessor_type) {
  78.         case AML_FIELD_ATTRIB_QUICK:
  79.  
  80.                 length = 0;
  81.                 break;
  82.  
  83.         case AML_FIELD_ATTRIB_SEND_RCV:
  84.         case AML_FIELD_ATTRIB_BYTE:
  85.  
  86.                 length = 1;
  87.                 break;
  88.  
  89.         case AML_FIELD_ATTRIB_WORD:
  90.         case AML_FIELD_ATTRIB_WORD_CALL:
  91.  
  92.                 length = 2;
  93.                 break;
  94.  
  95.         case AML_FIELD_ATTRIB_MULTIBYTE:
  96.         case AML_FIELD_ATTRIB_RAW_BYTES:
  97.         case AML_FIELD_ATTRIB_RAW_PROCESS:
  98.  
  99.                 length = access_length;
  100.                 break;
  101.  
  102.         case AML_FIELD_ATTRIB_BLOCK:
  103.         case AML_FIELD_ATTRIB_BLOCK_CALL:
  104.         default:
  105.  
  106.                 length = ACPI_GSBUS_BUFFER_SIZE - 2;
  107.                 break;
  108.         }
  109.  
  110.         return (length);
  111. }
  112.  
  113. /*******************************************************************************
  114.  *
  115.  * FUNCTION:    acpi_ex_read_data_from_field
  116.  *
  117.  * PARAMETERS:  walk_state          - Current execution state
  118.  *              obj_desc            - The named field
  119.  *              ret_buffer_desc     - Where the return data object is stored
  120.  *
  121.  * RETURN:      Status
  122.  *
  123.  * DESCRIPTION: Read from a named field. Returns either an Integer or a
  124.  *              Buffer, depending on the size of the field.
  125.  *
  126.  ******************************************************************************/
  127.  
  128. acpi_status
  129. acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state,
  130.                              union acpi_operand_object *obj_desc,
  131.                              union acpi_operand_object **ret_buffer_desc)
  132. {
  133.         acpi_status status;
  134.         union acpi_operand_object *buffer_desc;
  135.         acpi_size length;
  136.         void *buffer;
  137.         u32 function;
  138.         u16 accessor_type;
  139.  
  140.         ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
  141.  
  142.         /* Parameter validation */
  143.  
  144.         if (!obj_desc) {
  145.                 return_ACPI_STATUS(AE_AML_NO_OPERAND);
  146.         }
  147.         if (!ret_buffer_desc) {
  148.                 return_ACPI_STATUS(AE_BAD_PARAMETER);
  149.         }
  150.  
  151.         if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
  152.                 /*
  153.                  * If the buffer_field arguments have not been previously evaluated,
  154.                  * evaluate them now and save the results.
  155.                  */
  156.                 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
  157.                         status = acpi_ds_get_buffer_field_arguments(obj_desc);
  158.                         if (ACPI_FAILURE(status)) {
  159.                                 return_ACPI_STATUS(status);
  160.                         }
  161.                 }
  162.         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
  163.                    (obj_desc->field.region_obj->region.space_id ==
  164.                     ACPI_ADR_SPACE_SMBUS
  165.                     || obj_desc->field.region_obj->region.space_id ==
  166.                     ACPI_ADR_SPACE_GSBUS
  167.                     || obj_desc->field.region_obj->region.space_id ==
  168.                     ACPI_ADR_SPACE_IPMI)) {
  169.                 /*
  170.                  * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
  171.                  * the data and then directly access the region handler.
  172.                  *
  173.                  * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
  174.                  */
  175.                 if (obj_desc->field.region_obj->region.space_id ==
  176.                     ACPI_ADR_SPACE_SMBUS) {
  177.                         length = ACPI_SMBUS_BUFFER_SIZE;
  178.                         function =
  179.                             ACPI_READ | (obj_desc->field.attribute << 16);
  180.                 } else if (obj_desc->field.region_obj->region.space_id ==
  181.                            ACPI_ADR_SPACE_GSBUS) {
  182.                         accessor_type = obj_desc->field.attribute;
  183.                         length = acpi_ex_get_serial_access_length(accessor_type,
  184.                                                                   obj_desc->
  185.                                                                   field.
  186.                                                                   access_length);
  187.  
  188.                         /*
  189.                          * Add additional 2 bytes for the generic_serial_bus data buffer:
  190.                          *
  191.                          *     Status;      (Byte 0 of the data buffer)
  192.                          *     Length;      (Byte 1 of the data buffer)
  193.                          *     Data[x-1];   (Bytes 2-x of the arbitrary length data buffer)
  194.                          */
  195.                         length += 2;
  196.                         function = ACPI_READ | (accessor_type << 16);
  197.                 } else {        /* IPMI */
  198.  
  199.                         length = ACPI_IPMI_BUFFER_SIZE;
  200.                         function = ACPI_READ;
  201.                 }
  202.  
  203.                 buffer_desc = acpi_ut_create_buffer_object(length);
  204.                 if (!buffer_desc) {
  205.                         return_ACPI_STATUS(AE_NO_MEMORY);
  206.                 }
  207.  
  208.                 /* Lock entire transaction if requested */
  209.  
  210.                 acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  211.  
  212.                 /* Call the region handler for the read */
  213.  
  214.                 status = acpi_ex_access_region(obj_desc, 0,
  215.                                                ACPI_CAST_PTR(u64,
  216.                                                              buffer_desc->
  217.                                                              buffer.pointer),
  218.                                                function);
  219.                 acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  220.                 goto exit;
  221.         }
  222.  
  223.         /*
  224.          * Allocate a buffer for the contents of the field.
  225.          *
  226.          * If the field is larger than the current integer width, create
  227.          * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
  228.          * the use of arithmetic operators on the returned value if the
  229.          * field size is equal or smaller than an Integer.
  230.          *
  231.          * Note: Field.length is in bits.
  232.          */
  233.         length =
  234.             (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
  235.         if (length > acpi_gbl_integer_byte_width) {
  236.  
  237.                 /* Field is too large for an Integer, create a Buffer instead */
  238.  
  239.                 buffer_desc = acpi_ut_create_buffer_object(length);
  240.                 if (!buffer_desc) {
  241.                         return_ACPI_STATUS(AE_NO_MEMORY);
  242.                 }
  243.                 buffer = buffer_desc->buffer.pointer;
  244.         } else {
  245.                 /* Field will fit within an Integer (normal case) */
  246.  
  247.                 buffer_desc = acpi_ut_create_integer_object((u64) 0);
  248.                 if (!buffer_desc) {
  249.                         return_ACPI_STATUS(AE_NO_MEMORY);
  250.                 }
  251.  
  252.                 length = acpi_gbl_integer_byte_width;
  253.                 buffer = &buffer_desc->integer.value;
  254.         }
  255.  
  256.         if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
  257.             (obj_desc->field.region_obj->region.space_id ==
  258.              ACPI_ADR_SPACE_GPIO)) {
  259.                 /*
  260.                  * For GPIO (general_purpose_io), the Address will be the bit offset
  261.                  * from the previous Connection() operator, making it effectively a
  262.                  * pin number index. The bit_length is the length of the field, which
  263.                  * is thus the number of pins.
  264.                  */
  265.                 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
  266.                                   "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
  267.                                   obj_desc->field.pin_number_index,
  268.                                   obj_desc->field.bit_length));
  269.  
  270.                 /* Lock entire transaction if requested */
  271.  
  272.                 acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  273.  
  274.                 /* Perform the write */
  275.  
  276.                 status = acpi_ex_access_region(obj_desc, 0,
  277.                                                (u64 *)buffer, ACPI_READ);
  278.                 acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  279.                 if (ACPI_FAILURE(status)) {
  280.                         acpi_ut_remove_reference(buffer_desc);
  281.                 } else {
  282.                         *ret_buffer_desc = buffer_desc;
  283.                 }
  284.                 return_ACPI_STATUS(status);
  285.         }
  286.  
  287.         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
  288.                           "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
  289.                           obj_desc, obj_desc->common.type, buffer,
  290.                           (u32) length));
  291.         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
  292.                           "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
  293.                           obj_desc->common_field.bit_length,
  294.                           obj_desc->common_field.start_field_bit_offset,
  295.                           obj_desc->common_field.base_byte_offset));
  296.  
  297.         /* Lock entire transaction if requested */
  298.  
  299.         acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  300.  
  301.         /* Read from the field */
  302.  
  303.         status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
  304.         acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  305.  
  306. exit:
  307.         if (ACPI_FAILURE(status)) {
  308.                 acpi_ut_remove_reference(buffer_desc);
  309.         } else {
  310.                 *ret_buffer_desc = buffer_desc;
  311.         }
  312.  
  313.         return_ACPI_STATUS(status);
  314. }
  315.  
  316. /*******************************************************************************
  317.  *
  318.  * FUNCTION:    acpi_ex_write_data_to_field
  319.  *
  320.  * PARAMETERS:  source_desc         - Contains data to write
  321.  *              obj_desc            - The named field
  322.  *              result_desc         - Where the return value is returned, if any
  323.  *
  324.  * RETURN:      Status
  325.  *
  326.  * DESCRIPTION: Write to a named field
  327.  *
  328.  ******************************************************************************/
  329.  
  330. acpi_status
  331. acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
  332.                             union acpi_operand_object *obj_desc,
  333.                             union acpi_operand_object **result_desc)
  334. {
  335.         acpi_status status;
  336.         u32 length;
  337.         void *buffer;
  338.         union acpi_operand_object *buffer_desc;
  339.         u32 function;
  340.         u16 accessor_type;
  341.  
  342.         ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
  343.  
  344.         /* Parameter validation */
  345.  
  346.         if (!source_desc || !obj_desc) {
  347.                 return_ACPI_STATUS(AE_AML_NO_OPERAND);
  348.         }
  349.  
  350.         if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
  351.                 /*
  352.                  * If the buffer_field arguments have not been previously evaluated,
  353.                  * evaluate them now and save the results.
  354.                  */
  355.                 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
  356.                         status = acpi_ds_get_buffer_field_arguments(obj_desc);
  357.                         if (ACPI_FAILURE(status)) {
  358.                                 return_ACPI_STATUS(status);
  359.                         }
  360.                 }
  361.         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
  362.                    (obj_desc->field.region_obj->region.space_id ==
  363.                     ACPI_ADR_SPACE_SMBUS
  364.                     || obj_desc->field.region_obj->region.space_id ==
  365.                     ACPI_ADR_SPACE_GSBUS
  366.                     || obj_desc->field.region_obj->region.space_id ==
  367.                     ACPI_ADR_SPACE_IPMI)) {
  368.                 /*
  369.                  * This is an SMBus, GSBus or IPMI write. We will bypass the entire field
  370.                  * mechanism and handoff the buffer directly to the handler. For
  371.                  * these address spaces, the buffer is bi-directional; on a write,
  372.                  * return data is returned in the same buffer.
  373.                  *
  374.                  * Source must be a buffer of sufficient size:
  375.                  * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
  376.                  *
  377.                  * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function
  378.                  */
  379.                 if (source_desc->common.type != ACPI_TYPE_BUFFER) {
  380.                         ACPI_ERROR((AE_INFO,
  381.                                     "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s",
  382.                                     acpi_ut_get_object_type_name(source_desc)));
  383.  
  384.                         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
  385.                 }
  386.  
  387.                 if (obj_desc->field.region_obj->region.space_id ==
  388.                     ACPI_ADR_SPACE_SMBUS) {
  389.                         length = ACPI_SMBUS_BUFFER_SIZE;
  390.                         function =
  391.                             ACPI_WRITE | (obj_desc->field.attribute << 16);
  392.                 } else if (obj_desc->field.region_obj->region.space_id ==
  393.                            ACPI_ADR_SPACE_GSBUS) {
  394.                         accessor_type = obj_desc->field.attribute;
  395.                         length = acpi_ex_get_serial_access_length(accessor_type,
  396.                                                                   obj_desc->
  397.                                                                   field.
  398.                                                                   access_length);
  399.  
  400.                         /*
  401.                          * Add additional 2 bytes for the generic_serial_bus data buffer:
  402.                          *
  403.                          *     Status;      (Byte 0 of the data buffer)
  404.                          *     Length;      (Byte 1 of the data buffer)
  405.                          *     Data[x-1];   (Bytes 2-x of the arbitrary length data buffer)
  406.                          */
  407.                         length += 2;
  408.                         function = ACPI_WRITE | (accessor_type << 16);
  409.                 } else {        /* IPMI */
  410.  
  411.                         length = ACPI_IPMI_BUFFER_SIZE;
  412.                         function = ACPI_WRITE;
  413.                 }
  414.  
  415.                 if (source_desc->buffer.length < length) {
  416.                         ACPI_ERROR((AE_INFO,
  417.                                     "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u",
  418.                                     length, source_desc->buffer.length));
  419.  
  420.                         return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
  421.                 }
  422.  
  423.                 /* Create the bi-directional buffer */
  424.  
  425.                 buffer_desc = acpi_ut_create_buffer_object(length);
  426.                 if (!buffer_desc) {
  427.                         return_ACPI_STATUS(AE_NO_MEMORY);
  428.                 }
  429.  
  430.                 buffer = buffer_desc->buffer.pointer;
  431.                 memcpy(buffer, source_desc->buffer.pointer, length);
  432.  
  433.                 /* Lock entire transaction if requested */
  434.  
  435.                 acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  436.  
  437.                 /*
  438.                  * Perform the write (returns status and perhaps data in the
  439.                  * same buffer)
  440.                  */
  441.                 status = acpi_ex_access_region(obj_desc, 0,
  442.                                                (u64 *) buffer, function);
  443.                 acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  444.  
  445.                 *result_desc = buffer_desc;
  446.                 return_ACPI_STATUS(status);
  447.         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
  448.                    (obj_desc->field.region_obj->region.space_id ==
  449.                     ACPI_ADR_SPACE_GPIO)) {
  450.                 /*
  451.                  * For GPIO (general_purpose_io), we will bypass the entire field
  452.                  * mechanism and handoff the bit address and bit width directly to
  453.                  * the handler. The Address will be the bit offset
  454.                  * from the previous Connection() operator, making it effectively a
  455.                  * pin number index. The bit_length is the length of the field, which
  456.                  * is thus the number of pins.
  457.                  */
  458.                 if (source_desc->common.type != ACPI_TYPE_INTEGER) {
  459.                         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
  460.                 }
  461.  
  462.                 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
  463.                                   "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X  [TO]:  Pin %u Bits %u\n",
  464.                                   acpi_ut_get_type_name(source_desc->common.
  465.                                                         type),
  466.                                   source_desc->common.type,
  467.                                   (u32)source_desc->integer.value,
  468.                                   obj_desc->field.pin_number_index,
  469.                                   obj_desc->field.bit_length));
  470.  
  471.                 buffer = &source_desc->integer.value;
  472.  
  473.                 /* Lock entire transaction if requested */
  474.  
  475.                 acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  476.  
  477.                 /* Perform the write */
  478.  
  479.                 status = acpi_ex_access_region(obj_desc, 0,
  480.                                                (u64 *)buffer, ACPI_WRITE);
  481.                 acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  482.                 return_ACPI_STATUS(status);
  483.         }
  484.  
  485.         /* Get a pointer to the data to be written */
  486.  
  487.         switch (source_desc->common.type) {
  488.         case ACPI_TYPE_INTEGER:
  489.  
  490.                 buffer = &source_desc->integer.value;
  491.                 length = sizeof(source_desc->integer.value);
  492.                 break;
  493.  
  494.         case ACPI_TYPE_BUFFER:
  495.  
  496.                 buffer = source_desc->buffer.pointer;
  497.                 length = source_desc->buffer.length;
  498.                 break;
  499.  
  500.         case ACPI_TYPE_STRING:
  501.  
  502.                 buffer = source_desc->string.pointer;
  503.                 length = source_desc->string.length;
  504.                 break;
  505.  
  506.         default:
  507.  
  508.                 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
  509.         }
  510.  
  511.         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
  512.                           "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
  513.                           source_desc,
  514.                           acpi_ut_get_type_name(source_desc->common.type),
  515.                           source_desc->common.type, buffer, length));
  516.  
  517.         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
  518.                           "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
  519.                           obj_desc,
  520.                           acpi_ut_get_type_name(obj_desc->common.type),
  521.                           obj_desc->common.type,
  522.                           obj_desc->common_field.bit_length,
  523.                           obj_desc->common_field.start_field_bit_offset,
  524.                           obj_desc->common_field.base_byte_offset));
  525.  
  526.         /* Lock entire transaction if requested */
  527.  
  528.         acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  529.  
  530.         /* Write to the field */
  531.  
  532.         status = acpi_ex_insert_into_field(obj_desc, buffer, length);
  533.         acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  534.  
  535.         return_ACPI_STATUS(status);
  536. }
  537.