evmisc.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /******************************************************************************
  2.  *
  3.  * Module Name: evmisc - ACPI device notification handler dispatch
  4.  *                       and ACPI Global Lock support
  5.  *              $Revision: 35 $
  6.  *
  7.  *****************************************************************************/
  8. /*
  9.  *  Copyright (C) 2000, 2001 R. Byron Moore
  10.  *
  11.  *  This program is free software; you can redistribute it and/or modify
  12.  *  it under the terms of the GNU General Public License as published by
  13.  *  the Free Software Foundation; either version 2 of the License, or
  14.  *  (at your option) any later version.
  15.  *
  16.  *  This program is distributed in the hope that it will be useful,
  17.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  *  GNU General Public License for more details.
  20.  *
  21.  *  You should have received a copy of the GNU General Public License
  22.  *  along with this program; if not, write to the Free Software
  23.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  24.  */
  25. #include "acpi.h"
  26. #include "acevents.h"
  27. #include "acnamesp.h"
  28. #include "acinterp.h"
  29. #include "achware.h"
  30. #define _COMPONENT          ACPI_EVENTS
  31.  MODULE_NAME         ("evmisc")
  32. /*******************************************************************************
  33.  *
  34.  * FUNCTION:    Acpi_ev_queue_notify_request
  35.  *
  36.  * PARAMETERS:
  37.  *
  38.  * RETURN:      None.
  39.  *
  40.  * DESCRIPTION: Dispatch a device notification event to a previously
  41.  *              installed handler.
  42.  *
  43.  ******************************************************************************/
  44. acpi_status
  45. acpi_ev_queue_notify_request (
  46. acpi_namespace_node     *node,
  47. u32                     notify_value)
  48. {
  49. acpi_operand_object     *obj_desc;
  50. acpi_operand_object     *handler_obj = NULL;
  51. acpi_generic_state      *notify_info;
  52. acpi_status             status = AE_OK;
  53. PROC_NAME ("Ev_queue_notify_request");
  54. /*
  55.  * For value 1 (Ejection Request), some device method may need to be run.
  56.  * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
  57.  * For value 0x80 (Status Change) on the power button or sleep button,
  58.  * initiate soft-off or sleep operation?
  59.  */
  60. ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
  61. "Dispatching Notify(%X) on node %pn", notify_value, node));
  62. switch (notify_value) {
  63. case 0:
  64. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Re-enumerate Devicesn"));
  65. break;
  66. case 1:
  67. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Ejection Requestn"));
  68. break;
  69. case 2:
  70. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Device Waken"));
  71. break;
  72. case 0x80:
  73. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Status Changen"));
  74. break;
  75. default:
  76. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unknown Notify Value: %X n", notify_value));
  77. break;
  78. }
  79. /*
  80.  * Get the notify object attached to the device Node
  81.  */
  82. obj_desc = acpi_ns_get_attached_object (node);
  83. if (obj_desc) {
  84. /* We have the notify object, Get the right handler */
  85. switch (node->type) {
  86. case ACPI_TYPE_DEVICE:
  87. if (notify_value <= MAX_SYS_NOTIFY) {
  88. handler_obj = obj_desc->device.sys_handler;
  89. }
  90. else {
  91. handler_obj = obj_desc->device.drv_handler;
  92. }
  93. break;
  94. case ACPI_TYPE_THERMAL:
  95. if (notify_value <= MAX_SYS_NOTIFY) {
  96. handler_obj = obj_desc->thermal_zone.sys_handler;
  97. }
  98. else {
  99. handler_obj = obj_desc->thermal_zone.drv_handler;
  100. }
  101. break;
  102. }
  103. }
  104. /* If there is any handler to run, schedule the dispatcher */
  105. if ((acpi_gbl_sys_notify.handler && (notify_value <= MAX_SYS_NOTIFY)) ||
  106. (acpi_gbl_drv_notify.handler && (notify_value > MAX_SYS_NOTIFY)) ||
  107. handler_obj) {
  108. notify_info = acpi_ut_create_generic_state ();
  109. if (!notify_info) {
  110. return (AE_NO_MEMORY);
  111. }
  112. notify_info->common.data_type = ACPI_DESC_TYPE_STATE_NOTIFY;
  113. notify_info->notify.node      = node;
  114. notify_info->notify.value     = (u16) notify_value;
  115. notify_info->notify.handler_obj = handler_obj;
  116. status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH,
  117.   acpi_ev_notify_dispatch, notify_info);
  118. if (ACPI_FAILURE (status)) {
  119. acpi_ut_delete_generic_state (notify_info);
  120. }
  121. }
  122. if (!handler_obj) {
  123. /* There is no per-device notify handler for this device */
  124. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "No notify handler for node %p n", node));
  125. }
  126. return (status);
  127. }
  128. /*******************************************************************************
  129.  *
  130.  * FUNCTION:    Acpi_ev_notify_dispatch
  131.  *
  132.  * PARAMETERS:
  133.  *
  134.  * RETURN:      None.
  135.  *
  136.  * DESCRIPTION: Dispatch a device notification event to a previously
  137.  *              installed handler.
  138.  *
  139.  ******************************************************************************/
  140. void
  141. acpi_ev_notify_dispatch (
  142. void                    *context)
  143. {
  144. acpi_generic_state      *notify_info = (acpi_generic_state *) context;
  145. acpi_notify_handler     global_handler = NULL;
  146. void                    *global_context = NULL;
  147. acpi_operand_object     *handler_obj;
  148. FUNCTION_ENTRY ();
  149. /*
  150.  * We will invoke a global notify handler if installed.
  151.  * This is done _before_ we invoke the per-device handler attached to the device.
  152.  */
  153. if (notify_info->notify.value <= MAX_SYS_NOTIFY) {
  154. /* Global system notification handler */
  155. if (acpi_gbl_sys_notify.handler) {
  156. global_handler = acpi_gbl_sys_notify.handler;
  157. global_context = acpi_gbl_sys_notify.context;
  158. }
  159. }
  160. else {
  161. /* Global driver notification handler */
  162. if (acpi_gbl_drv_notify.handler) {
  163. global_handler = acpi_gbl_drv_notify.handler;
  164. global_context = acpi_gbl_drv_notify.context;
  165. }
  166. }
  167. /* Invoke the system handler first, if present */
  168. if (global_handler) {
  169. global_handler (notify_info->notify.node, notify_info->notify.value, global_context);
  170. }
  171. /* Now invoke the per-device handler, if present */
  172. handler_obj = notify_info->notify.handler_obj;
  173. if (handler_obj) {
  174. handler_obj->notify_handler.handler (notify_info->notify.node, notify_info->notify.value,
  175.   handler_obj->notify_handler.context);
  176. }
  177. /* All done with the info object */
  178. acpi_ut_delete_generic_state (notify_info);
  179. }
  180. /*******************************************************************************
  181.  *
  182.  * FUNCTION:    Acpi_ev_global_lock_thread
  183.  *
  184.  * RETURN:      None
  185.  *
  186.  * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
  187.  *              Global Lock.  Simply signal all threads that are waiting
  188.  *              for the lock.
  189.  *
  190.  ******************************************************************************/
  191. static void
  192. acpi_ev_global_lock_thread (
  193. void                    *context)
  194. {
  195. /* Signal threads that are waiting for the lock */
  196. if (acpi_gbl_global_lock_thread_count) {
  197. /* Send sufficient units to the semaphore */
  198. acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore,
  199.  acpi_gbl_global_lock_thread_count);
  200. }
  201. }
  202. /*******************************************************************************
  203.  *
  204.  * FUNCTION:    Acpi_ev_global_lock_handler
  205.  *
  206.  * RETURN:      Status
  207.  *
  208.  * DESCRIPTION: Invoked directly from the SCI handler when a global lock
  209.  *              release interrupt occurs.  Grab the global lock and queue
  210.  *              the global lock thread for execution
  211.  *
  212.  ******************************************************************************/
  213. static u32
  214. acpi_ev_global_lock_handler (
  215. void                    *context)
  216. {
  217. u8                      acquired = FALSE;
  218. void                    *global_lock;
  219. /*
  220.  * Attempt to get the lock
  221.  * If we don't get it now, it will be marked pending and we will
  222.  * take another interrupt when it becomes free.
  223.  */
  224. global_lock = acpi_gbl_FACS->global_lock;
  225. ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired);
  226. if (acquired) {
  227. /* Got the lock, now wake all threads waiting for it */
  228. acpi_gbl_global_lock_acquired = TRUE;
  229. /* Run the Global Lock thread which will signal all waiting threads */
  230. acpi_os_queue_for_execution (OSD_PRIORITY_HIGH, acpi_ev_global_lock_thread,
  231.   context);
  232. }
  233. return (INTERRUPT_HANDLED);
  234. }
  235. /*******************************************************************************
  236.  *
  237.  * FUNCTION:    Acpi_ev_init_global_lock_handler
  238.  *
  239.  * RETURN:      Status
  240.  *
  241.  * DESCRIPTION: Install a handler for the global lock release event
  242.  *
  243.  ******************************************************************************/
  244. acpi_status
  245. acpi_ev_init_global_lock_handler (void)
  246. {
  247. acpi_status             status;
  248. FUNCTION_TRACE ("Ev_init_global_lock_handler");
  249. acpi_gbl_global_lock_present = TRUE;
  250. status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL,
  251.   acpi_ev_global_lock_handler, NULL);
  252. /*
  253.  * If the global lock does not exist on this platform, the attempt
  254.  * to enable GBL_STS will fail (the GBL_EN bit will not stick)
  255.  * Map to AE_OK, but mark global lock as not present.
  256.  * Any attempt to actually use the global lock will be flagged
  257.  * with an error.
  258.  */
  259. if (status == AE_NO_HARDWARE_RESPONSE) {
  260. acpi_gbl_global_lock_present = FALSE;
  261. status = AE_OK;
  262. }
  263. return_ACPI_STATUS (status);
  264. }
  265. /******************************************************************************
  266.  *
  267.  * FUNCTION:    Acpi_ev_acquire_global_lock
  268.  *
  269.  * RETURN:      Status
  270.  *
  271.  * DESCRIPTION: Attempt to gain ownership of the Global Lock.
  272.  *
  273.  *****************************************************************************/
  274. acpi_status
  275. acpi_ev_acquire_global_lock(void)
  276. {
  277. acpi_status             status = AE_OK;
  278. u8                      acquired = FALSE;
  279. void                    *global_lock;
  280. FUNCTION_TRACE ("Ev_acquire_global_lock");
  281. /* Make sure that we actually have a global lock */
  282. if (!acpi_gbl_global_lock_present) {
  283. return_ACPI_STATUS (AE_NO_GLOBAL_LOCK);
  284. }
  285. /* One more thread wants the global lock */
  286. acpi_gbl_global_lock_thread_count++;
  287. /* If we (OS side) have the hardware lock already, we are done */
  288. if (acpi_gbl_global_lock_acquired) {
  289. return_ACPI_STATUS (AE_OK);
  290. }
  291. /* Only if the FACS is valid */
  292. if (!acpi_gbl_FACS) {
  293. return_ACPI_STATUS (AE_OK);
  294. }
  295. /* We must acquire the actual hardware lock */
  296. global_lock = acpi_gbl_FACS->global_lock;
  297. ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired);
  298. if (acquired) {
  299.    /* We got the lock */
  300. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Acquired the Global Lockn"));
  301. acpi_gbl_global_lock_acquired = TRUE;
  302. return_ACPI_STATUS (AE_OK);
  303. }
  304. /*
  305.  * Did not get the lock.  The pending bit was set above, and we must now
  306.  * wait until we get the global lock released interrupt.
  307.  */
  308. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Waiting for the HW Global Lockn"));
  309.  /*
  310.   * Acquire the global lock semaphore first.
  311.   * Since this wait will block, we must release the interpreter
  312.   */
  313. status = acpi_ex_system_wait_semaphore (acpi_gbl_global_lock_semaphore,
  314.   ACPI_UINT32_MAX);
  315. return_ACPI_STATUS (status);
  316. }
  317. /*******************************************************************************
  318.  *
  319.  * FUNCTION:    Acpi_ev_release_global_lock
  320.  *
  321.  * DESCRIPTION: Releases ownership of the Global Lock.
  322.  *
  323.  ******************************************************************************/
  324. void
  325. acpi_ev_release_global_lock (void)
  326. {
  327. u8                      pending = FALSE;
  328. void                    *global_lock;
  329. FUNCTION_TRACE ("Ev_release_global_lock");
  330. if (!acpi_gbl_global_lock_thread_count) {
  331. REPORT_WARNING(("Global Lock has not be acquired, cannot releasen"));
  332. return_VOID;
  333. }
  334.    /* One fewer thread has the global lock */
  335. acpi_gbl_global_lock_thread_count--;
  336. /* Have all threads released the lock? */
  337. if (!acpi_gbl_global_lock_thread_count) {
  338. /*
  339.  * No more threads holding lock, we can do the actual hardware
  340.  * release
  341.  */
  342. global_lock = acpi_gbl_FACS->global_lock;
  343. ACPI_RELEASE_GLOBAL_LOCK (global_lock, pending);
  344. acpi_gbl_global_lock_acquired = FALSE;
  345. /*
  346.  * If the pending bit was set, we must write GBL_RLS to the control
  347.  * register
  348.  */
  349. if (pending) {
  350. acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK,
  351.  GBL_RLS, 1);
  352. }
  353. }
  354. return_VOID;
  355. }