evregion.c 22.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/******************************************************************************
 *
3
 * Module Name: evregion - Operation Region support
L
Linus Torvalds 已提交
4 5 6 7
 *
 *****************************************************************************/

/*
8
 * Copyright (C) 2000 - 2012, Intel Corp.
L
Linus Torvalds 已提交
9 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 44
 * 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.
 */

#include <acpi/acpi.h>
L
Len Brown 已提交
45 46 47 48
#include "accommon.h"
#include "acevents.h"
#include "acnamesp.h"
#include "acinterp.h"
L
Linus Torvalds 已提交
49 50

#define _COMPONENT          ACPI_EVENTS
L
Len Brown 已提交
51
ACPI_MODULE_NAME("evregion")
L
Linus Torvalds 已提交
52

53 54
extern u8 acpi_gbl_default_address_spaces[];

R
Robert Moore 已提交
55
/* Local prototypes */
56

57 58
static void acpi_ev_orphan_ec_reg_method(void);

R
Robert Moore 已提交
59
static acpi_status
L
Len Brown 已提交
60 61
acpi_ev_reg_run(acpi_handle obj_handle,
		u32 level, void *context, void **return_value);
R
Robert Moore 已提交
62

L
Linus Torvalds 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75
/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_initialize_op_regions
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Execute _REG methods for all Operation Regions that have
 *              an installed default region handler.
 *
 ******************************************************************************/

L
Len Brown 已提交
76
acpi_status acpi_ev_initialize_op_regions(void)
L
Linus Torvalds 已提交
77
{
L
Len Brown 已提交
78
	acpi_status status;
79
	u32 i;
L
Linus Torvalds 已提交
80

B
Bob Moore 已提交
81
	ACPI_FUNCTION_TRACE(ev_initialize_op_regions);
L
Linus Torvalds 已提交
82

L
Len Brown 已提交
83 84 85
	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
86 87
	}

88
	/* Run the _REG methods for op_regions in each default address space */
B
Bob Moore 已提交
89

90 91
	for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
		/*
92 93 94
		 * Make sure the installed handler is the DEFAULT handler. If not the
		 * default, the _REG methods will have already been run (when the
		 * handler was installed)
L
Linus Torvalds 已提交
95
		 */
96 97 98 99 100 101 102 103
		if (acpi_ev_has_default_handler(acpi_gbl_root_node,
						acpi_gbl_default_address_spaces
						[i])) {
			status =
			    acpi_ev_execute_reg_methods(acpi_gbl_root_node,
							acpi_gbl_default_address_spaces
							[i]);
		}
L
Linus Torvalds 已提交
104 105
	}

106 107
	acpi_gbl_reg_methods_executed = TRUE;

L
Len Brown 已提交
108 109
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
110 111 112 113 114 115 116
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_address_space_dispatch
 *
 * PARAMETERS:  region_obj          - Internal region object
117
 *              field_obj           - Corresponding field. Can be NULL.
118
 *              function            - Read or Write operation
119
 *              region_offset       - Where in the region to read or write
L
Linus Torvalds 已提交
120
 *              bit_width           - Field width in bits (8, 16, 32, or 64)
121
 *              value               - Pointer to in or out value, must be
122
 *                                    a full 64-bit integer
L
Linus Torvalds 已提交
123 124 125 126 127 128 129 130 131
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Dispatch an address space or operation region access to
 *              a previously installed handler.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
132
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
133
			       union acpi_operand_object *field_obj,
L
Len Brown 已提交
134
			       u32 function,
135
			       u32 region_offset, u32 bit_width, u64 *value)
