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