1/******************************************************************************
2 *
3 * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
4 *              $Revision: 1.1.1.1 $
5 *
6 *****************************************************************************/
7
8/*
9 *  Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with this program; if not, write to the Free Software
23 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25
26
27#include "acpi.h"
28#include "acdispat.h"
29#include "acinterp.h"
30#include "amlcode.h"
31#include "acnamesp.h"
32#include "achware.h"
33#include "acevents.h"
34
35
36#define _COMPONENT          ACPI_EXECUTER
37	 MODULE_NAME         ("exfield")
38
39
40/*******************************************************************************
41 *
42 * FUNCTION:    Acpi_ex_read_data_from_field
43 *
44 * PARAMETERS:  Mode                - ACPI_READ or ACPI_WRITE
45 *              *Field_node         - Parent node for field to be accessed
46 *              *Buffer             - Value(s) to be read or written
47 *              Buffer_length       - Number of bytes to transfer
48 *
49 * RETURN:      Status3
50 *
51 * DESCRIPTION: Read or write a named field
52 *
53 ******************************************************************************/
54
55acpi_status
56acpi_ex_read_data_from_field (
57	acpi_operand_object     *obj_desc,
58	acpi_operand_object     **ret_buffer_desc)
59{
60	acpi_status             status;
61	acpi_operand_object     *buffer_desc;
62	u32                     length;
63	void                    *buffer;
64
65
66	FUNCTION_TRACE_PTR ("Ex_read_data_from_field", obj_desc);
67
68
69	/* Parameter validation */
70
71	if (!obj_desc) {
72		return_ACPI_STATUS (AE_AML_NO_OPERAND);
73	}
74
75	/*
76	 * Allocate a buffer for the contents of the field.
77	 *
78	 * If the field is larger than the size of an acpi_integer, create
79	 * a BUFFER to hold it.  Otherwise, use an INTEGER.  This allows
80	 * the use of arithmetic operators on the returned value if the
81	 * field size is equal or smaller than an Integer.
82	 *
83	 * Note: Field.length is in bits.
84	 */
85	length = ROUND_BITS_UP_TO_BYTES (obj_desc->field.bit_length);
86
87	if (length > sizeof (acpi_integer)) {
88		/* Field is too large for an Integer, create a Buffer instead */
89
90		buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
91		if (!buffer_desc) {
92			return_ACPI_STATUS (AE_NO_MEMORY);
93		}
94
95		/* Create the actual read buffer */
96
97		buffer_desc->buffer.pointer = ACPI_MEM_CALLOCATE (length);
98		if (!buffer_desc->buffer.pointer) {
99			acpi_ut_remove_reference (buffer_desc);
100			return_ACPI_STATUS (AE_NO_MEMORY);
101		}
102
103		buffer_desc->buffer.length = length;
104		buffer = buffer_desc->buffer.pointer;
105	}
106
107	else {
108		/* Field will fit within an Integer (normal case) */
109
110		buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
111		if (!buffer_desc) {
112			return_ACPI_STATUS (AE_NO_MEMORY);
113		}
114
115		length = sizeof (buffer_desc->integer.value);
116		buffer = &buffer_desc->integer.value;
117	}
118
119
120	/* Read from the appropriate field */
121
122	switch (obj_desc->common.type) {
123	case ACPI_TYPE_BUFFER_FIELD:
124		status = acpi_ex_access_buffer_field (ACPI_READ, obj_desc, buffer, length);
125		break;
126
127	case INTERNAL_TYPE_REGION_FIELD:
128		status = acpi_ex_access_region_field (ACPI_READ, obj_desc, buffer, length);
129		break;
130
131	case INTERNAL_TYPE_BANK_FIELD:
132		status = acpi_ex_access_bank_field (ACPI_READ, obj_desc, buffer, length);
133		break;
134
135	case INTERNAL_TYPE_INDEX_FIELD:
136		status = acpi_ex_access_index_field (ACPI_READ, obj_desc, buffer, length);
137		break;
138
139	default:
140		status = AE_AML_INTERNAL;
141	}
142
143
144	if (ACPI_FAILURE (status)) {
145		acpi_ut_remove_reference (buffer_desc);
146	}
147
148	else if (ret_buffer_desc) {
149		*ret_buffer_desc = buffer_desc;
150	}
151
152	return_ACPI_STATUS (status);
153}
154
155
156/*******************************************************************************
157 *
158 * FUNCTION:    Acpi_ex_write_data_to_field
159 *
160 * PARAMETERS:  Mode                - ACPI_READ or ACPI_WRITE
161 *              *Field_node         - Parent node for field to be accessed
162 *              *Buffer             - Value(s) to be read or written
163 *              Buffer_length       - Number of bytes to transfer
164 *
165 * RETURN:      Status
166 *
167 * DESCRIPTION: Read or write a named field
168 *
169 ******************************************************************************/
170
171
172acpi_status
173acpi_ex_write_data_to_field (
174	acpi_operand_object     *source_desc,
175	acpi_operand_object     *obj_desc)
176{
177	acpi_status             status;
178	u32                     length;
179	void                    *buffer;
180
181
182	FUNCTION_TRACE_PTR ("Ex_write_data_to_field", obj_desc);
183
184
185	/* Parameter validation */
186
187	if (!source_desc || !obj_desc) {
188		return_ACPI_STATUS (AE_AML_NO_OPERAND);
189	}
190
191
192	/*
193	 * Get a pointer to the data to be written
194	 */
195	switch (source_desc->common.type) {
196	case ACPI_TYPE_INTEGER:
197		buffer = &source_desc->integer.value;
198		length = sizeof (source_desc->integer.value);
199		break;
200
201	case ACPI_TYPE_BUFFER:
202		buffer = source_desc->buffer.pointer;
203		length = source_desc->buffer.length;
204		break;
205
206	case ACPI_TYPE_STRING:
207		buffer = source_desc->string.pointer;
208		length = source_desc->string.length;
209		break;
210
211	default:
212		return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
213	}
214
215
216	/*
217	 * Decode the type of field to be written
218	 */
219	switch (obj_desc->common.type) {
220	case ACPI_TYPE_BUFFER_FIELD:
221		status = acpi_ex_access_buffer_field (ACPI_WRITE, obj_desc, buffer, length);
222		break;
223
224	case INTERNAL_TYPE_REGION_FIELD:
225		status = acpi_ex_access_region_field (ACPI_WRITE, obj_desc, buffer, length);
226		break;
227
228	case INTERNAL_TYPE_BANK_FIELD:
229		status = acpi_ex_access_bank_field (ACPI_WRITE, obj_desc, buffer, length);
230		break;
231
232	case INTERNAL_TYPE_INDEX_FIELD:
233		status = acpi_ex_access_index_field (ACPI_WRITE, obj_desc, buffer, length);
234		break;
235
236	default:
237		return_ACPI_STATUS (AE_AML_INTERNAL);
238	}
239
240
241	return_ACPI_STATUS (status);
242}
243
244
245/*******************************************************************************
246 *
247 * FUNCTION:    Acpi_ex_access_buffer_field
248 *
249 * PARAMETERS:  Mode                - ACPI_READ or ACPI_WRITE
250 *              *Field_node         - Parent node for field to be accessed
251 *              *Buffer             - Value(s) to be read or written
252 *              Buffer_length       - Number of bytes to transfer
253 *
254 * RETURN:      Status
255 *
256 * DESCRIPTION: Read or write a named field
257 *
258 ******************************************************************************/
259
260acpi_status
261acpi_ex_access_buffer_field (
262	u32                     mode,
263	acpi_operand_object     *obj_desc,
264	void                    *buffer,
265	u32                     buffer_length)
266{
267	acpi_status             status;
268
269
270	FUNCTION_TRACE_PTR ("Ex_access_buffer_field", obj_desc);
271
272
273	/*
274	 * If the Buffer_field arguments have not been previously evaluated,
275	 * evaluate them now and save the results.
276	 */
277	if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
278		status = acpi_ds_get_buffer_field_arguments (obj_desc);
279		if (ACPI_FAILURE (status)) {
280			return_ACPI_STATUS (status);
281		}
282	}
283
284
285	status = acpi_ex_common_access_field (mode, obj_desc, buffer, buffer_length);
286
287	return_ACPI_STATUS (status);
288}
289
290
291/*******************************************************************************
292 *
293 * FUNCTION:    Acpi_ex_access_region_field
294 *
295 * PARAMETERS:  Mode                - ACPI_READ or ACPI_WRITE
296 *              *Field_node         - Parent node for field to be accessed
297 *              *Buffer             - Value(s) to be read or written
298 *              Buffer_length       - Number of bytes to transfer
299 *
300 * RETURN:      Status
301 *
302 * DESCRIPTION: Read or write a named field
303 *
304 ******************************************************************************/
305
306acpi_status
307acpi_ex_access_region_field (
308	u32                     mode,
309	acpi_operand_object     *obj_desc,
310	void                    *buffer,
311	u32                     buffer_length)
312{
313	acpi_status             status;
314	u8                      locked;
315
316
317	FUNCTION_TRACE_PTR ("Ex_access_region_field", obj_desc);
318
319
320	/*
321	 * Get the global lock if needed
322	 */
323	locked = acpi_ex_acquire_global_lock (obj_desc->field.lock_rule);
324
325	status = acpi_ex_common_access_field (mode, obj_desc, buffer, buffer_length);
326
327
328	/*
329	 * Release global lock if we acquired it earlier
330	 */
331	acpi_ex_release_global_lock (locked);
332
333	return_ACPI_STATUS (status);
334}
335
336
337/*******************************************************************************
338 *
339 * FUNCTION:    Acpi_ex_access_bank_field
340 *
341 * PARAMETERS:  Mode                - ACPI_READ or ACPI_WRITE
342 *              *Field_node         - Parent node for field to be accessed
343 *              *Buffer             - Value(s) to be read or written
344 *              Buffer_length       - Number of bytes to transfer
345 *
346 * RETURN:      Status
347 *
348 * DESCRIPTION: Read or write a Bank Field
349 *
350 ******************************************************************************/
351
352acpi_status
353acpi_ex_access_bank_field (
354	u32                     mode,
355	acpi_operand_object     *obj_desc,
356	void                    *buffer,
357	u32                     buffer_length)
358{
359	acpi_status             status;
360	u8                      locked;
361
362
363	FUNCTION_TRACE_PTR ("Ex_access_bank_field", obj_desc);
364
365
366	/*
367	 * Get the global lock if needed
368	 */
369	locked = acpi_ex_acquire_global_lock (obj_desc->bank_field.lock_rule);
370
371
372	/*
373	 * Write the Bank_value to the Bank_register to select the bank.
374	 * The Bank_value for this Bank_field is specified in the
375	 * Bank_field ASL declaration. The Bank_register is always a Field in
376	 * an operation region.
377	 */
378	status = acpi_ex_common_access_field (ACPI_WRITE,
379			 obj_desc->bank_field.bank_register_obj,
380			 &obj_desc->bank_field.value,
381			 sizeof (obj_desc->bank_field.value));
382	if (ACPI_FAILURE (status)) {
383		goto cleanup;
384	}
385
386	/*
387	 * The bank was successfully selected, now read or write the actual
388	 * data.
389	 */
390	status = acpi_ex_common_access_field (mode, obj_desc, buffer, buffer_length);
391
392
393cleanup:
394	/*
395	 * Release global lock if we acquired it earlier
396	 */
397	acpi_ex_release_global_lock (locked);
398
399	return_ACPI_STATUS (status);
400}
401
402
403/*******************************************************************************
404 *
405 * FUNCTION:    Acpi_ex_access_index_field
406 *
407 * PARAMETERS:  Mode                - ACPI_READ or ACPI_WRITE
408 *              *Field_node         - Parent node for field to be accessed
409 *              *Buffer             - Value(s) to be read or written
410 *              Buffer_length       - Number of bytes to transfer
411 *
412 * RETURN:      Status
413 *
414 * DESCRIPTION: Read or write a Index Field
415 *
416 ******************************************************************************/
417
418acpi_status
419acpi_ex_access_index_field (
420	u32                     mode,
421	acpi_operand_object     *obj_desc,
422	void                    *buffer,
423	u32                     buffer_length)
424{
425	acpi_status             status;
426	u8                      locked;
427
428
429	FUNCTION_TRACE_PTR ("Ex_access_index_field", obj_desc);
430
431
432	/*
433	 * Get the global lock if needed
434	 */
435	locked = acpi_ex_acquire_global_lock (obj_desc->index_field.lock_rule);
436
437
438	/*
439	 * Set Index value to select proper Data register
440	 */
441	status = acpi_ex_common_access_field (ACPI_WRITE,
442			 obj_desc->index_field.index_obj,
443			 &obj_desc->index_field.value,
444			 sizeof (obj_desc->index_field.value));
445	if (ACPI_FAILURE (status)) {
446		goto cleanup;
447	}
448
449	/* Now read/write the data register */
450
451	status = acpi_ex_common_access_field (mode, obj_desc->index_field.data_obj,
452			  buffer, buffer_length);
453
454cleanup:
455	/*
456	 * Release global lock if we acquired it earlier
457	 */
458	acpi_ex_release_global_lock (locked);
459
460	return_ACPI_STATUS (status);
461}
462
463
464/*******************************************************************************
465 *
466 * FUNCTION:    Acpi_ex_common_access_field
467 *
468 * PARAMETERS:  Mode                - ACPI_READ or ACPI_WRITE
469 *              *Field_node         - Parent node for field to be accessed
470 *              *Buffer             - Value(s) to be read or written
471 *              Buffer_length       - Size of buffer, in bytes.  Must be large
472 *                                    enough for all bits of the field.
473 *
474 * RETURN:      Status
475 *
476 * DESCRIPTION: Read or write a named field
477 *
478 ******************************************************************************/
479
480acpi_status
481acpi_ex_common_access_field (
482	u32                     mode,
483	acpi_operand_object     *obj_desc,
484	void                    *buffer,
485	u32                     buffer_length)
486{
487	acpi_status             status;
488
489
490	FUNCTION_TRACE_PTR ("Ex_common_access_field", obj_desc);
491
492
493	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj=%p Type=%X Buf=%p Len=%X\n",
494		obj_desc, obj_desc->common.type, buffer, buffer_length));
495	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode=%d Bit_len=%X Bit_off=%X Byte_off=%X\n",
496		mode, obj_desc->common_field.bit_length,
497		obj_desc->common_field.start_field_bit_offset,
498		obj_desc->common_field.base_byte_offset));
499
500
501	/* Perform the actual read or write of the field */
502
503	switch (mode) {
504	case ACPI_READ:
505
506		status = acpi_ex_extract_from_field (obj_desc, buffer, buffer_length);
507		break;
508
509
510	case ACPI_WRITE:
511
512		status = acpi_ex_insert_into_field (obj_desc, buffer, buffer_length);
513		break;
514
515
516	default:
517
518		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown I/O Mode: %X\n", mode));
519		status = AE_BAD_PARAMETER;
520		break;
521	}
522
523
524	return_ACPI_STATUS (status);
525}
526
527