/drivers/acpi/acpica/evmisc.c

http://github.com/mirrors/linux · C · 273 lines · 136 code · 55 blank · 82 comment · 21 complexity · dc4a08967606fb7fbce7a06b99f46870 MD5 · raw file

  1. // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2. /******************************************************************************
  3. *
  4. * Module Name: evmisc - Miscellaneous event manager support functions
  5. *
  6. * Copyright (C) 2000 - 2020, Intel Corp.
  7. *
  8. *****************************************************************************/
  9. #include <acpi/acpi.h>
  10. #include "accommon.h"
  11. #include "acevents.h"
  12. #include "acnamesp.h"
  13. #define _COMPONENT ACPI_EVENTS
  14. ACPI_MODULE_NAME("evmisc")
  15. /* Local prototypes */
  16. static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
  17. /*******************************************************************************
  18. *
  19. * FUNCTION: acpi_ev_is_notify_object
  20. *
  21. * PARAMETERS: node - Node to check
  22. *
  23. * RETURN: TRUE if notifies allowed on this object
  24. *
  25. * DESCRIPTION: Check type of node for a object that supports notifies.
  26. *
  27. * TBD: This could be replaced by a flag bit in the node.
  28. *
  29. ******************************************************************************/
  30. u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
  31. {
  32. switch (node->type) {
  33. case ACPI_TYPE_DEVICE:
  34. case ACPI_TYPE_PROCESSOR:
  35. case ACPI_TYPE_THERMAL:
  36. /*
  37. * These are the ONLY objects that can receive ACPI notifications
  38. */
  39. return (TRUE);
  40. default:
  41. return (FALSE);
  42. }
  43. }
  44. /*******************************************************************************
  45. *
  46. * FUNCTION: acpi_ev_queue_notify_request
  47. *
  48. * PARAMETERS: node - NS node for the notified object
  49. * notify_value - Value from the Notify() request
  50. *
  51. * RETURN: Status
  52. *
  53. * DESCRIPTION: Dispatch a device notification event to a previously
  54. * installed handler.
  55. *
  56. ******************************************************************************/
  57. acpi_status
  58. acpi_ev_queue_notify_request(struct acpi_namespace_node *node, u32 notify_value)
  59. {
  60. union acpi_operand_object *obj_desc;
  61. union acpi_operand_object *handler_list_head = NULL;
  62. union acpi_generic_state *info;
  63. u8 handler_list_id = 0;
  64. acpi_status status = AE_OK;
  65. ACPI_FUNCTION_NAME(ev_queue_notify_request);
  66. /* Are Notifies allowed on this object? */
  67. if (!acpi_ev_is_notify_object(node)) {
  68. return (AE_TYPE);
  69. }
  70. /* Get the correct notify list type (System or Device) */
  71. if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
  72. handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
  73. } else {
  74. handler_list_id = ACPI_DEVICE_HANDLER_LIST;
  75. }
  76. /* Get the notify object attached to the namespace Node */
  77. obj_desc = acpi_ns_get_attached_object(node);
  78. if (obj_desc) {
  79. /* We have an attached object, Get the correct handler list */
  80. handler_list_head =
  81. obj_desc->common_notify.notify_list[handler_list_id];
  82. }
  83. /*
  84. * If there is no notify handler (Global or Local)
  85. * for this object, just ignore the notify
  86. */
  87. if (!acpi_gbl_global_notify[handler_list_id].handler
  88. && !handler_list_head) {
  89. ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  90. "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
  91. acpi_ut_get_node_name(node), notify_value,
  92. node));
  93. return (AE_OK);
  94. }
  95. /* Setup notify info and schedule the notify dispatcher */
  96. info = acpi_ut_create_generic_state();
  97. if (!info) {
  98. return (AE_NO_MEMORY);
  99. }
  100. info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;
  101. info->notify.node = node;
  102. info->notify.value = (u16)notify_value;
  103. info->notify.handler_list_id = handler_list_id;
  104. info->notify.handler_list_head = handler_list_head;
  105. info->notify.global = &acpi_gbl_global_notify[handler_list_id];
  106. ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  107. "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
  108. acpi_ut_get_node_name(node),
  109. acpi_ut_get_type_name(node->type), notify_value,
  110. acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY),
  111. node));
  112. status = acpi_os_execute(OSL_NOTIFY_HANDLER,
  113. acpi_ev_notify_dispatch, info);
  114. if (ACPI_FAILURE(status)) {
  115. acpi_ut_delete_generic_state(info);
  116. }
  117. return (status);
  118. }
  119. /*******************************************************************************
  120. *
  121. * FUNCTION: acpi_ev_notify_dispatch
  122. *
  123. * PARAMETERS: context - To be passed to the notify handler
  124. *
  125. * RETURN: None.
  126. *
  127. * DESCRIPTION: Dispatch a device notification event to a previously
  128. * installed handler.
  129. *
  130. ******************************************************************************/
  131. static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
  132. {
  133. union acpi_generic_state *info = (union acpi_generic_state *)context;
  134. union acpi_operand_object *handler_obj;
  135. ACPI_FUNCTION_ENTRY();
  136. /* Invoke a global notify handler if installed */
  137. if (info->notify.global->handler) {
  138. info->notify.global->handler(info->notify.node,
  139. info->notify.value,
  140. info->notify.global->context);
  141. }
  142. /* Now invoke the local notify handler(s) if any are installed */
  143. handler_obj = info->notify.handler_list_head;
  144. while (handler_obj) {
  145. handler_obj->notify.handler(info->notify.node,
  146. info->notify.value,
  147. handler_obj->notify.context);
  148. handler_obj =
  149. handler_obj->notify.next[info->notify.handler_list_id];
  150. }
  151. /* All done with the info object */
  152. acpi_ut_delete_generic_state(info);
  153. }
  154. #if (!ACPI_REDUCED_HARDWARE)
  155. /******************************************************************************
  156. *
  157. * FUNCTION: acpi_ev_terminate
  158. *
  159. * PARAMETERS: none
  160. *
  161. * RETURN: none
  162. *
  163. * DESCRIPTION: Disable events and free memory allocated for table storage.
  164. *
  165. ******************************************************************************/
  166. void acpi_ev_terminate(void)
  167. {
  168. u32 i;
  169. acpi_status status;
  170. ACPI_FUNCTION_TRACE(ev_terminate);
  171. if (acpi_gbl_events_initialized) {
  172. /*
  173. * Disable all event-related functionality. In all cases, on error,
  174. * print a message but obviously we don't abort.
  175. */
  176. /* Disable all fixed events */
  177. for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
  178. status = acpi_disable_event(i, 0);
  179. if (ACPI_FAILURE(status)) {
  180. ACPI_ERROR((AE_INFO,
  181. "Could not disable fixed event %u",
  182. (u32) i));
  183. }
  184. }
  185. /* Disable all GPEs in all GPE blocks */
  186. status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
  187. if (ACPI_FAILURE(status)) {
  188. ACPI_EXCEPTION((AE_INFO, status,
  189. "Could not disable GPEs in GPE block"));
  190. }
  191. status = acpi_ev_remove_global_lock_handler();
  192. if (ACPI_FAILURE(status)) {
  193. ACPI_EXCEPTION((AE_INFO, status,
  194. "Could not remove Global Lock handler"));
  195. }
  196. acpi_gbl_events_initialized = FALSE;
  197. }
  198. /* Remove SCI handlers */
  199. status = acpi_ev_remove_all_sci_handlers();
  200. if (ACPI_FAILURE(status)) {
  201. ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
  202. }
  203. /* Deallocate all handler objects installed within GPE info structs */
  204. status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL);
  205. if (ACPI_FAILURE(status)) {
  206. ACPI_EXCEPTION((AE_INFO, status,
  207. "Could not delete GPE handlers"));
  208. }
  209. /* Return to original mode if necessary */
  210. if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
  211. status = acpi_disable();
  212. if (ACPI_FAILURE(status)) {
  213. ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
  214. }
  215. }
  216. return_VOID;
  217. }
  218. #endif /* !ACPI_REDUCED_HARDWARE */