power.c 15.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
/*
 *  acpi_power.c - ACPI Bus Power Management ($Revision: 39 $)
 *
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

/*
 * ACPI power-managed devices may be controlled in two ways:
 * 1. via "Device Specific (D-State) Control"
 * 2. via "Power Resource Control".
 * This module is used to manage devices relying on Power Resource Control.
 * 
 * An ACPI "power resource object" describes a software controllable power
 * plane, clock plane, or other resource used by a power managed device.
 * A device may rely on multiple power resources, and a power resource
 * may be shared by multiple devices.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
42
#include <linux/slab.h>
L
Linus Torvalds 已提交
43 44
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
45 46
#include "sleep.h"

47 48
#define PREFIX "ACPI: "

49
#define _COMPONENT			ACPI_POWER_COMPONENT
50
ACPI_MODULE_NAME("power");
L
Linus Torvalds 已提交
51 52 53 54 55 56 57
#define ACPI_POWER_CLASS		"power_resource"
#define ACPI_POWER_DEVICE_NAME		"Power Resource"
#define ACPI_POWER_FILE_INFO		"info"
#define ACPI_POWER_FILE_STATUS		"state"
#define ACPI_POWER_RESOURCE_STATE_OFF	0x00
#define ACPI_POWER_RESOURCE_STATE_ON	0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
58 59 60 61

int acpi_power_nocheck;
module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);

L
Len Brown 已提交
62 63
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
64
static int acpi_power_resume(struct acpi_device *device);
L
Linus Torvalds 已提交
65

66
static const struct acpi_device_id power_device_ids[] = {
67 68 69 70 71
	{ACPI_POWER_HID, 0},
	{"", 0},
};
MODULE_DEVICE_TABLE(acpi, power_device_ids);

L
Linus Torvalds 已提交
72
static struct acpi_driver acpi_power_driver = {
L
Len Brown 已提交
73
	.name = "power",
L
Len Brown 已提交
74
	.class = ACPI_POWER_CLASS,
75
	.ids = power_device_ids,
L
Len Brown 已提交
76 77 78
	.ops = {
		.add = acpi_power_add,
		.remove = acpi_power_remove,
79
		.resume = acpi_power_resume,
L
Len Brown 已提交
80
		},
L
Linus Torvalds 已提交
81 82
};

L
Len Brown 已提交
83
struct acpi_power_resource {
84
	struct acpi_device * device;
L
Len Brown 已提交
85 86 87
	acpi_bus_id name;
	u32 system_level;
	u32 order;
88
	unsigned int ref_count;
89
	struct mutex resource_lock;
L
Linus Torvalds 已提交
90 91
};

L
Len Brown 已提交
92
static struct list_head acpi_power_resource_list;
L
Linus Torvalds 已提交
93 94 95 96 97 98

/* --------------------------------------------------------------------------
                             Power Resource Management
   -------------------------------------------------------------------------- */

static int
L
Len Brown 已提交
99 100
acpi_power_get_context(acpi_handle handle,
		       struct acpi_power_resource **resource)
L
Linus Torvalds 已提交
101
{
L
Len Brown 已提交
102 103
	int result = 0;
	struct acpi_device *device = NULL;
L
Linus Torvalds 已提交
104 105 106


	if (!resource)
107
		return -ENODEV;
L
Linus Torvalds 已提交
108 109 110

	result = acpi_bus_get_device(handle, &device);
	if (result) {
111
		printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle);
112
		return result;
L
Linus Torvalds 已提交
113 114
	}

115
	*resource = acpi_driver_data(device);
116
	if (!*resource)
117
		return -ENODEV;
L
Linus Torvalds 已提交
118

119
	return 0;
L
Linus Torvalds 已提交
120 121
}

122
static int acpi_power_get_state(acpi_handle handle, int *state)
L
Linus Torvalds 已提交
123
{
L
Len Brown 已提交
124
	acpi_status status = AE_OK;
125
	unsigned long long sta = 0;
126 127
	char node_name[5];
	struct acpi_buffer buffer = { sizeof(node_name), node_name };
L
Linus Torvalds 已提交
128 129


130
	if (!handle || !state)
131
		return -EINVAL;
L
Linus Torvalds 已提交
132

133
	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
L
Linus Torvalds 已提交
134
	if (ACPI_FAILURE(status))
135
		return -ENODEV;
L
Linus Torvalds 已提交
136

137 138
	*state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON:
			      ACPI_POWER_RESOURCE_STATE_OFF;
L
Linus Torvalds 已提交
139

140 141
	acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);

