aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/namespace/nseval.c
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2006-05-26 16:36:00 -0400
committerLen Brown <len.brown@intel.com>2006-06-14 02:44:35 -0400
commit4119532c95547821dbe72d6916dfa1b2148475b3 (patch)
tree564eb8f69924fb7dc72e93526faf1547acac7d30 /drivers/acpi/namespace/nseval.c
parentb8d35192c55fb055792ff0641408eaaec7c88988 (diff)
ACPI: ACPICA 20060526
Restructured, flattened, and simplified the internal interfaces for namespace object evaluation - resulting in smaller code, less CPU stack use, and fewer interfaces. (With assistance from Mikhail Kouzmich) Fixed a problem with the CopyObject operator where the first parameter was not typed correctly for the parser, interpreter, compiler, and disassembler. Caused various errors and unexpected behavior. Fixed a problem where a ShiftLeft or ShiftRight of more than 64 bits produced incorrect results with some C compilers. Since the behavior of C compilers when the shift value is larger than the datatype width is apparently not well defined, the interpreter now detects this condition and simply returns zero as expected in all such cases. (BZ 395) Fixed problem reports (Valery Podrezov) integrated: - Update String-to-Integer conversion to match ACPI 3.0A spec http://bugzilla.kernel.org/show_bug.cgi?id=5329 Allow interpreter to handle nested method declarations http://bugzilla.kernel.org/show_bug.cgi?id=5361 Fixed problem reports (Fiodor Suietov) integrated: - acpi_terminate() doesn't free debug memory allocation list objects (BZ 355) - After Core Subsystem shutdown, acpi_subsystem_status() returns AE_OK (BZ 356) - acpi_os_unmap_memory() for RSDP can be invoked inconsistently (BZ 357) - Resource Manager should return AE_TYPE for non-device objects (BZ 358) - Incomplete cleanup branch in AcpiNsEvaluateRelative (BZ 359) - Use acpi_os_free() instead of ACPI_FREE in acpi_rs_set_srs_method_data (BZ 360) - Incomplete cleanup branch in acpi_ps_parse_aml (BZ 361) - Incomplete cleanup branch in acpi_ds_delete_walk_state (BZ 362) - acpi_get_table_header returns AE_NO_ACPI_TABLES until DSDT is loaded (BZ 365) - Status of the Global Initialization Handler call not used (BZ 366) - Incorrect object parameter to Global Initialization Handler (BZ 367) Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/namespace/nseval.c')
-rw-r--r--drivers/acpi/namespace/nseval.c485
1 files changed, 117 insertions, 368 deletions
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 4b054062b46a..4b0a4a8c9843 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -1,7 +1,6 @@
1/******************************************************************************* 1/*******************************************************************************
2 * 2 *
3 * Module Name: nseval - Object evaluation interfaces -- includes control 3 * Module Name: nseval - Object evaluation, includes control method execution
4 * method lookup and execution.
5 * 4 *
6 ******************************************************************************/ 5 ******************************************************************************/
7 6
@@ -50,196 +49,14 @@
50#define _COMPONENT ACPI_NAMESPACE 49#define _COMPONENT ACPI_NAMESPACE
51ACPI_MODULE_NAME("nseval") 50ACPI_MODULE_NAME("nseval")
52 51
53/* Local prototypes */
54static acpi_status
55acpi_ns_execute_control_method(struct acpi_parameter_info *info);
56
57static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info);
58
59/*******************************************************************************
60 *
61 * FUNCTION: acpi_ns_evaluate_relative
62 *
63 * PARAMETERS: Pathname - Name of method to execute, If NULL, the
64 * handle is the object to execute
65 * Info - Method info block, contains:
66 * return_object - Where to put method's return value (if
67 * any). If NULL, no value is returned.
68 * Params - List of parameters to pass to the method,
69 * terminated by NULL. Params itself may be
70 * NULL if no parameters are being passed.
71 *
72 * RETURN: Status
73 *
74 * DESCRIPTION: Evaluate the object or find and execute the requested method
75 *
76 * MUTEX: Locks Namespace
77 *
78 ******************************************************************************/
79
80acpi_status
81acpi_ns_evaluate_relative(char *pathname, struct acpi_parameter_info *info)
82{
83 acpi_status status;
84 struct acpi_namespace_node *node = NULL;
85 union acpi_generic_state *scope_info;
86 char *internal_path = NULL;
87
88 ACPI_FUNCTION_TRACE(ns_evaluate_relative);
89
90 /*
91 * Must have a valid object handle
92 */
93 if (!info || !info->node) {
94 return_ACPI_STATUS(AE_BAD_PARAMETER);
95 }
96
97 /* Build an internal name string for the method */
98
99 status = acpi_ns_internalize_name(pathname, &internal_path);
100 if (ACPI_FAILURE(status)) {
101 return_ACPI_STATUS(status);
102 }
103
104 scope_info = acpi_ut_create_generic_state();
105 if (!scope_info) {
106 goto cleanup1;
107 }
108
109 /* Get the prefix handle and Node */
110
111 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
112 if (ACPI_FAILURE(status)) {
113 goto cleanup;
114 }
115
116 info->node = acpi_ns_map_handle_to_node(info->node);
117 if (!info->node) {
118 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
119 status = AE_BAD_PARAMETER;
120 goto cleanup;
121 }
122
123 /* Lookup the name in the namespace */
124
125 scope_info->scope.node = info->node;
126 status = acpi_ns_lookup(scope_info, internal_path, ACPI_TYPE_ANY,
127 ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
128 &node);
129
130 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
131
132 if (ACPI_FAILURE(status)) {
133 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Object [%s] not found [%s]\n",
134 pathname, acpi_format_exception(status)));
135 goto cleanup;
136 }
137
138 /*
139 * Now that we have a handle to the object, we can attempt to evaluate it.
140 */
141 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n",
142 pathname, node, acpi_ns_get_attached_object(node)));
143
144 info->node = node;
145 status = acpi_ns_evaluate_by_handle(info);
146
147 ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
148 "*** Completed eval of object %s ***\n", pathname));
149
150 cleanup:
151 acpi_ut_delete_generic_state(scope_info);
152
153 cleanup1:
154 ACPI_FREE(internal_path);
155 return_ACPI_STATUS(status);
156}
157
158/*******************************************************************************
159 *
160 * FUNCTION: acpi_ns_evaluate_by_name
161 *
162 * PARAMETERS: Pathname - Fully qualified pathname to the object
163 * Info - Method info block, contains:
164 * return_object - Where to put method's return value (if
165 * any). If NULL, no value is returned.
166 * Params - List of parameters to pass to the method,
167 * terminated by NULL. Params itself may be
168 * NULL if no parameters are being passed.
169 *
170 * RETURN: Status
171 *
172 * DESCRIPTION: Evaluate the object or rind and execute the requested method
173 * passing the given parameters
174 *
175 * MUTEX: Locks Namespace
176 *
177 ******************************************************************************/
178
179acpi_status
180acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info)
181{
182 acpi_status status;
183 char *internal_path = NULL;
184
185 ACPI_FUNCTION_TRACE(ns_evaluate_by_name);
186
187 /* Build an internal name string for the method */
188
189 status = acpi_ns_internalize_name(pathname, &internal_path);
190 if (ACPI_FAILURE(status)) {
191 return_ACPI_STATUS(status);
192 }
193
194 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
195 if (ACPI_FAILURE(status)) {
196 goto cleanup;
197 }
198
199 /* Lookup the name in the namespace */
200
201 status = acpi_ns_lookup(NULL, internal_path, ACPI_TYPE_ANY,
202 ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
203 &info->node);
204
205 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
206
207 if (ACPI_FAILURE(status)) {
208 ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
209 "Object at [%s] was not found, status=%.4X\n",
210 pathname, status));
211 goto cleanup;
212 }
213
214 /*
215 * Now that we have a handle to the object, we can attempt to evaluate it.
216 */
217 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n",
218 pathname, info->node,
219 acpi_ns_get_attached_object(info->node)));
220
221 status = acpi_ns_evaluate_by_handle(info);
222
223 ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
224 "*** Completed eval of object %s ***\n", pathname));
225
226 cleanup:
227
228 /* Cleanup */
229
230 if (internal_path) {
231 ACPI_FREE(internal_path);
232 }
233
234 return_ACPI_STATUS(status);
235}
236
237/******************************************************************************* 52/*******************************************************************************
238 * 53 *
239 * FUNCTION: acpi_ns_evaluate_by_handle 54 * FUNCTION: acpi_ns_evaluate
240 * 55 *
241 * PARAMETERS: Info - Method info block, contains: 56 * PARAMETERS: Info - Evaluation info block, contains:
242 * Node - Method/Object Node to execute 57 * prefix_node - Prefix or Method/Object Node to execute
58 * Pathname - Name of method to execute, If NULL, the
59 * Node is the object to execute
243 * Parameters - List of parameters to pass to the method, 60 * Parameters - List of parameters to pass to the method,
244 * terminated by NULL. Params itself may be 61 * terminated by NULL. Params itself may be
245 * NULL if no parameters are being passed. 62 * NULL if no parameters are being passed.
@@ -248,29 +65,21 @@ acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info)
248 * parameter_type - Type of Parameter list 65 * parameter_type - Type of Parameter list
249 * return_object - Where to put method's return value (if 66 * return_object - Where to put method's return value (if
250 * any). If NULL, no value is returned. 67 * any). If NULL, no value is returned.
68 * Flags - ACPI_IGNORE_RETURN_VALUE to delete return
251 * 69 *
252 * RETURN: Status 70 * RETURN: Status
253 * 71 *
254 * DESCRIPTION: Evaluate object or execute the requested method passing the 72 * DESCRIPTION: Execute a control method or return the current value of an
255 * given parameters 73 * ACPI namespace object.
256 * 74 *
257 * MUTEX: Locks Namespace 75 * MUTEX: Locks interpreter
258 * 76 *
259 ******************************************************************************/ 77 ******************************************************************************/
260 78acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
261acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info)
262{ 79{
263 acpi_status status; 80 acpi_status status;
264 81
265 ACPI_FUNCTION_TRACE(ns_evaluate_by_handle); 82 ACPI_FUNCTION_TRACE(ns_evaluate);
266
267 /* Check if namespace has been initialized */
268
269 if (!acpi_gbl_root_node) {
270 return_ACPI_STATUS(AE_NO_NAMESPACE);
271 }
272
273 /* Parameter Validation */
274 83
275 if (!info) { 84 if (!info) {
276 return_ACPI_STATUS(AE_BAD_PARAMETER); 85 return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -280,203 +89,120 @@ acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info)
280 89
281 info->return_object = NULL; 90 info->return_object = NULL;
282 91
283 /* Get the prefix handle and Node */ 92 /*
284 93 * Get the actual namespace node for the target object. Handles these cases:
285 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 94 *
95 * 1) Null node, Pathname (absolute path)
96 * 2) Node, Pathname (path relative to Node)
97 * 3) Node, Null Pathname
98 */
99 status = acpi_ns_get_node(info->prefix_node, info->pathname,
100 ACPI_NS_NO_UPSEARCH, &info->resolved_node);
286 if (ACPI_FAILURE(status)) { 101 if (ACPI_FAILURE(status)) {
287 return_ACPI_STATUS(status); 102 return_ACPI_STATUS(status);
288 } 103 }
289 104
290 info->node = acpi_ns_map_handle_to_node(info->node);
291 if (!info->node) {
292 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
293 return_ACPI_STATUS(AE_BAD_PARAMETER);
294 }
295
296 /* 105 /*
297 * For a method alias, we must grab the actual method node so that proper 106 * For a method alias, we must grab the actual method node so that proper
298 * scoping context will be established before execution. 107 * scoping context will be established before execution.
299 */ 108 */
300 if (acpi_ns_get_type(info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { 109 if (acpi_ns_get_type(info->resolved_node) ==
301 info->node = 110 ACPI_TYPE_LOCAL_METHOD_ALIAS) {
111 info->resolved_node =
302 ACPI_CAST_PTR(struct acpi_namespace_node, 112 ACPI_CAST_PTR(struct acpi_namespace_node,
303 info->node->object); 113 info->resolved_node->object);
304 } 114 }
305 115
116 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", info->pathname,
117 info->resolved_node,
118 acpi_ns_get_attached_object(info->resolved_node)));
119
306 /* 120 /*
307 * Two major cases here: 121 * Two major cases here:
308 * 1) The object is an actual control method -- execute it.
309 * 2) The object is not a method -- just return it's current value
310 * 122 *
311 * In both cases, the namespace is unlocked by the acpi_ns* procedure 123 * 1) The object is a control method -- execute it
124 * 2) The object is not a method -- just return it's current value
312 */ 125 */
313 if (acpi_ns_get_type(info->node) == ACPI_TYPE_METHOD) { 126 if (acpi_ns_get_type(info->resolved_node) == ACPI_TYPE_METHOD) {
314 /* 127 /*
315 * Case 1) We have an actual control method to execute 128 * 1) Object is a control method - execute it
316 */ 129 */
317 status = acpi_ns_execute_control_method(info);
318 } else {
319 /*
320 * Case 2) Object is NOT a method, just return its current value
321 */
322 status = acpi_ns_get_object_value(info);
323 }
324
325 /*
326 * Check if there is a return value on the stack that must be dealt with
327 */
328 if (status == AE_CTRL_RETURN_VALUE) {
329
330 /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
331
332 status = AE_OK;
333 }
334
335 /*
336 * Namespace was unlocked by the handling acpi_ns* function, so we
337 * just return
338 */
339 return_ACPI_STATUS(status);
340}
341
342/*******************************************************************************
343 *
344 * FUNCTION: acpi_ns_execute_control_method
345 *
346 * PARAMETERS: Info - Method info block, contains:
347 * Node - Method Node to execute
348 * obj_desc - Method object
349 * Parameters - List of parameters to pass to the method,
350 * terminated by NULL. Params itself may be
351 * NULL if no parameters are being passed.
352 * return_object - Where to put method's return value (if
353 * any). If NULL, no value is returned.
354 * parameter_type - Type of Parameter list
355 * return_object - Where to put method's return value (if
356 * any). If NULL, no value is returned.
357 *
358 * RETURN: Status
359 *
360 * DESCRIPTION: Execute the requested method passing the given parameters
361 *
362 * MUTEX: Assumes namespace is locked
363 *
364 ******************************************************************************/
365
366static acpi_status
367acpi_ns_execute_control_method(struct acpi_parameter_info *info)
368{
369 acpi_status status;
370
371 ACPI_FUNCTION_TRACE(ns_execute_control_method);
372
373 /* Verify that there is a method associated with this object */
374
375 info->obj_desc = acpi_ns_get_attached_object(info->node);
376 if (!info->obj_desc) {
377 ACPI_ERROR((AE_INFO, "No attached method object"));
378 130
379 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 131 /* Verify that there is a method object associated with this node */
380 return_ACPI_STATUS(AE_NULL_OBJECT);
381 }
382
383 ACPI_DUMP_PATHNAME(info->node, "Execute Method:",
384 ACPI_LV_INFO, _COMPONENT);
385
386 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Method at AML address %p Length %X\n",
387 info->obj_desc->method.aml_start + 1,
388 info->obj_desc->method.aml_length - 1));
389
390 /*
391 * Unlock the namespace before execution. This allows namespace access
392 * via the external Acpi* interfaces while a method is being executed.
393 * However, any namespace deletion must acquire both the namespace and
394 * interpreter locks to ensure that no thread is using the portion of the
395 * namespace that is being deleted.
396 */
397 status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
398 if (ACPI_FAILURE(status)) {
399 return_ACPI_STATUS(status);
400 }
401 132
402 /* 133 info->obj_desc =
403 * Execute the method via the interpreter. The interpreter is locked 134 acpi_ns_get_attached_object(info->resolved_node);
404 * here before calling into the AML parser 135 if (!info->obj_desc) {
405 */ 136 ACPI_ERROR((AE_INFO,
406 status = acpi_ex_enter_interpreter(); 137 "Control method has no attached sub-object"));
407 if (ACPI_FAILURE(status)) { 138 return_ACPI_STATUS(AE_NULL_OBJECT);
408 return_ACPI_STATUS(status); 139 }
409 }
410 140
411 status = acpi_ps_execute_method(info); 141 ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:",
412 acpi_ex_exit_interpreter(); 142 ACPI_LV_INFO, _COMPONENT);
413 143
414 return_ACPI_STATUS(status); 144 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
415} 145 "Method at AML address %p Length %X\n",
146 info->obj_desc->method.aml_start + 1,
147 info->obj_desc->method.aml_length - 1));
416 148
417/******************************************************************************* 149 /*
418 * 150 * Any namespace deletion must acquire both the namespace and
419 * FUNCTION: acpi_ns_get_object_value 151 * interpreter locks to ensure that no thread is using the portion of
420 * 152 * the namespace that is being deleted.
421 * PARAMETERS: Info - Method info block, contains: 153 *
422 * Node - Object's NS node 154 * Execute the method via the interpreter. The interpreter is locked
423 * return_object - Where to put object value (if 155 * here before calling into the AML parser
424 * any). If NULL, no value is returned. 156 */
425 * 157 status = acpi_ex_enter_interpreter();
426 * RETURN: Status 158 if (ACPI_FAILURE(status)) {
427 * 159 return_ACPI_STATUS(status);
428 * DESCRIPTION: Return the current value of the object 160 }
429 *
430 * MUTEX: Assumes namespace is locked, leaves namespace unlocked
431 *
432 ******************************************************************************/
433 161
434static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info) 162 status = acpi_ps_execute_method(info);
435{ 163 acpi_ex_exit_interpreter();
436 acpi_status status = AE_OK; 164 } else {
437 struct acpi_namespace_node *resolved_node = info->node; 165 /*
166 * 2) Object is not a method, return its current value
167 */
438 168
439 ACPI_FUNCTION_TRACE(ns_get_object_value); 169 /*
170 * Objects require additional resolution steps (e.g., the Node may be
171 * a field that must be read, etc.) -- we can't just grab the object
172 * out of the node.
173 *
174 * Use resolve_node_to_value() to get the associated value.
175 *
176 * NOTE: we can get away with passing in NULL for a walk state because
177 * resolved_node is guaranteed to not be a reference to either a method
178 * local or a method argument (because this interface is never called
179 * from a running method.)
180 *
181 * Even though we do not directly invoke the interpreter for object
182 * resolution, we must lock it because we could access an opregion.
183 * The opregion access code assumes that the interpreter is locked.
184 */
185 status = acpi_ex_enter_interpreter();
186 if (ACPI_FAILURE(status)) {
187 return_ACPI_STATUS(status);
188 }
440 189
441 /* 190 /* Function has a strange interface */
442 * Objects require additional resolution steps (e.g., the Node may be a
443 * field that must be read, etc.) -- we can't just grab the object out of
444 * the node.
445 */
446 191
447 /* 192 status =
448 * Use resolve_node_to_value() to get the associated value. This call always 193 acpi_ex_resolve_node_to_value(&info->resolved_node, NULL);
449 * deletes obj_desc (allocated above). 194 acpi_ex_exit_interpreter();
450 *
451 * NOTE: we can get away with passing in NULL for a walk state because
452 * obj_desc is guaranteed to not be a reference to either a method local or
453 * a method argument (because this interface can only be called from the
454 * acpi_evaluate external interface, never called from a running method.)
455 *
456 * Even though we do not directly invoke the interpreter for this, we must
457 * enter it because we could access an opregion. The opregion access code
458 * assumes that the interpreter is locked.
459 *
460 * We must release the namespace lock before entering the intepreter.
461 */
462 status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
463 if (ACPI_FAILURE(status)) {
464 return_ACPI_STATUS(status);
465 }
466 195
467 status = acpi_ex_enter_interpreter();
468 if (ACPI_SUCCESS(status)) {
469 status = acpi_ex_resolve_node_to_value(&resolved_node, NULL);
470 /* 196 /*
471 * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed 197 * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
472 * in resolved_node. 198 * in resolved_node.
473 */ 199 */
474 acpi_ex_exit_interpreter();
475
476 if (ACPI_SUCCESS(status)) { 200 if (ACPI_SUCCESS(status)) {
477 status = AE_CTRL_RETURN_VALUE; 201 status = AE_CTRL_RETURN_VALUE;
478 info->return_object = ACPI_CAST_PTR 202 info->return_object =
479 (union acpi_operand_object, resolved_node); 203 ACPI_CAST_PTR(union acpi_operand_object,
204 info->resolved_node);
205
480 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 206 ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
481 "Returning object %p [%s]\n", 207 "Returning object %p [%s]\n",
482 info->return_object, 208 info->return_object,
@@ -485,7 +211,30 @@ static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info)
485 } 211 }
486 } 212 }
487 213
488 /* Namespace is unlocked */ 214 /*
215 * Check if there is a return value that must be dealt with
216 */
217 if (status == AE_CTRL_RETURN_VALUE) {
218
219 /* If caller does not want the return value, delete it */
489 220
221 if (info->flags & ACPI_IGNORE_RETURN_VALUE) {
222 acpi_ut_remove_reference(info->return_object);
223 info->return_object = NULL;
224 }
225
226 /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
227
228 status = AE_OK;
229 }
230
231 ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
232 "*** Completed evaluation of object %s ***\n",
233 info->pathname));
234
235 /*
236 * Namespace was unlocked by the handling acpi_ns* function, so we
237 * just return
238 */
490 return_ACPI_STATUS(status); 239 return_ACPI_STATUS(status);
491} 240}