Blame view

drivers/acpi/acpica/exmisc.c 19.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  
  /******************************************************************************
   *
   * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
   *
   *****************************************************************************/
  
  /*
75a44ce00   Len Brown   ACPICA: update In...
9
   * Copyright (C) 2000 - 2008, Intel Corp.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions, and the following disclaimer,
   *    without modification.
   * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   *    substantially similar to the "NO WARRANTY" disclaimer below
   *    ("Disclaimer") and any redistribution must be conditioned upon
   *    including a substantially similar Disclaimer requirement for further
   *    binary redistribution.
   * 3. Neither the names of the above-listed copyright holders nor the names
   *    of any contributors may be used to endorse or promote products derived
   *    from this software without specific prior written permission.
   *
   * Alternatively, this software may be distributed under the terms of the
   * GNU General Public License ("GPL") version 2 as published by the Free
   * Software Foundation.
   *
   * NO WARRANTY
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGES.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  #include <acpi/acpi.h>
e2f7a7772   Len Brown   ACPICA: hide priv...
45
46
47
48
  #include "accommon.h"
  #include "acinterp.h"
  #include "amlcode.h"
  #include "amlresrc.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  #define _COMPONENT          ACPI_EXECUTER
4be44fcd3   Len Brown   [ACPI] Lindent al...
51
  ACPI_MODULE_NAME("exmisc")
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  
  /*******************************************************************************
   *
   * FUNCTION:    acpi_ex_get_object_reference
   *
   * PARAMETERS:  obj_desc            - Create a reference to this object
   *              return_desc         - Where to store the reference
   *              walk_state          - Current state
   *
   * RETURN:      Status
   *
   * DESCRIPTION: Obtain and return a "reference" to the target object
   *              Common code for the ref_of_op and the cond_ref_of_op.
   *
   ******************************************************************************/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  acpi_status
4be44fcd3   Len Brown   [ACPI] Lindent al...
68
69
70
  acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
  			     union acpi_operand_object **return_desc,
  			     struct acpi_walk_state *walk_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
72
73
  	union acpi_operand_object *reference_obj;
  	union acpi_operand_object *referenced_obj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74

b229cf92e   Bob Moore   ACPI: ACPICA 2006...
75
  	ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
  
  	*return_desc = NULL;
4be44fcd3   Len Brown   [ACPI] Lindent al...
78
  	switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  	case ACPI_DESC_TYPE_OPERAND:
3371c19c2   Bob Moore   ACPICA: Remove AC...
80
  		if (obj_desc->common.type != ACPI_TYPE_LOCAL_REFERENCE) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
81
  			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
  		}
  
  		/*
  		 * Must be a reference to a Local or Arg
  		 */
1044f1f65   Bob Moore   ACPICA: Cleanup f...
87
88
89
90
  		switch (obj_desc->reference.class) {
  		case ACPI_REFCLASS_LOCAL:
  		case ACPI_REFCLASS_ARG:
  		case ACPI_REFCLASS_DEBUG:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
  
  			/* The referenced object is the pseudo-node for the local/arg */
  
  			referenced_obj = obj_desc->reference.object;
  			break;
  
  		default:
1044f1f65   Bob Moore   ACPICA: Cleanup f...
98
99
  			ACPI_ERROR((AE_INFO, "Unknown Reference Class %2.2X",
  				    obj_desc->reference.class));
4be44fcd3   Len Brown   [ACPI] Lindent al...
100
  			return_ACPI_STATUS(AE_AML_INTERNAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
  		}
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
  	case ACPI_DESC_TYPE_NAMED:
  
  		/*
  		 * A named reference that has already been resolved to a Node
  		 */
  		referenced_obj = obj_desc;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  	default:
b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
111
112
  		ACPI_ERROR((AE_INFO, "Invalid descriptor type %X",
  			    ACPI_GET_DESCRIPTOR_TYPE(obj_desc)));
4be44fcd3   Len Brown   [ACPI] Lindent al...
113
  		return_ACPI_STATUS(AE_TYPE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  	/* Create a new reference object */
4be44fcd3   Len Brown   [ACPI] Lindent al...
116
117
  	reference_obj =
  	    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  	if (!reference_obj) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
119
  		return_ACPI_STATUS(AE_NO_MEMORY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  	}
1044f1f65   Bob Moore   ACPICA: Cleanup f...
121
  	reference_obj->reference.class = ACPI_REFCLASS_REFOF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
  	reference_obj->reference.object = referenced_obj;
  	*return_desc = reference_obj;
4be44fcd3   Len Brown   [ACPI] Lindent al...
124
125
126
127
128
  	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
  			  "Object %p Type [%s], returning Reference %p
  ",
  			  obj_desc, acpi_ut_get_object_type_name(obj_desc),
  			  *return_desc));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

