OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [acpi/] [executer/] [exfldio.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/******************************************************************************
2
 *
3
 * Module Name: exfldio - Aml Field I/O
4
 *
5
 *****************************************************************************/
6
 
7
/*
8
 * Copyright (C) 2000 - 2007, 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_ERROR((AE_INFO, "Needed Region, found type %X (%s)",
98
                            ACPI_GET_OBJECT_TYPE(rgn_desc),
99
                            acpi_ut_get_object_type_name(rgn_desc)));
100
 
101
                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
102
        }
103
 
104
        /*
105
         * If the Region Address and Length have not been previously evaluated,
106
         * evaluate them now and save the results.
107
         */
108
        if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) {
109
                status = acpi_ds_get_region_arguments(rgn_desc);
110
                if (ACPI_FAILURE(status)) {
111
                        return_ACPI_STATUS(status);
112
                }
113
        }
114
 
115
        /* Exit if Address/Length have been disallowed by the host OS */
116
 
117
        if (rgn_desc->common.flags & AOPOBJ_INVALID) {
118
                return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS);
119
        }
120
 
121
        /*
122
         * Exit now for SMBus address space, it has a non-linear address space
123
         * and the request cannot be directly validated
124
         */
125
        if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) {
126
 
127
                /* SMBus has a non-linear address space */
128
 
129
                return_ACPI_STATUS(AE_OK);
130
        }
131
#ifdef ACPI_UNDER_DEVELOPMENT
132
        /*
133
         * If the Field access is any_acc, we can now compute the optimal
134
         * access (because we know know the length of the parent region)
135
         */
136
        if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
137
                if (ACPI_FAILURE(status)) {
138
                        return_ACPI_STATUS(status);
139
                }
140
        }
141
#endif
142
 
143
        /*
144
         * Validate the request.  The entire request from the byte offset for a
145
         * length of one field datum (access width) must fit within the region.
146
         * (Region length is specified in bytes)
147
         */
148
        if (rgn_desc->region.length <
149
            (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.
160
                                          access_byte_width) >=
161
                            (obj_desc->common_field.base_byte_offset +
162
                             (acpi_native_uint) obj_desc->common_field.
163
                             access_byte_width + field_datum_byte_offset)) {
164
                                return_ACPI_STATUS(AE_OK);
165
                        }
166
                }
167
 
168
                if (rgn_desc->region.length <
169
                    obj_desc->common_field.access_byte_width) {
170
                        /*
171
                         * This is the case where the access_type (acc_word, etc.) is wider
172
                         * than the region itself.  For example, a region of length one
173
                         * byte, and a field with Dword access specified.
174
                         */
175
                        ACPI_ERROR((AE_INFO,
176
                                    "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)",
177
                                    acpi_ut_get_node_name(obj_desc->
178
                                                          common_field.node),
179
                                    obj_desc->common_field.access_byte_width,
180
                                    acpi_ut_get_node_name(rgn_desc->region.
181
                                                          node),
182
                                    rgn_desc->region.length));
183
                }
184
 
185
                /*
186
                 * Offset rounded up to next multiple of field width
187
                 * exceeds region length, indicate an error
188
                 */
189
                ACPI_ERROR((AE_INFO,
190
                            "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)",
191
                            acpi_ut_get_node_name(obj_desc->common_field.node),
192
                            obj_desc->common_field.base_byte_offset,
193
                            field_datum_byte_offset,
194
                            obj_desc->common_field.access_byte_width,
195
                            acpi_ut_get_node_name(rgn_desc->region.node),
196
                            rgn_desc->region.length));
197
 
198
                return_ACPI_STATUS(AE_AML_REGION_LIMIT);
199
        }
200
 
201
        return_ACPI_STATUS(AE_OK);
202
}
203
 
204
/*******************************************************************************
205
 *
206
 * FUNCTION:    acpi_ex_access_region
207
 *
208
 * PARAMETERS:  obj_desc                - Field to be read
209
 *              field_datum_byte_offset - Byte offset of this datum within the
210
 *                                        parent field
211
 *              Value                   - Where to store value (must at least
212
 *                                        the size of acpi_integer)
213
 *              Function                - Read or Write flag plus other region-
214
 *                                        dependent flags
215
 *
216
 * RETURN:      Status
217
 *
218
 * DESCRIPTION: Read or Write a single field datum to an Operation Region.
219
 *
220
 ******************************************************************************/
