1 /******************************************************************************
3 * Module Name: exserial - FieldUnit support for serial address spaces
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2019, 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.
51 #define _COMPONENT ACPI_EXECUTER
52 ACPI_MODULE_NAME ("exserial")
55 /*******************************************************************************
57 * FUNCTION: AcpiExReadGpio
59 * PARAMETERS: ObjDesc - The named field to read
60 * Buffer - Where the return data is returnd
64 * DESCRIPTION: Read from a named field that references a Generic Serial Bus
67 ******************************************************************************/
71 ACPI_OPERAND_OBJECT
*ObjDesc
,
77 ACPI_FUNCTION_TRACE_PTR (ExReadGpio
, ObjDesc
);
81 * For GPIO (GeneralPurposeIo), the Address will be the bit offset
82 * from the previous Connection() operator, making it effectively a
83 * pin number index. The BitLength is the length of the field, which
84 * is thus the number of pins.
86 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
87 "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
88 ObjDesc
->Field
.PinNumberIndex
, ObjDesc
->Field
.BitLength
));
90 /* Lock entire transaction if requested */
92 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
94 /* Perform the read */
96 Status
= AcpiExAccessRegion (
97 ObjDesc
, 0, (UINT64
*) Buffer
, ACPI_READ
);
99 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
100 return_ACPI_STATUS (Status
);
104 /*******************************************************************************
106 * FUNCTION: AcpiExWriteGpio
108 * PARAMETERS: SourceDesc - Contains data to write. Expect to be
110 * ObjDesc - The named field
111 * ResultDesc - Where the return value is returned, if any
115 * DESCRIPTION: Write to a named field that references a General Purpose I/O
118 ******************************************************************************/
122 ACPI_OPERAND_OBJECT
*SourceDesc
,
123 ACPI_OPERAND_OBJECT
*ObjDesc
,
124 ACPI_OPERAND_OBJECT
**ReturnBuffer
)
130 ACPI_FUNCTION_TRACE_PTR (ExWriteGpio
, ObjDesc
);
134 * For GPIO (GeneralPurposeIo), we will bypass the entire field
135 * mechanism and handoff the bit address and bit width directly to
136 * the handler. The Address will be the bit offset
137 * from the previous Connection() operator, making it effectively a
138 * pin number index. The BitLength is the length of the field, which
139 * is thus the number of pins.
141 if (SourceDesc
->Common
.Type
!= ACPI_TYPE_INTEGER
)
143 return_ACPI_STATUS (AE_AML_OPERAND_TYPE
);
146 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
147 "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X [TO]: Pin %u Bits %u\n",
148 AcpiUtGetTypeName (SourceDesc
->Common
.Type
),
149 SourceDesc
->Common
.Type
, (UINT32
) SourceDesc
->Integer
.Value
,
150 ObjDesc
->Field
.PinNumberIndex
, ObjDesc
->Field
.BitLength
));
152 Buffer
= &SourceDesc
->Integer
.Value
;
154 /* Lock entire transaction if requested */
156 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
158 /* Perform the write */
160 Status
= AcpiExAccessRegion (
161 ObjDesc
, 0, (UINT64
*) Buffer
, ACPI_WRITE
);
162 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
163 return_ACPI_STATUS (Status
);
167 /*******************************************************************************
169 * FUNCTION: AcpiExReadSerialBus
171 * PARAMETERS: ObjDesc - The named field to read
172 * ReturnBuffer - Where the return value is returned, if any
176 * DESCRIPTION: Read from a named field that references a serial bus
177 * (SMBus, IPMI, or GSBus).
179 ******************************************************************************/
182 AcpiExReadSerialBus (
183 ACPI_OPERAND_OBJECT
*ObjDesc
,
184 ACPI_OPERAND_OBJECT
**ReturnBuffer
)
188 ACPI_OPERAND_OBJECT
*BufferDesc
;
193 ACPI_FUNCTION_TRACE_PTR (ExReadSerialBus
, ObjDesc
);
197 * This is an SMBus, GSBus or IPMI read. We must create a buffer to
198 * hold the data and then directly access the region handler.
200 * Note: SMBus and GSBus protocol value is passed in upper 16-bits
203 * Common buffer format:
204 * Status; (Byte 0 of the data buffer)
205 * Length; (Byte 1 of the data buffer)
206 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
208 switch (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
)
210 case ACPI_ADR_SPACE_SMBUS
:
212 BufferLength
= ACPI_SMBUS_BUFFER_SIZE
;
213 Function
= ACPI_READ
| (ObjDesc
->Field
.Attribute
<< 16);
216 case ACPI_ADR_SPACE_IPMI
:
218 BufferLength
= ACPI_IPMI_BUFFER_SIZE
;
219 Function
= ACPI_READ
;
222 case ACPI_ADR_SPACE_GSBUS
:
224 AccessorType
= ObjDesc
->Field
.Attribute
;
225 if (AccessorType
== AML_FIELD_ATTRIB_RAW_PROCESS_BYTES
)
227 ACPI_ERROR ((AE_INFO
,
228 "Invalid direct read using bidirectional write-then-read protocol"));
230 return_ACPI_STATUS (AE_AML_PROTOCOL
);
233 Status
= AcpiExGetProtocolBufferLength (AccessorType
, &BufferLength
);
234 if (ACPI_FAILURE (Status
))
236 ACPI_ERROR ((AE_INFO
,
237 "Invalid protocol ID for GSBus: 0x%4.4X", AccessorType
));
239 return_ACPI_STATUS (Status
);
242 /* Add header length to get the full size of the buffer */
244 BufferLength
+= ACPI_SERIAL_HEADER_SIZE
;
245 Function
= ACPI_READ
| (AccessorType
<< 16);
249 return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID
);
252 /* Create the local transfer buffer that is returned to the caller */
254 BufferDesc
= AcpiUtCreateBufferObject (BufferLength
);
257 return_ACPI_STATUS (AE_NO_MEMORY
);
260 /* Lock entire transaction if requested */
262 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
264 /* Call the region handler for the write-then-read */
266 Status
= AcpiExAccessRegion (ObjDesc
, 0,
267 ACPI_CAST_PTR (UINT64
, BufferDesc
->Buffer
.Pointer
), Function
);
268 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
270 *ReturnBuffer
= BufferDesc
;
271 return_ACPI_STATUS (Status
);
275 /*******************************************************************************
277 * FUNCTION: AcpiExWriteSerialBus
279 * PARAMETERS: SourceDesc - Contains data to write
280 * ObjDesc - The named field
281 * ReturnBuffer - Where the return value is returned, if any
285 * DESCRIPTION: Write to a named field that references a serial bus
286 * (SMBus, IPMI, GSBus).
288 ******************************************************************************/
291 AcpiExWriteSerialBus (
292 ACPI_OPERAND_OBJECT
*SourceDesc
,
293 ACPI_OPERAND_OBJECT
*ObjDesc
,
294 ACPI_OPERAND_OBJECT
**ReturnBuffer
)
300 ACPI_OPERAND_OBJECT
*BufferDesc
;
305 ACPI_FUNCTION_TRACE_PTR (ExWriteSerialBus
, ObjDesc
);
309 * This is an SMBus, GSBus or IPMI write. We will bypass the entire
310 * field mechanism and handoff the buffer directly to the handler.
311 * For these address spaces, the buffer is bidirectional; on a
312 * write, return data is returned in the same buffer.
314 * Source must be a buffer of sufficient size, these are fixed size:
315 * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
317 * Note: SMBus and GSBus protocol type is passed in upper 16-bits
320 * Common buffer format:
321 * Status; (Byte 0 of the data buffer)
322 * Length; (Byte 1 of the data buffer)
323 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
325 if (SourceDesc
->Common
.Type
!= ACPI_TYPE_BUFFER
)
327 ACPI_ERROR ((AE_INFO
,
328 "SMBus/IPMI/GenericSerialBus write requires "
329 "Buffer, found type %s",
330 AcpiUtGetObjectTypeName (SourceDesc
)));
332 return_ACPI_STATUS (AE_AML_OPERAND_TYPE
);
335 switch (ObjDesc
->Field
.RegionObj
->Region
.SpaceId
)
337 case ACPI_ADR_SPACE_SMBUS
:
339 BufferLength
= ACPI_SMBUS_BUFFER_SIZE
;
340 Function
= ACPI_WRITE
| (ObjDesc
->Field
.Attribute
<< 16);
343 case ACPI_ADR_SPACE_IPMI
:
345 BufferLength
= ACPI_IPMI_BUFFER_SIZE
;
346 Function
= ACPI_WRITE
;
349 case ACPI_ADR_SPACE_GSBUS
:
351 AccessorType
= ObjDesc
->Field
.Attribute
;
352 Status
= AcpiExGetProtocolBufferLength (AccessorType
, &BufferLength
);
353 if (ACPI_FAILURE (Status
))
355 ACPI_ERROR ((AE_INFO
,
356 "Invalid protocol ID for GSBus: 0x%4.4X", AccessorType
));
358 return_ACPI_STATUS (Status
);
361 /* Add header length to get the full size of the buffer */
363 BufferLength
+= ACPI_SERIAL_HEADER_SIZE
;
364 Function
= ACPI_WRITE
| (AccessorType
<< 16);
368 return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID
);
371 /* Create the transfer/bidirectional/return buffer */
373 BufferDesc
= AcpiUtCreateBufferObject (BufferLength
);
376 return_ACPI_STATUS (AE_NO_MEMORY
);
379 /* Copy the input buffer data to the transfer buffer */
381 Buffer
= BufferDesc
->Buffer
.Pointer
;
382 DataLength
= (BufferLength
< SourceDesc
->Buffer
.Length
?
383 BufferLength
: SourceDesc
->Buffer
.Length
);
384 memcpy (Buffer
, SourceDesc
->Buffer
.Pointer
, DataLength
);
386 /* Lock entire transaction if requested */
388 AcpiExAcquireGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
391 * Perform the write (returns status and perhaps data in the
394 Status
= AcpiExAccessRegion (
395 ObjDesc
, 0, (UINT64
*) Buffer
, Function
);
396 AcpiExReleaseGlobalLock (ObjDesc
->CommonField
.FieldFlags
);
398 *ReturnBuffer
= BufferDesc
;
399 return_ACPI_STATUS (Status
);