1/******************************************************************************
2 *
3 * Module Name: exfldio - Aml Field I/O
4 *              $Revision: 1.1.1.1 $
5 *
6 *****************************************************************************/
7
8/*
9 *  Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with this program; if not, write to the Free Software
23 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25
26
27#include "acpi.h"
28#include "acinterp.h"
29#include "amlcode.h"
30#include "acnamesp.h"
31#include "achware.h"
32#include "acevents.h"
33#include "acdispat.h"
34
35
36#define _COMPONENT          ACPI_EXECUTER
37	 MODULE_NAME         ("exfldio")
38
39
40/*******************************************************************************
41 *
42 * FUNCTION:    Acpi_ex_setup_field
43 *
44 * PARAMETERS:  *Obj_desc           - Field to be read or written
45 *              Field_datum_byte_offset  - Current offset into the field
46 *
47 * RETURN:      Status
48 *
49 * DESCRIPTION: Common processing for Acpi_ex_extract_from_field and
50 *              Acpi_ex_insert_into_field
51 *
52 ******************************************************************************/
53
54acpi_status
55acpi_ex_setup_field (
56	acpi_operand_object     *obj_desc,
57	u32                     field_datum_byte_offset)
58{
59	acpi_status             status = AE_OK;
60	acpi_operand_object     *rgn_desc;
61
62
63	FUNCTION_TRACE_U32 ("Ex_setup_field", field_datum_byte_offset);
64
65
66	rgn_desc = obj_desc->common_field.region_obj;
67
68	if (ACPI_TYPE_REGION != rgn_desc->common.type) {
69		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %x %s\n",
70			rgn_desc->common.type, acpi_ut_get_type_name (rgn_desc->common.type)));
71		return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
72	}
73
74	/*
75	 * If the Region Address and Length have not been previously evaluated,
76	 * evaluate them now and save the results.
77	 */
78	if (!(rgn_desc->region.flags & AOPOBJ_DATA_VALID)) {
79
80		status = acpi_ds_get_region_arguments (rgn_desc);
81		if (ACPI_FAILURE (status)) {
82			return_ACPI_STATUS (status);
83		}
84	}
85
86	/*
87	 * Validate the request.  The entire request from the byte offset for a
88	 * length of one field datum (access width) must fit within the region.
89	 * (Region length is specified in bytes)
90	 */
91	if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset +
92			   field_datum_byte_offset +
93			   obj_desc->common_field.access_byte_width)) {
94		if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) {
95			/*
96			 * This is the case where the Access_type (Acc_word, etc.) is wider
97			 * than the region itself.  For example, a region of length one
98			 * byte, and a field with Dword access specified.
99			 */
100			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
101				"Field access width (%d bytes) too large for region size (%X)\n",
102				obj_desc->common_field.access_byte_width, rgn_desc->region.length));
103		}
104
105		/*
106		 * Offset rounded up to next multiple of field width
107		 * exceeds region length, indicate an error
108		 */
109		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
110			"Field base+offset+width %X+%X+%X exceeds region size (%X bytes) field=%p region=%p\n",
111			obj_desc->common_field.base_byte_offset, field_datum_byte_offset,
112			obj_desc->common_field.access_byte_width,
113			rgn_desc->region.length, obj_desc, rgn_desc));
114
115		return_ACPI_STATUS (AE_AML_REGION_LIMIT);
116	}
117
118	return_ACPI_STATUS (AE_OK);
119}
120
121
122/*******************************************************************************
123 *
124 * FUNCTION:    Acpi_ex_read_field_datum
125 *
126 * PARAMETERS:  *Obj_desc           - Field to be read
127 *              *Value              - Where to store value (must be 32 bits)
128 *
129 * RETURN:      Status
130 *
131 * DESCRIPTION: Retrieve the value of the given field
132 *
133 ******************************************************************************/
134
135acpi_status
136acpi_ex_read_field_datum (
137	acpi_operand_object     *obj_desc,
138	u32                     field_datum_byte_offset,
139	u32                     *value)
140{
141	acpi_status             status;
142	acpi_operand_object     *rgn_desc;
143	ACPI_PHYSICAL_ADDRESS   address;
144	u32                     local_value;
145
146
147	FUNCTION_TRACE_U32 ("Ex_read_field_datum", field_datum_byte_offset);
148
149
150	if (!value) {
151		local_value = 0;
152		value = &local_value;   /*  support reads without saving value  */
153	}
154
155	/* Clear the entire return buffer first, [Very Important!] */
156
157	*value = 0;
158
159	/*
160	 * Buffer_fields - Read from a Buffer
161	 * Other Fields - Read from a Operation Region.
162	 */
163	switch (obj_desc->common.type) {
164	case ACPI_TYPE_BUFFER_FIELD:
165
166		/*
167		 * For Buffer_fields, we only need to copy the data from the
168		 * source buffer.  Length is the field width in bytes.
169		 */
170		MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer
171				  + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset,
172				  obj_desc->common_field.access_byte_width);
173		status = AE_OK;
174		break;
175
176
177	case INTERNAL_TYPE_REGION_FIELD:
178	case INTERNAL_TYPE_BANK_FIELD:
179
180		/*
181		 * For other fields, we need to go through an Operation Region
182		 * (Only types that will get here are Region_fields and Bank_fields)
183		 */
184		status = acpi_ex_setup_field (obj_desc, field_datum_byte_offset);
185		if (ACPI_FAILURE (status)) {
186			return_ACPI_STATUS (status);
187		}
188
189		/*
190		 * The physical address of this field datum is:
191		 *
192		 * 1) The base of the region, plus
193		 * 2) The base offset of the field, plus
194		 * 3) The current offset into the field
195		 */
196		rgn_desc = obj_desc->common_field.region_obj;
197		address = rgn_desc->region.address + obj_desc->common_field.base_byte_offset +
198				 field_datum_byte_offset;
199
200		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Region %s(%X) width %X base:off %X:%X at %8.8X%8.8X\n",
201			acpi_ut_get_region_name (rgn_desc->region.space_id),
202			rgn_desc->region.space_id, obj_desc->common_field.access_bit_width,
203			obj_desc->common_field.base_byte_offset, field_datum_byte_offset,
204			HIDWORD(address), LODWORD(address)));
205
206		/* Invoke the appropriate Address_space/Op_region handler */
207
208		status = acpi_ev_address_space_dispatch (rgn_desc, ACPI_READ_ADR_SPACE,
209				  address, obj_desc->common_field.access_bit_width, value);
210		if (status == AE_NOT_IMPLEMENTED) {
211			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) not implemented\n",
212				acpi_ut_get_region_name (rgn_desc->region.space_id),
213				rgn_desc->region.space_id));
214		}
215
216		else if (status == AE_NOT_EXIST) {
217			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) has no handler\n",
218				acpi_ut_get_region_name (rgn_desc->region.space_id),
219				rgn_desc->region.space_id));
220		}
221		break;
222
223
224	default:
225
226		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, wrong source type - %s\n",
227			obj_desc, acpi_ut_get_type_name (obj_desc->common.type)));
228		status = AE_AML_INTERNAL;
229		break;
230	}
231
232
233	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Returned value=%08X \n", *value));
234
235	return_ACPI_STATUS (status);
236}
237
238
239/*******************************************************************************
240 *
241 * FUNCTION:    Acpi_ex_get_buffer_datum
242 *
243 * PARAMETERS:  Merged_datum        - Value to store
244 *              Buffer              - Receiving buffer
245 *              Byte_granularity    - 1/2/4 Granularity of the field
246 *                                    (aka Datum Size)
247 *              Offset              - Datum offset into the buffer
248 *
249 * RETURN:      none
250 *
251 * DESCRIPTION: Store the merged datum to the buffer according to the
252 *              byte granularity
253 *
254 ******************************************************************************/
255
256static void
257acpi_ex_get_buffer_datum(
258	u32                     *datum,
259	void                    *buffer,
260	u32                     byte_granularity,
261	u32                     offset)
262{
263
264	FUNCTION_ENTRY ();
265
266
267	switch (byte_granularity) {
268	case ACPI_FIELD_BYTE_GRANULARITY:
269		*datum = ((u8 *) buffer) [offset];
270		break;
271
272	case ACPI_FIELD_WORD_GRANULARITY:
273		MOVE_UNALIGNED16_TO_32 (datum, &(((u16 *) buffer) [offset]));
274		break;
275
276	case ACPI_FIELD_DWORD_GRANULARITY:
277		MOVE_UNALIGNED32_TO_32 (datum, &(((u32 *) buffer) [offset]));
278		break;
279	}
280}
281
282
283/*******************************************************************************
284 *
285 * FUNCTION:    Acpi_ex_set_buffer_datum
286 *
287 * PARAMETERS:  Merged_datum        - Value to store
288 *              Buffer              - Receiving buffer
289 *              Byte_granularity    - 1/2/4 Granularity of the field
290 *                                    (aka Datum Size)
291 *              Offset              - Datum offset into the buffer
292 *
293 * RETURN:      none
294 *
295 * DESCRIPTION: Store the merged datum to the buffer according to the
296 *              byte granularity
297 *
298 ******************************************************************************/
299
300static void
301acpi_ex_set_buffer_datum (
302	u32                     merged_datum,
303	void                    *buffer,
304	u32                     byte_granularity,
305	u32                     offset)
306{
307
308	FUNCTION_ENTRY ();
309
310
311	switch (byte_granularity) {
312	case ACPI_FIELD_BYTE_GRANULARITY:
313		((u8 *) buffer) [offset] = (u8) merged_datum;
314		break;
315
316	case ACPI_FIELD_WORD_GRANULARITY:
317		MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer)[offset]), &merged_datum);
318		break;
319
320	case ACPI_FIELD_DWORD_GRANULARITY:
321		MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer)[offset]), &merged_datum);
322		break;
323	}
324}
325
326
327/*******************************************************************************
328 *
329 * FUNCTION:    Acpi_ex_extract_from_field
330 *
331 * PARAMETERS:  *Obj_desc           - Field to be read
332 *              *Value              - Where to store value
333 *
334 * RETURN:      Status
335 *
336 * DESCRIPTION: Retrieve the value of the given field
337 *
338 ******************************************************************************/
339
340acpi_status
341acpi_ex_extract_from_field (
342	acpi_operand_object     *obj_desc,
343	void                    *buffer,
344	u32                     buffer_length)
345{
346	acpi_status             status;
347	u32                     field_datum_byte_offset;
348	u32                     datum_offset;
349	u32                     previous_raw_datum;
350	u32                     this_raw_datum = 0;
351	u32                     merged_datum = 0;
352	u32                     byte_field_length;
353	u32                     datum_count;
354
355
356	FUNCTION_TRACE ("Ex_extract_from_field");
357
358
359	/*
360	 * The field must fit within the caller's buffer
361	 */
362	byte_field_length = ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
363	if (byte_field_length > buffer_length) {
364		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Field size %X (bytes) too large for buffer (%X)\n",
365			byte_field_length, buffer_length));
366
367		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
368	}
369
370	/* Convert field byte count to datum count, round up if necessary */
371
372	datum_count = ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width);
373
374	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
375		"Byte_len=%x, Datum_len=%x, Bit_gran=%x, Byte_gran=%x\n",
376		byte_field_length, datum_count, obj_desc->common_field.access_bit_width,
377		obj_desc->common_field.access_byte_width));
378
379	/*
380	 * Clear the caller's buffer (the whole buffer length as given)
381	 * This is very important, especially in the cases where a byte is read,
382	 * but the buffer is really a u32 (4 bytes).
383	 */
384	MEMSET (buffer, 0, buffer_length);
385
386	/* Read the first raw datum to prime the loop */
387
388	field_datum_byte_offset = 0;
389	datum_offset= 0;
390
391	status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset, &previous_raw_datum);
392	if (ACPI_FAILURE (status)) {
393		return_ACPI_STATUS (status);
394	}
395
396
397	/* We might actually be done if the request fits in one datum */
398
399	if ((datum_count == 1) &&
400		(obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM)) {
401		/* 1) Shift the valid data bits down to start at bit 0 */
402
403		merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset);
404
405		/* 2) Mask off any upper unused bits (bits not part of the field) */
406
407		if (obj_desc->common_field.end_buffer_valid_bits) {
408			merged_datum &= MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits);
409		}
410
411		/* Store the datum to the caller buffer */
412
413		acpi_ex_set_buffer_datum (merged_datum, buffer, obj_desc->common_field.access_byte_width,
414				datum_offset);
415
416		return_ACPI_STATUS (AE_OK);
417	}
418
419
420	/* We need to get more raw data to complete one or more field data */
421
422	while (datum_offset < datum_count) {
423		field_datum_byte_offset += obj_desc->common_field.access_byte_width;
424
425		/*
426		 * If the field is aligned on a byte boundary, we don't want
427		 * to perform a final read, since this would potentially read
428		 * past the end of the region.
429		 *
430		 * TBD: [Investigate] It may make more sense to just split the aligned
431		 * and non-aligned cases since the aligned case is so very simple,
432		 */
433		if ((obj_desc->common_field.start_field_bit_offset != 0)  ||
434			((obj_desc->common_field.start_field_bit_offset == 0) &&
435			(datum_offset < (datum_count -1)))) {
436			/*
437			 * Get the next raw datum, it contains some or all bits
438			 * of the current field datum
439			 */
440			status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset, &this_raw_datum);
441			if (ACPI_FAILURE (status)) {
442				return_ACPI_STATUS (status);
443			}
444		}
445
446		/*
447		 * Create the (possibly) merged datum to be stored to the caller buffer
448		 */
449		if (obj_desc->common_field.start_field_bit_offset == 0) {
450			/* Field is not skewed and we can just copy the datum */
451
452			merged_datum = previous_raw_datum;
453		}
454
455		else {
456			/*
457			 * Put together the appropriate bits of the two raw data to make a
458			 * single complete field datum
459			 *
460			 * 1) Normalize the first datum down to bit 0
461			 */
462			merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset);
463
464			/* 2) Insert the second datum "above" the first datum */
465
466			merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits);
467
468			if ((datum_offset >= (datum_count -1))) {
469				/*
470				 * This is the last iteration of the loop.  We need to clear
471				 * any unused bits (bits that are not part of this field) that
472				 * came from the last raw datum before we store the final
473				 * merged datum into the caller buffer.
474				 */
475				if (obj_desc->common_field.end_buffer_valid_bits) {
476					merged_datum &=
477						MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits);
478				}
479			}
480		}
481
482		/*
483		 * Store the merged field datum in the caller's buffer, according to
484		 * the granularity of the field (size of each datum).
485		 */
486		acpi_ex_set_buffer_datum (merged_datum, buffer, obj_desc->common_field.access_byte_width,
487				datum_offset);
488
489		/*
490		 * Save the raw datum that was just acquired since it may contain bits
491		 * of the *next* field datum.  Update offsets
492		 */
493		previous_raw_datum = this_raw_datum;
494		datum_offset++;
495	}
496
497	return_ACPI_STATUS (AE_OK);
498}
499
500
501/*******************************************************************************
502 *
503 * FUNCTION:    Acpi_ex_write_field_datum
504 *
505 * PARAMETERS:  *Obj_desc           - Field to be set
506 *              Value               - Value to store
507 *
508 * RETURN:      Status
509 *
510 * DESCRIPTION: Store the value into the given field
511 *
512 ******************************************************************************/
513
514static acpi_status
515acpi_ex_write_field_datum (
516	acpi_operand_object     *obj_desc,
517	u32                     field_datum_byte_offset,
518	u32                     value)
519{
520	acpi_status             status = AE_OK;
521	acpi_operand_object     *rgn_desc = NULL;
522	ACPI_PHYSICAL_ADDRESS   address;
523
524
525	FUNCTION_TRACE_U32 ("Ex_write_field_datum", field_datum_byte_offset);
526
527
528	/*
529	 * Buffer_fields - Read from a Buffer
530	 * Other Fields - Read from a Operation Region.
531	 */
532	switch (obj_desc->common.type) {
533	case ACPI_TYPE_BUFFER_FIELD:
534
535		/*
536		 * For Buffer_fields, we only need to copy the data to the
537		 * target buffer.  Length is the field width in bytes.
538		 */
539		MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer
540				+ obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset,
541				&value, obj_desc->common_field.access_byte_width);
542		status = AE_OK;
543		break;
544
545
546	case INTERNAL_TYPE_REGION_FIELD:
547	case INTERNAL_TYPE_BANK_FIELD:
548
549		/*
550		 * For other fields, we need to go through an Operation Region
551		 * (Only types that will get here are Region_fields and Bank_fields)
552		 */
553		status = acpi_ex_setup_field (obj_desc, field_datum_byte_offset);
554		if (ACPI_FAILURE (status)) {
555			return_ACPI_STATUS (status);
556		}
557
558		/*
559		 * The physical address of this field datum is:
560		 *
561		 * 1) The base of the region, plus
562		 * 2) The base offset of the field, plus
563		 * 3) The current offset into the field
564		 */
565		rgn_desc = obj_desc->common_field.region_obj;
566		address = rgn_desc->region.address +
567				 obj_desc->common_field.base_byte_offset +
568				 field_datum_byte_offset;
569
570		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
571			"Store %X in Region %s(%X) at %8.8X%8.8X width %X\n",
572			value, acpi_ut_get_region_name (rgn_desc->region.space_id),
573			rgn_desc->region.space_id, HIDWORD(address), LODWORD(address),
574			obj_desc->common_field.access_bit_width));
575
576		/* Invoke the appropriate Address_space/Op_region handler */
577
578		status = acpi_ev_address_space_dispatch (rgn_desc, ACPI_WRITE_ADR_SPACE,
579				  address, obj_desc->common_field.access_bit_width, &value);
580
581		if (status == AE_NOT_IMPLEMENTED) {
582			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
583				"**** Region type %s(%X) not implemented\n",
584				acpi_ut_get_region_name (rgn_desc->region.space_id),
585				rgn_desc->region.space_id));
586		}
587
588		else if (status == AE_NOT_EXIST) {
589			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
590				"**** Region type %s(%X) does not have a handler\n",
591				acpi_ut_get_region_name (rgn_desc->region.space_id),
592				rgn_desc->region.space_id));
593		}
594
595		break;
596
597
598	default:
599
600		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, wrong source type - %s\n",
601			obj_desc, acpi_ut_get_type_name (obj_desc->common.type)));
602		status = AE_AML_INTERNAL;
603		break;
604	}
605
606
607	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value written=%08X \n", value));
608	return_ACPI_STATUS (status);
609}
610
611
612/*******************************************************************************
613 *
614 * FUNCTION:    Acpi_ex_write_field_datum_with_update_rule
615 *
616 * PARAMETERS:  *Obj_desc           - Field to be set
617 *              Value               - Value to store
618 *
619 * RETURN:      Status
620 *
621 * DESCRIPTION: Apply the field update rule to a field write
622 *
623 ******************************************************************************/
624
625static acpi_status
626acpi_ex_write_field_datum_with_update_rule (
627	acpi_operand_object     *obj_desc,
628	u32                     mask,
629	u32                     field_value,
630	u32                     field_datum_byte_offset)
631{
632	acpi_status             status = AE_OK;
633	u32                     merged_value;
634	u32                     current_value;
635
636
637	FUNCTION_TRACE ("Ex_write_field_datum_with_update_rule");
638
639
640	/* Start with the new bits  */
641
642	merged_value = field_value;
643
644	/* If the mask is all ones, we don't need to worry about the update rule */
645
646	if (mask != ACPI_UINT32_MAX) {
647		/* Decode the update rule */
648
649		switch (obj_desc->common_field.update_rule) {
650		case UPDATE_PRESERVE:
651			/*
652			 * Check if update rule needs to be applied (not if mask is all
653			 * ones)  The left shift drops the bits we want to ignore.
654			 */
655			if ((~mask << (sizeof (mask) * 8 -
656					  obj_desc->common_field.access_bit_width)) != 0) {
657				/*
658				 * Read the current contents of the byte/word/dword containing
659				 * the field, and merge with the new field value.
660				 */
661				status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset,
662						  &current_value);
663				merged_value |= (current_value & ~mask);
664			}
665			break;
666
667
668		case UPDATE_WRITE_AS_ONES:
669
670			/* Set positions outside the field to all ones */
671
672			merged_value |= ~mask;
673			break;
674
675
676		case UPDATE_WRITE_AS_ZEROS:
677
678			/* Set positions outside the field to all zeros */
679
680			merged_value &= mask;
681			break;
682
683
684		default:
685			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
686				"Write_with_update_rule: Unknown Update_rule setting: %x\n",
687				obj_desc->common_field.update_rule));
688			return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
689			break;
690		}
691	}
692
693
694	/* Write the merged value */
695
696	status = acpi_ex_write_field_datum (obj_desc, field_datum_byte_offset,
697			  merged_value);
698
699	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Mask %X Datum_offset %X Value %X, Merged_value %X\n",
700		mask, field_datum_byte_offset, field_value, merged_value));
701
702	return_ACPI_STATUS (status);
703}
704
705
706/*******************************************************************************
707 *
708 * FUNCTION:    Acpi_ex_insert_into_field
709 *
710 * PARAMETERS:  *Obj_desc           - Field to be set
711 *              Buffer              - Value to store
712 *
713 * RETURN:      Status
714 *
715 * DESCRIPTION: Store the value into the given field
716 *
717 ******************************************************************************/
718
719acpi_status
720acpi_ex_insert_into_field (
721	acpi_operand_object     *obj_desc,
722	void                    *buffer,
723	u32                     buffer_length)
724{
725	acpi_status             status;
726	u32                     field_datum_byte_offset;
727	u32                     datum_offset;
728	u32                     mask;
729	u32                     merged_datum;
730	u32                     previous_raw_datum;
731	u32                     this_raw_datum;
732	u32                     byte_field_length;
733	u32                     datum_count;
734
735
736	FUNCTION_TRACE ("Ex_insert_into_field");
737
738
739	/*
740	 * Incoming buffer must be at least as long as the field, we do not
741	 * allow "partial" field writes.  We do not care if the buffer is
742	 * larger than the field, this typically happens when an integer is
743	 * written to a field that is actually smaller than an integer.
744	 */
745	byte_field_length = ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
746	if (buffer_length < byte_field_length) {
747		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Buffer length %X too small for field %X\n",
748			buffer_length, byte_field_length));
749
750		/* TBD: Need a better error code */
751
752		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
753	}
754
755	/* Convert byte count to datum count, round up if necessary */
756
757	datum_count = ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width);
758
759	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
760		"Byte_len=%x, Datum_len=%x, Bit_gran=%x, Byte_gran=%x\n",
761		byte_field_length, datum_count, obj_desc->common_field.access_bit_width,
762		obj_desc->common_field.access_byte_width));
763
764	/*
765	 * Break the request into up to three parts (similar to an I/O request):
766	 * 1) non-aligned part at start
767	 * 2) aligned part in middle
768	 * 3) non-aligned part at the end
769	 */
770	field_datum_byte_offset = 0;
771	datum_offset= 0;
772
773	/* Get a single datum from the caller's buffer */
774
775	acpi_ex_get_buffer_datum (&previous_raw_datum, buffer,
776			obj_desc->common_field.access_byte_width, datum_offset);
777
778	/*
779	 * Part1:
780	 * Write a partial field datum if field does not begin on a datum boundary
781	 * Note: The code in this section also handles the aligned case
782	 *
783	 * Construct Mask with 1 bits where the field is, 0 bits elsewhere
784	 * (Only the bottom 5 bits of Bit_length are valid for a shift operation)
785	 *
786	 * Mask off bits that are "below" the field (if any)
787	 */
788	mask = MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset);
789
790	/* If the field fits in one datum, may need to mask upper bits */
791
792	if ((obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM) &&
793		 obj_desc->common_field.end_field_valid_bits) {
794		/* There are bits above the field, mask them off also */
795
796		mask &= MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits);
797	}
798
799	/* Shift and mask the value into the field position */
800
801	merged_datum = (previous_raw_datum << obj_desc->common_field.start_field_bit_offset);
802	merged_datum &= mask;
803
804	/* Apply the update rule (if necessary) and write the datum to the field */
805
806	status = acpi_ex_write_field_datum_with_update_rule (obj_desc, mask, merged_datum,
807			   field_datum_byte_offset);
808	if (ACPI_FAILURE (status)) {
809		return_ACPI_STATUS (status);
810	}
811
812	/* If the entire field fits within one datum, we are done. */
813
814	if ((datum_count == 1) &&
815	   (obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM)) {
816		return_ACPI_STATUS (AE_OK);
817	}
818
819	/*
820	 * Part2:
821	 * Write the aligned data.
822	 *
823	 * We don't need to worry about the update rule for these data, because
824	 * all of the bits in each datum are part of the field.
825	 *
826	 * The last datum must be special cased because it might contain bits
827	 * that are not part of the field -- therefore the "update rule" must be
828	 * applied in Part3 below.
829	 */
830	while (datum_offset < datum_count) {
831		datum_offset++;
832		field_datum_byte_offset += obj_desc->common_field.access_byte_width;
833
834		/*
835		 * Get the next raw buffer datum.  It may contain bits of the previous
836		 * field datum
837		 */
838		acpi_ex_get_buffer_datum (&this_raw_datum, buffer,
839				obj_desc->common_field.access_byte_width, datum_offset);
840
841		/* Create the field datum based on the field alignment */
842
843		if (obj_desc->common_field.start_field_bit_offset != 0) {
844			/*
845			 * Put together appropriate bits of the two raw buffer data to make
846			 * a single complete field datum
847			 */
848			merged_datum =
849				(previous_raw_datum >> obj_desc->common_field.datum_valid_bits) |
850				(this_raw_datum << obj_desc->common_field.start_field_bit_offset);
851		}
852
853		else {
854			/* Field began aligned on datum boundary */
855
856			merged_datum = this_raw_datum;
857		}
858
859		/*
860		 * Special handling for the last datum if the field does NOT end on
861		 * a datum boundary.  Update Rule must be applied to the bits outside
862		 * the field.
863		 */
864		if (datum_offset == datum_count) {
865			/*
866			 * If there are dangling non-aligned bits, perform one more merged write
867			 * Else - field is aligned at the end, no need for any more writes
868			 */
869			if (obj_desc->common_field.end_field_valid_bits) {
870				/*
871				 * Part3:
872				 * This is the last datum and the field does not end on a datum boundary.
873				 * Build the partial datum and write with the update rule.
874				 *
875				 * Mask off the unused bits above (after) the end-of-field
876				 */
877				mask = MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits);
878				merged_datum &= mask;
879
880				/* Write the last datum with the update rule */
881
882				status = acpi_ex_write_field_datum_with_update_rule (obj_desc, mask,
883						  merged_datum, field_datum_byte_offset);
884				if (ACPI_FAILURE (status)) {
885					return_ACPI_STATUS (status);
886				}
887			}
888		}
889
890		else {
891			/* Normal case -- write the completed datum */
892
893			status = acpi_ex_write_field_datum (obj_desc,
894					  field_datum_byte_offset, merged_datum);
895			if (ACPI_FAILURE (status)) {
896				return_ACPI_STATUS (status);
897			}
898		}
899
900		/*
901		 * Save the most recent datum since it may contain bits of the *next*
902		 * field datum.  Update current byte offset.
903		 */
904		previous_raw_datum = this_raw_datum;
905	}
906
907	return_ACPI_STATUS (status);
908}
909
910
911