Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86ed4bc8 authored by Bob Moore's avatar Bob Moore Committed by Len Brown
Browse files

ACPICA: Add support for multiple notify handlers



This change adds support to allow multiple notify handlers on
Device, ThermalZone, and Processor objects. Also re-worked
and restructured the entire notify support code for handler
installation, handler removal, notify event queuing, and notify
dispatch to handler.

Extends and updates original commit 3f0be671("ACPI / ACPICA: Multiple
system notify handlers per device") by Rafael Wysocki.

Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 5134abfc
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -278,8 +278,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;


/* Global handlers */
/* Global handlers */


ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify;
ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
+11 −2
Original line number Original line Diff line number Diff line
@@ -600,13 +600,22 @@ acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state,


typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state);
typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state);


/* Global handlers for AML Notifies */

struct acpi_global_notify_handler {
	acpi_notify_handler handler;
	void *context;
};

/*
/*
 * Notify info - used to pass info to the deferred notify
 * Notify info - used to pass info to the deferred notify
 * handler/dispatcher.
 * handler/dispatcher.
 */
 */
struct acpi_notify_info {
struct acpi_notify_info {
	ACPI_STATE_COMMON struct acpi_namespace_node *node;
	ACPI_STATE_COMMON u8 handler_list_id;
	union acpi_operand_object *handler_obj;
	struct acpi_namespace_node *node;
	union acpi_operand_object *handler_list_head;
	struct acpi_global_notify_handler *global;
};
};


/* Generic state is union of structs above */
/* Generic state is union of structs above */
+4 −5
Original line number Original line Diff line number Diff line
@@ -206,8 +206,7 @@ struct acpi_object_method {
 * Common fields for objects that support ASL notifications
 * Common fields for objects that support ASL notifications
 */
 */
#define ACPI_COMMON_NOTIFY_INFO \
#define ACPI_COMMON_NOTIFY_INFO \
	union acpi_operand_object       *system_notify;     /* Handler for system notifies */\
	union acpi_operand_object       *notify_list[2];    /* Handlers for system/device notifies */\
	union acpi_operand_object       *device_notify;     /* Handler for driver notifies */\
	union acpi_operand_object       *handler;	/* Handler for Address space */
	union acpi_operand_object       *handler;	/* Handler for Address space */


struct acpi_object_notify_common {	/* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
struct acpi_object_notify_common {	/* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
@@ -296,10 +295,10 @@ struct acpi_object_buffer_field {


struct acpi_object_notify_handler {
struct acpi_object_notify_handler {
	ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node;	/* Parent device */
	ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node;	/* Parent device */
	u32 handler_type;
	u32 handler_type;	/* Type: Device/System/Both */
	acpi_notify_handler handler;
	acpi_notify_handler handler;	/* Handler address */
	void *context;
	void *context;
	struct acpi_object_notify_handler *next;
	union acpi_operand_object *next[2];	/* Device and System handler lists */
};
};


