Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: exfldio - Aml Field I/O | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
8 | * Copyright (C) 2000 - 2005, R. Byron Moore | |
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 | ||
45 | #include <acpi/acpi.h> | |
46 | #include <acpi/acinterp.h> | |
47 | #include <acpi/amlcode.h> | |
48 | #include <acpi/acevents.h> | |
49 | #include <acpi/acdispat.h> | |
50 | ||
51 | ||
52 | #define _COMPONENT ACPI_EXECUTER | |
53 | ACPI_MODULE_NAME ("exfldio") | |
54 | ||
55 | ||
56 | /******************************************************************************* | |
57 | * | |
58 | * FUNCTION: acpi_ex_setup_region | |
59 | * | |
60 | * PARAMETERS: *obj_desc - Field to be read or written | |
61 | * field_datum_byte_offset - Byte offset of this datum within the | |
62 | * parent field | |
63 | * | |
64 | * RETURN: Status | |
65 | * | |
66 | * DESCRIPTION: Common processing for acpi_ex_extract_from_field and | |
67 | * acpi_ex_insert_into_field. Initialize the Region if necessary and | |
68 | * validate the request. | |
69 | * | |
70 | ******************************************************************************/ | |
71 | ||
72 | acpi_status | |
73 | acpi_ex_setup_region ( | |
74 | union acpi_operand_object *obj_desc, | |
75 | u32 field_datum_byte_offset) | |
76 | { | |
77 | acpi_status status = AE_OK; | |
78 | union acpi_operand_object *rgn_desc; | |
79 | ||
80 | ||
81 | ACPI_FUNCTION_TRACE_U32 ("ex_setup_region", field_datum_byte_offset); | |
82 | ||
83 | ||
84 | rgn_desc = obj_desc->common_field.region_obj; | |
85 | ||
86 | /* We must have a valid region */ | |
87 | ||
88 | if (ACPI_GET_OBJECT_TYPE (rgn_desc) != ACPI_TYPE_REGION) { | |
89 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n", | |
90 | ACPI_GET_OBJECT_TYPE (rgn_desc), | |
91 | acpi_ut_get_object_type_name (rgn_desc))); | |
92 | ||
93 | return_ACPI_STATUS (AE_AML_OPERAND_TYPE); | |
94 | } | |
95 | ||
96 | /* | |
97 | * If the Region Address and Length have not been previously evaluated, | |
98 | * evaluate them now and save the results. | |
99 | */ | |
100 | if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) { | |
101 | status = acpi_ds_get_region_arguments (rgn_desc); | |
102 | if (ACPI_FAILURE (status)) { | |
103 | return_ACPI_STATUS (status); | |
104 | } | |
105 | } | |
106 | ||
107 | if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { | |
108 | /* SMBus has a non-linear address space */ | |
109 | ||
110 | return_ACPI_STATUS (AE_OK); | |
111 | } | |
112 | ||
113 | #ifdef ACPI_UNDER_DEVELOPMENT | |
114 | /* | |
115 | * If the Field access is any_acc, we can now compute the optimal | |
116 | * access (because we know know the length of the parent region) | |
117 | */ | |
118 | if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { | |
119 | if (ACPI_FAILURE (status)) { | |
120 | return_ACPI_STATUS (status); | |
121 | } | |
122 | } | |
123 | #endif | |
124 | ||
125 | /* | |
126 | * Validate the request. The entire request from the byte offset for a | |
127 | * length of one field datum (access width) must fit within the region. | |
128 | * (Region length is specified in bytes) | |
129 | */ | |
130 | if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset | |
131 | + field_datum_byte_offset | |
132 | + obj_desc->common_field.access_byte_width)) { | |
133 | if (acpi_gbl_enable_interpreter_slack) { | |
134 | /* | |
135 | * Slack mode only: We will go ahead and allow access to this | |
136 | * field if it is within the region length rounded up to the next | |
137 | * access width boundary. | |
138 | */ | |
139 | if (ACPI_ROUND_UP (rgn_desc->region.length, | |
140 | obj_desc->common_field.access_byte_width) >= | |
141 | (obj_desc->common_field.base_byte_offset + | |
142 | (acpi_native_uint) obj_desc->common_field.access_byte_width + | |
143 | field_datum_byte_offset)) { | |
144 | return_ACPI_STATUS (AE_OK); | |
145 | } | |
146 | } | |
147 | ||
148 | if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { | |
149 | /* | |
150 | * This is the case where the access_type (acc_word, etc.) is wider | |
151 | * than the region itself. For example, a region of length one | |
152 | * byte, and a field with Dword access specified. | |
153 | */ | |
154 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
155 | "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", | |
156 | acpi_ut_get_node_name (obj_desc->common_field.node), | |
157 | obj_desc->common_field.access_byte_width, | |
158 | acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); | |
159 | } | |
160 | ||
161 | /* | |
162 | * Offset rounded up to next multiple of field width | |
163 | * exceeds region length, indicate an error | |
164 | */ | |
165 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
166 | "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", | |
167 | acpi_ut_get_node_name (obj_desc->common_field.node), | |
168 | obj_desc->common_field.base_byte_offset, | |
169 | field_datum_byte_offset, obj_desc->common_field.access_byte_width, | |
170 | acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); | |
171 | ||
172 | return_ACPI_STATUS (AE_AML_REGION_LIMIT); | |
173 | } | |
174 | ||
175 | return_ACPI_STATUS (AE_OK); | |
176 | } | |
177 | ||
178 | ||
179 | /******************************************************************************* | |
180 | * | |
181 | * FUNCTION: acpi_ex_access_region | |
182 | * | |
183 | * PARAMETERS: *obj_desc - Field to be read | |
184 | * field_datum_byte_offset - Byte offset of this datum within the | |
185 | * parent field | |
186 | * *Value - Where to store value (must at least | |
187 | * the size of acpi_integer) | |
188 | * Function - Read or Write flag plus other region- | |
189 | * dependent flags | |
190 | * | |
191 | * RETURN: Status | |
192 | * | |
193 | * DESCRIPTION: Read or Write a single field datum to an Operation Region. | |
194 | * | |
195 | ******************************************************************************/ | |
196 | ||
197 | acpi_status | |
198 | acpi_ex_access_region ( | |
199 | union acpi_operand_object *obj_desc, | |
200 | u32 field_datum_byte_offset, | |
201 | acpi_integer *value, | |
202 | u32 function) | |
203 | { | |
204 | acpi_status status; | |
205 | union acpi_operand_object *rgn_desc; | |
206 | acpi_physical_address address; | |
207 | ||
208 | ||
209 | ACPI_FUNCTION_TRACE ("ex_access_region"); | |
210 | ||
211 | ||
212 | /* | |
213 | * Ensure that the region operands are fully evaluated and verify | |
214 | * the validity of the request | |
215 | */ | |
216 | status = acpi_ex_setup_region (obj_desc, field_datum_byte_offset); | |
217 | if (ACPI_FAILURE (status)) { | |
218 | return_ACPI_STATUS (status); | |
219 | } | |
220 | ||
221 | /* | |
222 | * The physical address of this field datum is: | |
223 | * | |
224 | * 1) The base of the region, plus | |
225 | * 2) The base offset of the field, plus | |
226 | * 3) The current offset into the field | |
227 | */ | |
228 | rgn_desc = obj_desc->common_field.region_obj; | |
229 | address = rgn_desc->region.address | |
230 | + obj_desc->common_field.base_byte_offset | |
231 | + field_datum_byte_offset; | |
232 | ||
233 | if ((function & ACPI_IO_MASK) == ACPI_READ) { | |
234 | ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); | |
235 | } | |
236 | else { | |
237 | ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); | |
238 | } | |
239 | ||
240 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, | |
241 | " Region [%s:%X], Width %X, byte_base %X, Offset %X at %8.8X%8.8X\n", | |
242 | acpi_ut_get_region_name (rgn_desc->region.space_id), | |
243 | rgn_desc->region.space_id, | |
244 | obj_desc->common_field.access_byte_width, | |
245 | obj_desc->common_field.base_byte_offset, | |
246 | field_datum_byte_offset, | |
247 | ACPI_FORMAT_UINT64 (address))); | |
248 | ||
249 | /* Invoke the appropriate address_space/op_region handler */ | |
250 | ||
251 | status = acpi_ev_address_space_dispatch (rgn_desc, function, | |
252 | address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); | |
253 | ||
254 | if (ACPI_FAILURE (status)) { | |
255 | if (status == AE_NOT_IMPLEMENTED) { | |
256 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
257 | "Region %s(%X) not implemented\n", | |
258 | acpi_ut_get_region_name (rgn_desc->region.space_id), | |
259 | rgn_desc->region.space_id)); | |
260 | } | |
261 | else if (status == AE_NOT_EXIST) { | |
262 | ACPI_REPORT_ERROR (( | |
263 | "Region %s(%X) has no handler\n", | |
264 | acpi_ut_get_region_name (rgn_desc->region.space_id), | |
265 | rgn_desc->region.space_id)); | |
266 | } | |
267 | } | |
268 | ||
269 | return_ACPI_STATUS (status); | |
270 | } | |
271 | ||
272 | ||
273 | /******************************************************************************* | |
274 | * | |
275 | * FUNCTION: acpi_ex_register_overflow | |
276 | * | |
277 | * PARAMETERS: *obj_desc - Register(Field) to be written | |
278 | * Value - Value to be stored | |
279 | * | |
280 | * RETURN: TRUE if value overflows the field, FALSE otherwise | |
281 | * | |
282 | * DESCRIPTION: Check if a value is out of range of the field being written. | |
283 | * Used to check if the values written to Index and Bank registers | |
284 | * are out of range. Normally, the value is simply truncated | |
285 | * to fit the field, but this case is most likely a serious | |
286 | * coding error in the ASL. | |
287 | * | |
288 | ******************************************************************************/ | |
289 | ||
290 | u8 | |
291 | acpi_ex_register_overflow ( | |
292 | union acpi_operand_object *obj_desc, | |
293 | acpi_integer value) | |
294 | { | |
295 | ||
296 | if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) { | |
297 | /* | |
298 | * The field is large enough to hold the maximum integer, so we can | |
299 | * never overflow it. | |
300 | */ | |
301 | return (FALSE); | |
302 | } | |
303 | ||
304 | if (value >= ((acpi_integer) 1 << obj_desc->common_field.bit_length)) { | |
305 | /* | |
306 | * The Value is larger than the maximum value that can fit into | |
307 | * the register. | |
308 | */ | |
309 | return (TRUE); | |
310 | } | |
311 | ||
312 | /* The Value will fit into the field with no truncation */ | |
313 | ||
314 | return (FALSE); | |
315 | } | |
316 | ||
317 | ||
318 | /******************************************************************************* | |
319 | * | |
320 | * FUNCTION: acpi_ex_field_datum_io | |
321 | * | |
322 | * PARAMETERS: *obj_desc - Field to be read | |
323 | * field_datum_byte_offset - Byte offset of this datum within the | |
324 | * parent field | |
325 | * *Value - Where to store value (must be 64 bits) | |
326 | * read_write - Read or Write flag | |
327 | * | |
328 | * RETURN: Status | |
329 | * | |
330 | * DESCRIPTION: Read or Write a single datum of a field. The field_type is | |
331 | * demultiplexed here to handle the different types of fields | |
332 | * (buffer_field, region_field, index_field, bank_field) | |
333 | * | |
334 | ******************************************************************************/ | |
335 | ||
336 | acpi_status | |
337 | acpi_ex_field_datum_io ( | |
338 | union acpi_operand_object *obj_desc, | |
339 | u32 field_datum_byte_offset, | |
340 | acpi_integer *value, | |
341 | u32 read_write) | |
342 | { | |
343 | acpi_status status; | |
344 | acpi_integer local_value; | |
345 | ||
346 | ||
347 | ACPI_FUNCTION_TRACE_U32 ("ex_field_datum_io", field_datum_byte_offset); | |
348 | ||
349 | ||
350 | if (read_write == ACPI_READ) { | |
351 | if (!value) { | |
352 | local_value = 0; | |
353 | value = &local_value; /* To support reads without saving return value */ | |
354 | } | |
355 | ||
356 | /* Clear the entire return buffer first, [Very Important!] */ | |
357 | ||
358 | *value = 0; | |
359 | } | |
360 | ||
361 | /* | |
362 | * The four types of fields are: | |
363 | * | |
364 | * buffer_field - Read/write from/to a Buffer | |
365 | * region_field - Read/write from/to a Operation Region. | |
366 | * bank_field - Write to a Bank Register, then read/write from/to an op_region | |
367 | * index_field - Write to an Index Register, then read/write from/to a Data Register | |
368 | */ | |
369 | switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { | |
370 | case ACPI_TYPE_BUFFER_FIELD: | |
371 | /* | |
372 | * If the buffer_field arguments have not been previously evaluated, | |
373 | * evaluate them now and save the results. | |
374 | */ | |
375 | if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { | |
376 | status = acpi_ds_get_buffer_field_arguments (obj_desc); | |
377 | if (ACPI_FAILURE (status)) { | |
378 | return_ACPI_STATUS (status); | |
379 | } | |
380 | } | |
381 | ||
382 | if (read_write == ACPI_READ) { | |
383 | /* | |
384 | * Copy the data from the source buffer. | |
385 | * Length is the field width in bytes. | |
386 | */ | |
387 | ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer | |
388 | + obj_desc->buffer_field.base_byte_offset | |
389 | + field_datum_byte_offset, | |
390 | obj_desc->common_field.access_byte_width); | |
391 | } | |
392 | else { | |
393 | /* | |
394 | * Copy the data to the target buffer. | |
395 | * Length is the field width in bytes. | |
396 | */ | |
397 | ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer | |
398 | + obj_desc->buffer_field.base_byte_offset | |
399 | + field_datum_byte_offset, | |
400 | value, obj_desc->common_field.access_byte_width); | |
401 | } | |
402 | ||
403 | status = AE_OK; | |
404 | break; | |
405 | ||
406 | ||
407 | case ACPI_TYPE_LOCAL_BANK_FIELD: | |
408 | ||
409 | /* Ensure that the bank_value is not beyond the capacity of the register */ | |
410 | ||
411 | if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj, | |
412 | (acpi_integer) obj_desc->bank_field.value)) { | |
413 | return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); | |
414 | } | |
415 | ||
416 | /* | |
417 | * For bank_fields, we must write the bank_value to the bank_register | |
418 | * (itself a region_field) before we can access the data. | |
419 | */ | |
420 | status = acpi_ex_insert_into_field (obj_desc->bank_field.bank_obj, | |
421 | &obj_desc->bank_field.value, | |
422 | sizeof (obj_desc->bank_field.value)); | |
423 | if (ACPI_FAILURE (status)) { | |
424 | return_ACPI_STATUS (status); | |
425 | } | |
426 | ||
427 | /* | |
428 | * Now that the Bank has been selected, fall through to the | |
429 | * region_field case and write the datum to the Operation Region | |
430 | */ | |
431 | ||
432 | /*lint -fallthrough */ | |
433 | ||
434 | ||
435 | case ACPI_TYPE_LOCAL_REGION_FIELD: | |
436 | /* | |
437 | * For simple region_fields, we just directly access the owning | |
438 | * Operation Region. | |
439 | */ | |
440 | status = acpi_ex_access_region (obj_desc, field_datum_byte_offset, value, | |
441 | read_write); | |
442 | break; | |
443 | ||
444 | ||
445 | case ACPI_TYPE_LOCAL_INDEX_FIELD: | |
446 | ||
447 | ||
448 | /* Ensure that the index_value is not beyond the capacity of the register */ | |
449 | ||
450 | if (acpi_ex_register_overflow (obj_desc->index_field.index_obj, | |
451 | (acpi_integer) obj_desc->index_field.value)) { | |
452 | return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); | |
453 | } | |
454 | ||
455 | /* Write the index value to the index_register (itself a region_field) */ | |
456 | ||
457 | field_datum_byte_offset += obj_desc->index_field.value; | |
458 | ||
459 | ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, | |
460 | "Write to Index Register: Value %8.8X\n", | |
461 | field_datum_byte_offset)); | |
462 | ||
463 | status = acpi_ex_insert_into_field (obj_desc->index_field.index_obj, | |
464 | &field_datum_byte_offset, | |
465 | sizeof (field_datum_byte_offset)); | |
466 | if (ACPI_FAILURE (status)) { | |
467 | return_ACPI_STATUS (status); | |
468 | } | |
469 | ||
470 | ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, | |
471 | "I/O to Data Register: value_ptr %p\n", | |
472 | value)); | |
473 | ||
474 | if (read_write == ACPI_READ) { | |
475 | /* Read the datum from the data_register */ | |
476 | ||
477 | status = acpi_ex_extract_from_field (obj_desc->index_field.data_obj, | |
478 | value, sizeof (acpi_integer)); | |
479 | } | |
480 | else { | |
481 | /* Write the datum to the data_register */ | |
482 | ||
483 | status = acpi_ex_insert_into_field (obj_desc->index_field.data_obj, | |
484 | value, sizeof (acpi_integer)); | |
485 | } | |
486 | break; | |
487 | ||
488 | ||
489 | default: | |
490 | ||
491 | ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n", | |
492 | ACPI_GET_OBJECT_TYPE (obj_desc))); | |
493 | status = AE_AML_INTERNAL; | |
494 | break; | |
495 | } | |
496 | ||
497 | if (ACPI_SUCCESS (status)) { | |
498 | if (read_write == ACPI_READ) { | |
499 | ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", | |
500 | ACPI_FORMAT_UINT64 (*value), | |
501 | obj_desc->common_field.access_byte_width)); | |
502 | } | |
503 | else { | |
504 | ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", | |
505 | ACPI_FORMAT_UINT64 (*value), | |
506 | obj_desc->common_field.access_byte_width)); | |
507 | } | |
508 | } | |
509 | ||
510 | return_ACPI_STATUS (status); | |
511 | } | |
512 | ||
513 | ||
514 | /******************************************************************************* | |
515 | * | |
516 | * FUNCTION: acpi_ex_write_with_update_rule | |
517 | * | |
518 | * PARAMETERS: *obj_desc - Field to be set | |
519 | * Value - Value to store | |
520 | * | |
521 | * RETURN: Status | |
522 | * | |
523 | * DESCRIPTION: Apply the field update rule to a field write | |
524 | * | |
525 | ******************************************************************************/ | |
526 | ||
527 | acpi_status | |
528 | acpi_ex_write_with_update_rule ( | |
529 | union acpi_operand_object *obj_desc, | |
530 | acpi_integer mask, | |
531 | acpi_integer field_value, | |
532 | u32 field_datum_byte_offset) | |
533 | { | |
534 | acpi_status status = AE_OK; | |
535 | acpi_integer merged_value; | |
536 | acpi_integer current_value; | |
537 | ||
538 | ||
539 | ACPI_FUNCTION_TRACE_U32 ("ex_write_with_update_rule", mask); | |
540 | ||
541 | ||
542 | /* Start with the new bits */ | |
543 | ||
544 | merged_value = field_value; | |
545 | ||
546 | /* If the mask is all ones, we don't need to worry about the update rule */ | |
547 | ||
548 | if (mask != ACPI_INTEGER_MAX) { | |
549 | /* Decode the update rule */ | |
550 | ||
551 | switch (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK) { | |
552 | case AML_FIELD_UPDATE_PRESERVE: | |
553 | /* | |
554 | * Check if update rule needs to be applied (not if mask is all | |
555 | * ones) The left shift drops the bits we want to ignore. | |
556 | */ | |
557 | if ((~mask << (ACPI_MUL_8 (sizeof (mask)) - | |
558 | ACPI_MUL_8 (obj_desc->common_field.access_byte_width))) != 0) { | |
559 | /* | |
560 | * Read the current contents of the byte/word/dword containing | |
561 | * the field, and merge with the new field value. | |
562 | */ | |
563 | status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, | |
564 | ¤t_value, ACPI_READ); | |
565 | if (ACPI_FAILURE (status)) { | |
566 | return_ACPI_STATUS (status); | |
567 | } | |
568 | ||
569 | merged_value |= (current_value & ~mask); | |
570 | } | |
571 | break; | |
572 | ||
573 | case AML_FIELD_UPDATE_WRITE_AS_ONES: | |
574 | ||
575 | /* Set positions outside the field to all ones */ | |
576 | ||
577 | merged_value |= ~mask; | |
578 | break; | |
579 | ||
580 | case AML_FIELD_UPDATE_WRITE_AS_ZEROS: | |
581 | ||
582 | /* Set positions outside the field to all zeros */ | |
583 | ||
584 | merged_value &= mask; | |
585 | break; | |
586 | ||
587 | default: | |
588 | ||
589 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
590 | "write_with_update_rule: Unknown update_rule setting: %X\n", | |
591 | (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK))); | |
592 | return_ACPI_STATUS (AE_AML_OPERAND_VALUE); | |
593 | } | |
594 | } | |
595 | ||
596 | ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, | |
597 | "Mask %8.8X%8.8X, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %8.8X%8.8X\n", | |
598 | ACPI_FORMAT_UINT64 (mask), | |
599 | field_datum_byte_offset, | |
600 | obj_desc->common_field.access_byte_width, | |
601 | ACPI_FORMAT_UINT64 (field_value), | |
602 | ACPI_FORMAT_UINT64 (merged_value))); | |
603 | ||
604 | /* Write the merged value */ | |
605 | ||
606 | status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, | |
607 | &merged_value, ACPI_WRITE); | |
608 | ||
609 | return_ACPI_STATUS (status); | |
610 | } | |
611 | ||
612 | ||
613 | /******************************************************************************* | |
614 | * | |
615 | * FUNCTION: acpi_ex_extract_from_field | |
616 | * | |
617 | * PARAMETERS: obj_desc - Field to be read | |
618 | * Buffer - Where to store the field data | |
619 | * buffer_length - Length of Buffer | |
620 | * | |
621 | * RETURN: Status | |
622 | * | |
623 | * DESCRIPTION: Retrieve the current value of the given field | |
624 | * | |
625 | ******************************************************************************/ | |
626 | ||
627 | acpi_status | |
628 | acpi_ex_extract_from_field ( | |
629 | union acpi_operand_object *obj_desc, | |
630 | void *buffer, | |
631 | u32 buffer_length) | |
632 | { | |
633 | acpi_status status; | |
634 | acpi_integer raw_datum; | |
635 | acpi_integer merged_datum; | |
636 | u32 field_offset = 0; | |
637 | u32 buffer_offset = 0; | |
638 | u32 buffer_tail_bits; | |
639 | u32 datum_count; | |
640 | u32 field_datum_count; | |
641 | u32 i; | |
642 | ||
643 | ||
644 | ACPI_FUNCTION_TRACE ("ex_extract_from_field"); | |
645 | ||
646 | ||
647 | /* Validate target buffer and clear it */ | |
648 | ||
649 | if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES ( | |
650 | obj_desc->common_field.bit_length)) { | |
651 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
652 | "Field size %X (bits) is too large for buffer (%X)\n", | |
653 | obj_desc->common_field.bit_length, buffer_length)); | |
654 | ||
655 | return_ACPI_STATUS (AE_BUFFER_OVERFLOW); | |
656 | } | |
657 | ACPI_MEMSET (buffer, 0, buffer_length); | |
658 | ||
659 | /* Compute the number of datums (access width data items) */ | |
660 | ||
661 | datum_count = ACPI_ROUND_UP_TO ( | |
662 | obj_desc->common_field.bit_length, | |
663 | obj_desc->common_field.access_bit_width); | |
664 | field_datum_count = ACPI_ROUND_UP_TO ( | |
665 | obj_desc->common_field.bit_length + | |
666 | obj_desc->common_field.start_field_bit_offset, | |
667 | obj_desc->common_field.access_bit_width); | |
668 | ||
669 | /* Priming read from the field */ | |
670 | ||
671 | status = acpi_ex_field_datum_io (obj_desc, field_offset, &raw_datum, ACPI_READ); | |
672 | if (ACPI_FAILURE (status)) { | |
673 | return_ACPI_STATUS (status); | |
674 | } | |
675 | merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; | |
676 | ||
677 | /* Read the rest of the field */ | |
678 | ||
679 | for (i = 1; i < field_datum_count; i++) { | |
680 | /* Get next input datum from the field */ | |
681 | ||
682 | field_offset += obj_desc->common_field.access_byte_width; | |
683 | status = acpi_ex_field_datum_io (obj_desc, field_offset, | |
684 | &raw_datum, ACPI_READ); | |
685 | if (ACPI_FAILURE (status)) { | |
686 | return_ACPI_STATUS (status); | |
687 | } | |
688 | ||
689 | /* Merge with previous datum if necessary */ | |
690 | ||
691 | merged_datum |= raw_datum << | |
692 | (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); | |
693 | ||
694 | if (i == datum_count) { | |
695 | break; | |
696 | } | |
697 | ||
698 | /* Write merged datum to target buffer */ | |
699 | ||
700 | ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum, | |
701 | ACPI_MIN(obj_desc->common_field.access_byte_width, | |
702 | buffer_length - buffer_offset)); | |
703 | ||
704 | buffer_offset += obj_desc->common_field.access_byte_width; | |
705 | merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; | |
706 | } | |
707 | ||
708 | /* Mask off any extra bits in the last datum */ | |
709 | ||
710 | buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width; | |
711 | if (buffer_tail_bits) { | |
712 | merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); | |
713 | } | |
714 | ||
715 | /* Write the last datum to the buffer */ | |
716 | ||
717 | ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum, | |
718 | ACPI_MIN(obj_desc->common_field.access_byte_width, | |
719 | buffer_length - buffer_offset)); | |
720 | ||
721 | return_ACPI_STATUS (AE_OK); | |
722 | } | |
723 | ||
724 | ||
725 | /******************************************************************************* | |
726 | * | |
727 | * FUNCTION: acpi_ex_insert_into_field | |
728 | * | |
729 | * PARAMETERS: obj_desc - Field to be written | |
730 | * Buffer - Data to be written | |
731 | * buffer_length - Length of Buffer | |
732 | * | |
733 | * RETURN: Status | |
734 | * | |
735 | * DESCRIPTION: Store the Buffer contents into the given field | |
736 | * | |
737 | ******************************************************************************/ | |
738 | ||
739 | acpi_status | |
740 | acpi_ex_insert_into_field ( | |
741 | union acpi_operand_object *obj_desc, | |
742 | void *buffer, | |
743 | u32 buffer_length) | |
744 | { | |
745 | acpi_status status; | |
746 | acpi_integer mask; | |
747 | acpi_integer merged_datum; | |
748 | acpi_integer raw_datum = 0; | |
749 | u32 field_offset = 0; | |
750 | u32 buffer_offset = 0; | |
751 | u32 buffer_tail_bits; | |
752 | u32 datum_count; | |
753 | u32 field_datum_count; | |
754 | u32 i; | |
755 | ||
756 | ||
757 | ACPI_FUNCTION_TRACE ("ex_insert_into_field"); | |
758 | ||
759 | ||
760 | /* Validate input buffer */ | |
761 | ||
762 | if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES ( | |
763 | obj_desc->common_field.bit_length)) { | |
764 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
765 | "Field size %X (bits) is too large for buffer (%X)\n", | |
766 | obj_desc->common_field.bit_length, buffer_length)); | |
767 | ||
768 | return_ACPI_STATUS (AE_BUFFER_OVERFLOW); | |
769 | } | |
770 | ||
771 | /* Compute the number of datums (access width data items) */ | |
772 | ||
773 | mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset); | |
774 | datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length, | |
775 | obj_desc->common_field.access_bit_width); | |
776 | field_datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length + | |
777 | obj_desc->common_field.start_field_bit_offset, | |
778 | obj_desc->common_field.access_bit_width); | |
779 | ||
780 | /* Get initial Datum from the input buffer */ | |
781 | ||
782 | ACPI_MEMCPY (&raw_datum, buffer, | |
783 | ACPI_MIN(obj_desc->common_field.access_byte_width, | |
784 | buffer_length - buffer_offset)); | |
785 | ||
786 | merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset; | |
787 | ||
788 | /* Write the entire field */ | |
789 | ||
790 | for (i = 1; i < field_datum_count; i++) { | |
791 | /* Write merged datum to the target field */ | |
792 | ||
793 | merged_datum &= mask; | |
794 | status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); | |
795 | if (ACPI_FAILURE (status)) { | |
796 | return_ACPI_STATUS (status); | |
797 | } | |
798 | ||
799 | /* Start new output datum by merging with previous input datum */ | |
800 | ||
801 | field_offset += obj_desc->common_field.access_byte_width; | |
802 | merged_datum = raw_datum >> | |
803 | (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); | |
804 | mask = ACPI_INTEGER_MAX; | |
805 | ||
806 | if (i == datum_count) { | |
807 | break; | |
808 | } | |
809 | ||
810 | /* Get the next input datum from the buffer */ | |
811 | ||
812 | buffer_offset += obj_desc->common_field.access_byte_width; | |
813 | ACPI_MEMCPY (&raw_datum, ((char *) buffer) + buffer_offset, | |
814 | ACPI_MIN(obj_desc->common_field.access_byte_width, | |
815 | buffer_length - buffer_offset)); | |
816 | merged_datum |= raw_datum << obj_desc->common_field.start_field_bit_offset; | |
817 | } | |
818 | ||
819 | /* Mask off any extra bits in the last datum */ | |
820 | ||
821 | buffer_tail_bits = (obj_desc->common_field.bit_length + | |
822 | obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width; | |
823 | if (buffer_tail_bits) { | |
824 | mask &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); | |
825 | } | |
826 | ||
827 | /* Write the last datum to the field */ | |
828 | ||
829 | merged_datum &= mask; | |
830 | status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); | |
831 | ||
832 | return_ACPI_STATUS (status); | |
833 | } | |
834 | ||
835 |