221
 
222
acpi_status
223
acpi_ex_access_region(union acpi_operand_object *obj_desc,
224
                      u32 field_datum_byte_offset,
225
                      acpi_integer * value, u32 function)
226
{
227
        acpi_status status;
228
        union acpi_operand_object *rgn_desc;
229
        acpi_physical_address address;
230
 
231
        ACPI_FUNCTION_TRACE(ex_access_region);
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 + field_datum_byte_offset;
252
 
253
        if ((function & ACPI_IO_MASK) == ACPI_READ) {
254
                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[READ]"));
255
        } else {
256
                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[WRITE]"));
257
        }
258
 
259
        ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
260
                              " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
261
                              acpi_ut_get_region_name(rgn_desc->region.
262
                                                      space_id),
263
                              rgn_desc->region.space_id,
264
                              obj_desc->common_field.access_byte_width,
265
                              obj_desc->common_field.base_byte_offset,
266
                              field_datum_byte_offset, (void *)address));
267
 
268
        /* Invoke the appropriate address_space/op_region handler */
269
 
270
        status = acpi_ev_address_space_dispatch(rgn_desc, function,
271
                                                address,
272
                                                ACPI_MUL_8(obj_desc->
273
                                                           common_field.
274
                                                           access_byte_width),
275
                                                value);
276
 
277
        if (ACPI_FAILURE(status)) {
278
                if (status == AE_NOT_IMPLEMENTED) {
279
                        ACPI_ERROR((AE_INFO,
280
                                    "Region %s(%X) not implemented",
281
                                    acpi_ut_get_region_name(rgn_desc->region.
282
                                                            space_id),
283
                                    rgn_desc->region.space_id));
284
                } else if (status == AE_NOT_EXIST) {
285
                        ACPI_ERROR((AE_INFO,
286
                                    "Region %s(%X) has no handler",
287
                                    acpi_ut_get_region_name(rgn_desc->region.
288
                                                            space_id),
289
                                    rgn_desc->region.space_id));
290
                }
291
        }
292
 
293
        return_ACPI_STATUS(status);
294
}
295
 
296
/*******************************************************************************
297
 *
298
 * FUNCTION:    acpi_ex_register_overflow
299
 *
300
 * PARAMETERS:  obj_desc                - Register(Field) to be written
301
 *              Value                   - Value to be stored
302
 *
303
 * RETURN:      TRUE if value overflows the field, FALSE otherwise
304
 *
305
 * DESCRIPTION: Check if a value is out of range of the field being written.
306
 *              Used to check if the values written to Index and Bank registers
307
 *              are out of range.  Normally, the value is simply truncated
308
 *              to fit the field, but this case is most likely a serious
309
 *              coding error in the ASL.
310
 *
311
 ******************************************************************************/
312
 
313
static u8
314
acpi_ex_register_overflow(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
 * FUNCTION:    acpi_ex_field_datum_io
342
 *
343
 * PARAMETERS:  obj_desc                - Field to be read
344
 *              field_datum_byte_offset - Byte offset of this datum within the
345
 *                                        parent field
346
 *              Value                   - Where to store value (must be 64 bits)
347
 *              read_write              - Read or Write flag
348
 *
349
 * RETURN:      Status
350
 *
351
 * DESCRIPTION: Read or Write a single datum of a field.  The field_type is
352
 *              demultiplexed here to handle the different types of fields
353
 *              (buffer_field, region_field, index_field, bank_field)
354
 *
355
 ******************************************************************************/
356
 
357
static acpi_status
358
acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
359
                       u32 field_datum_byte_offset,
360
                       acpi_integer * value, u32 read_write)
361
{
362
        acpi_status status;
363
        acpi_integer local_value;
364
 
365
        ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset);
366
 
367
        if (read_write == ACPI_READ) {
368
                if (!value) {
369
                        local_value = 0;
370
 
371
                        /* To support reads without saving return value */
372
                        value = &local_value;
373
                }
374
 
375
                /* Clear the entire return buffer first, [Very Important!] */
376
 
377
                *value = 0;
378
        }
379
 
380
        /*
381
         * The four types of fields are:
382
         *
383
         * buffer_field - Read/write from/to a Buffer
384
         * region_field - Read/write from/to a Operation Region.
385
         * bank_field  - Write to a Bank Register, then read/write from/to an
386
         *               operation_region
387
         * index_field - Write to an Index Register, then read/write from/to a
388
         *               Data Register
389
         */