L
Linus Torvalds 已提交
142
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
143
			  node_name,
144
				*state ? "on" : "off"));
L
Linus Torvalds 已提交
145

146
	return 0;
L
Linus Torvalds 已提交
147 148
}

L
Len Brown 已提交
149
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
L
Linus Torvalds 已提交
150
{
151
	int result = 0, state1;
L
Len Brown 已提交
152
	u32 i = 0;
L
Linus Torvalds 已提交
153 154 155


	if (!list || !state)
156
		return -EINVAL;
L
Linus Torvalds 已提交
157 158 159

	/* The state of the list is 'on' IFF all resources are 'on'. */

L
Len Brown 已提交
160
	for (i = 0; i < list->count; i++) {
161 162 163 164 165 166
		/*
		 * The state of the power resource can be obtained by
		 * using the ACPI handle. In such case it is unnecessary to
		 * get the Power resource first and then get its state again.
		 */
		result = acpi_power_get_state(list->handles[i], &state1);
L
Linus Torvalds 已提交
167
		if (result)
168
			return result;
L
Linus Torvalds 已提交
169

170
		*state = state1;
L
Linus Torvalds 已提交
171 172 173 174 175 176

		if (*state != ACPI_POWER_RESOURCE_STATE_ON)
			break;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
L
Len Brown 已提交
177
			  *state ? "on" : "off"));
L
Linus Torvalds 已提交
178

179
	return result;
L
Linus Torvalds 已提交
180 181
}

182
static int __acpi_power_on(struct acpi_power_resource *resource)
L
Linus Torvalds 已提交
183
{
L
Len Brown 已提交
184
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
185

186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
	status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	/* Update the power resource's _device_ power state */
	resource->device->power.state = ACPI_STATE_D0;

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
			  resource->name));

	return 0;
}

static int acpi_power_on(acpi_handle handle)
{
	int result = 0;
	struct acpi_power_resource *resource = NULL;
L
Linus Torvalds 已提交
203 204 205

	result = acpi_power_get_context(handle, &resource);
	if (result)
206
		return result;
L
Linus Torvalds 已提交
207

208 209
	mutex_lock(&resource->resource_lock);

210 211 212 213 214 215
	if (resource->ref_count++) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] already on",
				  resource->name));
	} else {
		result = __acpi_power_on(resource);
216 217
		if (result)
			resource->ref_count--;
218
	}
L
Linus Torvalds 已提交
219

220
	mutex_unlock(&resource->resource_lock);
L
Linus Torvalds 已提交
221

222
	return result;
L
Linus Torvalds 已提交
223 224
}

225
static int acpi_power_off_device(acpi_handle handle)
L
Linus Torvalds 已提交
226
{
227
	int result = 0;
L
Len Brown 已提交
228
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
229
	struct acpi_power_resource *resource = NULL;
230

L
Linus Torvalds 已提交
231 232
	result = acpi_power_get_context(handle, &resource);
	if (result)
233
		return result;
L
Linus Torvalds 已提交
234

235
	mutex_lock(&resource->resource_lock);
236 237 238 239 240 241

	if (!resource->ref_count) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] already off",
				  resource->name));
		goto unlock;
242
	}
L
Linus Torvalds 已提交
243

244 245 246 247 248
	if (--resource->ref_count) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] still in use\n",
				  resource->name));
		goto unlock;
L
Linus Torvalds 已提交
249 250
	}

251
	status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
252 253 254 255 256
	if (ACPI_FAILURE(status)) {
		result = -ENODEV;
	} else {
		/* Update the power resource's _device_ power state */
		resource->device->power.state = ACPI_STATE_D3;
L
Linus Torvalds 已提交
257

258 259 260 261
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] turned off\n",
				  resource->name));
	}
L
Linus Torvalds 已提交
262

263 264
 unlock:
	mutex_unlock(&resource->resource_lock);
L
Linus Torvalds 已提交
265

266
	return result;
