1 /******************************************************************************
3 * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2011, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
47 #include <contrib/dev/acpica/include/acpi.h>
48 #include <contrib/dev/acpica/include/accommon.h>
49 #include <contrib/dev/acpica/include/acdispat.h>
50 #include <contrib/dev/acpica/include/acinterp.h>
53 #define _COMPONENT ACPI_EXECUTER
54 ACPI_MODULE_NAME ("exfield")
57 /*******************************************************************************
59 * FUNCTION: AcpiExReadDataFromField
61 * PARAMETERS: WalkState - Current execution state
62 * ObjDesc - The named field
63 * RetBufferDesc - Where the return data object is stored
67 * DESCRIPTION: Read from a named field. Returns either an Integer or a
68 * Buffer, depending on the size of the field.
70 ******************************************************************************/
73 AcpiExReadDataFromField (
74 ACPI_WALK_STATE *WalkState,
75 ACPI_OPERAND_OBJECT *ObjDesc,
76 ACPI_OPERAND_OBJECT **RetBufferDesc)
79 ACPI_OPERAND_OBJECT *BufferDesc;
85 ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
88 /* Parameter validation */
92 return_ACPI_STATUS (AE_AML_NO_OPERAND);
96 return_ACPI_STATUS (AE_BAD_PARAMETER);
99 if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
102 * If the BufferField arguments have not been previously evaluated,
103 * evaluate them now and save the results.
105 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
107 Status = AcpiDsGetBufferFieldArguments (ObjDesc);
108 if (ACPI_FAILURE (Status))
110 return_ACPI_STATUS (Status);
114 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
115 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
116 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
119 * This is an SMBus or IPMI read. We must create a buffer to hold
120 * the data and then directly access the region handler.
122 * Note: Smbus protocol value is passed in upper 16-bits of Function
124 if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
126 Length = ACPI_SMBUS_BUFFER_SIZE;
127 Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
131 Length = ACPI_IPMI_BUFFER_SIZE;
132 Function = ACPI_READ;
135 BufferDesc = AcpiUtCreateBufferObject (Length);
138 return_ACPI_STATUS (AE_NO_MEMORY);
141 /* Lock entire transaction if requested */
143 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
145 /* Call the region handler for the read */
147 Status = AcpiExAccessRegion (ObjDesc, 0,
148 ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer),
150 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
155 * Allocate a buffer for the contents of the field.
157 * If the field is larger than the current integer width, create
158 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
159 * the use of arithmetic operators on the returned value if the
160 * field size is equal or smaller than an Integer.
162 * Note: Field.length is in bits.
164 Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength);
165 if (Length > AcpiGbl_IntegerByteWidth)
167 /* Field is too large for an Integer, create a Buffer instead */
169 BufferDesc = AcpiUtCreateBufferObject (Length);
172 return_ACPI_STATUS (AE_NO_MEMORY);
174 Buffer = BufferDesc->Buffer.Pointer;
178 /* Field will fit within an Integer (normal case) */
180 BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
183 return_ACPI_STATUS (AE_NO_MEMORY);
186 Length = AcpiGbl_IntegerByteWidth;
187 Buffer = &BufferDesc->Integer.Value;
190 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
191 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
192 ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
193 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
194 "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
195 ObjDesc->CommonField.BitLength,
196 ObjDesc->CommonField.StartFieldBitOffset,
197 ObjDesc->CommonField.BaseByteOffset));
199 /* Lock entire transaction if requested */
201 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
203 /* Read from the field */
205 Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
206 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
210 if (ACPI_FAILURE (Status))
212 AcpiUtRemoveReference (BufferDesc);
216 *RetBufferDesc = BufferDesc;
219 return_ACPI_STATUS (Status);
223 /*******************************************************************************
225 * FUNCTION: AcpiExWriteDataToField
227 * PARAMETERS: SourceDesc - Contains data to write
228 * ObjDesc - The named field
229 * ResultDesc - Where the return value is returned, if any
233 * DESCRIPTION: Write to a named field
235 ******************************************************************************/
238 AcpiExWriteDataToField (
239 ACPI_OPERAND_OBJECT *SourceDesc,
240 ACPI_OPERAND_OBJECT *ObjDesc,
241 ACPI_OPERAND_OBJECT **ResultDesc)
246 ACPI_OPERAND_OBJECT *BufferDesc;
250 ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
253 /* Parameter validation */
255 if (!SourceDesc || !ObjDesc)
257 return_ACPI_STATUS (AE_AML_NO_OPERAND);
260 if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
263 * If the BufferField arguments have not been previously evaluated,
264 * evaluate them now and save the results.
266 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
268 Status = AcpiDsGetBufferFieldArguments (ObjDesc);
269 if (ACPI_FAILURE (Status))
271 return_ACPI_STATUS (Status);
275 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
276 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
277 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
280 * This is an SMBus or IPMI write. We will bypass the entire field
281 * mechanism and handoff the buffer directly to the handler. For
282 * these address spaces, the buffer is bi-directional; on a write,
283 * return data is returned in the same buffer.
285 * Source must be a buffer of sufficient size:
286 * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE.
288 * Note: SMBus protocol type is passed in upper 16-bits of Function
290 if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
292 ACPI_ERROR ((AE_INFO,
293 "SMBus or IPMI write requires Buffer, found type %s",
294 AcpiUtGetObjectTypeName (SourceDesc)));
296 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
299 if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
301 Length = ACPI_SMBUS_BUFFER_SIZE;
302 Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
306 Length = ACPI_IPMI_BUFFER_SIZE;
307 Function = ACPI_WRITE;
310 if (SourceDesc->Buffer.Length < Length)
312 ACPI_ERROR ((AE_INFO,
313 "SMBus or IPMI write requires Buffer of length %u, found length %u",
314 Length, SourceDesc->Buffer.Length));
316 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
319 /* Create the bi-directional buffer */
321 BufferDesc = AcpiUtCreateBufferObject (Length);
324 return_ACPI_STATUS (AE_NO_MEMORY);
327 Buffer = BufferDesc->Buffer.Pointer;
328 ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length);
330 /* Lock entire transaction if requested */
332 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
335 * Perform the write (returns status and perhaps data in the
338 Status = AcpiExAccessRegion (ObjDesc, 0,
339 (UINT64 *) Buffer, Function);
340 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
342 *ResultDesc = BufferDesc;
343 return_ACPI_STATUS (Status);
346 /* Get a pointer to the data to be written */
348 switch (SourceDesc->Common.Type)
350 case ACPI_TYPE_INTEGER:
351 Buffer = &SourceDesc->Integer.Value;
352 Length = sizeof (SourceDesc->Integer.Value);
355 case ACPI_TYPE_BUFFER:
356 Buffer = SourceDesc->Buffer.Pointer;
357 Length = SourceDesc->Buffer.Length;
360 case ACPI_TYPE_STRING:
361 Buffer = SourceDesc->String.Pointer;
362 Length = SourceDesc->String.Length;
366 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
369 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
370 "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
371 SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
372 SourceDesc->Common.Type, Buffer, Length));
374 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
375 "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
376 ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
377 ObjDesc->Common.Type,
378 ObjDesc->CommonField.BitLength,
379 ObjDesc->CommonField.StartFieldBitOffset,
380 ObjDesc->CommonField.BaseByteOffset));
382 /* Lock entire transaction if requested */
384 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
386 /* Write to the field */
388 Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
389 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
391 return_ACPI_STATUS (Status);