390
        switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
391
        case ACPI_TYPE_BUFFER_FIELD:
392
                /*
393
                 * If the buffer_field arguments have not been previously evaluated,
394
                 * evaluate them now and save the results.
395
                 */
396
                if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
397
                        status = acpi_ds_get_buffer_field_arguments(obj_desc);
398
                        if (ACPI_FAILURE(status)) {
399
                                return_ACPI_STATUS(status);
400
                        }
401
                }
402
 
403
                if (read_write == ACPI_READ) {
404
                        /*
405
                         * Copy the data from the source buffer.
406
                         * Length is the field width in bytes.
407
                         */
408
                        ACPI_MEMCPY(value,
409
                                    (obj_desc->buffer_field.buffer_obj)->buffer.
410
                                    pointer +
411
                                    obj_desc->buffer_field.base_byte_offset +
412
                                    field_datum_byte_offset,
413
                                    obj_desc->common_field.access_byte_width);
414
                } else {
415
                        /*
416
                         * Copy the data to the target buffer.
417
                         * Length is the field width in bytes.
418
                         */
419
                        ACPI_MEMCPY((obj_desc->buffer_field.buffer_obj)->buffer.
420
                                    pointer +
421
                                    obj_desc->buffer_field.base_byte_offset +
422
                                    field_datum_byte_offset, value,
423
                                    obj_desc->common_field.access_byte_width);
424
                }
425
 
426
                status = AE_OK;
427
                break;
428
 
429
        case ACPI_TYPE_LOCAL_BANK_FIELD:
430
 
431
                /*
432
                 * Ensure that the bank_value is not beyond the capacity of
433
                 * the register
434
                 */
435
                if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj,
436
                                              (acpi_integer) obj_desc->
437
                                              bank_field.value)) {
438
                        return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
439
                }
440
 
441
                /*
442
                 * For bank_fields, we must write the bank_value to the bank_register
443
                 * (itself a region_field) before we can access the data.
444
                 */
445
                status =
446
                    acpi_ex_insert_into_field(obj_desc->bank_field.bank_obj,
447
                                              &obj_desc->bank_field.value,
448
                                              sizeof(obj_desc->bank_field.
449
                                                     value));
450
                if (ACPI_FAILURE(status)) {
451
                        return_ACPI_STATUS(status);
452
                }
453
 
454
                /*
455
                 * Now that the Bank has been selected, fall through to the
456
                 * region_field case and write the datum to the Operation Region
457
                 */
458
 
459
                /*lint -fallthrough */
460
 
461
        case ACPI_TYPE_LOCAL_REGION_FIELD:
462
                /*
463
                 * For simple region_fields, we just directly access the owning
464
                 * Operation Region.
465
                 */
466
                status =
467
                    acpi_ex_access_region(obj_desc, field_datum_byte_offset,
468
                                          value, read_write);
469
                break;
470
 
471
        case ACPI_TYPE_LOCAL_INDEX_FIELD:
472
 
473
                /*
474
                 * Ensure that the index_value is not beyond the capacity of
475
                 * the register
476
                 */
477
                if (acpi_ex_register_overflow(obj_desc->index_field.index_obj,
478
                                              (acpi_integer) obj_desc->
479
                                              index_field.value)) {
480
                        return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
481
                }
482
 
483
                /* Write the index value to the index_register (itself a region_field) */
484
 
485
                field_datum_byte_offset += obj_desc->index_field.value;
486
 
487
                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
488
                                  "Write to Index Register: Value %8.8X\n",
489
                                  field_datum_byte_offset));
490
 
491
                status =
492
                    acpi_ex_insert_into_field(obj_desc->index_field.index_obj,
493
                                              &field_datum_byte_offset,
494
                                              sizeof(field_datum_byte_offset));
495
                if (ACPI_FAILURE(status)) {
496
                        return_ACPI_STATUS(status);
497
                }
498
 
499
                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
500
                                  "I/O to Data Register: ValuePtr %p\n",
501
                                  value));
502
 
503
                if (read_write == ACPI_READ) {
504
 
505
                        /* Read the datum from the data_register */
506
 
507
                        status =
508
                            acpi_ex_extract_from_field(obj_desc->index_field.
509
                                                       data_obj, value,
510
                                                       sizeof(acpi_integer));
511
                } else {
512
                        /* Write the datum to the data_register */
513
 
514
                        status =
515
                            acpi_ex_insert_into_field(obj_desc->index_field.
516
                                                      data_obj, value,
517
                                                      sizeof(acpi_integer));
518
                }
