evmisc.c 8.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/******************************************************************************
 *
 * Module Name: evmisc - Miscellaneous event manager support functions
 *
 *****************************************************************************/

/*
8
 * Copyright (C) 2000 - 2013, 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
#include "accommon.h"
#include "acevents.h"
#include "acnamesp.h"
L
Linus Torvalds 已提交
48 49

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

R
Robert Moore 已提交
52
/* Local prototypes */
L
Len Brown 已提交
53
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
R
Robert Moore 已提交
54

L
Linus Torvalds 已提交
55 56 57 58
/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_is_notify_object
 *
59
 * PARAMETERS:  node            - Node to check
L
Linus Torvalds 已提交
60 61 62 63 64 65 66 67 68
 *
 * RETURN:      TRUE if notifies allowed on this object
 *
 * DESCRIPTION: Check type of node for a object that supports notifies.
 *
 *              TBD: This could be replaced by a flag bit in the node.
 *
 ******************************************************************************/

L
Len Brown 已提交
69
u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
L
Linus Torvalds 已提交
70 71 72 73 74 75 76 77 78 79 80
{
	switch (node->type) {
	case ACPI_TYPE_DEVICE:
	case ACPI_TYPE_PROCESSOR:
	case ACPI_TYPE_THERMAL:
		/*
		 * These are the ONLY objects that can receive ACPI notifications
		 */
		return (TRUE);

	default:
81

L
Linus Torvalds 已提交
82 83 84 85 86 87 88 89
		return (FALSE);
	}
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_queue_notify_request
 *
90
 * PARAMETERS:  node            - NS node for the notified object
L
Linus Torvalds 已提交
91 92 93 94 95 96 97 98 99 100
 *              notify_value    - Value from the Notify() request
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Dispatch a device notification event to a previously
 *              installed handler.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
101 102
acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
			     u32 notify_value)
L
Linus Torvalds 已提交
103
{
L
Len Brown 已提交
104
	union acpi_operand_object *obj_desc;
105 106 107
	union acpi_operand_object *handler_list_head = NULL;
	union acpi_generic_state *info;
	u8 handler_list_id = 0;
L
Len Brown 已提交
108
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
109

B
Bob Moore 已提交
110
	ACPI_FUNCTION_NAME(ev_queue_notify_request);
L
Linus Torvalds 已提交
111

112
	/* Are Notifies allowed on this object? */
B
Bob Moore 已提交
113

114 115 116
	if (!acpi_ev_is_notify_object(node)) {
		return (AE_TYPE);
	}
Z
Zhang Rui 已提交
117

118
	/* Get the correct notify list type (System or Device) */
Z
Zhang Rui 已提交
119

120 121 122 123 124
	if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
		handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
	} else {
		handler_list_id = ACPI_DEVICE_HANDLER_LIST;
	}
L
Linus Torvalds 已提交
125

126
	/* Get the notify object attached to the namespace Node */
L
Linus Torvalds 已提交
127

128 129
	obj_desc = acpi_ns_get_attached_object(node);
	if (obj_desc) {
130

131
		/* We have an attached object, Get the correct handler list */
132

133 134
		handler_list_head =
		    obj_desc->common_notify.notify_list[handler_list_id];
L
Linus Torvalds 已提交
135 136
	}

Z
Zhang Rui 已提交
137
	/*
138 139
	 * If there is no notify handler (Global or Local)
	 * for this object, just ignore the notify
Z
Zhang Rui 已提交
140
	 */
141 142
	if (!acpi_gbl_global_notify[handler_list_id].handler
	    && !handler_list_head) {
L
Len Brown 已提交
143
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
144
				  "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
L
Len Brown 已提交
145 146
				  acpi_ut_get_node_name(node), notify_value,
				  node));
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

		return (AE_OK);
	}

	/* Setup notify info and schedule the notify dispatcher */

	info = acpi_ut_create_generic_state();
	if (!info) {
		return (AE_NO_MEMORY);
	}

	info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;

	info->notify.node = node;
	info->notify.value = (u16)notify_value;
	info->notify.handler_list_id = handler_list_id;
	info->notify.handler_list_head = handler_list_head;
	info->notify.global = &acpi_gbl_global_notify[handler_list_id];

	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
			  acpi_ut_get_node_name(node),
			  acpi_ut_get_type_name(node->type), notify_value,
			  acpi_ut_get_notify_name(notify_value), node));

	status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
				 info);
	if (ACPI_FAILURE(status)) {
		acpi_ut_delete_generic_state(info);
L
Linus Torvalds 已提交
176 177 178 179 180 181 182 183 184
	}

	return (status);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_notify_dispatch
 *
