1db2bae30SDana Myers /******************************************************************************
2db2bae30SDana Myers *
3db2bae30SDana Myers * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
4db2bae30SDana Myers *
5db2bae30SDana Myers *****************************************************************************/
6db2bae30SDana Myers
726f3cdf0SGordon Ross /*
8*cb565728SJerry Jelinek * Copyright (C) 2000 - 2016, Intel Corp.
9db2bae30SDana Myers * All rights reserved.
10db2bae30SDana Myers *
1126f3cdf0SGordon Ross * Redistribution and use in source and binary forms, with or without
1226f3cdf0SGordon Ross * modification, are permitted provided that the following conditions
1326f3cdf0SGordon Ross * are met:
1426f3cdf0SGordon Ross * 1. Redistributions of source code must retain the above copyright
1526f3cdf0SGordon Ross * notice, this list of conditions, and the following disclaimer,
1626f3cdf0SGordon Ross * without modification.
1726f3cdf0SGordon Ross * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1826f3cdf0SGordon Ross * substantially similar to the "NO WARRANTY" disclaimer below
1926f3cdf0SGordon Ross * ("Disclaimer") and any redistribution must be conditioned upon
2026f3cdf0SGordon Ross * including a substantially similar Disclaimer requirement for further
2126f3cdf0SGordon Ross * binary redistribution.
2226f3cdf0SGordon Ross * 3. Neither the names of the above-listed copyright holders nor the names
2326f3cdf0SGordon Ross * of any contributors may be used to endorse or promote products derived
2426f3cdf0SGordon Ross * from this software without specific prior written permission.
25db2bae30SDana Myers *
2626f3cdf0SGordon Ross * Alternatively, this software may be distributed under the terms of the
2726f3cdf0SGordon Ross * GNU General Public License ("GPL") version 2 as published by the Free
2826f3cdf0SGordon Ross * Software Foundation.
29db2bae30SDana Myers *
3026f3cdf0SGordon Ross * NO WARRANTY
3126f3cdf0SGordon Ross * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3226f3cdf0SGordon Ross * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3326f3cdf0SGordon Ross * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3426f3cdf0SGordon Ross * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3526f3cdf0SGordon Ross * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3626f3cdf0SGordon Ross * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3726f3cdf0SGordon Ross * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3826f3cdf0SGordon Ross * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3926f3cdf0SGordon Ross * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4026f3cdf0SGordon Ross * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4126f3cdf0SGordon Ross * POSSIBILITY OF SUCH DAMAGES.
4226f3cdf0SGordon Ross */
43db2bae30SDana Myers
44db2bae30SDana Myers #include "acpi.h"
45aa2aa9a6SDana Myers #include "accommon.h"
46db2bae30SDana Myers #include "acdispat.h"
47db2bae30SDana Myers #include "acinterp.h"
48*cb565728SJerry Jelinek #include "amlcode.h"
49db2bae30SDana Myers
50db2bae30SDana Myers
51db2bae30SDana Myers #define _COMPONENT ACPI_EXECUTER
52db2bae30SDana Myers ACPI_MODULE_NAME ("exfield")
53db2bae30SDana Myers
54*cb565728SJerry Jelinek /* Local prototypes */
55*cb565728SJerry Jelinek
56*cb565728SJerry Jelinek static UINT32
57*cb565728SJerry Jelinek AcpiExGetSerialAccessLength (
58*cb565728SJerry Jelinek UINT32 AccessorType,
59*cb565728SJerry Jelinek UINT32 AccessLength);
60*cb565728SJerry Jelinek
61*cb565728SJerry Jelinek
62*cb565728SJerry Jelinek /*******************************************************************************
63*cb565728SJerry Jelinek *
64*cb565728SJerry Jelinek * FUNCTION: AcpiExGetSerialAccessLength
65*cb565728SJerry Jelinek *
66*cb565728SJerry Jelinek * PARAMETERS: AccessorType - The type of the protocol indicated by region
67*cb565728SJerry Jelinek * field access attributes
68*cb565728SJerry Jelinek * AccessLength - The access length of the region field
69*cb565728SJerry Jelinek *
70*cb565728SJerry Jelinek * RETURN: Decoded access length
71*cb565728SJerry Jelinek *
72*cb565728SJerry Jelinek * DESCRIPTION: This routine returns the length of the GenericSerialBus
73*cb565728SJerry Jelinek * protocol bytes
74*cb565728SJerry Jelinek *
75*cb565728SJerry Jelinek ******************************************************************************/
76*cb565728SJerry Jelinek
77*cb565728SJerry Jelinek static UINT32
AcpiExGetSerialAccessLength(UINT32 AccessorType,UINT32 AccessLength)78*cb565728SJerry Jelinek AcpiExGetSerialAccessLength (
79*cb565728SJerry Jelinek UINT32 AccessorType,
80*cb565728SJerry Jelinek UINT32 AccessLength)
81*cb565728SJerry Jelinek {
82*cb565728SJerry Jelinek UINT32 Length;
83*cb565728SJerry Jelinek
84*cb565728SJerry Jelinek
85*cb565728SJerry Jelinek switch (AccessorType)
86*cb565728SJerry Jelinek {
87*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_QUICK:
88*cb565728SJerry Jelinek
89*cb565728SJerry Jelinek Length = 0;
90*cb565728SJerry Jelinek break;
91*cb565728SJerry Jelinek
92*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_SEND_RCV:
93*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_BYTE:
94*cb565728SJerry Jelinek
95*cb565728SJerry Jelinek Length = 1;
96*cb565728SJerry Jelinek break;
97*cb565728SJerry Jelinek
98*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_WORD:
99*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_WORD_CALL:
100*cb565728SJerry Jelinek
101*cb565728SJerry Jelinek Length = 2;
102*cb565728SJerry Jelinek break;
103*cb565728SJerry Jelinek
104*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_MULTIBYTE:
105*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_RAW_BYTES:
106*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_RAW_PROCESS:
107*cb565728SJerry Jelinek
108*cb565728SJerry Jelinek Length = AccessLength;
109*cb565728SJerry Jelinek break;
110*cb565728SJerry Jelinek
111*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_BLOCK:
112*cb565728SJerry Jelinek case AML_FIELD_ATTRIB_BLOCK_CALL:
113*cb565728SJerry Jelinek default:
114*cb565728SJerry Jelinek
115*cb565728SJerry Jelinek Length = ACPI_GSBUS_BUFFER_SIZE - 2;
116*cb565728SJerry Jelinek break;
117*cb565728SJerry Jelinek }
118*cb565728SJerry Jelinek
119*cb565728SJerry Jelinek return (Length);
120*cb565728SJerry Jelinek }
121*cb565728SJerry Jelinek
122db2bae30SDana Myers
123db2bae30SDana Myers /*******************************************************************************
124db2bae30SDana Myers *
125db2bae30SDana Myers * FUNCTION: AcpiExReadDataFromField
126db2bae30SDana Myers *
127db2bae30SDana Myers * PARAMETERS: WalkState - Current execution state
128db2bae30SDana Myers * ObjDesc - The named field
129db2bae30SDana Myers * RetBufferDesc - Where the return data object is stored
130db2bae30SDana Myers *
131db2bae30SDana Myers * RETURN: Status
132db2bae30SDana Myers *
133db2bae30SDana Myers * DESCRIPTION: Read from a named field. Returns either an Integer or a
134db2bae30SDana Myers * Buffer, depending on the size of the field.
135db2bae30SDana Myers *
136db2bae30SDana Myers ******************************************************************************/
137db2bae30SDana Myers
138db2bae30SDana Myers ACPI_STATUS
AcpiExReadDataFromField(ACPI_WALK_STATE * WalkState,ACPI_OPERAND_OBJECT * ObjDesc,ACPI_OPERAND_OBJECT ** RetBufferDesc)139db2bae30SDana Myers AcpiExReadDataFromField (
140db2bae30SDana Myers ACPI_WALK_STATE *WalkState,
141db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc,
142db2bae30SDana Myers ACPI_OPERAND_OBJECT **RetBufferDesc)
143db2bae30SDana Myers {
144db2bae30SDana Myers ACPI_STATUS Status;
145db2bae30SDana Myers ACPI_OPERAND_OBJECT *BufferDesc;
146db2bae30SDana Myers ACPI_SIZE Length;
147db2bae30SDana Myers void *Buffer;
14857190917SDana Myers UINT32 Function;
149*cb565728SJerry Jelinek UINT16 AccessorType;
150db2bae30SDana Myers
151db2bae30SDana Myers
152db2bae30SDana Myers ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
153db2bae30SDana Myers
154db2bae30SDana Myers
155db2bae30SDana Myers /* Parameter validation */
156db2bae30SDana Myers
157db2bae30SDana Myers if (!ObjDesc)
158db2bae30SDana Myers {
159db2bae30SDana Myers return_ACPI_STATUS (AE_AML_NO_OPERAND);
160db2bae30SDana Myers }
161db2bae30SDana Myers if (!RetBufferDesc)
162db2bae30SDana Myers {
163db2bae30SDana Myers return_ACPI_STATUS (AE_BAD_PARAMETER);
164db2bae30SDana Myers }
165db2bae30SDana Myers
166aa2aa9a6SDana Myers if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
167db2bae30SDana Myers {
168db2bae30SDana Myers /*
169db2bae30SDana Myers * If the BufferField arguments have not been previously evaluated,
170db2bae30SDana Myers * evaluate them now and save the results.
171db2bae30SDana Myers */
172db2bae30SDana Myers if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
173db2bae30SDana Myers {
174db2bae30SDana Myers Status = AcpiDsGetBufferFieldArguments (ObjDesc);
175db2bae30SDana Myers if (ACPI_FAILURE (Status))
176db2bae30SDana Myers {
177db2bae30SDana Myers return_ACPI_STATUS (Status);
178db2bae30SDana Myers }
179db2bae30SDana Myers }
180db2bae30SDana Myers }
181aa2aa9a6SDana Myers else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
18257190917SDana Myers (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
183*cb565728SJerry Jelinek ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
18457190917SDana Myers ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
185db2bae30SDana Myers {
186db2bae30SDana Myers /*
187*cb565728SJerry Jelinek * This is an SMBus, GSBus or IPMI read. We must create a buffer to
188*cb565728SJerry Jelinek * hold the data and then directly access the region handler.
18957190917SDana Myers *
190*cb565728SJerry Jelinek * Note: SMBus and GSBus protocol value is passed in upper 16-bits
191*cb565728SJerry Jelinek * of Function
192db2bae30SDana Myers */
193*cb565728SJerry Jelinek if (ObjDesc->Field.RegionObj->Region.SpaceId ==
194*cb565728SJerry Jelinek ACPI_ADR_SPACE_SMBUS)
19557190917SDana Myers {
19657190917SDana Myers Length = ACPI_SMBUS_BUFFER_SIZE;
19757190917SDana Myers Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
19857190917SDana Myers }
199*cb565728SJerry Jelinek else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
200*cb565728SJerry Jelinek ACPI_ADR_SPACE_GSBUS)
201*cb565728SJerry Jelinek {
202*cb565728SJerry Jelinek AccessorType = ObjDesc->Field.Attribute;
203*cb565728SJerry Jelinek Length = AcpiExGetSerialAccessLength (
204*cb565728SJerry Jelinek AccessorType, ObjDesc->Field.AccessLength);
205*cb565728SJerry Jelinek
206*cb565728SJerry Jelinek /*
207*cb565728SJerry Jelinek * Add additional 2 bytes for the GenericSerialBus data buffer:
208*cb565728SJerry Jelinek *
209*cb565728SJerry Jelinek * Status; (Byte 0 of the data buffer)
210*cb565728SJerry Jelinek * Length; (Byte 1 of the data buffer)
211*cb565728SJerry Jelinek * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
212*cb565728SJerry Jelinek */
213*cb565728SJerry Jelinek Length += 2;
214*cb565728SJerry Jelinek Function = ACPI_READ | (AccessorType << 16);
215*cb565728SJerry Jelinek }
21657190917SDana Myers else /* IPMI */
21757190917SDana Myers {
21857190917SDana Myers Length = ACPI_IPMI_BUFFER_SIZE;
21957190917SDana Myers Function = ACPI_READ;
22057190917SDana Myers }
22157190917SDana Myers
22257190917SDana Myers BufferDesc = AcpiUtCreateBufferObject (Length);
223db2bae30SDana Myers if (!BufferDesc)
224db2bae30SDana Myers {
225db2bae30SDana Myers return_ACPI_STATUS (AE_NO_MEMORY);
226db2bae30SDana Myers }
227db2bae30SDana Myers
228db2bae30SDana Myers /* Lock entire transaction if requested */
229db2bae30SDana Myers
230db2bae30SDana Myers AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
231db2bae30SDana Myers
23257190917SDana Myers /* Call the region handler for the read */
23357190917SDana Myers
234db2bae30SDana Myers Status = AcpiExAccessRegion (ObjDesc, 0,
235*cb565728SJerry Jelinek ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function);
236*cb565728SJerry Jelinek
237db2bae30SDana Myers AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
238db2bae30SDana Myers goto Exit;
239db2bae30SDana Myers }
240db2bae30SDana Myers
241db2bae30SDana Myers /*
242db2bae30SDana Myers * Allocate a buffer for the contents of the field.
243db2bae30SDana Myers *
24426f3cdf0SGordon Ross * If the field is larger than the current integer width, create
245db2bae30SDana Myers * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
246db2bae30SDana Myers * the use of arithmetic operators on the returned value if the
247db2bae30SDana Myers * field size is equal or smaller than an Integer.
248db2bae30SDana Myers *
249db2bae30SDana Myers * Note: Field.length is in bits.
250db2bae30SDana Myers */
251*cb565728SJerry Jelinek Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (
252*cb565728SJerry Jelinek ObjDesc->Field.BitLength);
253*cb565728SJerry Jelinek
254db2bae30SDana Myers if (Length > AcpiGbl_IntegerByteWidth)
255db2bae30SDana Myers {
256db2bae30SDana Myers /* Field is too large for an Integer, create a Buffer instead */
257db2bae30SDana Myers
258db2bae30SDana Myers BufferDesc = AcpiUtCreateBufferObject (Length);
259db2bae30SDana Myers if (!BufferDesc)
260db2bae30SDana Myers {
261db2bae30SDana Myers return_ACPI_STATUS (AE_NO_MEMORY);
262db2bae30SDana Myers }
263db2bae30SDana Myers Buffer = BufferDesc->Buffer.Pointer;
264db2bae30SDana Myers }
265db2bae30SDana Myers else
266db2bae30SDana Myers {
267db2bae30SDana Myers /* Field will fit within an Integer (normal case) */
268db2bae30SDana Myers
26957190917SDana Myers BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
270db2bae30SDana Myers if (!BufferDesc)
271db2bae30SDana Myers {
272db2bae30SDana Myers return_ACPI_STATUS (AE_NO_MEMORY);
273db2bae30SDana Myers }
274db2bae30SDana Myers
275db2bae30SDana Myers Length = AcpiGbl_IntegerByteWidth;
276db2bae30SDana Myers Buffer = &BufferDesc->Integer.Value;
277db2bae30SDana Myers }
278db2bae30SDana Myers
279*cb565728SJerry Jelinek if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
280*cb565728SJerry Jelinek (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
281*cb565728SJerry Jelinek {
282*cb565728SJerry Jelinek /*
283*cb565728SJerry Jelinek * For GPIO (GeneralPurposeIo), the Address will be the bit offset
284*cb565728SJerry Jelinek * from the previous Connection() operator, making it effectively a
285*cb565728SJerry Jelinek * pin number index. The BitLength is the length of the field, which
286*cb565728SJerry Jelinek * is thus the number of pins.
287*cb565728SJerry Jelinek */
288*cb565728SJerry Jelinek ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
289*cb565728SJerry Jelinek "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
290*cb565728SJerry Jelinek ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
291*cb565728SJerry Jelinek
292*cb565728SJerry Jelinek /* Lock entire transaction if requested */
293*cb565728SJerry Jelinek
294*cb565728SJerry Jelinek AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
295*cb565728SJerry Jelinek
296*cb565728SJerry Jelinek /* Perform the write */
297*cb565728SJerry Jelinek
298*cb565728SJerry Jelinek Status = AcpiExAccessRegion (
299*cb565728SJerry Jelinek ObjDesc, 0, (UINT64 *) Buffer, ACPI_READ);
300*cb565728SJerry Jelinek
301*cb565728SJerry Jelinek AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
302*cb565728SJerry Jelinek if (ACPI_FAILURE (Status))
303*cb565728SJerry Jelinek {
304*cb565728SJerry Jelinek AcpiUtRemoveReference (BufferDesc);
305*cb565728SJerry Jelinek }
306*cb565728SJerry Jelinek else
307*cb565728SJerry Jelinek {
308*cb565728SJerry Jelinek *RetBufferDesc = BufferDesc;
309*cb565728SJerry Jelinek }
310*cb565728SJerry Jelinek return_ACPI_STATUS (Status);
311*cb565728SJerry Jelinek }
312*cb565728SJerry Jelinek
313db2bae30SDana Myers ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
314db2bae30SDana Myers "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
315aa2aa9a6SDana Myers ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
316db2bae30SDana Myers ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
317db2bae30SDana Myers "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
318db2bae30SDana Myers ObjDesc->CommonField.BitLength,
319db2bae30SDana Myers ObjDesc->CommonField.StartFieldBitOffset,
320db2bae30SDana Myers ObjDesc->CommonField.BaseByteOffset));
321db2bae30SDana Myers
322db2bae30SDana Myers /* Lock entire transaction if requested */
323db2bae30SDana Myers
324db2bae30SDana Myers AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
325db2bae30SDana Myers
326db2bae30SDana Myers /* Read from the field */
327db2bae30SDana Myers
328db2bae30SDana Myers Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
329db2bae30SDana Myers AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
330db2bae30SDana Myers
331db2bae30SDana Myers
332db2bae30SDana Myers Exit:
333db2bae30SDana Myers if (ACPI_FAILURE (Status))
334db2bae30SDana Myers {
335db2bae30SDana Myers AcpiUtRemoveReference (BufferDesc);
336db2bae30SDana Myers }
337db2bae30SDana Myers else
338db2bae30SDana Myers {
339db2bae30SDana Myers *RetBufferDesc = BufferDesc;
340db2bae30SDana Myers }
341db2bae30SDana Myers
342db2bae30SDana Myers return_ACPI_STATUS (Status);
343db2bae30SDana Myers }
344db2bae30SDana Myers
345db2bae30SDana Myers
346db2bae30SDana Myers /*******************************************************************************
347db2bae30SDana Myers *
348db2bae30SDana Myers * FUNCTION: AcpiExWriteDataToField
349db2bae30SDana Myers *
350db2bae30SDana Myers * PARAMETERS: SourceDesc - Contains data to write
351db2bae30SDana Myers * ObjDesc - The named field
352db2bae30SDana Myers * ResultDesc - Where the return value is returned, if any
353db2bae30SDana Myers *
354db2bae30SDana Myers * RETURN: Status
355db2bae30SDana Myers *
356db2bae30SDana Myers * DESCRIPTION: Write to a named field
357db2bae30SDana Myers *
358db2bae30SDana Myers ******************************************************************************/
359db2bae30SDana Myers
360db2bae30SDana Myers ACPI_STATUS
AcpiExWriteDataToField(ACPI_OPERAND_OBJECT * SourceDesc,ACPI_OPERAND_OBJECT * ObjDesc,ACPI_OPERAND_OBJECT ** ResultDesc)361db2bae30SDana Myers AcpiExWriteDataToField (
362db2bae30SDana Myers ACPI_OPERAND_OBJECT *SourceDesc,
363db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc,
364db2bae30SDana Myers ACPI_OPERAND_OBJECT **ResultDesc)
365db2bae30SDana Myers {
366db2bae30SDana Myers ACPI_STATUS Status;
367db2bae30SDana Myers UINT32 Length;
368db2bae30SDana Myers void *Buffer;
369db2bae30SDana Myers ACPI_OPERAND_OBJECT *BufferDesc;
37057190917SDana Myers UINT32 Function;
371*cb565728SJerry Jelinek UINT16 AccessorType;
372db2bae30SDana Myers
373db2bae30SDana Myers
374db2bae30SDana Myers ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
375db2bae30SDana Myers
376db2bae30SDana Myers
377db2bae30SDana Myers /* Parameter validation */
378db2bae30SDana Myers
379db2bae30SDana Myers if (!SourceDesc || !ObjDesc)
380db2bae30SDana Myers {
381db2bae30SDana Myers return_ACPI_STATUS (AE_AML_NO_OPERAND);
382db2bae30SDana Myers }
383db2bae30SDana Myers
384aa2aa9a6SDana Myers if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
385db2bae30SDana Myers {
386db2bae30SDana Myers /*
387db2bae30SDana Myers * If the BufferField arguments have not been previously evaluated,
388db2bae30SDana Myers * evaluate them now and save the results.
389db2bae30SDana Myers */
390db2bae30SDana Myers if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
391db2bae30SDana Myers {
392db2bae30SDana Myers Status = AcpiDsGetBufferFieldArguments (ObjDesc);
393db2bae30SDana Myers if (ACPI_FAILURE (Status))
394db2bae30SDana Myers {
395db2bae30SDana Myers return_ACPI_STATUS (Status);
396db2bae30SDana Myers }
397db2bae30SDana Myers }
398db2bae30SDana Myers }
399aa2aa9a6SDana Myers else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
40057190917SDana Myers (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
401*cb565728SJerry Jelinek ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
40257190917SDana Myers ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
403db2bae30SDana Myers {
404db2bae30SDana Myers /*
405*cb565728SJerry Jelinek * This is an SMBus, GSBus or IPMI write. We will bypass the entire
406*cb565728SJerry Jelinek * field mechanism and handoff the buffer directly to the handler.
407*cb565728SJerry Jelinek * For these address spaces, the buffer is bi-directional; on a
408*cb565728SJerry Jelinek * write, return data is returned in the same buffer.
409db2bae30SDana Myers *
41057190917SDana Myers * Source must be a buffer of sufficient size:
411*cb565728SJerry Jelinek * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
412*cb565728SJerry Jelinek * ACPI_IPMI_BUFFER_SIZE.
41357190917SDana Myers *
414*cb565728SJerry Jelinek * Note: SMBus and GSBus protocol type is passed in upper 16-bits
415*cb565728SJerry Jelinek * of Function
416db2bae30SDana Myers */
417aa2aa9a6SDana Myers if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
418db2bae30SDana Myers {
41957190917SDana Myers ACPI_ERROR ((AE_INFO,
420*cb565728SJerry Jelinek "SMBus/IPMI/GenericSerialBus write requires "
421*cb565728SJerry Jelinek "Buffer, found type %s",
422db2bae30SDana Myers AcpiUtGetObjectTypeName (SourceDesc)));
423db2bae30SDana Myers
424db2bae30SDana Myers return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
425db2bae30SDana Myers }
426db2bae30SDana Myers
427*cb565728SJerry Jelinek if (ObjDesc->Field.RegionObj->Region.SpaceId ==
428*cb565728SJerry Jelinek ACPI_ADR_SPACE_SMBUS)
42957190917SDana Myers {
43057190917SDana Myers Length = ACPI_SMBUS_BUFFER_SIZE;
43157190917SDana Myers Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
43257190917SDana Myers }
433*cb565728SJerry Jelinek else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
434*cb565728SJerry Jelinek ACPI_ADR_SPACE_GSBUS)
435*cb565728SJerry Jelinek {
436*cb565728SJerry Jelinek AccessorType = ObjDesc->Field.Attribute;
437*cb565728SJerry Jelinek Length = AcpiExGetSerialAccessLength (
438*cb565728SJerry Jelinek AccessorType, ObjDesc->Field.AccessLength);
439*cb565728SJerry Jelinek
440*cb565728SJerry Jelinek /*
441*cb565728SJerry Jelinek * Add additional 2 bytes for the GenericSerialBus data buffer:
442*cb565728SJerry Jelinek *
443*cb565728SJerry Jelinek * Status; (Byte 0 of the data buffer)
444*cb565728SJerry Jelinek * Length; (Byte 1 of the data buffer)
445*cb565728SJerry Jelinek * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
446*cb565728SJerry Jelinek */
447*cb565728SJerry Jelinek Length += 2;
448*cb565728SJerry Jelinek Function = ACPI_WRITE | (AccessorType << 16);
449*cb565728SJerry Jelinek }
45057190917SDana Myers else /* IPMI */
45157190917SDana Myers {
45257190917SDana Myers Length = ACPI_IPMI_BUFFER_SIZE;
45357190917SDana Myers Function = ACPI_WRITE;
45457190917SDana Myers }
45557190917SDana Myers
45657190917SDana Myers if (SourceDesc->Buffer.Length < Length)
457db2bae30SDana Myers {
458db2bae30SDana Myers ACPI_ERROR ((AE_INFO,
459*cb565728SJerry Jelinek "SMBus/IPMI/GenericSerialBus write requires "
460*cb565728SJerry Jelinek "Buffer of length %u, found length %u",
46157190917SDana Myers Length, SourceDesc->Buffer.Length));
462db2bae30SDana Myers
463db2bae30SDana Myers return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
464db2bae30SDana Myers }
465db2bae30SDana Myers
46657190917SDana Myers /* Create the bi-directional buffer */
46757190917SDana Myers
46857190917SDana Myers BufferDesc = AcpiUtCreateBufferObject (Length);
469db2bae30SDana Myers if (!BufferDesc)
470db2bae30SDana Myers {
471db2bae30SDana Myers return_ACPI_STATUS (AE_NO_MEMORY);
472db2bae30SDana Myers }
473db2bae30SDana Myers
474db2bae30SDana Myers Buffer = BufferDesc->Buffer.Pointer;
475*cb565728SJerry Jelinek memcpy (Buffer, SourceDesc->Buffer.Pointer, Length);
476db2bae30SDana Myers
477db2bae30SDana Myers /* Lock entire transaction if requested */
478db2bae30SDana Myers
479db2bae30SDana Myers AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
480db2bae30SDana Myers
481db2bae30SDana Myers /*
482db2bae30SDana Myers * Perform the write (returns status and perhaps data in the
483db2bae30SDana Myers * same buffer)
484db2bae30SDana Myers */
485*cb565728SJerry Jelinek Status = AcpiExAccessRegion (
486*cb565728SJerry Jelinek ObjDesc, 0, (UINT64 *) Buffer, Function);
487db2bae30SDana Myers AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
488db2bae30SDana Myers
489db2bae30SDana Myers *ResultDesc = BufferDesc;
490db2bae30SDana Myers return_ACPI_STATUS (Status);
491db2bae30SDana Myers }
492*cb565728SJerry Jelinek else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
493*cb565728SJerry Jelinek (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
494*cb565728SJerry Jelinek {
495*cb565728SJerry Jelinek /*
496*cb565728SJerry Jelinek * For GPIO (GeneralPurposeIo), we will bypass the entire field
497*cb565728SJerry Jelinek * mechanism and handoff the bit address and bit width directly to
498*cb565728SJerry Jelinek * the handler. The Address will be the bit offset
499*cb565728SJerry Jelinek * from the previous Connection() operator, making it effectively a
500*cb565728SJerry Jelinek * pin number index. The BitLength is the length of the field, which
501*cb565728SJerry Jelinek * is thus the number of pins.
502*cb565728SJerry Jelinek */
503*cb565728SJerry Jelinek if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
504*cb565728SJerry Jelinek {
505*cb565728SJerry Jelinek return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
506*cb565728SJerry Jelinek }
507*cb565728SJerry Jelinek
508*cb565728SJerry Jelinek ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
509*cb565728SJerry Jelinek "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
510*cb565728SJerry Jelinek AcpiUtGetTypeName (SourceDesc->Common.Type),
511*cb565728SJerry Jelinek SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
512*cb565728SJerry Jelinek ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
513*cb565728SJerry Jelinek
514*cb565728SJerry Jelinek Buffer = &SourceDesc->Integer.Value;
515*cb565728SJerry Jelinek
516*cb565728SJerry Jelinek /* Lock entire transaction if requested */
517*cb565728SJerry Jelinek
518*cb565728SJerry Jelinek AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
519*cb565728SJerry Jelinek
520*cb565728SJerry Jelinek /* Perform the write */
521*cb565728SJerry Jelinek
522*cb565728SJerry Jelinek Status = AcpiExAccessRegion (
523*cb565728SJerry Jelinek ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE);
524*cb565728SJerry Jelinek AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
525*cb565728SJerry Jelinek return_ACPI_STATUS (Status);
526*cb565728SJerry Jelinek }
527db2bae30SDana Myers
528db2bae30SDana Myers /* Get a pointer to the data to be written */
529db2bae30SDana Myers
530aa2aa9a6SDana Myers switch (SourceDesc->Common.Type)
531db2bae30SDana Myers {
532db2bae30SDana Myers case ACPI_TYPE_INTEGER:
533*cb565728SJerry Jelinek
534db2bae30SDana Myers Buffer = &SourceDesc->Integer.Value;
535db2bae30SDana Myers Length = sizeof (SourceDesc->Integer.Value);
536db2bae30SDana Myers break;
537db2bae30SDana Myers
538db2bae30SDana Myers case ACPI_TYPE_BUFFER:
539*cb565728SJerry Jelinek
540db2bae30SDana Myers Buffer = SourceDesc->Buffer.Pointer;
541db2bae30SDana Myers Length = SourceDesc->Buffer.Length;
542db2bae30SDana Myers break;
543db2bae30SDana Myers
544db2bae30SDana Myers case ACPI_TYPE_STRING:
545*cb565728SJerry Jelinek
546db2bae30SDana Myers Buffer = SourceDesc->String.Pointer;
547db2bae30SDana Myers Length = SourceDesc->String.Length;
548db2bae30SDana Myers break;
549db2bae30SDana Myers
550db2bae30SDana Myers default:
551*cb565728SJerry Jelinek
552db2bae30SDana Myers return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
553db2bae30SDana Myers }
554db2bae30SDana Myers
555db2bae30SDana Myers ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
556db2bae30SDana Myers "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
557aa2aa9a6SDana Myers SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
558aa2aa9a6SDana Myers SourceDesc->Common.Type, Buffer, Length));
559db2bae30SDana Myers
560db2bae30SDana Myers ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
561db2bae30SDana Myers "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
562aa2aa9a6SDana Myers ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
563aa2aa9a6SDana Myers ObjDesc->Common.Type,
564db2bae30SDana Myers ObjDesc->CommonField.BitLength,
565db2bae30SDana Myers ObjDesc->CommonField.StartFieldBitOffset,
566db2bae30SDana Myers ObjDesc->CommonField.BaseByteOffset));
567db2bae30SDana Myers
568db2bae30SDana Myers /* Lock entire transaction if requested */
569db2bae30SDana Myers
570db2bae30SDana Myers AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
571db2bae30SDana Myers
572db2bae30SDana Myers /* Write to the field */
573db2bae30SDana Myers
574db2bae30SDana Myers Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
575db2bae30SDana Myers AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
576db2bae30SDana Myers
577db2bae30SDana Myers return_ACPI_STATUS (Status);
578db2bae30SDana Myers }
579