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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  *
  3.  * Module Name: bmpm.c
  4.  *   $Revision: 14 $
  5.  *
  6.  *****************************************************************************/
  7. /*
  8.  *  Copyright (C) 2000, 2001 Andrew Grover
  9.  *
  10.  *  This program is free software; you can redistribute it and/or modify
  11.  *  it under the terms of the GNU General Public License as published by
  12.  *  the Free Software Foundation; either version 2 of the License, or
  13.  *  (at your option) any later version.
  14.  *
  15.  *  This program is distributed in the hope that it will be useful,
  16.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  *  GNU General Public License for more details.
  19.  *
  20.  *  You should have received a copy of the GNU General Public License
  21.  *  along with this program; if not, write to the Free Software
  22.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  23.  */
  24. #include <acpi.h>
  25. #include "bm.h"
  26. #include "bmpower.h"
  27. #define _COMPONENT ACPI_BUS
  28. MODULE_NAME ("bmpm")
  29. /****************************************************************************
  30.  *                             Internal Functions
  31.  ****************************************************************************/
  32. /****************************************************************************
  33.  *
  34.  * FUNCTION:    bm_get_inferred_power_state
  35.  *
  36.  * PARAMETERS:
  37.  *
  38.  * RETURN:
  39.  *
  40.  * DESCRIPTION:
  41.  *
  42.  ****************************************************************************/
  43. acpi_status
  44. bm_get_inferred_power_state (
  45. BM_DEVICE               *device)
  46. {
  47. acpi_status             status = AE_OK;
  48. BM_HANDLE_LIST          pr_list;
  49. BM_POWER_STATE          list_state = ACPI_STATE_UNKNOWN;
  50. char                    object_name[5] = {'_','P','R','0',''};
  51. u32                     i = 0;
  52. FUNCTION_TRACE("bm_get_inferred_power_state");
  53. if (!device) {
  54. return_ACPI_STATUS(AE_BAD_PARAMETER);
  55. }
  56. MEMSET(&pr_list, 0, sizeof(BM_HANDLE_LIST));
  57. device->power.state = ACPI_STATE_D3;
  58. /*
  59.  * Calculate Power State:
  60.  * ----------------------
  61.  * Try to infer the devices's power state by checking the state of
  62.  * the devices's power resources.  We start by evaluating _PR0
  63.  * (resource requirements at D0) and work through _PR1 and _PR2.
  64.  * We know the current devices power state when all resources (for
  65.  * a give Dx state) are ON.  If no power resources are on then the
  66.  * device is assumed to be off (D3).
  67.  */
  68. for (i=ACPI_STATE_D0; i<ACPI_STATE_D3; i++) {
  69. object_name[3] = '0' + i;
  70. status = bm_evaluate_reference_list(device->acpi_handle,
  71. object_name, &pr_list);
  72. if (ACPI_SUCCESS(status)) {
  73. status = bm_pr_list_get_state(&pr_list, &list_state);
  74. if (ACPI_SUCCESS(status)) {
  75. if (list_state == ACPI_STATE_D0) {
  76. device->power.state = i;
  77. break;
  78. }
  79. }
  80. }
  81. }
  82. return_ACPI_STATUS(AE_OK);
  83. }
  84. /****************************************************************************
  85.  *                             External Functions
  86.  ****************************************************************************/
  87. /****************************************************************************
  88.  *
  89.  * FUNCTION:    bm_get_power_state
  90.  *
  91.  * PARAMETERS:
  92.  *
  93.  * RETURN:
  94.  *
  95.  * DESCRIPTION:
  96.  *
  97.  ****************************************************************************/
  98. acpi_status
  99. bm_get_power_state (
  100. BM_NODE *node)
  101. {
  102. acpi_status             status = AE_OK;
  103. BM_DEVICE               *device = NULL;
  104. FUNCTION_TRACE("bm_get_power_state");
  105. if (!node || !node->parent) {
  106. return_ACPI_STATUS(AE_BAD_PARAMETER);
  107. }
  108. device = &(node->device);
  109. device->power.state = ACPI_STATE_UNKNOWN;
  110. /*
  111.  * Power Control?
  112.  * --------------
  113.  * If this device isn't directly power manageable (e.g. doesn't
  114.  * include _PR0/_PS0) then there's nothing to do (state is static).
  115.  */
  116. if (!BM_IS_POWER_CONTROL(device)) {
  117. return_ACPI_STATUS(AE_OK);
  118. }
  119. /*
  120.  * Parent Present?
  121.  * ---------------
  122.  * Make sure the parent is present before mucking with the child.
  123.  */
  124. if (!BM_NODE_PRESENT(node->parent)) {
  125. return_ACPI_STATUS(AE_NOT_EXIST);
  126. }
  127. /*
  128.  * Get Power State:
  129.  * ----------------
  130.  * Either directly (via _PSC) or inferred (via power resource
  131.  * dependencies).
  132.  */
  133. if (BM_IS_POWER_STATE(device)) {
  134. status = bm_evaluate_simple_integer(device->acpi_handle,
  135. "_PSC", &(device->power.state));
  136. }
  137. else {
  138. status = bm_get_inferred_power_state(device);
  139. }
  140. if (ACPI_SUCCESS(status)) {
  141. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Device [%02x] is at power state [D%d].n", device->handle, device->power.state));
  142. }
  143. else {
  144. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Error getting power state for device [%02x]n", device->handle));
  145. }
  146. return_ACPI_STATUS(status);
  147. }
  148. /****************************************************************************
  149.  *
  150.  * FUNCTION:    bm_set_power_state
  151.  *
  152.  * PARAMETERS:
  153.  *
  154.  * RETURN:
  155.  *
  156.  * DESCRIPTION:
  157.  *
  158.  ****************************************************************************/
  159. acpi_status
  160. bm_set_power_state (
  161. BM_NODE *node,
  162. BM_POWER_STATE          state)
  163. {
  164. acpi_status             status = AE_OK;
  165. BM_DEVICE *device = NULL;
  166. BM_DEVICE *parent_device = NULL;
  167. BM_HANDLE_LIST          current_list;
  168. BM_HANDLE_LIST          target_list;
  169. char                    object_name[5] = {'_','P','R','0',''};
  170. FUNCTION_TRACE("bm_set_power_state");
  171. if (!node || !node->parent || (state > ACPI_STATE_D3)) {
  172. return_ACPI_STATUS(AE_BAD_PARAMETER);
  173. }
  174. MEMSET(&current_list, 0, sizeof(BM_HANDLE_LIST));
  175. MEMSET(&target_list, 0, sizeof(BM_HANDLE_LIST));
  176. device = &(node->device);
  177. parent_device = &(node->parent->device);
  178. /*
  179.  * Power Control?
  180.  * --------------
  181.  * If this device isn't directly power manageable (e.g. doesn't
  182.  * include _PR0/_PS0) then return an error (can't set state).
  183.  */
  184. if (!BM_IS_POWER_CONTROL(device)) {
  185. return_ACPI_STATUS(AE_ERROR);
  186. }
  187. /*
  188.  * Parent Present?
  189.  * ---------------
  190.  * Make sure the parent is present before mucking with the child.
  191.  */
  192. if (!BM_NODE_PRESENT(node->parent)) {
  193. return_ACPI_STATUS(AE_NOT_EXIST);
  194. }
  195. /*
  196.  * Check Parent's Power State:
  197.  * ---------------------------
  198.  * Can't be in a higher power state (lower Dx value) than parent.
  199.  */
  200. if (state < parent_device->power.state) {
  201. ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Cannot set device [%02x] to a higher-powered state than parent_device.n", device->handle));
  202. return_ACPI_STATUS(AE_ERROR);
  203. }
  204. /*
  205.  * Get Resources:
  206.  * --------------
  207.  * Get the power resources associated with the device's current
  208.  * and target power states.
  209.  */
  210. if (device->power.state != ACPI_STATE_UNKNOWN) {
  211. object_name[3] = '0' + device->power.state;
  212. bm_evaluate_reference_list(device->acpi_handle,
  213. object_name, &current_list);
  214. }
  215. object_name[3] = '0' + state;
  216. bm_evaluate_reference_list(device->acpi_handle, object_name,
  217. &target_list);
  218. /*
  219.  * Transition Resources:
  220.  * ---------------------
  221.  * Transition all power resources referenced by this device to
  222.  * the correct power state (taking into consideration sequencing
  223.  * and dependencies to other devices).
  224.  */
  225. if (current_list.count || target_list.count) {
  226. status = bm_pr_list_transition(&current_list, &target_list);
  227. }
  228. if (ACPI_FAILURE(status)) {
  229. return_ACPI_STATUS(status);
  230. }
  231. /*
  232.  * Execute _PSx:
  233.  * -------------
  234.  * Execute the _PSx method corresponding to the target Dx state,
  235.  * if it exists.
  236.  */
  237. object_name[2] = 'S';
  238. object_name[3] = '0' + state;
  239. bm_evaluate_object(device->acpi_handle, object_name, NULL, NULL);
  240. if (ACPI_SUCCESS(status)) {
  241. ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Device [%02x] is now at [D%d].n", device->handle, state));
  242. device->power.state = state;
  243. }
  244. return_ACPI_STATUS(status);
  245. }
  246. /****************************************************************************
  247.  *
  248.  * FUNCTION:    bm_get_pm_capabilities
  249.  *
  250.  * PARAMETERS:
  251.  *
  252.  * RETURN:
  253.  *
  254.  * DESCRIPTION:
  255.  *
  256.  ****************************************************************************/
  257. acpi_status
  258. bm_get_pm_capabilities (
  259. BM_NODE *node)
  260. {
  261. acpi_status             status = AE_OK;
  262. BM_DEVICE *device = NULL;
  263. BM_DEVICE *parent_device = NULL;
  264. acpi_handle             acpi_handle = NULL;
  265. BM_POWER_STATE          dx_supported = ACPI_STATE_UNKNOWN;
  266. char                    object_name[5] = {'_','S','0','D',''};
  267. u32                     i = 0;
  268. FUNCTION_TRACE("bm_get_pm_capabilities");
  269. if (!node || !node->parent) {
  270. return_ACPI_STATUS(AE_BAD_PARAMETER);
  271. }
  272. device = &(node->device);
  273. parent_device = &(node->parent->device);
  274. /*
  275.  * Power Management Flags:
  276.  * -----------------------
  277.  */
  278. if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PSC",
  279. &acpi_handle))) {
  280. device->power.flags |= BM_FLAGS_POWER_STATE;
  281. }
  282. if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_IRC",
  283. &acpi_handle))) {
  284. device->power.flags |= BM_FLAGS_INRUSH_CURRENT;
  285. }
  286. if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PRW",
  287. &acpi_handle))) {
  288. device->power.flags |= BM_FLAGS_WAKE_CAPABLE;
  289. }
  290. /*
  291.  * Device Power State:
  292.  * -------------------
  293.  * Note that we can't get the device's power state until we've
  294.  * initialized all power resources, so for now we just set to
  295.  * unknown.
  296.  */
  297. device->power.state = ACPI_STATE_UNKNOWN;
  298. /*
  299.  * Dx Supported in S0:
  300.  * -------------------
  301.  * Figure out which Dx states are supported by this device for the
  302.  * S0 (working) state.  Note that D0 and D3 are required (assumed).
  303.  */
  304. device->power.dx_supported[ACPI_STATE_S0] = BM_FLAGS_D0_SUPPORT |
  305. BM_FLAGS_D3_SUPPORT;
  306. if ((ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PR1",
  307. &acpi_handle))) ||
  308. (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PS1",
  309. &acpi_handle)))) {
  310. device->power.dx_supported[ACPI_STATE_S0] |=
  311. BM_FLAGS_D1_SUPPORT;
  312. }
  313. if ((ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PR2",
  314. &acpi_handle))) ||
  315. (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, "_PS2",
  316. &acpi_handle)))) {
  317. device->power.dx_supported[ACPI_STATE_S0] |=
  318. BM_FLAGS_D2_SUPPORT;
  319. }
  320. /*
  321.  * Dx Supported in S1-S5:
  322.  * ----------------------
  323.  * Figure out which Dx states are supported by this device for
  324.  * all other Sx states.
  325.  */
  326. for (i = ACPI_STATE_S1; i <= ACPI_STATE_S5; i++) {
  327. /*
  328.  * D3 support is assumed (off is always possible!).
  329.  */
  330. device->power.dx_supported[i] = BM_FLAGS_D3_SUPPORT;
  331. /*
  332.  * Evalute _Sx_d:
  333.  * -------------
  334.  * Which returns the highest (power) Dx state supported in
  335.  * this system (Sx) state.  We convert this value to a bit
  336.  * mask of supported states (conceptually simpler).
  337.  */
  338. status = bm_evaluate_simple_integer(device->acpi_handle,
  339. object_name, &dx_supported);
  340. if (ACPI_SUCCESS(status)) {
  341. switch (dx_supported) {
  342. case 0:
  343. device->power.dx_supported[i] |=
  344. BM_FLAGS_D0_SUPPORT;
  345. /* fall through */
  346. case 1:
  347. device->power.dx_supported[i] |=
  348. BM_FLAGS_D1_SUPPORT;
  349. /* fall through */
  350. case 2:
  351. device->power.dx_supported[i] |=
  352. BM_FLAGS_D2_SUPPORT;
  353. /* fall through */
  354. case 3:
  355. device->power.dx_supported[i] |=
  356. BM_FLAGS_D3_SUPPORT;
  357. break;
  358. }
  359. /*
  360.  * Validate:
  361.  * ---------
  362.  * Mask of any states that _Sx_d falsely advertises
  363.  * (e.g.claims D1 support but neither _PR2 or _PS2
  364.  * exist).  In other words, S1-S5 can't offer a Dx
  365.  * state that isn't supported by S0.
  366.  */
  367. device->power.dx_supported[i] &=
  368. device->power.dx_supported[ACPI_STATE_S0];
  369. }
  370. object_name[2]++;
  371. }
  372. return_ACPI_STATUS(AE_OK);
  373. }