L
Linus Torvalds 已提交
136
{
L
Len Brown 已提交
137 138 139 140 141 142
	acpi_status status;
	acpi_adr_space_handler handler;
	acpi_adr_space_setup region_setup;
	union acpi_operand_object *handler_desc;
	union acpi_operand_object *region_obj2;
	void *region_context = NULL;
143
	struct acpi_connection_info *context;
L
Linus Torvalds 已提交
144

B
Bob Moore 已提交
145
	ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
L
Linus Torvalds 已提交
146

L
Len Brown 已提交
147
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
L
Linus Torvalds 已提交
148
	if (!region_obj2) {
L
Len Brown 已提交
149
		return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
150 151 152 153 154 155
	}

	/* Ensure that there is a handler associated with this region */

	handler_desc = region_obj->region.handler;
	if (!handler_desc) {
B
Bob Moore 已提交
156 157 158 159 160 161
		ACPI_ERROR((AE_INFO,
			    "No handler for Region [%4.4s] (%p) [%s]",
			    acpi_ut_get_node_name(region_obj->region.node),
			    region_obj,
			    acpi_ut_get_region_name(region_obj->region.
						    space_id)));
L
Len Brown 已提交
162 163

		return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
164 165
	}

166 167
	context = handler_desc->address_space.context;

L
Linus Torvalds 已提交
168
	/*
169
	 * It may be the case that the region has never been initialized.
L
Linus Torvalds 已提交
170 171 172
	 * Some types of regions require special init code
	 */
	if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
173 174 175

		/* This region has not been initialized yet, do it */

L
Linus Torvalds 已提交
176 177
		region_setup = handler_desc->address_space.setup;
		if (!region_setup) {
B
Bob Moore 已提交
178

L
Linus Torvalds 已提交
179 180
			/* No initialization routine, exit with error */

B
Bob Moore 已提交
181 182 183 184 185
			ACPI_ERROR((AE_INFO,
				    "No init routine for region(%p) [%s]",
				    region_obj,
				    acpi_ut_get_region_name(region_obj->region.
							    space_id)));
L
Len Brown 已提交
186
			return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
187 188 189
		}

		/*
190 191 192
		 * We must exit the interpreter because the region setup will
		 * potentially execute control methods (for example, the _REG method
		 * for this region)
L
Linus Torvalds 已提交
193
		 */
194
		acpi_ex_exit_interpreter();
L
Linus Torvalds 已提交
195

L
Len Brown 已提交
196
		status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
197
				      context, &region_context);
L
Linus Torvalds 已提交
198 199 200

		/* Re-enter the interpreter */

201
		acpi_ex_enter_interpreter();
L
Linus Torvalds 已提交
202 203 204

		/* Check for failure of the Region Setup */

L
Len Brown 已提交
205
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
206 207 208 209 210
			ACPI_EXCEPTION((AE_INFO, status,
					"During region initialization: [%s]",
					acpi_ut_get_region_name(region_obj->
								region.
								space_id)));
L
Len Brown 已提交
211
			return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
212 213
		}

214 215
		/* Region initialization may have been completed by region_setup */

L
Linus Torvalds 已提交
216 217 218 219
		if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
			region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE;

			if (region_obj2->extra.region_context) {
B
Bob Moore 已提交
220

L
Linus Torvalds 已提交
221 222
				/* The handler for this region was already installed */

B
Bob Moore 已提交
223
				ACPI_FREE(region_context);
L
Len Brown 已提交
224
			} else {
L
Linus Torvalds 已提交
225 226 227 228
				/*
				 * Save the returned context for use in all accesses to
				 * this particular region
				 */
L
Len Brown 已提交
229 230
				region_obj2->extra.region_context =
				    region_context;
L
Linus Torvalds 已提交
231 232 233 234 235 236 237 238
			}
		}
	}

	/* We have everything we need, we can invoke the address space handler */

	handler = handler_desc->address_space.handler;

L
Len Brown 已提交
239 240 241
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
			  &region_obj->region.handler->address_space, handler,
242 243
			  ACPI_FORMAT_NATIVE_UINT(region_obj->region.address +
						  region_offset),
L
Len Brown 已提交
244 245
			  acpi_ut_get_region_name(region_obj->region.
						  space_id)));
L
Linus Torvalds 已提交
246

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	/*
	 * Special handling for generic_serial_bus and general_purpose_io:
	 * There are three extra parameters that must be passed to the
	 * handler via the context:
	 *   1) Connection buffer, a resource template from Connection() op.
	 *   2) Length of the above buffer.
	 *   3) Actual access length from the access_as() op.
	 */
	if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) ||
	     (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) &&
	    context && field_obj) {

		/* Get the Connection (resource_template) buffer */

		context->connection = field_obj->field.resource_buffer;
		context->length = field_obj->field.resource_length;
		context->access_length = field_obj->field.access_length;
	}

B
Bob Moore 已提交
266 267
	if (!(handler_desc->address_space.handler_flags &
	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
L
Linus Torvalds 已提交
268 269 270 271 272
		/*
		 * For handlers other than the default (supplied) handlers, we must
		 * exit the interpreter because the handler *might* block -- we don't
		 * know what it will do, so we can't hold the lock on the intepreter.
		 */
273
		acpi_ex_exit_interpreter();
L
Linus Torvalds 已提交
274 275 276 277
	}

	/* Call the handler */

278 279
	status = handler(function,
			 (region_obj->region.address + region_offset),
280
			 bit_width, value, context,
L
Linus Torvalds 已提交
281 282
			 region_obj2->extra.region_context);

L
Len Brown 已提交
283
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
284 285 286
		ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
				acpi_ut_get_region_name(region_obj->region.
							space_id)));