519
                break;
520
 
521
        default:
522
 
523
                ACPI_ERROR((AE_INFO, "Wrong object type in field I/O %X",
524
                            ACPI_GET_OBJECT_TYPE(obj_desc)));
525
                status = AE_AML_INTERNAL;
526
                break;
527
        }
528
 
529
        if (ACPI_SUCCESS(status)) {
530
                if (read_write == ACPI_READ) {
531
                        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
532
                                          "Value Read %8.8X%8.8X, Width %d\n",
533
                                          ACPI_FORMAT_UINT64(*value),
534
                                          obj_desc->common_field.
535
                                          access_byte_width));
536
                } else {
537
                        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
538
                                          "Value Written %8.8X%8.8X, Width %d\n",
539
                                          ACPI_FORMAT_UINT64(*value),
540
                                          obj_desc->common_field.
541
                                          access_byte_width));
542
                }
543
        }
544
 
545
        return_ACPI_STATUS(status);
546
}
547
 
548
/*******************************************************************************
549
 *
550
 * FUNCTION:    acpi_ex_write_with_update_rule
551
 *
552
 * PARAMETERS:  obj_desc                - Field to be written
553
 *              Mask                    - bitmask within field datum
554
 *              field_value             - Value to write
555
 *              field_datum_byte_offset - Offset of datum within field
556
 *
557
 * RETURN:      Status
558
 *
559
 * DESCRIPTION: Apply the field update rule to a field write
560
 *
561
 ******************************************************************************/
562
 
563
acpi_status
564
acpi_ex_write_with_update_rule(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
        ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask);
574
 
575
        /* Start with the new bits  */
576
 
577
        merged_value = field_value;
578
 
579
        /* If the mask is all ones, we don't need to worry about the update rule */
580
 
581
        if (mask != ACPI_INTEGER_MAX) {
582
 
583
                /* Decode the update rule */
584
 
585
                switch (obj_desc->common_field.
586
                        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.
594
                                                  access_byte_width))) != 0) {
595
                                /*
596
                                 * Read the current contents of the byte/word/dword containing
597
                                 * the field, and merge with the new field value.
598
                                 */
599
                                status =
600
                                    acpi_ex_field_datum_io(obj_desc,
601
                                                           field_datum_byte_offset,
602
                                                           &current_value,
603
                                                           ACPI_READ);
604
                                if (ACPI_FAILURE(status)) {
605
                                        return_ACPI_STATUS(status);
606
                                }
607
 
608
                                merged_value |= (current_value & ~mask);
609
                        }
610
                        break;
611
 
612
                case AML_FIELD_UPDATE_WRITE_AS_ONES:
613
 
614
                        /* Set positions outside the field to all ones */
615
 
616
                        merged_value |= ~mask;
617
                        break;
618
 
619
                case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
620
 
621
                        /* Set positions outside the field to all zeros */
622
 
623
                        merged_value &= mask;
624
                        break;
625
 
626
                default:
627
 
628
                        ACPI_ERROR((AE_INFO,
629
                                    "Unknown UpdateRule value: %X",
630
                                    (obj_desc->common_field.
631
                                     field_flags &
632
                                     AML_FIELD_UPDATE_RULE_MASK)));
633
                        return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
634
                }
635
        }
636
 
637
        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
638
                          "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
639
                          ACPI_FORMAT_UINT64(mask),
640
                          field_datum_byte_offset,
641
                          obj_desc->common_field.access_byte_width,
642
                          ACPI_FORMAT_UINT64(field_value),
643
                          ACPI_FORMAT_UINT64(merged_value)));
644
 
645
        /* Write the merged value */
646
 
647
        status = acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset,
648
                                        &merged_value, ACPI_WRITE);
649
 
650
        return_ACPI_STATUS(status);
651
}
652
 
653
/*******************************************************************************
654
 *
655
 * FUNCTION:    acpi_ex_extract_from_field
656
 *
657
 * PARAMETERS:  obj_desc            - Field to be read
658
 *              Buffer              - Where to store the field data
659
 *              buffer_length       - Length of Buffer
660
 *
661
 * RETURN:      Status
662
 *
663
 * DESCRIPTION: Retrieve the current value of the given field
664
 *
665
 ******************************************************************************/
