Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6595 serge 1
/******************************************************************************
2
 *
3
 * Module Name: evregion - Operation Region support
4
 *
5
 *****************************************************************************/
6
 
7
/*
8
 * Copyright (C) 2000 - 2015, Intel Corp.
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions, and the following disclaimer,
16
 *    without modification.
17
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18
 *    substantially similar to the "NO WARRANTY" disclaimer below
19
 *    ("Disclaimer") and any redistribution must be conditioned upon
20
 *    including a substantially similar Disclaimer requirement for further
21
 *    binary redistribution.
22
 * 3. Neither the names of the above-listed copyright holders nor the names
23
 *    of any contributors may be used to endorse or promote products derived
24
 *    from this software without specific prior written permission.
25
 *
26
 * Alternatively, this software may be distributed under the terms of the
27
 * GNU General Public License ("GPL") version 2 as published by the Free
28
 * Software Foundation.
29
 *
30
 * NO WARRANTY
31
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41
 * POSSIBILITY OF SUCH DAMAGES.
42
 */
43
 
44
#include 
45
#include "accommon.h"
46
#include "acevents.h"
47
#include "acnamesp.h"
48
#include "acinterp.h"
49
 
50
#define _COMPONENT          ACPI_EVENTS
51
ACPI_MODULE_NAME("evregion")
52
 
53
extern u8 acpi_gbl_default_address_spaces[];
54
 
55
/* Local prototypes */
56
 
57
static void
58
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node);
59
 
60
static acpi_status
61
acpi_ev_reg_run(acpi_handle obj_handle,
62
		u32 level, void *context, void **return_value);
63
 
64
/*******************************************************************************
65
 *
66
 * FUNCTION:    acpi_ev_initialize_op_regions
67
 *
68
 * PARAMETERS:  None
69
 *
70
 * RETURN:      Status
71
 *
72
 * DESCRIPTION: Execute _REG methods for all Operation Regions that have
73
 *              an installed default region handler.
74
 *
75
 ******************************************************************************/
76
 
77
acpi_status acpi_ev_initialize_op_regions(void)
78
{
79
	acpi_status status;
80
	u32 i;
81
 
82
	ACPI_FUNCTION_TRACE(ev_initialize_op_regions);
83
 
84
	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
85
	if (ACPI_FAILURE(status)) {
86
		return_ACPI_STATUS(status);
87
	}
88
 
89
	/* Run the _REG methods for op_regions in each default address space */
90
 
91
	for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
92
		/*
93
		 * Make sure the installed handler is the DEFAULT handler. If not the
94
		 * default, the _REG methods will have already been run (when the
95
		 * handler was installed)
96
		 */
97
		if (acpi_ev_has_default_handler(acpi_gbl_root_node,
98
						acpi_gbl_default_address_spaces
99
						[i])) {
100
			status =
101
			    acpi_ev_execute_reg_methods(acpi_gbl_root_node,
102
							acpi_gbl_default_address_spaces
103
							[i]);
104
		}
105
	}
106
 
107
	acpi_gbl_reg_methods_executed = TRUE;
108
 
109
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
110
	return_ACPI_STATUS(status);
111
}
112
 
113
/*******************************************************************************
114
 *
115
 * FUNCTION:    acpi_ev_address_space_dispatch
116
 *
117
 * PARAMETERS:  region_obj          - Internal region object
118
 *              field_obj           - Corresponding field. Can be NULL.
119
 *              function            - Read or Write operation
120
 *              region_offset       - Where in the region to read or write
121
 *              bit_width           - Field width in bits (8, 16, 32, or 64)
122
 *              value               - Pointer to in or out value, must be
123
 *                                    a full 64-bit integer
124
 *
125
 * RETURN:      Status
126
 *
127
 * DESCRIPTION: Dispatch an address space or operation region access to
128
 *              a previously installed handler.
129
 *
130
 ******************************************************************************/
131
 
132
acpi_status
133
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
134
			       union acpi_operand_object *field_obj,
135
			       u32 function,
136
			       u32 region_offset, u32 bit_width, u64 *value)
