ace88c859ca5c2523796dffda70f58fac95f75be
[reactos.git] / drivers / bus / acpi / acpica / executer / exfield.c
1 /******************************************************************************
2 *
3 * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2017, 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.h"
45 #include "accommon.h"
46 #include "acdispat.h"
47 #include "acinterp.h"
48 #include "amlcode.h"
49
50
51 #define _COMPONENT ACPI_EXECUTER
52 ACPI_MODULE_NAME ("exfield")
53
54 /* Local prototypes */
55
56 static UINT32
57 AcpiExGetSerialAccessLength (
58 UINT32 AccessorType,
59 UINT32 AccessLength);
60
61
62 /*******************************************************************************
63 *
64 * FUNCTION: AcpiExGetSerialAccessLength
65 *
66 * PARAMETERS: AccessorType - The type of the protocol indicated by region
67 * field access attributes
68 * AccessLength - The access length of the region field
69 *
70 * RETURN: Decoded access length
71 *
72 * DESCRIPTION: This routine returns the length of the GenericSerialBus
73 * protocol bytes
74 *
75 ******************************************************************************/
76
77 static UINT32
78 AcpiExGetSerialAccessLength (
79 UINT32 AccessorType,
80 UINT32 AccessLength)
81 {
82 UINT32 Length;
83
84
85 switch (AccessorType)
86 {
87 case AML_FIELD_ATTRIB_QUICK:
88
89 Length = 0;
90 break;
91
92 case AML_FIELD_ATTRIB_SEND_RCV:
93 case AML_FIELD_ATTRIB_BYTE:
94
95 Length = 1;
96 break;
97
98 case AML_FIELD_ATTRIB_WORD:
99 case AML_FIELD_ATTRIB_WORD_CALL:
100
101 Length = 2;
102 break;
103
104 case AML_FIELD_ATTRIB_MULTIBYTE:
105 case AML_FIELD_ATTRIB_RAW_BYTES:
106 case AML_FIELD_ATTRIB_RAW_PROCESS:
107
108 Length = AccessLength;
109 break;
110
111 case AML_FIELD_ATTRIB_BLOCK:
112 case AML_FIELD_ATTRIB_BLOCK_CALL:
113 default:
114
115 Length = ACPI_GSBUS_BUFFER_SIZE - 2;
116 break;
117 }
118
119 return (Length);
120 }
121
122
123 /*******************************************************************************
124 *
125 * FUNCTION: AcpiExReadDataFromField
126 *
127 * PARAMETERS: WalkState - Current execution state
128 * ObjDesc - The named field
129 * RetBufferDesc - Where the return data object is stored
130 *
131 * RETURN: Status
132 *
133 * DESCRIPTION: Read from a named field. Returns either an Integer or a
134 * Buffer, depending on the size of the field.
135 *
136 ******************************************************************************/
137
138 ACPI_STATUS
139 AcpiExReadDataFromField (
140 ACPI_WALK_STATE *WalkState,
141 ACPI_OPERAND_OBJECT *ObjDesc,
142 ACPI_OPERAND_OBJECT **RetBufferDesc)
143 {
144 ACPI_STATUS Status;
145 ACPI_OPERAND_OBJECT *BufferDesc;
146 ACPI_SIZE Length;
147 void *Buffer;
148 UINT32 Function;
149 UINT16 AccessorType;
150
151
152 ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
153
154
155 /* Parameter validation */
156
157 if (!ObjDesc)
158 {
159 return_ACPI_STATUS (AE_AML_NO_OPERAND);
160 }
161 if (!RetBufferDesc)
162 {
163 return_ACPI_STATUS (AE_BAD_PARAMETER);
164 }
165
166 if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
167 {
168 /*
169 * If the BufferField arguments have not been previously evaluated,
170 * evaluate them now and save the results.
171 */
172 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
173 {
174 Status = AcpiDsGetBufferFieldArguments (ObjDesc);
175 if (ACPI_FAILURE (Status))
176 {
177 return_ACPI_STATUS (Status);
178 }
179 }
180 }
181 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
182 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
183 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
184 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
185 {
186 /*
187 * This is an SMBus, GSBus or IPMI read. We must create a buffer to
188 * hold the data and then directly access the region handler.
189 *
190 * Note: SMBus and GSBus protocol value is passed in upper 16-bits
191 * of Function
192 */
193 if (ObjDesc->Field.RegionObj->Region.SpaceId ==
194 ACPI_ADR_SPACE_SMBUS)
195 {
196 Length = ACPI_SMBUS_BUFFER_SIZE;
197 Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
198 }
199 else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
200 ACPI_ADR_SPACE_GSBUS)
201 {
202 AccessorType = ObjDesc->Field.Attribute;
203 Length = AcpiExGetSerialAccessLength (
204 AccessorType, ObjDesc->Field.AccessLength);
205
206 /*
207 * Add additional 2 bytes for the GenericSerialBus data buffer:
208 *
209 * Status; (Byte 0 of the data buffer)
210 * Length; (Byte 1 of the data buffer)
211 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
212 */
213 Length += 2;
214 Function = ACPI_READ | (AccessorType << 16);
215 }
216 else /* IPMI */
217 {
218 Length = ACPI_IPMI_BUFFER_SIZE;
219 Function = ACPI_READ;
220 }
221
222 BufferDesc = AcpiUtCreateBufferObject (Length);
223 if (!BufferDesc)
224 {
225 return_ACPI_STATUS (AE_NO_MEMORY);
226 }
227
228 /* Lock entire transaction if requested */
229
230 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
231
232 /* Call the region handler for the read */
233
234 Status = AcpiExAccessRegion (ObjDesc, 0,
235 ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function);
236
237 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
238 goto Exit;
239 }
240
241 /*
242 * Allocate a buffer for the contents of the field.
243 *
244 * If the field is larger than the current integer width, create
245 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
246 * the use of arithmetic operators on the returned value if the
247 * field size is equal or smaller than an Integer.
248 *
249 * Note: Field.length is in bits.
250 */
251 Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (
252 ObjDesc->Field.BitLength);
253
254 if (Length > AcpiGbl_IntegerByteWidth)
255 {
256 /* Field is too large for an Integer, create a Buffer instead */
257
258 BufferDesc = AcpiUtCreateBufferObject (Length);
259 if (!BufferDesc)
260 {
261 return_ACPI_STATUS (AE_NO_MEMORY);
262 }
263 Buffer = BufferDesc->Buffer.Pointer;
264 }
265 else
266 {
267 /* Field will fit within an Integer (normal case) */
268
269 BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
270 if (!BufferDesc)
271 {
272 return_ACPI_STATUS (AE_NO_MEMORY);
273 }
274
275 Length = AcpiGbl_IntegerByteWidth;
276 Buffer = &BufferDesc->Integer.Value;
277 }
278
279 if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
280 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
281 {
282 /*
283 * For GPIO (GeneralPurposeIo), the Address will be the bit offset
284 * from the previous Connection() operator, making it effectively a
285 * pin number index. The BitLength is the length of the field, which
286 * is thus the number of pins.
287 */
288 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
289 "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
290 ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
291
292 /* Lock entire transaction if requested */
293
294 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
295
296 /* Perform the write */
297
298 Status = AcpiExAccessRegion (
299 ObjDesc, 0, (UINT64 *) Buffer, ACPI_READ);
300
301 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
302 if (ACPI_FAILURE (Status))
303 {
304 AcpiUtRemoveReference (BufferDesc);
305 }
306 else
307 {
308 *RetBufferDesc = BufferDesc;
309 }
310 return_ACPI_STATUS (Status);
311 }
312
313 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
314 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
315 ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
316 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
317 "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
318 ObjDesc->CommonField.BitLength,
319 ObjDesc->CommonField.StartFieldBitOffset,
320 ObjDesc->CommonField.BaseByteOffset));
321
322 /* Lock entire transaction if requested */
323
324 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
325
326 /* Read from the field */
327
328 Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
329 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
330
331
332 Exit:
333 if (ACPI_FAILURE (Status))
334 {
335 AcpiUtRemoveReference (BufferDesc);
336 }
337 else
338 {
339 *RetBufferDesc = BufferDesc;
340 }
341
342 return_ACPI_STATUS (Status);
343 }
344
345
346 /*******************************************************************************
347 *
348 * FUNCTION: AcpiExWriteDataToField
349 *
350 * PARAMETERS: SourceDesc - Contains data to write
351 * ObjDesc - The named field
352 * ResultDesc - Where the return value is returned, if any
353 *
354 * RETURN: Status
355 *
356 * DESCRIPTION: Write to a named field
357 *
358 ******************************************************************************/
359
360 ACPI_STATUS
361 AcpiExWriteDataToField (
362 ACPI_OPERAND_OBJECT *SourceDesc,
363 ACPI_OPERAND_OBJECT *ObjDesc,
364 ACPI_OPERAND_OBJECT **ResultDesc)
365 {
366 ACPI_STATUS Status;
367 UINT32 Length;
368 void *Buffer;
369 ACPI_OPERAND_OBJECT *BufferDesc;
370 UINT32 Function;
371 UINT16 AccessorType;
372
373
374 ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
375
376
377 /* Parameter validation */
378
379 if (!SourceDesc || !ObjDesc)
380 {
381 return_ACPI_STATUS (AE_AML_NO_OPERAND);
382 }
383
384 if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
385 {
386 /*
387 * If the BufferField arguments have not been previously evaluated,
388 * evaluate them now and save the results.
389 */
390 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
391 {
392 Status = AcpiDsGetBufferFieldArguments (ObjDesc);
393 if (ACPI_FAILURE (Status))
394 {
395 return_ACPI_STATUS (Status);
396 }
397 }
398 }
399 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
400 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
401 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
402 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
403 {
404 /*
405 * This is an SMBus, GSBus or IPMI write. We will bypass the entire
406 * field mechanism and handoff the buffer directly to the handler.
407 * For these address spaces, the buffer is bi-directional; on a
408 * write, return data is returned in the same buffer.
409 *
410 * Source must be a buffer of sufficient size:
411 * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
412 * ACPI_IPMI_BUFFER_SIZE.
413 *
414 * Note: SMBus and GSBus protocol type is passed in upper 16-bits
415 * of Function
416 */
417 if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
418 {
419 ACPI_ERROR ((AE_INFO,
420 "SMBus/IPMI/GenericSerialBus write requires "
421 "Buffer, found type %s",
422 AcpiUtGetObjectTypeName (SourceDesc)));
423
424 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
425 }
426
427 if (ObjDesc->Field.RegionObj->Region.SpaceId ==
428 ACPI_ADR_SPACE_SMBUS)
429 {
430 Length = ACPI_SMBUS_BUFFER_SIZE;
431 Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
432 }
433 else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
434 ACPI_ADR_SPACE_GSBUS)
435 {
436 AccessorType = ObjDesc->Field.Attribute;
437 Length = AcpiExGetSerialAccessLength (
438 AccessorType, ObjDesc->Field.AccessLength);
439
440 /*
441 * Add additional 2 bytes for the GenericSerialBus data buffer:
442 *
443 * Status; (Byte 0 of the data buffer)
444 * Length; (Byte 1 of the data buffer)
445 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
446 */
447 Length += 2;
448 Function = ACPI_WRITE | (AccessorType << 16);
449 }
450 else /* IPMI */
451 {
452 Length = ACPI_IPMI_BUFFER_SIZE;
453 Function = ACPI_WRITE;
454 }
455
456 if (SourceDesc->Buffer.Length < Length)
457 {
458 ACPI_ERROR ((AE_INFO,
459 "SMBus/IPMI/GenericSerialBus write requires "
460 "Buffer of length %u, found length %u",
461 Length, SourceDesc->Buffer.Length));
462
463 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
464 }
465
466 /* Create the bi-directional buffer */
467
468 BufferDesc = AcpiUtCreateBufferObject (Length);
469 if (!BufferDesc)
470 {
471 return_ACPI_STATUS (AE_NO_MEMORY);
472 }
473
474 Buffer = BufferDesc->Buffer.Pointer;
475 memcpy (Buffer, SourceDesc->Buffer.Pointer, Length);
476
477 /* Lock entire transaction if requested */
478
479 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
480
481 /*
482 * Perform the write (returns status and perhaps data in the
483 * same buffer)
484 */
485 Status = AcpiExAccessRegion (
486 ObjDesc, 0, (UINT64 *) Buffer, Function);
487 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
488
489 *ResultDesc = BufferDesc;
490 return_ACPI_STATUS (Status);
491 }
492 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
493 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
494 {
495 /*
496 * For GPIO (GeneralPurposeIo), we will bypass the entire field
497 * mechanism and handoff the bit address and bit width directly to
498 * the handler. The Address will be the bit offset
499 * from the previous Connection() operator, making it effectively a
500 * pin number index. The BitLength is the length of the field, which
501 * is thus the number of pins.
502 */
503 if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
504 {
505 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
506 }
507
508 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
509 "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
510 AcpiUtGetTypeName (SourceDesc->Common.Type),
511 SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
512 ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
513
514 Buffer = &SourceDesc->Integer.Value;
515
516 /* Lock entire transaction if requested */
517
518 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
519
520 /* Perform the write */
521
522 Status = AcpiExAccessRegion (
523 ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE);
524 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
525 return_ACPI_STATUS (Status);
526 }
527
528 /* Get a pointer to the data to be written */
529
530 switch (SourceDesc->Common.Type)
531 {
532 case ACPI_TYPE_INTEGER:
533
534 Buffer = &SourceDesc->Integer.Value;
535 Length = sizeof (SourceDesc->Integer.Value);
536 break;
537
538 case ACPI_TYPE_BUFFER:
539
540 Buffer = SourceDesc->Buffer.Pointer;
541 Length = SourceDesc->Buffer.Length;
542 break;
543
544 case ACPI_TYPE_STRING:
545
546 Buffer = SourceDesc->String.Pointer;
547 Length = SourceDesc->String.Length;
548 break;
549
550 default:
551
552 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
553 }
554
555 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
556 "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
557 SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
558 SourceDesc->Common.Type, Buffer, Length));
559
560 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
561 "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
562 ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
563 ObjDesc->Common.Type,
564 ObjDesc->CommonField.BitLength,
565 ObjDesc->CommonField.StartFieldBitOffset,
566 ObjDesc->CommonField.BaseByteOffset));
567
568 /* Lock entire transaction if requested */
569
570 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
571
572 /* Write to the field */
573
574 Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
575 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
576
577 return_ACPI_STATUS (Status);
578 }