666
 
667
acpi_status
668
acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
669
                           void *buffer, u32 buffer_length)
670
{
671
        acpi_status status;
672
        acpi_integer raw_datum;
673
        acpi_integer merged_datum;
674
        u32 field_offset = 0;
675
        u32 buffer_offset = 0;
676
        u32 buffer_tail_bits;
677
        u32 datum_count;
678
        u32 field_datum_count;
679
        u32 i;
680
 
681
        ACPI_FUNCTION_TRACE(ex_extract_from_field);
682
 
683
        /* Validate target buffer and clear it */
684
 
685
        if (buffer_length <
686
            ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
687
                ACPI_ERROR((AE_INFO,
688
                            "Field size %X (bits) is too large for buffer (%X)",
689
                            obj_desc->common_field.bit_length, buffer_length));
690
 
691
                return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
692
        }
693
        ACPI_MEMSET(buffer, 0, buffer_length);
694
 
695
        /* Compute the number of datums (access width data items) */
696
 
697
        datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
698
                                       obj_desc->common_field.access_bit_width);
699
        field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
700
                                             obj_desc->common_field.
701
                                             start_field_bit_offset,
702
                                             obj_desc->common_field.
703
                                             access_bit_width);
704
 
705
        /* Priming read from the field */
706
 
707
        status =
708
            acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum,
709
                                   ACPI_READ);
710
        if (ACPI_FAILURE(status)) {
711
                return_ACPI_STATUS(status);
712
        }
713
        merged_datum =
714
            raw_datum >> obj_desc->common_field.start_field_bit_offset;
715
 
716
        /* Read the rest of the field */
717
 
718
        for (i = 1; i < field_datum_count; i++) {
719
 
720
                /* Get next input datum from the field */
721
 
722
                field_offset += obj_desc->common_field.access_byte_width;
723
                status = acpi_ex_field_datum_io(obj_desc, field_offset,
724
                                                &raw_datum, ACPI_READ);
725
                if (ACPI_FAILURE(status)) {
726
                        return_ACPI_STATUS(status);
727
                }
728
 
729
                /*
730
                 * Merge with previous datum if necessary.
731
                 *
732
                 * Note: Before the shift, check if the shift value will be larger than
733
                 * the integer size. If so, there is no need to perform the operation.
734
                 * This avoids the differences in behavior between different compilers
735
                 * concerning shift values larger than the target data width.
736
                 */
737
                if ((obj_desc->common_field.access_bit_width -
738
                     obj_desc->common_field.start_field_bit_offset) <
739
                    ACPI_INTEGER_BIT_SIZE) {
740
                        merged_datum |=
741
                            raw_datum << (obj_desc->common_field.
742
                                          access_bit_width -
743
                                          obj_desc->common_field.
744
                                          start_field_bit_offset);
745
                }
746
 
747
                if (i == datum_count) {
748
                        break;
749
                }
750
 
751
                /* Write merged datum to target 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
                buffer_offset += obj_desc->common_field.access_byte_width;
758
                merged_datum =
759
                    raw_datum >> obj_desc->common_field.start_field_bit_offset;
760
        }
761
 
762
        /* Mask off any extra bits in the last datum */
763
 
764
        buffer_tail_bits = obj_desc->common_field.bit_length %
765
            obj_desc->common_field.access_bit_width;
766
        if (buffer_tail_bits) {
767
                merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
768
        }
769
 
770
        /* Write the last datum to the buffer */
771
 
772
        ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum,
773
                    ACPI_MIN(obj_desc->common_field.access_byte_width,
774
                             buffer_length - buffer_offset));
775
 
776
        return_ACPI_STATUS(AE_OK);
777
}
778
 
779
/*******************************************************************************
780
 *
781
 * FUNCTION:    acpi_ex_insert_into_field
782
 *
783
 * PARAMETERS:  obj_desc            - Field to be written
784
 *              Buffer              - Data to be written
785
 *              buffer_length       - Length of Buffer
786
 *
787
 * RETURN:      Status
788
 *
789
 * DESCRIPTION: Store the Buffer contents into the given field
790
 *
791
 ******************************************************************************/
792
 
793
acpi_status
794
acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
795
                          void *buffer, u32 buffer_length)