137
{
138
	acpi_status status;
139
	acpi_adr_space_handler handler;
140
	acpi_adr_space_setup region_setup;
141
	union acpi_operand_object *handler_desc;
142
	union acpi_operand_object *region_obj2;
143
	void *region_context = NULL;
144
	struct acpi_connection_info *context;
145
	acpi_physical_address address;
146
 
147
	ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
148
 
149
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
150
	if (!region_obj2) {
151
		return_ACPI_STATUS(AE_NOT_EXIST);
152
	}
153
 
154
	/* Ensure that there is a handler associated with this region */
155
 
156
	handler_desc = region_obj->region.handler;
157
	if (!handler_desc) {
158
		ACPI_ERROR((AE_INFO,
159
			    "No handler for Region [%4.4s] (%p) [%s]",
160
			    acpi_ut_get_node_name(region_obj->region.node),
161
			    region_obj,
162
			    acpi_ut_get_region_name(region_obj->region.
163
						    space_id)));
164
 
165
		return_ACPI_STATUS(AE_NOT_EXIST);
166
	}
167
 
168
	context = handler_desc->address_space.context;
169
 
170
	/*
171
	 * It may be the case that the region has never been initialized.
172
	 * Some types of regions require special init code
173
	 */
174
	if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
175
 
176
		/* This region has not been initialized yet, do it */
177
 
178
		region_setup = handler_desc->address_space.setup;
179
		if (!region_setup) {
180
 
181
			/* No initialization routine, exit with error */
182
 
183
			ACPI_ERROR((AE_INFO,
184
				    "No init routine for region(%p) [%s]",
185
				    region_obj,
186
				    acpi_ut_get_region_name(region_obj->region.
187
							    space_id)));
188
			return_ACPI_STATUS(AE_NOT_EXIST);
189
		}
190
 
191
		/*
192
		 * We must exit the interpreter because the region setup will
193
		 * potentially execute control methods (for example, the _REG method
194
		 * for this region)
195
		 */
196
		acpi_ex_exit_interpreter();
197
 
198
		status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
199
				      context, ®ion_context);
200
 
201
		/* Re-enter the interpreter */
202
 
203
		acpi_ex_enter_interpreter();
204
 
205
		/* Check for failure of the Region Setup */
206
 
207
		if (ACPI_FAILURE(status)) {
208
			ACPI_EXCEPTION((AE_INFO, status,
209
					"During region initialization: [%s]",
210
					acpi_ut_get_region_name(region_obj->
211
								region.
212
								space_id)));
213
			return_ACPI_STATUS(status);
214
		}
215
 
216
		/* Region initialization may have been completed by region_setup */
217
 
218
		if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
219
			region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE;
220
 
221
			/*
222
			 * Save the returned context for use in all accesses to
223
			 * the handler for this particular region
224
			 */
225
			if (!(region_obj2->extra.region_context)) {
226
				region_obj2->extra.region_context =
227
				    region_context;
228
			}
229
		}
230
	}
231
 
232
	/* We have everything we need, we can invoke the address space handler */
233
 
234
	handler = handler_desc->address_space.handler;
235
	address = (region_obj->region.address + region_offset);
236
 
237
	/*
238
	 * Special handling for generic_serial_bus and general_purpose_io:
239
	 * There are three extra parameters that must be passed to the
240
	 * handler via the context:
241
	 *   1) Connection buffer, a resource template from Connection() op
242
	 *   2) Length of the above buffer
243
	 *   3) Actual access length from the access_as() op
244
	 *
245
	 * In addition, for general_purpose_io, the Address and bit_width fields
246
	 * are defined as follows:
247
	 *   1) Address is the pin number index of the field (bit offset from
248
	 *      the previous Connection)
249
	 *   2) bit_width is the actual bit length of the field (number of pins)
250
	 */
251
	if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) &&
252
	    context && field_obj) {
253
 
254
		/* Get the Connection (resource_template) buffer */
255
 
256
		context->connection = field_obj->field.resource_buffer;
257
		context->length = field_obj->field.resource_length;
258
		context->access_length = field_obj->field.access_length;
259
	}
260
	if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
261
	    context && field_obj) {
262
 
263
		/* Get the Connection (resource_template) buffer */
264
 
265
		context->connection = field_obj->field.resource_buffer;
266
		context->length = field_obj->field.resource_length;
267
		context->access_length = field_obj->field.access_length;
268
		address = field_obj->field.pin_number_index;
269
		bit_width = field_obj->field.bit_length;
270
	}
271
 
272
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
273
			  "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
274
			  ®ion_obj->region.handler->address_space, handler,
275
			  ACPI_FORMAT_UINT64(address),
