11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_power.c - ACPI Bus Power Management ($Revision: 39 $) 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License for more details. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI power-managed devices may be controlled in two ways: 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. via "Device Specific (D-State) Control" 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. via "Power Resource Control". 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This module is used to manage devices relying on Power Resource Control. 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * An ACPI "power resource object" describes a software controllable power 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * plane, clock plane, or other resource used by a power managed device. 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A device may rely on multiple power resources, and a power resource 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may be shared by multiple devices. 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 425a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h> 459b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki#include "sleep.h" 469b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 47a192a9580bcc41692be1f36b77c3b681827f566aLen Brown#define PREFIX "ACPI: " 48a192a9580bcc41692be1f36b77c3b681827f566aLen Brown 4989595b8f2850a080d290bf778ec933ea1d99f78eBjorn Helgaas#define _COMPONENT ACPI_POWER_COMPONENT 50f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("power"); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_CLASS "power_resource" 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_DEVICE_NAME "Power Resource" 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_FILE_INFO "info" 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_FILE_STATUS "state" 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_RESOURCE_STATE_OFF 0x00 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_RESOURCE_STATE_ON 0x01 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF 58f5adfaa372c76423b6e8e4727a9701330374f364Zhao Yakui 594be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_add(struct acpi_device *device); 604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_remove(struct acpi_device *device, int type); 61e8363f332757ac22395fb120cc33b3262f9ee26cLen Brownstatic int acpi_power_resume(struct acpi_device *device); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63c97adf9e7bebf17a86b95e2131bf9ba76c4857c7Márton Némethstatic const struct acpi_device_id power_device_ids[] = { 641ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger {ACPI_POWER_HID, 0}, 651ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger {"", 0}, 661ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger}; 671ba90e3a87c46500623afdc3898573e4a5ebb21bThomas RenningerMODULE_DEVICE_TABLE(acpi, power_device_ids); 681ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_driver acpi_power_driver = { 70c2b6705b75d9c7aff98a4602a32230639e10891cLen Brown .name = "power", 714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .class = ACPI_POWER_CLASS, 721ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger .ids = power_device_ids, 734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .ops = { 744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .add = acpi_power_add, 754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .remove = acpi_power_remove, 760a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov .resume = acpi_power_resume, 774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown }, 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 804be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstruct acpi_power_resource { 81415985728895ba3127116bc4f999caf94420ed85Patrick Mochel struct acpi_device * device; 824be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_bus_id name; 834be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u32 system_level; 844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u32 order; 853e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki unsigned int ref_count; 860a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov struct mutex resource_lock; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic struct list_head acpi_power_resource_list; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Power Resource Management 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_power_get_context(acpi_handle handle, 974be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_power_resource **resource) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 1004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_device *device = NULL; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!resource) 104d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_device(handle, &device); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 108cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle); 109d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11250dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt *resource = acpi_driver_data(device); 113a815ab8b5891f3d2515316655729272f68269e3bLi Zefan if (!*resource) 114d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 116d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 119a51e145f379ae48003129610922595893e8efde0Zhao Yakuistatic int acpi_power_get_state(acpi_handle handle, int *state) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1214be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 12227663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long sta = 0; 12360a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming char node_name[5]; 12460a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming struct acpi_buffer buffer = { sizeof(node_name), node_name }; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127a51e145f379ae48003129610922595893e8efde0Zhao Yakui if (!handle || !state) 128d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 130a51e145f379ae48003129610922595893e8efde0Zhao Yakui status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 132d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 134c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON: 135c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy ACPI_POWER_RESOURCE_STATE_OFF; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13760a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); 13860a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", 14060a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming node_name, 141b1b57fbe9bb10d94682a975456de7a727d1dbc84Zhao Yakui *state ? "on" : "off")); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1464be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 148d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki int cur_state; 149d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki int i = 0; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!list || !state) 152d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The state of the list is 'on' IFF all resources are 'on'. */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown for (i = 0; i < list->count; i++) { 157d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki struct acpi_power_resource *resource; 158d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki acpi_handle handle = list->handles[i]; 159d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki int result; 160d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 161d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki result = acpi_power_get_context(handle, &resource); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 163d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 165d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki mutex_lock(&resource->resource_lock); 166d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 167d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki result = acpi_power_get_state(handle, &cur_state); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 169d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki mutex_unlock(&resource->resource_lock); 170d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 171d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki if (result) 172d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki return result; 173d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 174d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki if (cur_state != ACPI_POWER_RESOURCE_STATE_ON) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n", 179d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki cur_state ? "on" : "off")); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki *state = cur_state; 182d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 183d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki return 0; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1863e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysockistatic int __acpi_power_on(struct acpi_power_resource *resource) 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1884be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1903e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); 1913e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (ACPI_FAILURE(status)) 1923e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return -ENODEV; 1933e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 1943e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki /* Update the power resource's _device_ power state */ 1953e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->device->power.state = ACPI_STATE_D0; 1963e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 1973e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", 1983e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 1993e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 2003e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return 0; 2013e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki} 2023e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 2033e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysockistatic int acpi_power_on(acpi_handle handle) 2043e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki{ 2053e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki int result = 0; 2063e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki struct acpi_power_resource *resource = NULL; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_power_get_context(handle, &resource); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 210d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2120a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov mutex_lock(&resource->resource_lock); 2130a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 2143e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (resource->ref_count++) { 2153e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2163e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki "Power resource [%s] already on", 2173e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 2183e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki } else { 2193e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki result = __acpi_power_on(resource); 22012b3b5afed67e08aa641d30e57df20dab2e33432Rafael J. Wysocki if (result) 22112b3b5afed67e08aa641d30e57df20dab2e33432Rafael J. Wysocki resource->ref_count--; 2220a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov } 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2243e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki mutex_unlock(&resource->resource_lock); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22612b3b5afed67e08aa641d30e57df20dab2e33432Rafael J. Wysocki return result; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22936237fa0a711c309a38d7a7a9aed727e0eb76449Rafael J. Wysockistatic int acpi_power_off(acpi_handle handle) 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 231bdf43bbf2e19952d82995a50e00cb4b66afa4f0cBjorn Helgaas int result = 0; 2324be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_power_resource *resource = NULL; 2340a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_power_get_context(handle, &resource); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 237d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2390a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov mutex_lock(&resource->resource_lock); 2403e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 2413e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!resource->ref_count) { 2423e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2433e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki "Power resource [%s] already off", 2443e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 2453e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki goto unlock; 2460a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov } 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2483e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (--resource->ref_count) { 2493e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2503e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki "Power resource [%s] still in use\n", 2513e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 2523e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki goto unlock; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2555fbc19efdbedf9c9125774f66f80d6a6ccce4566Patrick Mochel status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL); 2563e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (ACPI_FAILURE(status)) { 2573e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki result = -ENODEV; 2583e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki } else { 2593e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki /* Update the power resource's _device_ power state */ 2603e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->device->power.state = ACPI_STATE_D3; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2623e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2633e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki "Power resource [%s] turned off\n", 2643e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 2653e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2673e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki unlock: 2683e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki mutex_unlock(&resource->resource_lock); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2703e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return result; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 273d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysockistatic void __acpi_power_off_list(struct acpi_handle_list *list, int num_res) 274d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki{ 275d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki int i; 276d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 277d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki for (i = num_res - 1; i >= 0 ; i--) 27836237fa0a711c309a38d7a7a9aed727e0eb76449Rafael J. Wysocki acpi_power_off(list->handles[i]); 279d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki} 280d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 281d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysockistatic void acpi_power_off_list(struct acpi_handle_list *list) 282d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki{ 283d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki __acpi_power_off_list(list, list->count); 284d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki} 285d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 286d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysockistatic int acpi_power_on_list(struct acpi_handle_list *list) 287d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki{ 288d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki int result = 0; 289d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki int i; 290d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 291d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki for (i = 0; i < list->count; i++) { 292d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki result = acpi_power_on(list->handles[i]); 293d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki if (result) { 294d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki __acpi_power_off_list(list, i); 295d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki break; 296d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki } 297d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki } 298d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 299d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki return result; 300d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki} 301d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 30277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki/** 30377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in 30477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * ACPI 3.0) _PSW (Power State Wake) 30577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * @dev: Device to handle. 30677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * @enable: 0 - disable, 1 - enable the wake capabilities of the device. 30777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * @sleep_state: Target sleep state of the system. 30877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * @dev_state: Target power state of the device. 30977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 31077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power 31177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * State Wake) for the device, if present. On failure reset the device's 31277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * wakeup.flags.valid flag. 31377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 31477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * RETURN VALUE: 31577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 0 if either _DSW or _PSW has been successfully executed 31677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 0 if neither _DSW nor _PSW has been found 31777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * -ENODEV if the execution of either _DSW or _PSW has failed 31877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki */ 31977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysockiint acpi_device_sleep_wake(struct acpi_device *dev, 32077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki int enable, int sleep_state, int dev_state) 32177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki{ 32277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki union acpi_object in_arg[3]; 32377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki struct acpi_object_list arg_list = { 3, in_arg }; 32477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki acpi_status status = AE_OK; 32577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki 32677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki /* 32777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Try to execute _DSW first. 32877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 32977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Three agruments are needed for the _DSW object: 33077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Argument 0: enable/disable the wake capabilities 33177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Argument 1: target system state 33277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Argument 2: target device state 33377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * When _DSW object is called to disable the wake capabilities, maybe 33477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * the first argument is filled. The values of the other two agruments 33577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * are meaningless. 33677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki */ 33777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[0].type = ACPI_TYPE_INTEGER; 33877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[0].integer.value = enable; 33977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[1].type = ACPI_TYPE_INTEGER; 34077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[1].integer.value = sleep_state; 34177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[2].type = ACPI_TYPE_INTEGER; 34277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[2].integer.value = dev_state; 34377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL); 34477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki if (ACPI_SUCCESS(status)) { 34577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return 0; 34677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki } else if (status != AE_NOT_FOUND) { 34777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki printk(KERN_ERR PREFIX "_DSW execution failed\n"); 34877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki dev->wakeup.flags.valid = 0; 34977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return -ENODEV; 35077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki } 35177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki 35277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki /* Execute _PSW */ 35377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki arg_list.count = 1; 35477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[0].integer.value = enable; 35577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); 35677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { 35777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki printk(KERN_ERR PREFIX "_PSW execution failed\n"); 35877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki dev->wakeup.flags.valid = 0; 35977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return -ENODEV; 36077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki } 36177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki 36277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return 0; 36377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki} 36477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229): 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. Power on the power resources required for the wakeup device 36877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power 36977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * State Wake) for the device, if present 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysockiint acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3739b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki int i, err = 0; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev || !dev->wakeup.flags.valid) 37677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return -EINVAL; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3789b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki mutex_lock(&acpi_device_lock); 3799b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 3809b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (dev->wakeup.prepare_count++) 3819b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto out; 3820af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Open power resource */ 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < dev->wakeup.resources.count; i++) { 3853e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki int ret = acpi_power_on(dev->wakeup.resources.handles[i]); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 3876468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Transition power state\n"); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->wakeup.flags.valid = 0; 3899b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki err = -ENODEV; 3909b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto err_out; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki /* 39577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Passing 3 as the third argument below means the device may be placed 39677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * in arbitrary power state afterwards. 39777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki */ 3980af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki err = acpi_device_sleep_wake(dev, 1, sleep_state, 3); 3990af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki 4009b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki err_out: 4019b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (err) 4029b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki dev->wakeup.prepare_count = 0; 4039b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 4049b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki out: 4059b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki mutex_unlock(&acpi_device_lock); 4060af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki return err; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Shutdown a wakeup device, counterpart of above method 41177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power 41277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * State Wake) for the device, if present 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. Shutdown down the power resources 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_disable_wakeup_device_power(struct acpi_device *dev) 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4179b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki int i, err = 0; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev || !dev->wakeup.flags.valid) 42077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return -EINVAL; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4229b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki mutex_lock(&acpi_device_lock); 4239b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 4249b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (--dev->wakeup.prepare_count > 0) 4259b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto out; 4269b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 4270af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki /* 4289b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki * Executing the code below even if prepare_count is already zero when 4299b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki * the function is called may be useful, for example for initialisation. 4300af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki */ 4319b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (dev->wakeup.prepare_count < 0) 4329b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki dev->wakeup.prepare_count = 0; 4330af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki 4349b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki err = acpi_device_sleep_wake(dev, 0, 0, 0); 4359b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (err) 4369b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto out; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Close power resource */ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < dev->wakeup.resources.count; i++) { 44036237fa0a711c309a38d7a7a9aed727e0eb76449Rafael J. Wysocki int ret = acpi_power_off(dev->wakeup.resources.handles[i]); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 4426468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Transition power state\n"); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->wakeup.flags.valid = 0; 4449b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki err = -ENODEV; 4459b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto out; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4499b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki out: 4509b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki mutex_unlock(&acpi_device_lock); 4519b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki return err; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Device Power Management 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45832a00d274e877eab3ea7ab196b75c9be5170d25eRafael J. Wysockiint acpi_power_get_inferred_state(struct acpi_device *device, int *state) 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4604be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 4614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_handle_list *list = NULL; 4624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int list_state = 0; 4634be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i = 0; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46532a00d274e877eab3ea7ab196b75c9be5170d25eRafael J. Wysocki if (!device || !state) 466d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We know a device's inferred power state when all the resources 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * required for a given D-state are 'on'. 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown for (i = ACPI_STATE_D0; i < ACPI_STATE_D3; i++) { 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list = &device->power.states[i].resources; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list->count < 1) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_power_get_list_state(list, &list_state); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 479d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { 48232a00d274e877eab3ea7ab196b75c9be5170d25eRafael J. Wysocki *state = i; 483d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48732a00d274e877eab3ea7ab196b75c9be5170d25eRafael J. Wysocki *state = ACPI_STATE_D3; 488d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49130d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysockiint acpi_power_on_resources(struct acpi_device *device, int state) 49230d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki{ 49330d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3) 49430d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki return -EINVAL; 49530d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki 49630d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki return acpi_power_on_list(&device->power.states[state].resources); 49730d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki} 49830d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki 4994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_power_transition(struct acpi_device *device, int state) 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 501d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki int result; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) 504d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 506212967c69afd348342548272aedbe4d46a9325d6Rafael J. Wysocki if (device->power.state == state) 507212967c69afd348342548272aedbe4d46a9325d6Rafael J. Wysocki return 0; 508212967c69afd348342548272aedbe4d46a9325d6Rafael J. Wysocki 5094be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if ((device->power.state < ACPI_STATE_D0) 5104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown || (device->power.state > ACPI_STATE_D3)) 511d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: Resources must be ordered. */ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First we reference all power resources required in the target list 517d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki * (e.g. so the device doesn't lose power while transitioning). Then, 518d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki * we dereference all power resources used in the current list. 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 520d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki result = acpi_power_on_list(&device->power.states[state].resources); 521d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki if (!result) 522d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki acpi_power_off_list( 523d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki &device->power.states[device->power.state].resources); 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 525d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki /* We shouldn't change the state unless the above operations succeed. */ 526d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki device->power.state = result ? ACPI_STATE_UNKNOWN : state; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 528d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Driver Interface 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5354be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_add(struct acpi_device *device) 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 537c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy int result = 0, state; 5384be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_power_resource *resource = NULL; 5404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown union acpi_object acpi_object; 5414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object }; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!device) 545d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54736bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!resource) 549d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551415985728895ba3127116bc4f999caf94420ed85Patrick Mochel resource->device = device; 5520a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov mutex_init(&resource->resource_lock); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(resource->name, device->pnp.bus_id); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_class(device), ACPI_POWER_CLASS); 556db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek device->driver_data = resource; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Evalute the object to get the system level and resource order. */ 5595fbc19efdbedf9c9125774f66f80d6a6ccce4566Patrick Mochel status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->system_level = acpi_object.power_resource.system_level; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->order = acpi_object.power_resource.resource_order; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 567a51e145f379ae48003129610922595893e8efde0Zhao Yakui result = acpi_power_get_state(device->handle, &state); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy switch (state) { 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_POWER_RESOURCE_STATE_ON: 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device->power.state = ACPI_STATE_D0; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_POWER_RESOURCE_STATE_OFF: 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device->power.state = ACPI_STATE_D3; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device->power.state = ACPI_STATE_UNKNOWN; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), 584c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy acpi_device_bid(device), state ? "on" : "off"); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5864be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(resource); 5894be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 590d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5934be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_remove(struct acpi_device *device, int type) 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5953e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki struct acpi_power_resource *resource; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5973e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!device) 598d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60050dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt resource = acpi_driver_data(device); 6013e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!resource) 6023e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return -EINVAL; 6030a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(resource); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 606d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 609e8363f332757ac22395fb120cc33b3262f9ee26cLen Brownstatic int acpi_power_resume(struct acpi_device *device) 6100a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov{ 611c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy int result = 0, state; 6123e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki struct acpi_power_resource *resource; 6130a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 6143e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!device) 6150a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov return -EINVAL; 6160a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 617db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek resource = acpi_driver_data(device); 6183e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!resource) 6193e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return -EINVAL; 6203e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 6213e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki mutex_lock(&resource->resource_lock); 6220a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 623a51e145f379ae48003129610922595893e8efde0Zhao Yakui result = acpi_power_get_state(device->handle, &state); 6240a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov if (result) 6253e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki goto unlock; 6260a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 6273e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count) 6283e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki result = __acpi_power_on(resource); 6290a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 6303e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki unlock: 6310a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov mutex_unlock(&resource->resource_lock); 6323e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 6333e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return result; 6340a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov} 6350a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 63644515374cba9e46d5622256b43eb06b9c349cee1Bjorn Helgaasint __init acpi_power_init(void) 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&acpi_power_resource_list); 63906af7eb043c02822072cea862fce1b7c74115e8fZhang Rui return acpi_bus_register_driver(&acpi_power_driver); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 641