L
Linus Torvalds 已提交
267 268
}

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
{
	int i;

	for (i = num_res - 1; i >= 0 ; i--)
		acpi_power_off_device(list->handles[i]);
}

static void acpi_power_off_list(struct acpi_handle_list *list)
{
	__acpi_power_off_list(list, list->count);
}

static int acpi_power_on_list(struct acpi_handle_list *list)
{
	int result = 0;
	int i;

	for (i = 0; i < list->count; i++) {
		result = acpi_power_on(list->handles[i]);
		if (result) {
			__acpi_power_off_list(list, i);
			break;
		}
	}

	return result;
}

298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
/**
 * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
 *                          ACPI 3.0) _PSW (Power State Wake)
 * @dev: Device to handle.
 * @enable: 0 - disable, 1 - enable the wake capabilities of the device.
 * @sleep_state: Target sleep state of the system.
 * @dev_state: Target power state of the device.
 *
 * Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 * State Wake) for the device, if present.  On failure reset the device's
 * wakeup.flags.valid flag.
 *
 * RETURN VALUE:
 * 0 if either _DSW or _PSW has been successfully executed
 * 0 if neither _DSW nor _PSW has been found
 * -ENODEV if the execution of either _DSW or _PSW has failed
 */
int acpi_device_sleep_wake(struct acpi_device *dev,
                           int enable, int sleep_state, int dev_state)
{
	union acpi_object in_arg[3];
	struct acpi_object_list arg_list = { 3, in_arg };
	acpi_status status = AE_OK;

	/*
	 * Try to execute _DSW first.
	 *
	 * Three agruments are needed for the _DSW object:
	 * Argument 0: enable/disable the wake capabilities
	 * Argument 1: target system state
	 * Argument 2: target device state
	 * When _DSW object is called to disable the wake capabilities, maybe
	 * the first argument is filled. The values of the other two agruments
	 * are meaningless.
	 */
	in_arg[0].type = ACPI_TYPE_INTEGER;
	in_arg[0].integer.value = enable;
	in_arg[1].type = ACPI_TYPE_INTEGER;
	in_arg[1].integer.value = sleep_state;
	in_arg[2].type = ACPI_TYPE_INTEGER;
	in_arg[2].integer.value = dev_state;
	status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL);
	if (ACPI_SUCCESS(status)) {
		return 0;
	} else if (status != AE_NOT_FOUND) {
		printk(KERN_ERR PREFIX "_DSW execution failed\n");
		dev->wakeup.flags.valid = 0;
		return -ENODEV;
	}

	/* Execute _PSW */
	arg_list.count = 1;
	in_arg[0].integer.value = enable;
	status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
		printk(KERN_ERR PREFIX "_PSW execution failed\n");
		dev->wakeup.flags.valid = 0;
		return -ENODEV;
	}

	return 0;
}

L
Linus Torvalds 已提交
361 362 363
/*
 * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229):
 * 1. Power on the power resources required for the wakeup device 
364 365
 * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 *    State Wake) for the device, if present
L
Linus Torvalds 已提交
366
 */
367
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
L
Linus Torvalds 已提交
368
{
369
	int i, err = 0;
L
Linus Torvalds 已提交
370 371

	if (!dev || !dev->wakeup.flags.valid)
372
		return -EINVAL;
L
Linus Torvalds 已提交
373

374 375 376 377
	mutex_lock(&acpi_device_lock);

	if (dev->wakeup.prepare_count++)
		goto out;
378

L
Linus Torvalds 已提交
379 380
	/* Open power resource */
	for (i = 0; i < dev->wakeup.resources.count; i++) {
381
		int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
L
Linus Torvalds 已提交
382
		if (ret) {
383
			printk(KERN_ERR PREFIX "Transition power state\n");
L
Linus Torvalds 已提交
384
			dev->wakeup.flags.valid = 0;
385 386
			err = -ENODEV;
			goto err_out;
L
Linus Torvalds 已提交
387 388 389
		}
	}

390 391 392 393
	/*
	 * Passing 3 as the third argument below means the device may be placed
	 * in arbitrary power state afterwards.
	 */
394 395
	err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);

396 397 398 399 400 401
 err_out:
	if (err)
		dev->wakeup.prepare_count = 0;

 out:
	mutex_unlock(&acpi_device_lock);