276
			  acpi_ut_get_region_name(region_obj->region.
277
						  space_id)));
278
 
279
	if (!(handler_desc->address_space.handler_flags &
280
	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
281
		/*
282
		 * For handlers other than the default (supplied) handlers, we must
283
		 * exit the interpreter because the handler *might* block -- we don't
284
		 * know what it will do, so we can't hold the lock on the intepreter.
285
		 */
286
		acpi_ex_exit_interpreter();
287
	}
288
 
289
	/* Call the handler */
290
 
291
	status = handler(function, address, bit_width, value, context,
292
			 region_obj2->extra.region_context);
293
 
294
	if (ACPI_FAILURE(status)) {
295
		ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
296
				acpi_ut_get_region_name(region_obj->region.
297
							space_id)));
298
	}
299
 
300
	if (!(handler_desc->address_space.handler_flags &
301
	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
302
		/*
303
		 * We just returned from a non-default handler, we must re-enter the
304
		 * interpreter
305
		 */
306
		acpi_ex_enter_interpreter();
307
	}
308
 
309
	return_ACPI_STATUS(status);
310
}
311
 
312
/*******************************************************************************
313
 *
314
 * FUNCTION:    acpi_ev_detach_region
315
 *
316
 * PARAMETERS:  region_obj          - Region Object
317
 *              acpi_ns_is_locked   - Namespace Region Already Locked?
318
 *
319
 * RETURN:      None
320
 *
321
 * DESCRIPTION: Break the association between the handler and the region
322
 *              this is a two way association.
323
 *
324
 ******************************************************************************/
325
 
326
void
327
acpi_ev_detach_region(union acpi_operand_object *region_obj,
328
		      u8 acpi_ns_is_locked)
329
{
330
	union acpi_operand_object *handler_obj;
331
	union acpi_operand_object *obj_desc;
332
	union acpi_operand_object *start_desc;
333
	union acpi_operand_object **last_obj_ptr;
334
	acpi_adr_space_setup region_setup;
335
	void **region_context;
336
	union acpi_operand_object *region_obj2;
337
	acpi_status status;
338
 
339
	ACPI_FUNCTION_TRACE(ev_detach_region);
340
 
341
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
342
	if (!region_obj2) {
343
		return_VOID;
344
	}
345
	region_context = ®ion_obj2->extra.region_context;
346
 
347
	/* Get the address handler from the region object */
348
 
349
	handler_obj = region_obj->region.handler;
350
	if (!handler_obj) {
351
 
352
		/* This region has no handler, all done */
353
 
354
		return_VOID;
355
	}
356
 
357
	/* Find this region in the handler's list */
358
 
359
	obj_desc = handler_obj->address_space.region_list;
360
	start_desc = obj_desc;
361
	last_obj_ptr = &handler_obj->address_space.region_list;
362
 
363
	while (obj_desc) {
364
 
365
		/* Is this the correct Region? */
366
 
367
		if (obj_desc == region_obj) {
368
			ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
369
					  "Removing Region %p from address handler %p\n",
370
					  region_obj, handler_obj));
371
 
372
			/* This is it, remove it from the handler's list */
373
 
374
			*last_obj_ptr = obj_desc->region.next;
375
			obj_desc->region.next = NULL;	/* Must clear field */
376
 
377
			if (acpi_ns_is_locked) {
378
				status =
379
				    acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
380
				if (ACPI_FAILURE(status)) {
381
					return_VOID;
382
				}
383
			}
384
 
385
			/* Now stop region accesses by executing the _REG method */
386
 
387
			status =
388
			    acpi_ev_execute_reg_method(region_obj,
389
						       ACPI_REG_DISCONNECT);
390
			if (ACPI_FAILURE(status)) {
391
				ACPI_EXCEPTION((AE_INFO, status,
392
						"from region _REG, [%s]",
393
						acpi_ut_get_region_name
394
						(region_obj->region.space_id)));
395
			}
396
 
397
			if (acpi_ns_is_locked) {
398
				status =
399
				    acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
400
				if (ACPI_FAILURE(status)) {
401
					return_VOID;
402
				}
403
			}
404
 
405
			/*
406
			 * If the region has been activated, call the setup handler with
407
			 * the deactivate notification
408
			 */
409
			if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
410
				region_setup = handler_obj->address_space.setup;
411
				status =
412
				    region_setup(region_obj,
413
						 ACPI_REGION_DEACTIVATE,
414
						 handler_obj->address_space.
415
						 context, region_context);
416
 
417
				/*
418
				 * region_context should have been released by the deactivate
419
				 * operation. We don't need access to it anymore here.
420
				 */
421
				if (region_context) {
422
					*region_context = NULL;
423
				}
424
 
425
				/* Init routine may fail, Just ignore errors */
426
 
427
				if (ACPI_FAILURE(status)) {
428
					ACPI_EXCEPTION((AE_INFO, status,
429
							"from region handler - deactivate, [%s]",
430
							acpi_ut_get_region_name
431
							(region_obj->region.
432
							 space_id)));
433
				}
434
 
435
				region_obj->region.flags &=
436
				    ~(AOPOBJ_SETUP_COMPLETE);
437
			}