796
{
797
        acpi_status status;
798
        acpi_integer mask;
799
        acpi_integer width_mask;
800
        acpi_integer merged_datum;
801
        acpi_integer raw_datum = 0;
802
        u32 field_offset = 0;
803
        u32 buffer_offset = 0;
804
        u32 buffer_tail_bits;
805
        u32 datum_count;
806
        u32 field_datum_count;
807
        u32 i;
808
 
809
        ACPI_FUNCTION_TRACE(ex_insert_into_field);
810
 
811
        /* Validate input buffer */
812
 
813
        if (buffer_length <
814
            ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
815
                ACPI_ERROR((AE_INFO,
816
                            "Field size %X (bits) is too large for buffer (%X)",
817
                            obj_desc->common_field.bit_length, buffer_length));
818
 
819
                return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
820
        }
821
 
822
        /*
823
         * Create the bitmasks used for bit insertion.
824
         * Note: This if/else is used to bypass compiler differences with the
825
         * shift operator
826
         */
827
        if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
828
                width_mask = ACPI_INTEGER_MAX;
829
        } else {
830
                width_mask =
831
                    ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
832
                                         access_bit_width);
833
        }
834
 
835
        mask = width_mask &
836
            ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset);
837
 
838
        /* Compute the number of datums (access width data items) */
839
 
840
        datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
841
                                       obj_desc->common_field.access_bit_width);
842
 
843
        field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
844
                                             obj_desc->common_field.
845
                                             start_field_bit_offset,
846
                                             obj_desc->common_field.
847
                                             access_bit_width);
848
 
849
        /* Get initial Datum from the input buffer */
850
 
851
        ACPI_MEMCPY(&raw_datum, buffer,
852
                    ACPI_MIN(obj_desc->common_field.access_byte_width,
853
                             buffer_length - buffer_offset));
854
 
855
        merged_datum =
856
            raw_datum << obj_desc->common_field.start_field_bit_offset;
857
 
858
        /* Write the entire field */
859
 
860
        for (i = 1; i < field_datum_count; i++) {
861
 
862
                /* Write merged datum to the target field */
863
 
864
                merged_datum &= mask;
865
                status = acpi_ex_write_with_update_rule(obj_desc, mask,
866
                                                        merged_datum,
867
                                                        field_offset);
868
                if (ACPI_FAILURE(status)) {
869
                        return_ACPI_STATUS(status);
870
                }
871
 
872
                field_offset += obj_desc->common_field.access_byte_width;
873
 
874
                /*
875
                 * Start new output datum by merging with previous input datum
876
                 * if necessary.
877
                 *
878
                 * Note: Before the shift, check if the shift value will be larger than
879
                 * the integer size. If so, there is no need to perform the operation.
880
                 * This avoids the differences in behavior between different compilers
881
                 * concerning shift values larger than the target data width.
882
                 */
883
                if ((obj_desc->common_field.access_bit_width -
884
                     obj_desc->common_field.start_field_bit_offset) <
885
                    ACPI_INTEGER_BIT_SIZE) {
886
                        merged_datum =
887
                            raw_datum >> (obj_desc->common_field.
888
                                          access_bit_width -
889
                                          obj_desc->common_field.
890
                                          start_field_bit_offset);
891
                } else {
892
                        merged_datum = 0;
893
                }
894
 
895
                mask = width_mask;
896
 
897
                if (i == datum_count) {
898
                        break;
899
                }
900
 
901
                /* Get the next input datum from the buffer */
902
 
903
                buffer_offset += obj_desc->common_field.access_byte_width;
904
                ACPI_MEMCPY(&raw_datum, ((char *)buffer) + buffer_offset,
905
                            ACPI_MIN(obj_desc->common_field.access_byte_width,
906
                                     buffer_length - buffer_offset));
907
                merged_datum |=
908
                    raw_datum << obj_desc->common_field.start_field_bit_offset;
909
        }
910
 
911
        /* Mask off any extra bits in the last datum */
912
 
913
        buffer_tail_bits = (obj_desc->common_field.bit_length +
914
                            obj_desc->common_field.start_field_bit_offset) %
915
            obj_desc->common_field.access_bit_width;
916
        if (buffer_tail_bits) {
917
                mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
918
        }
919
 
920
        /* Write the last datum to the field */
921
 
922
        merged_datum &= mask;
923
        status = acpi_ex_write_with_update_rule(obj_desc,
924
                                                mask, merged_datum,
925
                                                field_offset);
926
 
927
        return_ACPI_STATUS(status);
928
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.