402
	return err;
L
Linus Torvalds 已提交
403 404 405 406
}

/*
 * Shutdown a wakeup device, counterpart of above method
407 408
 * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 *    State Wake) for the device, if present
L
Linus Torvalds 已提交
409 410
 * 2. Shutdown down the power resources
 */
L
Len Brown 已提交
411
int acpi_disable_wakeup_device_power(struct acpi_device *dev)
L
Linus Torvalds 已提交
412
{
413
	int i, err = 0;
L
Linus Torvalds 已提交
414 415

	if (!dev || !dev->wakeup.flags.valid)
416
		return -EINVAL;
L
Linus Torvalds 已提交
417

418 419 420 421 422
	mutex_lock(&acpi_device_lock);

	if (--dev->wakeup.prepare_count > 0)
		goto out;

423
	/*
424 425
	 * Executing the code below even if prepare_count is already zero when
	 * the function is called may be useful, for example for initialisation.
426
	 */
427 428
	if (dev->wakeup.prepare_count < 0)
		dev->wakeup.prepare_count = 0;
429

430 431 432
	err = acpi_device_sleep_wake(dev, 0, 0, 0);
	if (err)
		goto out;
L
Linus Torvalds 已提交
433 434 435

	/* Close power resource */
	for (i = 0; i < dev->wakeup.resources.count; i++) {
436
		int ret = acpi_power_off_device(
437
				dev->wakeup.resources.handles[i]);
L
Linus Torvalds 已提交
438
		if (ret) {
439
			printk(KERN_ERR PREFIX "Transition power state\n");
L
Linus Torvalds 已提交
440
			dev->wakeup.flags.valid = 0;
441 442
			err = -ENODEV;
			goto out;
L
Linus Torvalds 已提交
443 444 445
		}
	}

446 447 448
 out:
	mutex_unlock(&acpi_device_lock);
	return err;
L
Linus Torvalds 已提交
449 450 451 452 453 454
}

/* --------------------------------------------------------------------------
                             Device Power Management
   -------------------------------------------------------------------------- */

455
int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
L
Linus Torvalds 已提交
456
{
L
Len Brown 已提交
457 458 459 460
	int result = 0;
	struct acpi_handle_list *list = NULL;
	int list_state = 0;
	int i = 0;
L
Linus Torvalds 已提交
461

462
	if (!device || !state)
463
		return -EINVAL;
L
Linus Torvalds 已提交
464 465 466 467 468

	/*
	 * We know a device's inferred power state when all the resources
	 * required for a given D-state are 'on'.
	 */
L
Len Brown 已提交
469
	for (i = ACPI_STATE_D0; i < ACPI_STATE_D3; i++) {
L
Linus Torvalds 已提交
470 471 472 473 474 475
		list = &device->power.states[i].resources;
		if (list->count < 1)
			continue;

		result = acpi_power_get_list_state(list, &list_state);
		if (result)
476
			return result;
L
Linus Torvalds 已提交
477 478

		if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
479
			*state = i;
480
			return 0;
L
Linus Torvalds 已提交
481 482 483
		}
	}

484
	*state = ACPI_STATE_D3;
485
	return 0;
L
Linus Torvalds 已提交
486 487
}

L
Len Brown 已提交
488
int acpi_power_transition(struct acpi_device *device, int state)
L
Linus Torvalds 已提交
489
{
490
	int result;
L
Linus Torvalds 已提交
491 492

	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
493
		return -EINVAL;
L
Linus Torvalds 已提交
494

495 496 497
	if (device->power.state == state)
		return 0;

L
Len Brown 已提交
498 499
	if ((device->power.state < ACPI_STATE_D0)
	    || (device->power.state > ACPI_STATE_D3))
500
		return -ENODEV;
L
Linus Torvalds 已提交
501 502 503 504 505

	/* TBD: Resources must be ordered. */

	/*
	 * First we reference all power resources required in the target list
506 507
	 * (e.g. so the device doesn't lose power while transitioning).  Then,
	 * we dereference all power resources used in the current list.
L
Linus Torvalds 已提交
508
	 */
509 510 511 512
	result = acpi_power_on_list(&device->power.states[state].resources);
	if (!result)
		acpi_power_off_list(
			&device->power.states[device->power.state].resources);
L
Linus Torvalds 已提交
513

514 515
	/* We shouldn't change the state unless the above operations succeed. */
	device->power.state = result ? ACPI_STATE_UNKNOWN : state;
L
Linus Torvalds 已提交
516

517
	return result;
L
Linus Torvalds 已提交
518 519 520 521 522 523
}