L
Linus Torvalds 已提交
287 288
	}

B
Bob Moore 已提交
289 290
	if (!(handler_desc->address_space.handler_flags &
	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
L
Linus Torvalds 已提交
291 292 293 294
		/*
		 * We just returned from a non-default handler, we must re-enter the
		 * interpreter
		 */
295
		acpi_ex_enter_interpreter();
L
Linus Torvalds 已提交
296 297
	}

L
Len Brown 已提交
298
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_detach_region
 *
 * PARAMETERS:  region_obj          - Region Object
 *              acpi_ns_is_locked   - Namespace Region Already Locked?
 *
 * RETURN:      None
 *
 * DESCRIPTION: Break the association between the handler and the region
 *              this is a two way association.
 *
 ******************************************************************************/

void
L
Len Brown 已提交
316 317
acpi_ev_detach_region(union acpi_operand_object *region_obj,
		      u8 acpi_ns_is_locked)
L
Linus Torvalds 已提交
318
{
L
Len Brown 已提交
319 320 321 322 323 324 325
	union acpi_operand_object *handler_obj;
	union acpi_operand_object *obj_desc;
	union acpi_operand_object **last_obj_ptr;
	acpi_adr_space_setup region_setup;
	void **region_context;
	union acpi_operand_object *region_obj2;
	acpi_status status;
L
Linus Torvalds 已提交
326

B
Bob Moore 已提交
327
	ACPI_FUNCTION_TRACE(ev_detach_region);
L
Linus Torvalds 已提交
328

L
Len Brown 已提交
329
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
L
Linus Torvalds 已提交
330 331 332 333 334 335 336 337 338
	if (!region_obj2) {
		return_VOID;
	}
	region_context = &region_obj2->extra.region_context;

	/* Get the address handler from the region object */

	handler_obj = region_obj->region.handler;
	if (!handler_obj) {
B
Bob Moore 已提交
339

L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347 348 349 350
		/* This region has no handler, all done */

		return_VOID;
	}

	/* Find this region in the handler's list */

	obj_desc = handler_obj->address_space.region_list;
	last_obj_ptr = &handler_obj->address_space.region_list;

	while (obj_desc) {
B
Bob Moore 已提交
351

L
Linus Torvalds 已提交
352 353 354
		/* Is this the correct Region? */

		if (obj_desc == region_obj) {
L
Len Brown 已提交
355 356 357
			ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
					  "Removing Region %p from address handler %p\n",
					  region_obj, handler_obj));
L
Linus Torvalds 已提交
358 359 360 361

			/* This is it, remove it from the handler's list */

			*last_obj_ptr = obj_desc->region.next;
L
Len Brown 已提交
362
			obj_desc->region.next = NULL;	/* Must clear field */
L
Linus Torvalds 已提交
363 364

			if (acpi_ns_is_locked) {
L
Len Brown 已提交
365 366 367
				status =
				    acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
				if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
368 369 370 371 372 373
					return_VOID;
				}
			}

			/* Now stop region accesses by executing the _REG method */

374 375 376
			status =
			    acpi_ev_execute_reg_method(region_obj,
						       ACPI_REG_DISCONNECT);
L
Len Brown 已提交
377
			if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
378 379 380 381
				ACPI_EXCEPTION((AE_INFO, status,
						"from region _REG, [%s]",
						acpi_ut_get_region_name
						(region_obj->region.space_id)));
L
Linus Torvalds 已提交
382 383 384
			}

			if (acpi_ns_is_locked) {
L
Len Brown 已提交
385 386 387
				status =
				    acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
				if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
388 389 390 391
					return_VOID;
				}
			}

B
Bob Moore 已提交
392
			/*
393 394
			 * If the region has been activated, call the setup handler with
			 * the deactivate notification
B
Bob Moore 已提交
395 396 397 398 399 400 401 402
			 */
			if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
				region_setup = handler_obj->address_space.setup;
				status =
				    region_setup(region_obj,
						 ACPI_REGION_DEACTIVATE,
						 handler_obj->address_space.
						 context, region_context);
L
Linus Torvalds 已提交
403

B
Bob Moore 已提交
404
				/* Init routine may fail, Just ignore errors */