185
 * PARAMETERS:  context         - To be passed to the notify handler
L
Linus Torvalds 已提交
186 187 188 189 190 191 192 193
 *
 * RETURN:      None.
 *
 * DESCRIPTION: Dispatch a device notification event to a previously
 *              installed handler.
 *
 ******************************************************************************/

L
Len Brown 已提交
194
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
L
Linus Torvalds 已提交
195
{
196
	union acpi_generic_state *info = (union acpi_generic_state *)context;
L
Len Brown 已提交
197
	union acpi_operand_object *handler_obj;
L
Linus Torvalds 已提交
198

L
Len Brown 已提交
199
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
200

201
	/* Invoke a global notify handler if installed */
L
Linus Torvalds 已提交
202

203 204 205 206
	if (info->notify.global->handler) {
		info->notify.global->handler(info->notify.node,
					     info->notify.value,
					     info->notify.global->context);
L
Linus Torvalds 已提交
207 208
	}

209
	/* Now invoke the local notify handler(s) if any are installed */
L
Linus Torvalds 已提交
210

211 212 213 214 215
	handler_obj = info->notify.handler_list_head;
	while (handler_obj) {
		handler_obj->notify.handler(info->notify.node,
					    info->notify.value,
					    handler_obj->notify.context);
216

217 218
		handler_obj =
		    handler_obj->notify.next[info->notify.handler_list_id];
L
Linus Torvalds 已提交
219 220 221 222
	}

	/* All done with the info object */

223
	acpi_ut_delete_generic_state(info);
L
Linus Torvalds 已提交
224 225
}

226
#if (!ACPI_REDUCED_HARDWARE)
L
Linus Torvalds 已提交
227 228 229 230 231 232 233 234 235 236 237 238
/******************************************************************************
 *
 * FUNCTION:    acpi_ev_terminate
 *
 * PARAMETERS:  none
 *
 * RETURN:      none
 *
 * DESCRIPTION: Disable events and free memory allocated for table storage.
 *
 ******************************************************************************/

L
Len Brown 已提交
239
void acpi_ev_terminate(void)
L
Linus Torvalds 已提交
240
{
241
	u32 i;
L
Len Brown 已提交
242
	acpi_status status;
L
Linus Torvalds 已提交
243

B
Bob Moore 已提交
244
	ACPI_FUNCTION_TRACE(ev_terminate);
L
Linus Torvalds 已提交
245 246 247

	if (acpi_gbl_events_initialized) {
		/*
248 249
		 * Disable all event-related functionality. In all cases, on error,
		 * print a message but obviously we don't abort.
L
Linus Torvalds 已提交
250 251 252 253 254
		 */

		/* Disable all fixed events */

		for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
255
			status = acpi_disable_event(i, 0);
L
Len Brown 已提交
256
			if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
257
				ACPI_ERROR((AE_INFO,
258
					    "Could not disable fixed event %u",
B
Bob Moore 已提交
259
					    (u32) i));
L
Linus Torvalds 已提交
260 261 262 263 264
			}
		}

		/* Disable all GPEs in all GPE blocks */

265
		status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
L
Linus Torvalds 已提交
266 267 268

		/* Remove SCI handler */

L
Len Brown 已提交
269
		status = acpi_ev_remove_sci_handler();
L
Linus Torvalds 已提交
270
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
271
			ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
L
Linus Torvalds 已提交
272
		}
273 274 275 276 277 278

		status = acpi_ev_remove_global_lock_handler();
		if (ACPI_FAILURE(status)) {
			ACPI_ERROR((AE_INFO,
				    "Could not remove Global Lock handler"));
		}
279 280

		acpi_gbl_events_initialized = FALSE;
L
Linus Torvalds 已提交
281 282 283 284
	}

	/* Deallocate all handler objects installed within GPE info structs */

285
	status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL);
L
Linus Torvalds 已提交
286 287 288 289

	/* Return to original mode if necessary */

	if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
L
Len Brown 已提交
290 291
		status = acpi_disable();
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
292
			ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
L
Linus Torvalds 已提交
293 294 295 296
		}
	}
	return_VOID;
}
297 298

#endif				/* !ACPI_REDUCED_HARDWARE */