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