/* --------------------------------------------------------------------------
                                Driver Interface
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
524
static int acpi_power_add(struct acpi_device *device)
L
Linus Torvalds 已提交
525
{
526
	int result = 0, state;
L
Len Brown 已提交
527
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
528
	struct acpi_power_resource *resource = NULL;
L
Len Brown 已提交
529 530
	union acpi_object acpi_object;
	struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
L
Linus Torvalds 已提交
531 532 533


	if (!device)
534
		return -EINVAL;
L
Linus Torvalds 已提交
535

536
	resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
L
Linus Torvalds 已提交
537
	if (!resource)
538
		return -ENOMEM;
L
Linus Torvalds 已提交
539

540
	resource->device = device;
541
	mutex_init(&resource->resource_lock);
L
Linus Torvalds 已提交
542 543 544
	strcpy(resource->name, device->pnp.bus_id);
	strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
545
	device->driver_data = resource;
L
Linus Torvalds 已提交
546 547

	/* Evalute the object to get the system level and resource order. */
548
	status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
L
Linus Torvalds 已提交
549 550 551 552 553 554 555
	if (ACPI_FAILURE(status)) {
		result = -ENODEV;
		goto end;
	}
	resource->system_level = acpi_object.power_resource.system_level;
	resource->order = acpi_object.power_resource.resource_order;

556
	result = acpi_power_get_state(device->handle, &state);
L
Linus Torvalds 已提交
557 558 559
	if (result)
		goto end;

560
	switch (state) {
L
Linus Torvalds 已提交
561 562 563 564 565 566 567 568 569 570 571 572
	case ACPI_POWER_RESOURCE_STATE_ON:
		device->power.state = ACPI_STATE_D0;
		break;
	case ACPI_POWER_RESOURCE_STATE_OFF:
		device->power.state = ACPI_STATE_D3;
		break;
	default:
		device->power.state = ACPI_STATE_UNKNOWN;
		break;
	}

	printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
573
	       acpi_device_bid(device), state ? "on" : "off");
L
Linus Torvalds 已提交
574

L
Len Brown 已提交
575
      end:
L
Linus Torvalds 已提交
576 577
	if (result)
		kfree(resource);
L
Len Brown 已提交
578

579
	return result;
L
Linus Torvalds 已提交
580 581
}

L
Len Brown 已提交
582
static int acpi_power_remove(struct acpi_device *device, int type)
L
Linus Torvalds 已提交
583
{
584
	struct acpi_power_resource *resource;
L
Linus Torvalds 已提交
585

586
	if (!device)
587
		return -EINVAL;
L
Linus Torvalds 已提交
588

589
	resource = acpi_driver_data(device);
590 591
	if (!resource)
		return -EINVAL;
592

L
Linus Torvalds 已提交
593 594
	kfree(resource);

595
	return 0;
L
Linus Torvalds 已提交
596 597
}

598
static int acpi_power_resume(struct acpi_device *device)
599
{
600
	int result = 0, state;
601
	struct acpi_power_resource *resource;
602

603
	if (!device)
604 605
		return -EINVAL;

606
	resource = acpi_driver_data(device);
607 608 609 610
	if (!resource)
		return -EINVAL;

	mutex_lock(&resource->resource_lock);
611

612
	result = acpi_power_get_state(device->handle, &state);
613
	if (result)
614
		goto unlock;
615

616 617
	if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
		result = __acpi_power_on(resource);
618

619
 unlock:
620
	mutex_unlock(&resource->resource_lock);
621 622

	return result;
623 624
}

625
int __init acpi_power_init(void)
L
Linus Torvalds 已提交
626 627
{
	INIT_LIST_HEAD(&acpi_power_resource_list);
628
	return acpi_bus_register_driver(&acpi_power_driver);
L
Linus Torvalds 已提交
629
}