struct acpi_object_addr_handler {
struct acpi_object_addr_handler {
+67 −118
Original line number Original line Diff line number Diff line
@@ -101,102 +101,77 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
			     u32 notify_value)
			     u32 notify_value)
{
{
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *handler_obj = NULL;
	union acpi_operand_object *handler_list_head = NULL;
	union acpi_generic_state *notify_info;
	union acpi_generic_state *info;
	u8 handler_list_id = 0;
	acpi_status status = AE_OK;
	acpi_status status = AE_OK;


	ACPI_FUNCTION_NAME(ev_queue_notify_request);
	ACPI_FUNCTION_NAME(ev_queue_notify_request);


	/*
	/* Are Notifies allowed on this object? */
	 * For value 0x03 (Ejection Request), may need to run a device method.
	 * For value 0x02 (Device Wake), if _PRW exists, may need to run
	 *   the _PS0 method.
	 * For value 0x80 (Status Change) on the power button or sleep button,
	 *   initiate soft-off or sleep operation.
	 *
	 * For all cases, simply dispatch the notify to the handler.
	 */
	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));

	/* Get the notify object attached to the NS Node */

	obj_desc = acpi_ns_get_attached_object(node);
	if (obj_desc) {

		/* We have the notify object, Get the correct handler */

		switch (node->type) {


			/* Notify is allowed only on these types */
	if (!acpi_ev_is_notify_object(node)) {
		return (AE_TYPE);
	}


		case ACPI_TYPE_DEVICE:
	/* Get the correct notify list type (System or Device) */
		case ACPI_TYPE_THERMAL:
		case ACPI_TYPE_PROCESSOR:


	if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
	if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
				handler_obj =
		handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
				    obj_desc->common_notify.system_notify;
	} else {
	} else {
				handler_obj =
		handler_list_id = ACPI_DEVICE_HANDLER_LIST;
				    obj_desc->common_notify.device_notify;
	}
	}
			break;


		default:
	/* Get the notify object attached to the namespace Node */


			/* All other types are not supported */
	obj_desc = acpi_ns_get_attached_object(node);
	if (obj_desc) {


			return (AE_TYPE);
		/* We have an attached object, Get the correct handler list */
		}

		handler_list_head =
		    obj_desc->common_notify.notify_list[handler_list_id];
	}
	}


	/*
	/*
	 * If there is a handler to run, schedule the dispatcher.
	 * If there is no notify handler (Global or Local)
	 * Check for:
	 * for this object, just ignore the notify
	 * 1) Global system notify handler
	 * 2) Global device notify handler
	 * 3) Per-device notify handler
	 */
	 */
	if ((acpi_gbl_system_notify.handler &&
	if (!acpi_gbl_global_notify[handler_list_id].handler
	     (notify_value <= ACPI_MAX_SYS_NOTIFY)) ||
	    && !handler_list_head) {
	    (acpi_gbl_device_notify.handler &&
	     (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
		notify_info = acpi_ut_create_generic_state();
		if (!notify_info) {
			return (AE_NO_MEMORY);
		}

		if (!handler_obj) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					  "Executing system notify handler for Notify (%4.4s, %X) "
				  "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
					  "node %p\n",
				  acpi_ut_get_node_name(node), notify_value,
					  acpi_ut_get_node_name(node),
				  node));
					  notify_value, node));

		return (AE_OK);
	}
	}


		notify_info->common.descriptor_type =
	/* Setup notify info and schedule the notify dispatcher */
		    ACPI_DESC_TYPE_STATE_NOTIFY;
		notify_info->notify.node = node;
		notify_info->notify.value = (u16) notify_value;
		notify_info->notify.handler_obj = handler_obj;


		status =
	info = acpi_ut_create_generic_state();
		    acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
	if (!info) {
				    notify_info);
		return (AE_NO_MEMORY);
		if (ACPI_FAILURE(status)) {
			acpi_ut_delete_generic_state(notify_info);
	}
	}
	} else {

		/* There is no notify handler (per-device or system) for this device */
	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,
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "No notify handler for Notify (%4.4s, %X) node %p\n",
			  "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
				  acpi_ut_get_node_name(node), notify_value,
			  acpi_ut_get_node_name(node),
				  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);
	}
	}


	return (status);
	return (status);
@@ -217,60 +192,34 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,


static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
{
{
	union acpi_generic_state *notify_info =
	union acpi_generic_state *info = (union acpi_generic_state *)context;
	    (union acpi_generic_state *)context;
	acpi_notify_handler global_handler = NULL;
	void *global_context = NULL;
	union acpi_operand_object *handler_obj;
	union acpi_operand_object *handler_obj;


	ACPI_FUNCTION_ENTRY();
	ACPI_FUNCTION_ENTRY();


	/*
	/* Invoke a global notify handler if installed */
	 * We will invoke a global notify handler if installed. This is done
	 * _before_ we invoke the per-device handler attached to the device.
	 */
	if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {

		/* Global system notification handler */


		if (acpi_gbl_system_notify.handler) {
	if (info->notify.global->handler) {
			global_handler = acpi_gbl_system_notify.handler;
		info->notify.global->handler(info->notify.node,
			global_context = acpi_gbl_system_notify.context;
					     info->notify.value,
					     info->notify.global->context);
	}
	}
	} else {
		/* Global driver notification handler */


		if (acpi_gbl_device_notify.handler) {
	/* Now invoke the local notify handler(s) if any are installed */
			global_handler = acpi_gbl_device_notify.handler;
			global_context = acpi_gbl_device_notify.context;
		}
	}

	/* Invoke the system handler first, if present */

	if (global_handler) {
		global_handler(notify_info->notify.node,
			       notify_info->notify.value, global_context);
	}


	/* Now invoke the per-device handler, if present */
	handler_obj = info->notify.handler_list_head;
	while (handler_obj) {
		handler_obj->notify.handler(info->notify.node,
					    info->notify.value,
					    handler_obj->notify.context);


	handler_obj = notify_info->notify.handler_obj;
		handler_obj =
	if (handler_obj) {
		    handler_obj->notify.next[info->notify.handler_list_id];
		struct acpi_object_notify_handler *notifier;

		notifier = &handler_obj->notify;
		while (notifier) {
			notifier->handler(notify_info->notify.node,
					  notify_info->notify.value,
					  notifier->context);
			notifier = notifier->next;
		}
	}
	}


	/* All done with the info object */
	/* All done with the info object */


	acpi_ut_delete_generic_state(notify_info);
	acpi_ut_delete_generic_state(info);
}
}


#if (!ACPI_REDUCED_HARDWARE)
#if (!ACPI_REDUCED_HARDWARE)
+145 −295

File changed.

Preview size limit exceeded, changes collapsed.

Loading