438
 
439
			/*
440
			 * Remove handler reference in the region
441
			 *
442
			 * NOTE: this doesn't mean that the region goes away, the region
443
			 * is just inaccessible as indicated to the _REG method
444
			 *
445
			 * If the region is on the handler's list, this must be the
446
			 * region's handler
447
			 */
448
			region_obj->region.handler = NULL;
449
			acpi_ut_remove_reference(handler_obj);
450
 
451
			return_VOID;
452
		}
453
 
454
		/* Walk the linked list of handlers */
455
 
456
		last_obj_ptr = &obj_desc->region.next;
457
		obj_desc = obj_desc->region.next;
458
 
459
		/* Prevent infinite loop if list is corrupted */
460
 
461
		if (obj_desc == start_desc) {
462
			ACPI_ERROR((AE_INFO,
463
				    "Circular handler list in region object %p",
464
				    region_obj));
465
			return_VOID;
466
		}
467
	}
468
 
469
	/* If we get here, the region was not in the handler's region list */
470
 
471
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
472
			  "Cannot remove region %p from address handler %p\n",
473
			  region_obj, handler_obj));
474
 
475
	return_VOID;
476
}
477
 
478
/*******************************************************************************
479
 *
480
 * FUNCTION:    acpi_ev_attach_region
481
 *
482
 * PARAMETERS:  handler_obj         - Handler Object
483
 *              region_obj          - Region Object
484
 *              acpi_ns_is_locked   - Namespace Region Already Locked?
485
 *
486
 * RETURN:      None
487
 *
488
 * DESCRIPTION: Create the association between the handler and the region
489
 *              this is a two way association.
490
 *
491
 ******************************************************************************/
492
 
493
acpi_status
494
acpi_ev_attach_region(union acpi_operand_object *handler_obj,
495
		      union acpi_operand_object *region_obj,
496
		      u8 acpi_ns_is_locked)
497
{
498
 
499
	ACPI_FUNCTION_TRACE(ev_attach_region);
500
 
501
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
502
			  "Adding Region [%4.4s] %p to address handler %p [%s]\n",
503
			  acpi_ut_get_node_name(region_obj->region.node),
504
			  region_obj, handler_obj,
505
			  acpi_ut_get_region_name(region_obj->region.
506
						  space_id)));
507
 
508
	/* Link this region to the front of the handler's list */
509
 
510
	region_obj->region.next = handler_obj->address_space.region_list;
511
	handler_obj->address_space.region_list = region_obj;
512
 
513
	/* Install the region's handler */
514
 
515
	if (region_obj->region.handler) {
516
		return_ACPI_STATUS(AE_ALREADY_EXISTS);
517
	}
518
 
519
	region_obj->region.handler = handler_obj;
520
	acpi_ut_add_reference(handler_obj);
521
 
522
	return_ACPI_STATUS(AE_OK);
523
}
524
 
525
/*******************************************************************************
526
 *
527
 * FUNCTION:    acpi_ev_execute_reg_method
528
 *
529
 * PARAMETERS:  region_obj          - Region object
530
 *              function            - Passed to _REG: On (1) or Off (0)
531
 *
532
 * RETURN:      Status
533
 *
534
 * DESCRIPTION: Execute _REG method for a region
535
 *
536
 ******************************************************************************/
537
 