4be44fcd3   Len Brown   [ACPI] Lindent al...
130
  	return_ACPI_STATUS(AE_OK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  /*******************************************************************************
   *
   * FUNCTION:    acpi_ex_concat_template
   *
   * PARAMETERS:  Operand0            - First source object
   *              Operand1            - Second source object
   *              actual_return_desc  - Where to place the return object
   *              walk_state          - Current walk state
   *
   * RETURN:      Status
   *
   * DESCRIPTION: Concatenate two resource templates
   *
   ******************************************************************************/
  
  acpi_status
4be44fcd3   Len Brown   [ACPI] Lindent al...
148
149
150
151
  acpi_ex_concat_template(union acpi_operand_object *operand0,
  			union acpi_operand_object *operand1,
  			union acpi_operand_object **actual_return_desc,
  			struct acpi_walk_state *walk_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  {
96db255c8   Bob Moore   [ACPI] ACPICA 200...
153
  	acpi_status status;
4be44fcd3   Len Brown   [ACPI] Lindent al...
154
155
  	union acpi_operand_object *return_desc;
  	u8 *new_buf;
96db255c8   Bob Moore   [ACPI] ACPICA 200...
156
157
  	u8 *end_tag;
  	acpi_size length0;
4be44fcd3   Len Brown   [ACPI] Lindent al...
158
  	acpi_size length1;
b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
159
  	acpi_size new_length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

b229cf92e   Bob Moore   ACPI: ACPICA 2006...
161
  	ACPI_FUNCTION_TRACE(ex_concat_template);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162

96db255c8   Bob Moore   [ACPI] ACPICA 200...
163
164
  	/*
  	 * Find the end_tag descriptor in each resource template.
b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
165
166
  	 * Note1: returned pointers point TO the end_tag, not past it.
  	 * Note2: zero-length buffers are allowed; treated like one end_tag
96db255c8   Bob Moore   [ACPI] ACPICA 200...
167
  	 */
b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
168
169
  
  	/* Get the length of the first resource template */
96db255c8   Bob Moore   [ACPI] ACPICA 200...
170
171
172
173
174
175
  	status = acpi_ut_get_resource_end_tag(operand0, &end_tag);
  	if (ACPI_FAILURE(status)) {
  		return_ACPI_STATUS(status);
  	}
  
  	length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176

b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
177
  	/* Get the length of the second resource template */
96db255c8   Bob Moore   [ACPI] ACPICA 200...
178
179
180
  	status = acpi_ut_get_resource_end_tag(operand1, &end_tag);
  	if (ACPI_FAILURE(status)) {
  		return_ACPI_STATUS(status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  	}
b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
182
183
184
  	length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);
  
  	/* Combine both lengths, minimum size will be 2 for end_tag */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185

b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
186
  	new_length = length0 + length1 + sizeof(struct aml_resource_end_tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187

b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
188
  	/* Create a new buffer object for the result (with one end_tag) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189

b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
190
  	return_desc = acpi_ut_create_buffer_object(new_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	if (!return_desc) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
192
  		return_ACPI_STATUS(AE_NO_MEMORY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  	}
96db255c8   Bob Moore   [ACPI] ACPICA 200...
194
195
196
197
  	/*
  	 * Copy the templates to the new buffer, 0 first, then 1 follows. One
  	 * end_tag descriptor is copied from Operand1.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  	new_buf = return_desc->buffer.pointer;
96db255c8   Bob Moore   [ACPI] ACPICA 200...
199
200
  	ACPI_MEMCPY(new_buf, operand0->buffer.pointer, length0);
  	ACPI_MEMCPY(new_buf + length0, operand1->buffer.pointer, length1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201

b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
202
  	/* Insert end_tag and set the checksum to zero, means "ignore checksum" */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203

b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
204
205
  	new_buf[new_length - 1] = 0;
  	new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206

96db255c8   Bob Moore   [ACPI] ACPICA 200...
207
  	/* Return the completed resource template */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  
  	*actual_return_desc = return_desc;
4be44fcd3   Len Brown   [ACPI] Lindent al...
210
  	return_ACPI_STATUS(AE_OK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  /*******************************************************************************
   *
   * FUNCTION:    acpi_ex_do_concatenate
   *
   * PARAMETERS:  Operand0            - First source object
   *              Operand1            - Second source object
   *              actual_return_desc  - Where to place the return object
   *              walk_state          - Current walk state
   *
   * RETURN:      Status
   *
   * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
   *
   ******************************************************************************/
  
  acpi_status
4be44fcd3   Len Brown   [ACPI] Lindent al...
228
229
230
231
  acpi_ex_do_concatenate(union acpi_operand_object *operand0,
  		       union acpi_operand_object *operand1,
  		       union acpi_operand_object **actual_return_desc,
  		       struct acpi_walk_state *walk_state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
233
234
235
236
  	union acpi_operand_object *local_operand1 = operand1;
  	union acpi_operand_object *return_desc;
  	char *new_buf;
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237

b229cf92e   Bob Moore   ACPI: ACPICA 2006...
238
  	ACPI_FUNCTION_TRACE(ex_do_concatenate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
244
245
246
  
  	/*
  	 * Convert the second operand if necessary.  The first operand
  	 * determines the type of the second operand, (See the Data Types
  	 * section of the ACPI specification.)  Both object types are
  	 * guaranteed to be either Integer/String/Buffer by the operand
  	 * resolution mechanism.
  	 */
3371c19c2   Bob Moore   ACPICA: Remove AC...
247
  	switch (operand0->common.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  	case ACPI_TYPE_INTEGER:
4be44fcd3   Len Brown   [ACPI] Lindent al...
249
250
  		status =
  		    acpi_ex_convert_to_integer(operand1, &local_operand1, 16);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
  		break;
  
  	case ACPI_TYPE_STRING:
4be44fcd3   Len Brown   [ACPI] Lindent al...
254
255
  		status = acpi_ex_convert_to_string(operand1, &local_operand1,
  						   ACPI_IMPLICIT_CONVERT_HEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
  		break;
  
  	case ACPI_TYPE_BUFFER:
4be44fcd3   Len Brown   [ACPI] Lindent al...
259
  		status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
  		break;
  
  	default:
b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
263
  		ACPI_ERROR((AE_INFO, "Invalid object type: %X",
3371c19c2   Bob Moore   ACPICA: Remove AC...
264
  			    operand0->common.type));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
  		status = AE_AML_INTERNAL;
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
267
  	if (ACPI_FAILURE(status)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  		goto cleanup;
  	}
  
  	/*
  	 * Both operands are now known to be the same object type
  	 * (Both are Integer, String, or Buffer), and we can now perform the
  	 * concatenation.
  	 */
  
  	/*
  	 * There are three cases to handle:
  	 *
  	 * 1) Two Integers concatenated to produce a new Buffer
  	 * 2) Two Strings concatenated to produce a new String
  	 * 3) Two Buffers concatenated to produce a new Buffer
  	 */
3371c19c2   Bob Moore   ACPICA: Remove AC...
284
  	switch (operand0->common.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
  	case ACPI_TYPE_INTEGER:
  
  		/* Result of two Integers is a Buffer */
  		/* Need enough buffer space for two integers */
4be44fcd3   Len Brown   [ACPI] Lindent al...
289
290
291
  		return_desc = acpi_ut_create_buffer_object((acpi_size)
  							   ACPI_MUL_2
  							   (acpi_gbl_integer_byte_width));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
  		if (!return_desc) {
  			status = AE_NO_MEMORY;
  			goto cleanup;
  		}
4be44fcd3   Len Brown   [ACPI] Lindent al...
296
  		new_buf = (char *)return_desc->buffer.pointer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  
  		/* Copy the first integer, LSB first */
c51a4de85   Bob Moore   [ACPI] ACPICA 200...
299
  		ACPI_MEMCPY(new_buf, &operand0->integer.value,
4be44fcd3   Len Brown   [ACPI] Lindent al...
300
  			    acpi_gbl_integer_byte_width);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
  
  		/* Copy the second integer (LSB first) after the first */
4be44fcd3   Len Brown   [ACPI] Lindent al...
303
304
305
  		ACPI_MEMCPY(new_buf + acpi_gbl_integer_byte_width,
  			    &local_operand1->integer.value,
  			    acpi_gbl_integer_byte_width);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
  		break;
  
  	case ACPI_TYPE_STRING:
  
  		/* Result of two Strings is a String */
67a119f99   Bob Moore   ACPICA: Eliminate...
311
312
  		return_desc = acpi_ut_create_string_object(((acpi_size)
  							    operand0->string.
c51a4de85   Bob Moore   [ACPI] ACPICA 200...
313
314
315
  							    length +
  							    local_operand1->
  							    string.length));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
322
323
  		if (!return_desc) {
  			status = AE_NO_MEMORY;
  			goto cleanup;
  		}
  
  		new_buf = return_desc->string.pointer;
  
  		/* Concatenate the strings */
4be44fcd3   Len Brown   [ACPI] Lindent al...
324
325
326
  		ACPI_STRCPY(new_buf, operand0->string.pointer);
  		ACPI_STRCPY(new_buf + operand0->string.length,
  			    local_operand1->string.pointer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
  		break;
  
  	case ACPI_TYPE_BUFFER:
  
  		/* Result of two Buffers is a Buffer */
67a119f99   Bob Moore   ACPICA: Eliminate...
332
333
  		return_desc = acpi_ut_create_buffer_object(((acpi_size)
  							    operand0->buffer.
c51a4de85   Bob Moore   [ACPI] ACPICA 200...
334
335
336
  							    length +
  							    local_operand1->
  							    buffer.length));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
  		if (!return_desc) {
  			status = AE_NO_MEMORY;
  			goto cleanup;
  		}
4be44fcd3   Len Brown   [ACPI] Lindent al...
341
  		new_buf = (char *)return_desc->buffer.pointer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
  
  		/* Concatenate the buffers */
c51a4de85   Bob Moore   [ACPI] ACPICA 200...
344
345
  		ACPI_MEMCPY(new_buf, operand0->buffer.pointer,
  			    operand0->buffer.length);
4be44fcd3   Len Brown   [ACPI] Lindent al...
346
347
348
  		ACPI_MEMCPY(new_buf + operand0->buffer.length,
  			    local_operand1->buffer.pointer,
  			    local_operand1->buffer.length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
  		break;
  
  	default:
  
  		/* Invalid object type, should not happen here */
b8e4d8935   Bob Moore   [ACPI] ACPICA 200...
354
  		ACPI_ERROR((AE_INFO, "Invalid object type: %X",
3371c19c2   Bob Moore   ACPICA: Remove AC...
355
  			    operand0->common.type));
4be44fcd3   Len Brown   [ACPI] Lindent al...
356
  		status = AE_AML_INTERNAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
  		goto cleanup;
  	}
  
  	*actual_return_desc = return_desc;
4be44fcd3   Len Brown   [ACPI] Lindent al...
361
        cleanup:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  	if (local_operand1 != operand1) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
363
  		acpi_ut_remove_reference(local_operand1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
365
  	return_ACPI_STATUS(status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  /*******************************************************************************
   *
   * FUNCTION:    acpi_ex_do_math_op
   *
   * PARAMETERS:  Opcode              - AML opcode
   *              Integer0            - Integer operand #0
   *              Integer1            - Integer operand #1
   *
   * RETURN:      Integer result of the operation
   *
   * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
   *              math functions here is to prevent a lot of pointer dereferencing
   *              to obtain the operands.
   *
   ******************************************************************************/
  
  acpi_integer
4be44fcd3   Len Brown   [ACPI] Lindent al...
384
  acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
386
  	ACPI_FUNCTION_ENTRY();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
  
  	switch (opcode) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
389
  	case AML_ADD_OP:	/* Add (Integer0, Integer1, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  
  		return (integer0 + integer1);
4be44fcd3   Len Brown   [ACPI] Lindent al...
392
  	case AML_BIT_AND_OP:	/* And (Integer0, Integer1, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
  
  		return (integer0 & integer1);
4be44fcd3   Len Brown   [ACPI] Lindent al...
395
  	case AML_BIT_NAND_OP:	/* NAnd (Integer0, Integer1, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
  
  		return (~(integer0 & integer1));
4be44fcd3   Len Brown   [ACPI] Lindent al...
398
  	case AML_BIT_OR_OP:	/* Or (Integer0, Integer1, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
  
  		return (integer0 | integer1);
4be44fcd3   Len Brown   [ACPI] Lindent al...
401
  	case AML_BIT_NOR_OP:	/* NOr (Integer0, Integer1, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
  
  		return (~(integer0 | integer1));
4be44fcd3   Len Brown   [ACPI] Lindent al...
404
  	case AML_BIT_XOR_OP:	/* XOr (Integer0, Integer1, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  
  		return (integer0 ^ integer1);
4be44fcd3   Len Brown   [ACPI] Lindent al...
407
  	case AML_MULTIPLY_OP:	/* Multiply (Integer0, Integer1, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
  
  		return (integer0 * integer1);
4be44fcd3   Len Brown   [ACPI] Lindent al...
410
  	case AML_SHIFT_LEFT_OP:	/* shift_left (Operand, shift_count, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411

4119532c9   Bob Moore   ACPI: ACPICA 2006...
412
413
414
415
416
417
418
  		/*
  		 * We need to check if the shiftcount is larger than the integer bit
  		 * width since the behavior of this is not well-defined in the C language.
  		 */
  		if (integer1 >= acpi_gbl_integer_bit_width) {
  			return (0);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  		return (integer0 << integer1);
4be44fcd3   Len Brown   [ACPI] Lindent al...
420
  	case AML_SHIFT_RIGHT_OP:	/* shift_right (Operand, shift_count, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

4119532c9   Bob Moore   ACPI: ACPICA 2006...
422
423
424
425
426
427
428
  		/*
  		 * We need to check if the shiftcount is larger than the integer bit
  		 * width since the behavior of this is not well-defined in the C language.
  		 */
  		if (integer1 >= acpi_gbl_integer_bit_width) {
  			return (0);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  		return (integer0 >> integer1);
4be44fcd3   Len Brown   [ACPI] Lindent al...
430
  	case AML_SUBTRACT_OP:	/* Subtract (Integer0, Integer1, Result) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
434
435
436
437
438
  
  		return (integer0 - integer1);
  
  	default:
  
  		return (0);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  /*******************************************************************************
   *
   * FUNCTION:    acpi_ex_do_logical_numeric_op
   *
   * PARAMETERS:  Opcode              - AML opcode
   *              Integer0            - Integer operand #0
   *              Integer1            - Integer operand #1
   *              logical_result      - TRUE/FALSE result of the operation
   *
   * RETURN:      Status
   *
   * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
   *              operators (LAnd and LOr), both operands must be integers.
   *
   *              Note: cleanest machine code seems to be produced by the code
   *              below, rather than using statements of the form:
   *                  Result = (Integer0 && Integer1);
   *
   ******************************************************************************/
  
  acpi_status
4be44fcd3   Len Brown   [ACPI] Lindent al...
460
461
462
  acpi_ex_do_logical_numeric_op(u16 opcode,
  			      acpi_integer integer0,
  			      acpi_integer integer1, u8 * logical_result)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
464
465
  	acpi_status status = AE_OK;
  	u8 local_result = FALSE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466

b229cf92e   Bob Moore   ACPI: ACPICA 2006...
467
  	ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  
  	switch (opcode) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
470
  	case AML_LAND_OP:	/* LAnd (Integer0, Integer1) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
  
  		if (integer0 && integer1) {
  			local_result = TRUE;
  		}
  		break;
4be44fcd3   Len Brown   [ACPI] Lindent al...
476
  	case AML_LOR_OP:	/* LOr (Integer0, Integer1) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
487
488
489
490
  
  		if (integer0 || integer1) {
  			local_result = TRUE;
  		}
  		break;
  
  	default:
  		status = AE_AML_INTERNAL;
  		break;
  	}
  
  	/* Return the logical result and status */
  
  	*logical_result = local_result;
4be44fcd3   Len Brown   [ACPI] Lindent al...
491
  	return_ACPI_STATUS(status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  /*******************************************************************************
   *
   * FUNCTION:    acpi_ex_do_logical_op
   *
   * PARAMETERS:  Opcode              - AML opcode
   *              Operand0            - operand #0
   *              Operand1            - operand #1
   *              logical_result      - TRUE/FALSE result of the operation
   *
   * RETURN:      Status
   *
   * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
   *              functions here is to prevent a lot of pointer dereferencing
   *              to obtain the operands and to simplify the generation of the
   *              logical value. For the Numeric operators (LAnd and LOr), both
   *              operands must be integers. For the other logical operators,
   *              operands can be any combination of Integer/String/Buffer. The
   *              first operand determines the type to which the second operand
   *              will be converted.
   *
   *              Note: cleanest machine code seems to be produced by the code
   *              below, rather than using statements of the form:
   *                  Result = (Operand0 == Operand1);
   *
   ******************************************************************************/
  
  acpi_status
4be44fcd3   Len Brown   [ACPI] Lindent al...
520
521
522
  acpi_ex_do_logical_op(u16 opcode,
  		      union acpi_operand_object *operand0,
  		      union acpi_operand_object *operand1, u8 * logical_result)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
524
525
526
527
528
529
530
531
  	union acpi_operand_object *local_operand1 = operand1;
  	acpi_integer integer0;
  	acpi_integer integer1;
  	u32 length0;
  	u32 length1;
  	acpi_status status = AE_OK;
  	u8 local_result = FALSE;
  	int compare;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532

b229cf92e   Bob Moore   ACPI: ACPICA 2006...
533
  	ACPI_FUNCTION_TRACE(ex_do_logical_op);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
538
539
540
541
  
  	/*
  	 * Convert the second operand if necessary.  The first operand
  	 * determines the type of the second operand, (See the Data Types
  	 * section of the ACPI 3.0+ specification.)  Both object types are
  	 * guaranteed to be either Integer/String/Buffer by the operand
  	 * resolution mechanism.
  	 */
3371c19c2   Bob Moore   ACPICA: Remove AC...
542
  	switch (operand0->common.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  	case ACPI_TYPE_INTEGER:
4be44fcd3   Len Brown   [ACPI] Lindent al...
544
545
  		status =
  		    acpi_ex_convert_to_integer(operand1, &local_operand1, 16);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
  		break;
  
  	case ACPI_TYPE_STRING:
4be44fcd3   Len Brown   [ACPI] Lindent al...
549
550
  		status = acpi_ex_convert_to_string(operand1, &local_operand1,
  						   ACPI_IMPLICIT_CONVERT_HEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
  		break;
  
  	case ACPI_TYPE_BUFFER:
4be44fcd3   Len Brown   [ACPI] Lindent al...
554
  		status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
559
560
  		break;
  
  	default:
  		status = AE_AML_INTERNAL;
  		break;
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
561
  	if (ACPI_FAILURE(status)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
565
566
567
  		goto cleanup;
  	}
  
  	/*
  	 * Two cases: 1) Both Integers, 2) Both Strings or Buffers
  	 */
3371c19c2   Bob Moore   ACPICA: Remove AC...
568
  	if (operand0->common.type == ACPI_TYPE_INTEGER) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
571
572
573
574
575
576
  		/*
  		 * 1) Both operands are of type integer
  		 *    Note: local_operand1 may have changed above
  		 */
  		integer0 = operand0->integer.value;
  		integer1 = local_operand1->integer.value;
  
  		switch (opcode) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
577
  		case AML_LEQUAL_OP:	/* LEqual (Operand0, Operand1) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
582
  
  			if (integer0 == integer1) {
  				local_result = TRUE;
  			}
  			break;
4be44fcd3   Len Brown   [ACPI] Lindent al...
583
  		case AML_LGREATER_OP:	/* LGreater (Operand0, Operand1) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
588
  
  			if (integer0 > integer1) {
  				local_result = TRUE;
  			}
  			break;
4be44fcd3   Len Brown   [ACPI] Lindent al...
589
  		case AML_LLESS_OP:	/* LLess (Operand0, Operand1) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
593
594
595
596
597
598
599
  
  			if (integer0 < integer1) {
  				local_result = TRUE;
  			}
  			break;
  
  		default:
  			status = AE_AML_INTERNAL;
  			break;
  		}
4be44fcd3   Len Brown   [ACPI] Lindent al...
600
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
606
607
608
609
610
  		/*
  		 * 2) Both operands are Strings or both are Buffers
  		 *    Note: Code below takes advantage of common Buffer/String
  		 *          object fields. local_operand1 may have changed above. Use
  		 *          memcmp to handle nulls in buffers.
  		 */
  		length0 = operand0->buffer.length;
  		length1 = local_operand1->buffer.length;
  
  		/* Lexicographic compare: compare the data bytes */
0897831bb   Bob Moore   [ACPI] ACPICA 200...
611
612
  		compare = ACPI_MEMCMP(operand0->buffer.pointer,
  				      local_operand1->buffer.pointer,
4be44fcd3   Len Brown   [ACPI] Lindent al...
613
  				      (length0 > length1) ? length1 : length0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
  
  		switch (opcode) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
616
  		case AML_LEQUAL_OP:	/* LEqual (Operand0, Operand1) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
  
  			/* Length and all bytes must be equal */
4be44fcd3   Len Brown   [ACPI] Lindent al...
619
  			if ((length0 == length1) && (compare == 0)) {
52fc0b026   Bob Moore   [ACPI] ACPICA 200...
620

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
  				/* Length and all bytes match ==> TRUE */
  
  				local_result = TRUE;
  			}
  			break;
4be44fcd3   Len Brown   [ACPI] Lindent al...
626
  		case AML_LGREATER_OP:	/* LGreater (Operand0, Operand1) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
  
  			if (compare > 0) {
  				local_result = TRUE;
4be44fcd3   Len Brown   [ACPI] Lindent al...
630
  				goto cleanup;	/* TRUE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
  			}
  			if (compare < 0) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
633
  				goto cleanup;	/* FALSE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
637
638
639
640
641
  			}
  
  			/* Bytes match (to shortest length), compare lengths */
  
  			if (length0 > length1) {
  				local_result = TRUE;
  			}
  			break;
4be44fcd3   Len Brown   [ACPI] Lindent al...
642
  		case AML_LLESS_OP:	/* LLess (Operand0, Operand1) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
  
  			if (compare > 0) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
645
  				goto cleanup;	/* FALSE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
  			}
  			if (compare < 0) {
  				local_result = TRUE;
4be44fcd3   Len Brown   [ACPI] Lindent al...
649
  				goto cleanup;	/* TRUE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
654
655
656
657
658
659
660
661
662
663
  			}
  
  			/* Bytes match (to shortest length), compare lengths */
  
  			if (length0 < length1) {
  				local_result = TRUE;
  			}
  			break;
  
  		default:
  			status = AE_AML_INTERNAL;
  			break;
  		}
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
664
        cleanup:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
667
668
  
  	/* New object was created if implicit conversion performed - delete */
  
  	if (local_operand1 != operand1) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
669
  		acpi_ut_remove_reference(local_operand1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
  	}
  
  	/* Return the logical result and status */
  
  	*logical_result = local_result;
4be44fcd3   Len Brown   [ACPI] Lindent al...
675
  	return_ACPI_STATUS(status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
  }