L
Linus Torvalds 已提交
405

B
Bob Moore 已提交
406 407 408 409 410 411 412
				if (ACPI_FAILURE(status)) {
					ACPI_EXCEPTION((AE_INFO, status,
							"from region handler - deactivate, [%s]",
							acpi_ut_get_region_name
							(region_obj->region.
							 space_id)));
				}
L
Linus Torvalds 已提交
413

B
Bob Moore 已提交
414 415
				region_obj->region.flags &=
				    ~(AOPOBJ_SETUP_COMPLETE);
L
Linus Torvalds 已提交
416 417 418 419 420
			}

			/*
			 * Remove handler reference in the region
			 *
B
Bob Moore 已提交
421 422
			 * NOTE: this doesn't mean that the region goes away, the region
			 * is just inaccessible as indicated to the _REG method
L
Linus Torvalds 已提交
423
			 *
B
Bob Moore 已提交
424 425
			 * If the region is on the handler's list, this must be the
			 * region's handler
L
Linus Torvalds 已提交
426 427
			 */
			region_obj->region.handler = NULL;
L
Len Brown 已提交
428
			acpi_ut_remove_reference(handler_obj);
L
Linus Torvalds 已提交
429 430 431 432 433 434 435 436 437 438 439 440

			return_VOID;
		}

		/* Walk the linked list of handlers */

		last_obj_ptr = &obj_desc->region.next;
		obj_desc = obj_desc->region.next;
	}

	/* If we get here, the region was not in the handler's region list */

L
Len Brown 已提交
441 442 443
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Cannot remove region %p from address handler %p\n",
			  region_obj, handler_obj));
L
Linus Torvalds 已提交
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463

	return_VOID;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_attach_region
 *
 * PARAMETERS:  handler_obj         - Handler Object
 *              region_obj          - Region Object
 *              acpi_ns_is_locked   - Namespace Region Already Locked?
 *
 * RETURN:      None
 *
 * DESCRIPTION: Create the association between the handler and the region
 *              this is a two way association.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
464 465 466
acpi_ev_attach_region(union acpi_operand_object *handler_obj,
		      union acpi_operand_object *region_obj,
		      u8 acpi_ns_is_locked)
L
Linus Torvalds 已提交
467 468
{

B
Bob Moore 已提交
469
	ACPI_FUNCTION_TRACE(ev_attach_region);
L
Linus Torvalds 已提交
470

L
Len Brown 已提交
471 472 473 474 475 476
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Adding Region [%4.4s] %p to address handler %p [%s]\n",
			  acpi_ut_get_node_name(region_obj->region.node),
			  region_obj, handler_obj,
			  acpi_ut_get_region_name(region_obj->region.
						  space_id)));
L
Linus Torvalds 已提交
477 478 479 480 481 482 483 484 485

	/* Link this region to the front of the handler's list */

	region_obj->region.next = handler_obj->address_space.region_list;
	handler_obj->address_space.region_list = region_obj;

	/* Install the region's handler */

	if (region_obj->region.handler) {
L
Len Brown 已提交
486
		return_ACPI_STATUS(AE_ALREADY_EXISTS);
L
Linus Torvalds 已提交
487 488 489
	}

	region_obj->region.handler = handler_obj;
L
Len Brown 已提交
490
	acpi_ut_add_reference(handler_obj);
L
Linus Torvalds 已提交
491

L
Len Brown 已提交
492
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
493 494 495 496
}

/*******************************************************************************
 *
497
 * FUNCTION:    acpi_ev_execute_reg_method
L
Linus Torvalds 已提交
498
 *
499 500
 * PARAMETERS:  region_obj          - Region object
 *              function            - Passed to _REG: On (1) or Off (0)
L
Linus Torvalds 已提交
501 502 503
 *
 * RETURN:      Status
 *
504
 * DESCRIPTION: Execute _REG method for a region
L
Linus Torvalds 已提交
505 506 507 508
 *
 ******************************************************************************/