538
acpi_status
539
acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
540
{
541
	struct acpi_evaluate_info *info;
542
	union acpi_operand_object *args[3];
543
	union acpi_operand_object *region_obj2;
544
	acpi_status status;
545
 
546
	ACPI_FUNCTION_TRACE(ev_execute_reg_method);
547
 
548
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
549
	if (!region_obj2) {
550
		return_ACPI_STATUS(AE_NOT_EXIST);
551
	}
552
 
553
	if (region_obj2->extra.method_REG == NULL) {
554
		return_ACPI_STATUS(AE_OK);
555
	}
556
 
557
	/* Allocate and initialize the evaluation information block */
558
 
559
	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
560
	if (!info) {
561
		return_ACPI_STATUS(AE_NO_MEMORY);
562
	}
563
 
564
	info->prefix_node = region_obj2->extra.method_REG;
565
	info->relative_pathname = NULL;
566
	info->parameters = args;
567
	info->flags = ACPI_IGNORE_RETURN_VALUE;
568
 
569
	/*
570
	 * The _REG method has two arguments:
571
	 *
572
	 * arg0 - Integer:
573
	 *  Operation region space ID Same value as region_obj->Region.space_id
574
	 *
575
	 * arg1 - Integer:
576
	 *  connection status 1 for connecting the handler, 0 for disconnecting
577
	 *  the handler (Passed as a parameter)
578
	 */
579
	args[0] =
580
	    acpi_ut_create_integer_object((u64)region_obj->region.space_id);
581
	if (!args[0]) {
582
		status = AE_NO_MEMORY;
583
		goto cleanup1;
584
	}
585
 
586
	args[1] = acpi_ut_create_integer_object((u64)function);
587
	if (!args[1]) {
588
		status = AE_NO_MEMORY;
589
		goto cleanup2;
590
	}
591
 
592
	args[2] = NULL;		/* Terminate list */
593
 
594
	/* Execute the method, no return value */
595
 
596
	ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
597
			(ACPI_TYPE_METHOD, info->prefix_node, NULL));
598
 
599
	status = acpi_ns_evaluate(info);
600
	acpi_ut_remove_reference(args[1]);
601
 
602
cleanup2:
603
	acpi_ut_remove_reference(args[0]);
604
 
605
cleanup1:
606
	ACPI_FREE(info);
607
	return_ACPI_STATUS(status);
608
}
609
 
610
/*******************************************************************************
611
 *
612
 * FUNCTION:    acpi_ev_execute_reg_methods
613
 *
614
 * PARAMETERS:  node            - Namespace node for the device
615
 *              space_id        - The address space ID
616
 *
617
 * RETURN:      Status
618
 *
619
 * DESCRIPTION: Run all _REG methods for the input Space ID;
620
 *              Note: assumes namespace is locked, or system init time.
621
 *
622
 ******************************************************************************/
623
 
624
acpi_status
625
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
626
			    acpi_adr_space_type space_id)
627
{
628
	acpi_status status;
629
	struct acpi_reg_walk_info info;
630
 
631
	ACPI_FUNCTION_TRACE(ev_execute_reg_methods);
632
 
633
	info.space_id = space_id;
634
	info.reg_run_count = 0;
635
 
636
	ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES,
637
			      "    Running _REG methods for SpaceId %s\n",
638
			      acpi_ut_get_region_name(info.space_id)));
639
 
640
	/*
641
	 * Run all _REG methods for all Operation Regions for this space ID. This
642
	 * is a separate walk in order to handle any interdependencies between
643
	 * regions and _REG methods. (i.e. handlers must be installed for all
644
	 * regions of this Space ID before we can run any _REG methods)
645
	 */
646
	status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
647
					ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run,
648
					NULL, &info, NULL);
649
 
650
	/* Special case for EC: handle "orphan" _REG methods with no region */
651
 
652
	if (space_id == ACPI_ADR_SPACE_EC) {
653
		acpi_ev_orphan_ec_reg_method(node);
654
	}
655
 
656
	ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES,
657
			      "    Executed %u _REG methods for SpaceId %s\n",
658
			      info.reg_run_count,
659
			      acpi_ut_get_region_name(info.space_id)));
660
 
661
	return_ACPI_STATUS(status);
662
}
663
 
664
/*******************************************************************************
665
 *
666
 * FUNCTION:    acpi_ev_reg_run
667
 *
668
 * PARAMETERS:  walk_namespace callback
669
 *
670
 * DESCRIPTION: Run _REG method for region objects of the requested spaceID
671
 *
672
 ******************************************************************************/
673
 
674
static acpi_status
675
acpi_ev_reg_run(acpi_handle obj_handle,
676
		u32 level, void *context, void **return_value)
