1433d6423SLionel Sambuc /******************************************************************************
2433d6423SLionel Sambuc *
3433d6423SLionel Sambuc * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
4433d6423SLionel Sambuc *
5433d6423SLionel Sambuc *****************************************************************************/
6433d6423SLionel Sambuc
7*29492bb7SDavid van Moolenbroek /*
8*29492bb7SDavid van Moolenbroek * Copyright (C) 2000 - 2014, Intel Corp.
9433d6423SLionel Sambuc * All rights reserved.
10433d6423SLionel Sambuc *
11*29492bb7SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
12*29492bb7SDavid van Moolenbroek * modification, are permitted provided that the following conditions
13*29492bb7SDavid van Moolenbroek * are met:
14*29492bb7SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
15*29492bb7SDavid van Moolenbroek * notice, this list of conditions, and the following disclaimer,
16*29492bb7SDavid van Moolenbroek * without modification.
17*29492bb7SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18*29492bb7SDavid van Moolenbroek * substantially similar to the "NO WARRANTY" disclaimer below
19*29492bb7SDavid van Moolenbroek * ("Disclaimer") and any redistribution must be conditioned upon
20*29492bb7SDavid van Moolenbroek * including a substantially similar Disclaimer requirement for further
21*29492bb7SDavid van Moolenbroek * binary redistribution.
22*29492bb7SDavid van Moolenbroek * 3. Neither the names of the above-listed copyright holders nor the names
23*29492bb7SDavid van Moolenbroek * of any contributors may be used to endorse or promote products derived
24*29492bb7SDavid van Moolenbroek * from this software without specific prior written permission.
25433d6423SLionel Sambuc *
26*29492bb7SDavid van Moolenbroek * Alternatively, this software may be distributed under the terms of the
27*29492bb7SDavid van Moolenbroek * GNU General Public License ("GPL") version 2 as published by the Free
28*29492bb7SDavid van Moolenbroek * Software Foundation.
29433d6423SLionel Sambuc *
30*29492bb7SDavid van Moolenbroek * NO WARRANTY
31*29492bb7SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32*29492bb7SDavid van Moolenbroek * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33*29492bb7SDavid van Moolenbroek * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34*29492bb7SDavid van Moolenbroek * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35*29492bb7SDavid van Moolenbroek * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36*29492bb7SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37*29492bb7SDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38*29492bb7SDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39*29492bb7SDavid van Moolenbroek * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40*29492bb7SDavid van Moolenbroek * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41*29492bb7SDavid van Moolenbroek * POSSIBILITY OF SUCH DAMAGES.
42*29492bb7SDavid van Moolenbroek */
43433d6423SLionel Sambuc
44433d6423SLionel Sambuc #include "acpi.h"
45433d6423SLionel Sambuc #include "accommon.h"
46433d6423SLionel Sambuc #include "acdispat.h"
47433d6423SLionel Sambuc #include "acinterp.h"
48*29492bb7SDavid van Moolenbroek #include "amlcode.h"
49433d6423SLionel Sambuc
50433d6423SLionel Sambuc
51433d6423SLionel Sambuc #define _COMPONENT ACPI_EXECUTER
52433d6423SLionel Sambuc ACPI_MODULE_NAME ("exfield")
53433d6423SLionel Sambuc
54*29492bb7SDavid van Moolenbroek /* Local prototypes */
55*29492bb7SDavid van Moolenbroek
56*29492bb7SDavid van Moolenbroek static UINT32
57*29492bb7SDavid van Moolenbroek AcpiExGetSerialAccessLength (
58*29492bb7SDavid van Moolenbroek UINT32 AccessorType,
59*29492bb7SDavid van Moolenbroek UINT32 AccessLength);
60*29492bb7SDavid van Moolenbroek
61*29492bb7SDavid van Moolenbroek
62*29492bb7SDavid van Moolenbroek /*******************************************************************************
63*29492bb7SDavid van Moolenbroek *
64*29492bb7SDavid van Moolenbroek * FUNCTION: AcpiExGetSerialAccessLength
65*29492bb7SDavid van Moolenbroek *
66*29492bb7SDavid van Moolenbroek * PARAMETERS: AccessorType - The type of the protocol indicated by region
67*29492bb7SDavid van Moolenbroek * field access attributes
68*29492bb7SDavid van Moolenbroek * AccessLength - The access length of the region field
69*29492bb7SDavid van Moolenbroek *
70*29492bb7SDavid van Moolenbroek * RETURN: Decoded access length
71*29492bb7SDavid van Moolenbroek *
72*29492bb7SDavid van Moolenbroek * DESCRIPTION: This routine returns the length of the GenericSerialBus
73*29492bb7SDavid van Moolenbroek * protocol bytes
74*29492bb7SDavid van Moolenbroek *
75*29492bb7SDavid van Moolenbroek ******************************************************************************/
76*29492bb7SDavid van Moolenbroek
77*29492bb7SDavid van Moolenbroek static UINT32
AcpiExGetSerialAccessLength(UINT32 AccessorType,UINT32 AccessLength)78*29492bb7SDavid van Moolenbroek AcpiExGetSerialAccessLength (
79*29492bb7SDavid van Moolenbroek UINT32 AccessorType,
80*29492bb7SDavid van Moolenbroek UINT32 AccessLength)
81*29492bb7SDavid van Moolenbroek {
82*29492bb7SDavid van Moolenbroek UINT32 Length;
83*29492bb7SDavid van Moolenbroek
84*29492bb7SDavid van Moolenbroek
85*29492bb7SDavid van Moolenbroek switch (AccessorType)
86*29492bb7SDavid van Moolenbroek {
87*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_QUICK:
88*29492bb7SDavid van Moolenbroek
89*29492bb7SDavid van Moolenbroek Length = 0;
90*29492bb7SDavid van Moolenbroek break;
91*29492bb7SDavid van Moolenbroek
92*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_SEND_RCV:
93*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_BYTE:
94*29492bb7SDavid van Moolenbroek
95*29492bb7SDavid van Moolenbroek Length = 1;
96*29492bb7SDavid van Moolenbroek break;
97*29492bb7SDavid van Moolenbroek
98*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_WORD:
99*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_WORD_CALL:
100*29492bb7SDavid van Moolenbroek
101*29492bb7SDavid van Moolenbroek Length = 2;
102*29492bb7SDavid van Moolenbroek break;
103*29492bb7SDavid van Moolenbroek
104*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_MULTIBYTE:
105*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_RAW_BYTES:
106*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_RAW_PROCESS:
107*29492bb7SDavid van Moolenbroek
108*29492bb7SDavid van Moolenbroek Length = AccessLength;
109*29492bb7SDavid van Moolenbroek break;
110*29492bb7SDavid van Moolenbroek
111*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_BLOCK:
112*29492bb7SDavid van Moolenbroek case AML_FIELD_ATTRIB_BLOCK_CALL:
113*29492bb7SDavid van Moolenbroek default:
114*29492bb7SDavid van Moolenbroek
115*29492bb7SDavid van Moolenbroek Length = ACPI_GSBUS_BUFFER_SIZE - 2;
116*29492bb7SDavid van Moolenbroek break;
117*29492bb7SDavid van Moolenbroek }
118*29492bb7SDavid van Moolenbroek
119*29492bb7SDavid van Moolenbroek return (Length);
120*29492bb7SDavid van Moolenbroek }
121*29492bb7SDavid van Moolenbroek
122433d6423SLionel Sambuc
123433d6423SLionel Sambuc /*******************************************************************************
124433d6423SLionel Sambuc *
125433d6423SLionel Sambuc * FUNCTION: AcpiExReadDataFromField
126433d6423SLionel Sambuc *
127433d6423SLionel Sambuc * PARAMETERS: WalkState - Current execution state
128433d6423SLionel Sambuc * ObjDesc - The named field
129433d6423SLionel Sambuc * RetBufferDesc - Where the return data object is stored
130433d6423SLionel Sambuc *
131433d6423SLionel Sambuc * RETURN: Status
132433d6423SLionel Sambuc *
133433d6423SLionel Sambuc * DESCRIPTION: Read from a named field. Returns either an Integer or a
134433d6423SLionel Sambuc * Buffer, depending on the size of the field.
135433d6423SLionel Sambuc *
136433d6423SLionel Sambuc ******************************************************************************/
137433d6423SLionel Sambuc
138433d6423SLionel Sambuc ACPI_STATUS
AcpiExReadDataFromField(ACPI_WALK_STATE * WalkState,ACPI_OPERAND_OBJECT * ObjDesc,ACPI_OPERAND_OBJECT ** RetBufferDesc)139433d6423SLionel Sambuc AcpiExReadDataFromField (
140433d6423SLionel Sambuc ACPI_WALK_STATE *WalkState,
141433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *ObjDesc,
142433d6423SLionel Sambuc ACPI_OPERAND_OBJECT **RetBufferDesc)
143433d6423SLionel Sambuc {
144433d6423SLionel Sambuc ACPI_STATUS Status;
145433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *BufferDesc;
146433d6423SLionel Sambuc ACPI_SIZE Length;
147433d6423SLionel Sambuc void *Buffer;
148433d6423SLionel Sambuc UINT32 Function;
149*29492bb7SDavid van Moolenbroek UINT16 AccessorType;
150433d6423SLionel Sambuc
151433d6423SLionel Sambuc
152433d6423SLionel Sambuc ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
153433d6423SLionel Sambuc
154433d6423SLionel Sambuc
155433d6423SLionel Sambuc /* Parameter validation */
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc if (!ObjDesc)
158433d6423SLionel Sambuc {
159433d6423SLionel Sambuc return_ACPI_STATUS (AE_AML_NO_OPERAND);
160433d6423SLionel Sambuc }
161433d6423SLionel Sambuc if (!RetBufferDesc)
162433d6423SLionel Sambuc {
163433d6423SLionel Sambuc return_ACPI_STATUS (AE_BAD_PARAMETER);
164433d6423SLionel Sambuc }
165433d6423SLionel Sambuc
166433d6423SLionel Sambuc if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
167433d6423SLionel Sambuc {
168433d6423SLionel Sambuc /*
169433d6423SLionel Sambuc * If the BufferField arguments have not been previously evaluated,
170433d6423SLionel Sambuc * evaluate them now and save the results.
171433d6423SLionel Sambuc */
172433d6423SLionel Sambuc if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
173433d6423SLionel Sambuc {
174433d6423SLionel Sambuc Status = AcpiDsGetBufferFieldArguments (ObjDesc);
175433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
176433d6423SLionel Sambuc {
177433d6423SLionel Sambuc return_ACPI_STATUS (Status);
178433d6423SLionel Sambuc }
179433d6423SLionel Sambuc }
180433d6423SLionel Sambuc }
181433d6423SLionel Sambuc else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
182433d6423SLionel Sambuc (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
183*29492bb7SDavid van Moolenbroek ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
184433d6423SLionel Sambuc ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
185433d6423SLionel Sambuc {
186433d6423SLionel Sambuc /*
187*29492bb7SDavid van Moolenbroek * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
188433d6423SLionel Sambuc * the data and then directly access the region handler.
189433d6423SLionel Sambuc *
190*29492bb7SDavid van Moolenbroek * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
191433d6423SLionel Sambuc */
192433d6423SLionel Sambuc if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
193433d6423SLionel Sambuc {
194433d6423SLionel Sambuc Length = ACPI_SMBUS_BUFFER_SIZE;
195433d6423SLionel Sambuc Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
196433d6423SLionel Sambuc }
197*29492bb7SDavid van Moolenbroek else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
198*29492bb7SDavid van Moolenbroek {
199*29492bb7SDavid van Moolenbroek AccessorType = ObjDesc->Field.Attribute;
200*29492bb7SDavid van Moolenbroek Length = AcpiExGetSerialAccessLength (AccessorType,
201*29492bb7SDavid van Moolenbroek ObjDesc->Field.AccessLength);
202*29492bb7SDavid van Moolenbroek
203*29492bb7SDavid van Moolenbroek /*
204*29492bb7SDavid van Moolenbroek * Add additional 2 bytes for the GenericSerialBus data buffer:
205*29492bb7SDavid van Moolenbroek *
206*29492bb7SDavid van Moolenbroek * Status; (Byte 0 of the data buffer)
207*29492bb7SDavid van Moolenbroek * Length; (Byte 1 of the data buffer)
208*29492bb7SDavid van Moolenbroek * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer)
209*29492bb7SDavid van Moolenbroek */
210*29492bb7SDavid van Moolenbroek Length += 2;
211*29492bb7SDavid van Moolenbroek Function = ACPI_READ | (AccessorType << 16);
212*29492bb7SDavid van Moolenbroek }
213433d6423SLionel Sambuc else /* IPMI */
214433d6423SLionel Sambuc {
215433d6423SLionel Sambuc Length = ACPI_IPMI_BUFFER_SIZE;
216433d6423SLionel Sambuc Function = ACPI_READ;
217433d6423SLionel Sambuc }
218433d6423SLionel Sambuc
219433d6423SLionel Sambuc BufferDesc = AcpiUtCreateBufferObject (Length);
220433d6423SLionel Sambuc if (!BufferDesc)
221433d6423SLionel Sambuc {
222433d6423SLionel Sambuc return_ACPI_STATUS (AE_NO_MEMORY);
223433d6423SLionel Sambuc }
224433d6423SLionel Sambuc
225433d6423SLionel Sambuc /* Lock entire transaction if requested */
226433d6423SLionel Sambuc
227433d6423SLionel Sambuc AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
228433d6423SLionel Sambuc
229433d6423SLionel Sambuc /* Call the region handler for the read */
230433d6423SLionel Sambuc
231433d6423SLionel Sambuc Status = AcpiExAccessRegion (ObjDesc, 0,
232433d6423SLionel Sambuc ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer),
233433d6423SLionel Sambuc Function);
234433d6423SLionel Sambuc AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
235433d6423SLionel Sambuc goto Exit;
236433d6423SLionel Sambuc }
237433d6423SLionel Sambuc
238433d6423SLionel Sambuc /*
239433d6423SLionel Sambuc * Allocate a buffer for the contents of the field.
240433d6423SLionel Sambuc *
241433d6423SLionel Sambuc * If the field is larger than the current integer width, create
242433d6423SLionel Sambuc * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
243433d6423SLionel Sambuc * the use of arithmetic operators on the returned value if the
244433d6423SLionel Sambuc * field size is equal or smaller than an Integer.
245433d6423SLionel Sambuc *
246433d6423SLionel Sambuc * Note: Field.length is in bits.
247433d6423SLionel Sambuc */
248433d6423SLionel Sambuc Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength);
249433d6423SLionel Sambuc if (Length > AcpiGbl_IntegerByteWidth)
250433d6423SLionel Sambuc {
251433d6423SLionel Sambuc /* Field is too large for an Integer, create a Buffer instead */
252433d6423SLionel Sambuc
253433d6423SLionel Sambuc BufferDesc = AcpiUtCreateBufferObject (Length);
254433d6423SLionel Sambuc if (!BufferDesc)
255433d6423SLionel Sambuc {
256433d6423SLionel Sambuc return_ACPI_STATUS (AE_NO_MEMORY);
257433d6423SLionel Sambuc }
258433d6423SLionel Sambuc Buffer = BufferDesc->Buffer.Pointer;
259433d6423SLionel Sambuc }
260433d6423SLionel Sambuc else
261433d6423SLionel Sambuc {
262433d6423SLionel Sambuc /* Field will fit within an Integer (normal case) */
263433d6423SLionel Sambuc
264433d6423SLionel Sambuc BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
265433d6423SLionel Sambuc if (!BufferDesc)
266433d6423SLionel Sambuc {
267433d6423SLionel Sambuc return_ACPI_STATUS (AE_NO_MEMORY);
268433d6423SLionel Sambuc }
269433d6423SLionel Sambuc
270433d6423SLionel Sambuc Length = AcpiGbl_IntegerByteWidth;
271433d6423SLionel Sambuc Buffer = &BufferDesc->Integer.Value;
272433d6423SLionel Sambuc }
273433d6423SLionel Sambuc
274*29492bb7SDavid van Moolenbroek if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
275*29492bb7SDavid van Moolenbroek (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
276*29492bb7SDavid van Moolenbroek {
277*29492bb7SDavid van Moolenbroek /*
278*29492bb7SDavid van Moolenbroek * For GPIO (GeneralPurposeIo), the Address will be the bit offset
279*29492bb7SDavid van Moolenbroek * from the previous Connection() operator, making it effectively a
280*29492bb7SDavid van Moolenbroek * pin number index. The BitLength is the length of the field, which
281*29492bb7SDavid van Moolenbroek * is thus the number of pins.
282*29492bb7SDavid van Moolenbroek */
283*29492bb7SDavid van Moolenbroek ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
284*29492bb7SDavid van Moolenbroek "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
285*29492bb7SDavid van Moolenbroek ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
286*29492bb7SDavid van Moolenbroek
287*29492bb7SDavid van Moolenbroek /* Lock entire transaction if requested */
288*29492bb7SDavid van Moolenbroek
289*29492bb7SDavid van Moolenbroek AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
290*29492bb7SDavid van Moolenbroek
291*29492bb7SDavid van Moolenbroek /* Perform the write */
292*29492bb7SDavid van Moolenbroek
293*29492bb7SDavid van Moolenbroek Status = AcpiExAccessRegion (ObjDesc, 0,
294*29492bb7SDavid van Moolenbroek (UINT64 *) Buffer, ACPI_READ);
295*29492bb7SDavid van Moolenbroek AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
296*29492bb7SDavid van Moolenbroek if (ACPI_FAILURE (Status))
297*29492bb7SDavid van Moolenbroek {
298*29492bb7SDavid van Moolenbroek AcpiUtRemoveReference (BufferDesc);
299*29492bb7SDavid van Moolenbroek }
300*29492bb7SDavid van Moolenbroek else
301*29492bb7SDavid van Moolenbroek {
302*29492bb7SDavid van Moolenbroek *RetBufferDesc = BufferDesc;
303*29492bb7SDavid van Moolenbroek }
304*29492bb7SDavid van Moolenbroek return_ACPI_STATUS (Status);
305*29492bb7SDavid van Moolenbroek }
306*29492bb7SDavid van Moolenbroek
307433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
308433d6423SLionel Sambuc "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
309433d6423SLionel Sambuc ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
310433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
311433d6423SLionel Sambuc "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
312433d6423SLionel Sambuc ObjDesc->CommonField.BitLength,
313433d6423SLionel Sambuc ObjDesc->CommonField.StartFieldBitOffset,
314433d6423SLionel Sambuc ObjDesc->CommonField.BaseByteOffset));
315433d6423SLionel Sambuc
316433d6423SLionel Sambuc /* Lock entire transaction if requested */
317433d6423SLionel Sambuc
318433d6423SLionel Sambuc AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
319433d6423SLionel Sambuc
320433d6423SLionel Sambuc /* Read from the field */
321433d6423SLionel Sambuc
322433d6423SLionel Sambuc Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
323433d6423SLionel Sambuc AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
324433d6423SLionel Sambuc
325433d6423SLionel Sambuc
326433d6423SLionel Sambuc Exit:
327433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
328433d6423SLionel Sambuc {
329433d6423SLionel Sambuc AcpiUtRemoveReference (BufferDesc);
330433d6423SLionel Sambuc }
331433d6423SLionel Sambuc else
332433d6423SLionel Sambuc {
333433d6423SLionel Sambuc *RetBufferDesc = BufferDesc;
334433d6423SLionel Sambuc }
335433d6423SLionel Sambuc
336433d6423SLionel Sambuc return_ACPI_STATUS (Status);
337433d6423SLionel Sambuc }
338433d6423SLionel Sambuc
339433d6423SLionel Sambuc
340433d6423SLionel Sambuc /*******************************************************************************
341433d6423SLionel Sambuc *
342433d6423SLionel Sambuc * FUNCTION: AcpiExWriteDataToField
343433d6423SLionel Sambuc *
344433d6423SLionel Sambuc * PARAMETERS: SourceDesc - Contains data to write
345433d6423SLionel Sambuc * ObjDesc - The named field
346433d6423SLionel Sambuc * ResultDesc - Where the return value is returned, if any
347433d6423SLionel Sambuc *
348433d6423SLionel Sambuc * RETURN: Status
349433d6423SLionel Sambuc *
350433d6423SLionel Sambuc * DESCRIPTION: Write to a named field
351433d6423SLionel Sambuc *
352433d6423SLionel Sambuc ******************************************************************************/
353433d6423SLionel Sambuc
354433d6423SLionel Sambuc ACPI_STATUS
AcpiExWriteDataToField(ACPI_OPERAND_OBJECT * SourceDesc,ACPI_OPERAND_OBJECT * ObjDesc,ACPI_OPERAND_OBJECT ** ResultDesc)355433d6423SLionel Sambuc AcpiExWriteDataToField (
356433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *SourceDesc,
357433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *ObjDesc,
358433d6423SLionel Sambuc ACPI_OPERAND_OBJECT **ResultDesc)
359433d6423SLionel Sambuc {
360433d6423SLionel Sambuc ACPI_STATUS Status;
361433d6423SLionel Sambuc UINT32 Length;
362433d6423SLionel Sambuc void *Buffer;
363433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *BufferDesc;
364433d6423SLionel Sambuc UINT32 Function;
365*29492bb7SDavid van Moolenbroek UINT16 AccessorType;
366433d6423SLionel Sambuc
367433d6423SLionel Sambuc
368433d6423SLionel Sambuc ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
369433d6423SLionel Sambuc
370433d6423SLionel Sambuc
371433d6423SLionel Sambuc /* Parameter validation */
372433d6423SLionel Sambuc
373433d6423SLionel Sambuc if (!SourceDesc || !ObjDesc)
374433d6423SLionel Sambuc {
375433d6423SLionel Sambuc return_ACPI_STATUS (AE_AML_NO_OPERAND);
376433d6423SLionel Sambuc }
377433d6423SLionel Sambuc
378433d6423SLionel Sambuc if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
379433d6423SLionel Sambuc {
380433d6423SLionel Sambuc /*
381433d6423SLionel Sambuc * If the BufferField arguments have not been previously evaluated,
382433d6423SLionel Sambuc * evaluate them now and save the results.
383433d6423SLionel Sambuc */
384433d6423SLionel Sambuc if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
385433d6423SLionel Sambuc {
386433d6423SLionel Sambuc Status = AcpiDsGetBufferFieldArguments (ObjDesc);
387433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
388433d6423SLionel Sambuc {
389433d6423SLionel Sambuc return_ACPI_STATUS (Status);
390433d6423SLionel Sambuc }
391433d6423SLionel Sambuc }
392433d6423SLionel Sambuc }
393433d6423SLionel Sambuc else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
394433d6423SLionel Sambuc (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
395*29492bb7SDavid van Moolenbroek ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
396433d6423SLionel Sambuc ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
397433d6423SLionel Sambuc {
398433d6423SLionel Sambuc /*
399*29492bb7SDavid van Moolenbroek * This is an SMBus, GSBus or IPMI write. We will bypass the entire field
400433d6423SLionel Sambuc * mechanism and handoff the buffer directly to the handler. For
401433d6423SLionel Sambuc * these address spaces, the buffer is bi-directional; on a write,
402433d6423SLionel Sambuc * return data is returned in the same buffer.
403433d6423SLionel Sambuc *
404433d6423SLionel Sambuc * Source must be a buffer of sufficient size:
405*29492bb7SDavid van Moolenbroek * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
406433d6423SLionel Sambuc *
407*29492bb7SDavid van Moolenbroek * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function
408433d6423SLionel Sambuc */
409433d6423SLionel Sambuc if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
410433d6423SLionel Sambuc {
411433d6423SLionel Sambuc ACPI_ERROR ((AE_INFO,
412*29492bb7SDavid van Moolenbroek "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s",
413433d6423SLionel Sambuc AcpiUtGetObjectTypeName (SourceDesc)));
414433d6423SLionel Sambuc
415433d6423SLionel Sambuc return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
416433d6423SLionel Sambuc }
417433d6423SLionel Sambuc
418433d6423SLionel Sambuc if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
419433d6423SLionel Sambuc {
420433d6423SLionel Sambuc Length = ACPI_SMBUS_BUFFER_SIZE;
421433d6423SLionel Sambuc Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
422433d6423SLionel Sambuc }
423*29492bb7SDavid van Moolenbroek else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
424*29492bb7SDavid van Moolenbroek {
425*29492bb7SDavid van Moolenbroek AccessorType = ObjDesc->Field.Attribute;
426*29492bb7SDavid van Moolenbroek Length = AcpiExGetSerialAccessLength (AccessorType,
427*29492bb7SDavid van Moolenbroek ObjDesc->Field.AccessLength);
428*29492bb7SDavid van Moolenbroek
429*29492bb7SDavid van Moolenbroek /*
430*29492bb7SDavid van Moolenbroek * Add additional 2 bytes for the GenericSerialBus data buffer:
431*29492bb7SDavid van Moolenbroek *
432*29492bb7SDavid van Moolenbroek * Status; (Byte 0 of the data buffer)
433*29492bb7SDavid van Moolenbroek * Length; (Byte 1 of the data buffer)
434*29492bb7SDavid van Moolenbroek * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer)
435*29492bb7SDavid van Moolenbroek */
436*29492bb7SDavid van Moolenbroek Length += 2;
437*29492bb7SDavid van Moolenbroek Function = ACPI_WRITE | (AccessorType << 16);
438*29492bb7SDavid van Moolenbroek }
439433d6423SLionel Sambuc else /* IPMI */
440433d6423SLionel Sambuc {
441433d6423SLionel Sambuc Length = ACPI_IPMI_BUFFER_SIZE;
442433d6423SLionel Sambuc Function = ACPI_WRITE;
443433d6423SLionel Sambuc }
444433d6423SLionel Sambuc
445433d6423SLionel Sambuc if (SourceDesc->Buffer.Length < Length)
446433d6423SLionel Sambuc {
447433d6423SLionel Sambuc ACPI_ERROR ((AE_INFO,
448*29492bb7SDavid van Moolenbroek "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u",
449433d6423SLionel Sambuc Length, SourceDesc->Buffer.Length));
450433d6423SLionel Sambuc
451433d6423SLionel Sambuc return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
452433d6423SLionel Sambuc }
453433d6423SLionel Sambuc
454433d6423SLionel Sambuc /* Create the bi-directional buffer */
455433d6423SLionel Sambuc
456433d6423SLionel Sambuc BufferDesc = AcpiUtCreateBufferObject (Length);
457433d6423SLionel Sambuc if (!BufferDesc)
458433d6423SLionel Sambuc {
459433d6423SLionel Sambuc return_ACPI_STATUS (AE_NO_MEMORY);
460433d6423SLionel Sambuc }
461433d6423SLionel Sambuc
462433d6423SLionel Sambuc Buffer = BufferDesc->Buffer.Pointer;
463433d6423SLionel Sambuc ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length);
464433d6423SLionel Sambuc
465433d6423SLionel Sambuc /* Lock entire transaction if requested */
466433d6423SLionel Sambuc
467433d6423SLionel Sambuc AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
468433d6423SLionel Sambuc
469433d6423SLionel Sambuc /*
470433d6423SLionel Sambuc * Perform the write (returns status and perhaps data in the
471433d6423SLionel Sambuc * same buffer)
472433d6423SLionel Sambuc */
473433d6423SLionel Sambuc Status = AcpiExAccessRegion (ObjDesc, 0,
474433d6423SLionel Sambuc (UINT64 *) Buffer, Function);
475433d6423SLionel Sambuc AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
476433d6423SLionel Sambuc
477433d6423SLionel Sambuc *ResultDesc = BufferDesc;
478433d6423SLionel Sambuc return_ACPI_STATUS (Status);
479433d6423SLionel Sambuc }
480*29492bb7SDavid van Moolenbroek else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
481*29492bb7SDavid van Moolenbroek (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
482*29492bb7SDavid van Moolenbroek {
483*29492bb7SDavid van Moolenbroek /*
484*29492bb7SDavid van Moolenbroek * For GPIO (GeneralPurposeIo), we will bypass the entire field
485*29492bb7SDavid van Moolenbroek * mechanism and handoff the bit address and bit width directly to
486*29492bb7SDavid van Moolenbroek * the handler. The Address will be the bit offset
487*29492bb7SDavid van Moolenbroek * from the previous Connection() operator, making it effectively a
488*29492bb7SDavid van Moolenbroek * pin number index. The BitLength is the length of the field, which
489*29492bb7SDavid van Moolenbroek * is thus the number of pins.
490*29492bb7SDavid van Moolenbroek */
491*29492bb7SDavid van Moolenbroek if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
492*29492bb7SDavid van Moolenbroek {
493*29492bb7SDavid van Moolenbroek return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
494*29492bb7SDavid van Moolenbroek }
495*29492bb7SDavid van Moolenbroek
496*29492bb7SDavid van Moolenbroek ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
497*29492bb7SDavid van Moolenbroek "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
498*29492bb7SDavid van Moolenbroek AcpiUtGetTypeName (SourceDesc->Common.Type),
499*29492bb7SDavid van Moolenbroek SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
500*29492bb7SDavid van Moolenbroek ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
501*29492bb7SDavid van Moolenbroek
502*29492bb7SDavid van Moolenbroek Buffer = &SourceDesc->Integer.Value;
503*29492bb7SDavid van Moolenbroek
504*29492bb7SDavid van Moolenbroek /* Lock entire transaction if requested */
505*29492bb7SDavid van Moolenbroek
506*29492bb7SDavid van Moolenbroek AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
507*29492bb7SDavid van Moolenbroek
508*29492bb7SDavid van Moolenbroek /* Perform the write */
509*29492bb7SDavid van Moolenbroek
510*29492bb7SDavid van Moolenbroek Status = AcpiExAccessRegion (ObjDesc, 0,
511*29492bb7SDavid van Moolenbroek (UINT64 *) Buffer, ACPI_WRITE);
512*29492bb7SDavid van Moolenbroek AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
513*29492bb7SDavid van Moolenbroek return_ACPI_STATUS (Status);
514*29492bb7SDavid van Moolenbroek }
515433d6423SLionel Sambuc
516433d6423SLionel Sambuc /* Get a pointer to the data to be written */
517433d6423SLionel Sambuc
518433d6423SLionel Sambuc switch (SourceDesc->Common.Type)
519433d6423SLionel Sambuc {
520433d6423SLionel Sambuc case ACPI_TYPE_INTEGER:
521*29492bb7SDavid van Moolenbroek
522433d6423SLionel Sambuc Buffer = &SourceDesc->Integer.Value;
523433d6423SLionel Sambuc Length = sizeof (SourceDesc->Integer.Value);
524433d6423SLionel Sambuc break;
525433d6423SLionel Sambuc
526433d6423SLionel Sambuc case ACPI_TYPE_BUFFER:
527*29492bb7SDavid van Moolenbroek
528433d6423SLionel Sambuc Buffer = SourceDesc->Buffer.Pointer;
529433d6423SLionel Sambuc Length = SourceDesc->Buffer.Length;
530433d6423SLionel Sambuc break;
531433d6423SLionel Sambuc
532433d6423SLionel Sambuc case ACPI_TYPE_STRING:
533*29492bb7SDavid van Moolenbroek
534433d6423SLionel Sambuc Buffer = SourceDesc->String.Pointer;
535433d6423SLionel Sambuc Length = SourceDesc->String.Length;
536433d6423SLionel Sambuc break;
537433d6423SLionel Sambuc
538433d6423SLionel Sambuc default:
539*29492bb7SDavid van Moolenbroek
540433d6423SLionel Sambuc return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
541433d6423SLionel Sambuc }
542433d6423SLionel Sambuc
543433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
544433d6423SLionel Sambuc "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
545433d6423SLionel Sambuc SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
546433d6423SLionel Sambuc SourceDesc->Common.Type, Buffer, Length));
547433d6423SLionel Sambuc
548433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
549433d6423SLionel Sambuc "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
550433d6423SLionel Sambuc ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
551433d6423SLionel Sambuc ObjDesc->Common.Type,
552433d6423SLionel Sambuc ObjDesc->CommonField.BitLength,
553433d6423SLionel Sambuc ObjDesc->CommonField.StartFieldBitOffset,
554433d6423SLionel Sambuc ObjDesc->CommonField.BaseByteOffset));
555433d6423SLionel Sambuc
556433d6423SLionel Sambuc /* Lock entire transaction if requested */
557433d6423SLionel Sambuc
558433d6423SLionel Sambuc AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
559433d6423SLionel Sambuc
560433d6423SLionel Sambuc /* Write to the field */
561433d6423SLionel Sambuc
562433d6423SLionel Sambuc Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
563433d6423SLionel Sambuc AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
564433d6423SLionel Sambuc
565433d6423SLionel Sambuc return_ACPI_STATUS (Status);
566433d6423SLionel Sambuc }
567