acpi_status
509
acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
L
Linus Torvalds 已提交
510
{
511 512 513
	struct acpi_evaluate_info *info;
	union acpi_operand_object *args[3];
	union acpi_operand_object *region_obj2;
L
Len Brown 已提交
514
	acpi_status status;
L
Linus Torvalds 已提交
515

516
	ACPI_FUNCTION_TRACE(ev_execute_reg_method);
L
Linus Torvalds 已提交
517

518 519 520
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
	if (!region_obj2) {
		return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
521 522
	}

523 524
	if (region_obj2->extra.method_REG == NULL) {
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
525 526
	}

527
	/* Allocate and initialize the evaluation information block */
L
Linus Torvalds 已提交
528

529 530 531
	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
	if (!info) {
		return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
532 533
	}

534 535 536 537
	info->prefix_node = region_obj2->extra.method_REG;
	info->pathname = NULL;
	info->parameters = args;
	info->flags = ACPI_IGNORE_RETURN_VALUE;
L
Linus Torvalds 已提交
538 539

	/*
540 541 542 543
	 * The _REG method has two arguments:
	 *
	 * arg0 - Integer:
	 *  Operation region space ID Same value as region_obj->Region.space_id
L
Linus Torvalds 已提交
544
	 *
545 546 547
	 * arg1 - Integer:
	 *  connection status 1 for connecting the handler, 0 for disconnecting
	 *  the handler (Passed as a parameter)
L
Linus Torvalds 已提交
548
	 */
549 550 551
	args[0] =
	    acpi_ut_create_integer_object((u64)region_obj->region.space_id);
	if (!args[0]) {
L
Linus Torvalds 已提交
552
		status = AE_NO_MEMORY;
553
		goto cleanup1;
L
Linus Torvalds 已提交
554 555
	}

556 557 558 559 560
	args[1] = acpi_ut_create_integer_object((u64)function);
	if (!args[1]) {
		status = AE_NO_MEMORY;
		goto cleanup2;
	}
L
Linus Torvalds 已提交
561

562
	args[2] = NULL;		/* Terminate list */
L
Linus Torvalds 已提交
563

564
	/* Execute the method, no return value */
L
Linus Torvalds 已提交
565

566 567
	ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
			(ACPI_TYPE_METHOD, info->prefix_node, NULL));
L
Linus Torvalds 已提交
568

569 570
	status = acpi_ns_evaluate(info);
	acpi_ut_remove_reference(args[1]);
L
Linus Torvalds 已提交
571

572 573
      cleanup2:
	acpi_ut_remove_reference(args[0]);
L
Linus Torvalds 已提交
574

575 576
      cleanup1:
	ACPI_FREE(info);
L
Len Brown 已提交
577
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
578 579 580 581 582 583
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_execute_reg_methods
 *
584
 * PARAMETERS:  node            - Namespace node for the device
L
Linus Torvalds 已提交
585 586 587 588 589 590 591 592 593 594
 *              space_id        - The address space ID
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Run all _REG methods for the input Space ID;
 *              Note: assumes namespace is locked, or system init time.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
595 596
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
			    acpi_adr_space_type space_id)
L
Linus Torvalds 已提交
597
{
L
Len Brown 已提交
598
	acpi_status status;
L
Linus Torvalds 已提交
599

B
Bob Moore 已提交
600
	ACPI_FUNCTION_TRACE(ev_execute_reg_methods);
L
Linus Torvalds 已提交
601 602

	/*
603 604 605 606
	 * Run all _REG methods for all Operation Regions for this space ID. This
	 * is a separate walk in order to handle any interdependencies between
	 * regions and _REG methods. (i.e. handlers must be installed for all
	 * regions of this Space ID before we can run any _REG methods)
L
Linus Torvalds 已提交
607
	 */
L
Len Brown 已提交
608 609
	status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
					ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run,
610
					NULL, &space_id, NULL);
L
Linus Torvalds 已提交
611

612 613 614 615 616 617
	/* Special case for EC: handle "orphan" _REG methods with no region */

	if (space_id == ACPI_ADR_SPACE_EC) {
		acpi_ev_orphan_ec_reg_method();
	}

L
Len Brown 已提交
618
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
619 620 621 622 623 624 625 626
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_reg_run
 *
 * PARAMETERS:  walk_namespace callback
 *
627
 * DESCRIPTION: Run _REG method for region objects of the requested spaceID
L
Linus Torvalds 已提交
628 629 630
 *
 ******************************************************************************/

R
Robert Moore 已提交
631
static acpi_status
L
Len Brown 已提交
632 633
acpi_ev_reg_run(acpi_handle obj_handle,
		u32 level, void *context, void **return_value)