677
{
678
	union acpi_operand_object *obj_desc;
679
	struct acpi_namespace_node *node;
680
	acpi_status status;
681
	struct acpi_reg_walk_info *info;
682
 
683
	info = ACPI_CAST_PTR(struct acpi_reg_walk_info, context);
684
 
685
	/* Convert and validate the device handle */
686
 
687
	node = acpi_ns_validate_handle(obj_handle);
688
	if (!node) {
689
		return (AE_BAD_PARAMETER);
690
	}
691
 
692
	/*
693
	 * We only care about regions.and objects that are allowed to have address
694
	 * space handlers
695
	 */
696
	if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
697
		return (AE_OK);
698
	}
699
 
700
	/* Check for an existing internal object */
701
 
702
	obj_desc = acpi_ns_get_attached_object(node);
703
	if (!obj_desc) {
704
 
705
		/* No object, just exit */
706
 
707
		return (AE_OK);
708
	}
709
 
710
	/* Object is a Region */
711
 
712
	if (obj_desc->region.space_id != info->space_id) {
713
 
714
		/* This region is for a different address space, just ignore it */
715
 
716
		return (AE_OK);
717
	}
718
 
719
	info->reg_run_count++;
720
	status = acpi_ev_execute_reg_method(obj_desc, ACPI_REG_CONNECT);
721
	return (status);
722
}
723
 
724
/*******************************************************************************
725
 *
726
 * FUNCTION:    acpi_ev_orphan_ec_reg_method
727
 *
728
 * PARAMETERS:  ec_device_node      - Namespace node for an EC device
729
 *
730
 * RETURN:      None
731
 *
732
 * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC
733
 *              device. This is a _REG method that has no corresponding region
734
 *              within the EC device scope. The orphan _REG method appears to
735
 *              have been enabled by the description of the ECDT in the ACPI
736
 *              specification: "The availability of the region space can be
737
 *              detected by providing a _REG method object underneath the
738
 *              Embedded Controller device."
739
 *
740
 *              To quickly access the EC device, we use the ec_device_node used
741
 *              during EC handler installation. Otherwise, we would need to
742
 *              perform a time consuming namespace walk, executing _HID
743
 *              methods to find the EC device.
744
 *
745
 *  MUTEX:      Assumes the namespace is locked
746
 *
747
 ******************************************************************************/
748
 
749
static void
750
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
751
{
752
	acpi_handle reg_method;
753
	struct acpi_namespace_node *next_node;
754
	acpi_status status;
755
	struct acpi_object_list args;
756
	union acpi_object objects[2];
757
 
758
	ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method);
759
 
760
	if (!ec_device_node) {
761
		return_VOID;
762
	}
763
 
764
	/* Namespace is currently locked, must release */
765
 
766
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
767
 
768
	/* Get a handle to a _REG method immediately under the EC device */
769
 
770
	status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, ®_method);
771
	if (ACPI_FAILURE(status)) {
772
		goto exit;	/* There is no _REG method present */
773
	}
774
 
775
	/*
776
	 * Execute the _REG method only if there is no Operation Region in
777
	 * this scope with the Embedded Controller space ID. Otherwise, it
778
	 * will already have been executed. Note, this allows for Regions
779
	 * with other space IDs to be present; but the code below will then
780
	 * execute the _REG method with the embedded_control space_ID argument.
781
	 */
782
	next_node = acpi_ns_get_next_node(ec_device_node, NULL);
783
	while (next_node) {
784
		if ((next_node->type == ACPI_TYPE_REGION) &&
785
		    (next_node->object) &&
786
		    (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) {
787
			goto exit;	/* Do not execute the _REG */
788
		}
789
 
790
		next_node = acpi_ns_get_next_node(ec_device_node, next_node);
791
	}
792
 
793
	/* Evaluate the _REG(embedded_control,Connect) method */
794
 
795
	args.count = 2;
796
	args.pointer = objects;
797
	objects[0].type = ACPI_TYPE_INTEGER;
798
	objects[0].integer.value = ACPI_ADR_SPACE_EC;
799
	objects[1].type = ACPI_TYPE_INTEGER;
800
	objects[1].integer.value = ACPI_REG_CONNECT;
801
 
802
	status = acpi_evaluate_object(reg_method, NULL, &args, NULL);
803
 
804
exit:
805
	/* We ignore all errors from above, don't care */
806
 
807
	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
808
	return_VOID;
809
}