L
Linus Torvalds 已提交
634
{
L
Len Brown 已提交
635 636 637 638
	union acpi_operand_object *obj_desc;
	struct acpi_namespace_node *node;
	acpi_adr_space_type space_id;
	acpi_status status;
L
Linus Torvalds 已提交
639

L
Len Brown 已提交
640
	space_id = *ACPI_CAST_PTR(acpi_adr_space_type, context);
L
Linus Torvalds 已提交
641 642 643

	/* Convert and validate the device handle */

644
	node = acpi_ns_validate_handle(obj_handle);
L
Linus Torvalds 已提交
645 646 647 648 649
	if (!node) {
		return (AE_BAD_PARAMETER);
	}

	/*
650 651
	 * We only care about regions.and objects that are allowed to have address
	 * space handlers
L
Linus Torvalds 已提交
652
	 */
L
Len Brown 已提交
653
	if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
L
Linus Torvalds 已提交
654 655 656 657 658
		return (AE_OK);
	}

	/* Check for an existing internal object */

L
Len Brown 已提交
659
	obj_desc = acpi_ns_get_attached_object(node);
L
Linus Torvalds 已提交
660
	if (!obj_desc) {
B
Bob Moore 已提交
661

L
Linus Torvalds 已提交
662 663 664 665 666 667 668 669
		/* No object, just exit */

		return (AE_OK);
	}

	/* Object is a Region */

	if (obj_desc->region.space_id != space_id) {
670 671 672

		/* This region is for a different address space, just ignore it */

L
Linus Torvalds 已提交
673 674 675
		return (AE_OK);
	}

676
	status = acpi_ev_execute_reg_method(obj_desc, ACPI_REG_CONNECT);
L
Linus Torvalds 已提交
677 678
	return (status);
}
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_orphan_ec_reg_method
 *
 * PARAMETERS:  None
 *
 * RETURN:      None
 *
 * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC
 *              device. This is a _REG method that has no corresponding region
 *              within the EC device scope. The orphan _REG method appears to
 *              have been enabled by the description of the ECDT in the ACPI
 *              specification: "The availability of the region space can be
 *              detected by providing a _REG method object underneath the
 *              Embedded Controller device."
 *
 *              To quickly access the EC device, we use the EC_ID that appears
 *              within the ECDT. Otherwise, we would need to perform a time-
 *              consuming namespace walk, executing _HID methods to find the
 *              EC device.
 *
 ******************************************************************************/

static void acpi_ev_orphan_ec_reg_method(void)
{
	struct acpi_table_ecdt *table;
	acpi_status status;
	struct acpi_object_list args;
	union acpi_object objects[2];
	struct acpi_namespace_node *ec_device_node;
	struct acpi_namespace_node *reg_method;
	struct acpi_namespace_node *next_node;

	ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method);

	/* Get the ECDT (if present in system) */

	status = acpi_get_table(ACPI_SIG_ECDT, 0,
				ACPI_CAST_INDIRECT_PTR(struct acpi_table_header,
						       &table));
	if (ACPI_FAILURE(status)) {
		return_VOID;
	}

	/* We need a valid EC_ID string */

	if (!(*table->id)) {
		return_VOID;
	}

	/* Namespace is currently locked, must release */

	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);

	/* Get a handle to the EC device referenced in the ECDT */

	status = acpi_get_handle(NULL,
				 ACPI_CAST_PTR(char, table->id),
				 ACPI_CAST_PTR(acpi_handle, &ec_device_node));
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	/* Get a handle to a _REG method immediately under the EC device */

	status = acpi_get_handle(ec_device_node,
				 METHOD_NAME__REG, ACPI_CAST_PTR(acpi_handle,
								 &reg_method));
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	/*
	 * Execute the _REG method only if there is no Operation Region in
	 * this scope with the Embedded Controller space ID. Otherwise, it
	 * will already have been executed. Note, this allows for Regions
	 * with other space IDs to be present; but the code below will then
	 * execute the _REG method with the EC space ID argument.
	 */
	next_node = acpi_ns_get_next_node(ec_device_node, NULL);
	while (next_node) {
		if ((next_node->type == ACPI_TYPE_REGION) &&
		    (next_node->object) &&
		    (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) {
			goto exit;	/* Do not execute _REG */
		}
		next_node = acpi_ns_get_next_node(ec_device_node, next_node);
	}

	/* Evaluate the _REG(EC,Connect) method */

	args.count = 2;
	args.pointer = objects;
	objects[0].type = ACPI_TYPE_INTEGER;
	objects[0].integer.value = ACPI_ADR_SPACE_EC;
	objects[1].type = ACPI_TYPE_INTEGER;
	objects[1].integer.value = ACPI_REG_CONNECT;

	status = acpi_evaluate_object(reg_method, NULL, &args, NULL);

      exit:
	/* We ignore all errors from above, don't care */

	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	return_VOID;
}