power.c 16.1 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

L
Len Brown 已提交
59 60
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
61
static int acpi_power_resume(struct acpi_device *device);
L
Linus Torvalds 已提交
62

63
static const struct acpi_device_id power_device_ids[] = {
64 65 66 67 68
	{ACPI_POWER_HID, 0},
	{"", 0},
};
MODULE_DEVICE_TABLE(acpi, power_device_ids);

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

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

L
Len Brown 已提交
89
static struct list_head acpi_power_resource_list;
L
Linus Torvalds 已提交
90 91 92 93 94 95

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

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


	if (!resource)
104
		return -ENODEV;
L
Linus Torvalds 已提交
105 106 107

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

112
	*resource = acpi_driver_data(device);
113
	if (!*resource)
114
		return -ENODEV;
L
Linus Torvalds 已提交
115

116
	return 0;
L
Linus Torvalds 已提交
117 118
}

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


127
	if (!handle || !state)
128
		return -EINVAL;
L
Linus Torvalds 已提交
129

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

134 135
	*state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON:
			      ACPI_POWER_RESOURCE_STATE_OFF;
L
Linus Torvalds 已提交
136

137 138
	acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);

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

143
	return 0;
L
Linus Torvalds 已提交
144 145
}

L
Len Brown 已提交
146
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
L
Linus Torvalds 已提交
147
{
148 149
	int cur_state;
	int i = 0;
L
Linus Torvalds 已提交
150 151

	if (!list || !state)
152
		return -EINVAL;
L
Linus Torvalds 已提交
153 154 155

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

L
Len Brown 已提交
156
	for (i = 0; i < list->count; i++) {
157 158 159 160 161
		struct acpi_power_resource *resource;
		acpi_handle handle = list->handles[i];
		int result;

		result = acpi_power_get_context(handle, &resource);
L
Linus Torvalds 已提交
162
		if (result)
163
			return result;
L
Linus Torvalds 已提交
164

165 166 167
		mutex_lock(&resource->resource_lock);

		result = acpi_power_get_state(handle, &cur_state);
L
Linus Torvalds 已提交
168

169 170 171 172 173 174
		mutex_unlock(&resource->resource_lock);

		if (result)
			return result;

		if (cur_state != ACPI_POWER_RESOURCE_STATE_ON)
L
Linus Torvalds 已提交
175 176 177 178
			break;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
179
			  cur_state ? "on" : "off"));
L
Linus Torvalds 已提交
180

181 182 183
	*state = cur_state;

	return 0;
L
Linus Torvalds 已提交
184 185
}

186
static int __acpi_power_on(struct acpi_power_resource *resource)
L
Linus Torvalds 已提交
187
{
L
Len Brown 已提交
188
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
189

190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
	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 已提交
207 208 209

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

212 213
	mutex_lock(&resource->resource_lock);

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

224
	mutex_unlock(&resource->resource_lock);
L
Linus Torvalds 已提交
225

226
	return result;
L
Linus Torvalds 已提交
227 228
}

229
static int acpi_power_off(acpi_handle handle)
L
Linus Torvalds 已提交
230
{
231
	int result = 0;
L
Len Brown 已提交
232
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
233
	struct acpi_power_resource *resource = NULL;
234

L
Linus Torvalds 已提交
235 236
	result = acpi_power_get_context(handle, &resource);
	if (result)
237
		return result;
L
Linus Torvalds 已提交
238

239
	mutex_lock(&resource->resource_lock);
240 241 242 243 244 245

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

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

255
	status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
256 257 258 259 260
	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 已提交
261

262 263 264 265
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] turned off\n",
				  resource->name));
	}
L
Linus Torvalds 已提交
266

267 268
 unlock:
	mutex_unlock(&resource->resource_lock);
L
Linus Torvalds 已提交
269

270
	return result;
L
Linus Torvalds 已提交
271 272
}

273 274 275 276 277
static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
{
	int i;

	for (i = num_res - 1; i >= 0 ; i--)
278
		acpi_power_off(list->handles[i]);
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
}

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;
}

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

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

378 379 380 381
	mutex_lock(&acpi_device_lock);

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

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

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

400 401 402 403 404 405
 err_out:
	if (err)
		dev->wakeup.prepare_count = 0;

 out:
	mutex_unlock(&acpi_device_lock);
406
	return err;
L
Linus Torvalds 已提交
407 408 409 410
}

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

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

422 423 424 425 426
	mutex_lock(&acpi_device_lock);

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

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

434 435 436
	err = acpi_device_sleep_wake(dev, 0, 0, 0);
	if (err)
		goto out;
L
Linus Torvalds 已提交
437 438 439

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

449 450 451
 out:
	mutex_unlock(&acpi_device_lock);
	return err;
L
Linus Torvalds 已提交
452 453 454 455 456 457
}

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

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

465
	if (!device || !state)
466
		return -EINVAL;
L
Linus Torvalds 已提交
467 468 469 470 471

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

		result = acpi_power_get_list_state(list, &list_state);
		if (result)
479
			return result;
L
Linus Torvalds 已提交
480 481

		if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
482
			*state = i;
483
			return 0;
L
Linus Torvalds 已提交
484 485 486
		}
	}

487
	*state = ACPI_STATE_D3;
488
	return 0;
L
Linus Torvalds 已提交
489 490
}

491 492 493 494 495 496 497 498
int acpi_power_on_resources(struct acpi_device *device, int state)
{
	if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
		return -EINVAL;

	return acpi_power_on_list(&device->power.states[state].resources);
}

L
Len Brown 已提交
499
int acpi_power_transition(struct acpi_device *device, int state)
L
Linus Torvalds 已提交
500
{
501
	int result;
L
Linus Torvalds 已提交
502

503
	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
504
		return -EINVAL;
L
Linus Torvalds 已提交
505

506 507 508
	if (device->power.state == state)
		return 0;

L
Len Brown 已提交
509
	if ((device->power.state < ACPI_STATE_D0)
510
	    || (device->power.state > ACPI_STATE_D3_COLD))
511
		return -ENODEV;
L
Linus Torvalds 已提交
512 513 514 515 516

	/* TBD: Resources must be ordered. */

	/*
	 * First we reference all power resources required in the target list
517 518
	 * (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 已提交
519
	 */
520 521 522 523
	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 已提交
524

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

528
	return result;
L
Linus Torvalds 已提交
529 530 531 532 533 534
}

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

L
Len Brown 已提交
535
static int acpi_power_add(struct acpi_device *device)
L
Linus Torvalds 已提交
536
{
537
	int result = 0, state;
L
Len Brown 已提交
538
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
539
	struct acpi_power_resource *resource = NULL;
L
Len Brown 已提交
540 541
	union acpi_object acpi_object;
	struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
L
Linus Torvalds 已提交
542 543 544


	if (!device)
545
		return -EINVAL;
L
Linus Torvalds 已提交
546

547
	resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
L
Linus Torvalds 已提交
548
	if (!resource)
549
		return -ENOMEM;
L
Linus Torvalds 已提交
550

551
	resource->device = device;
552
	mutex_init(&resource->resource_lock);
L
Linus Torvalds 已提交
553 554 555
	strcpy(resource->name, device->pnp.bus_id);
	strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
556
	device->driver_data = resource;
L
Linus Torvalds 已提交
557 558

	/* Evalute the object to get the system level and resource order. */
559
	status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
L
Linus Torvalds 已提交
560 561 562 563 564 565 566
	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;

567
	result = acpi_power_get_state(device->handle, &state);
L
Linus Torvalds 已提交
568 569 570
	if (result)
		goto end;

571
	switch (state) {
L
Linus Torvalds 已提交
572 573 574 575 576 577 578 579 580 581 582 583
	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),
584
	       acpi_device_bid(device), state ? "on" : "off");
L
Linus Torvalds 已提交
585

L
Len Brown 已提交
586
      end:
L
Linus Torvalds 已提交
587 588
	if (result)
		kfree(resource);
L
Len Brown 已提交
589

590
	return result;
L
Linus Torvalds 已提交
591 592
}

L
Len Brown 已提交
593
static int acpi_power_remove(struct acpi_device *device, int type)
L
Linus Torvalds 已提交
594
{
595
	struct acpi_power_resource *resource;
L
Linus Torvalds 已提交
596

597
	if (!device)
598
		return -EINVAL;
L
Linus Torvalds 已提交
599

600
	resource = acpi_driver_data(device);
601 602
	if (!resource)
		return -EINVAL;
603

L
Linus Torvalds 已提交
604 605
	kfree(resource);

606
	return 0;
L
Linus Torvalds 已提交
607 608
}

609
static int acpi_power_resume(struct acpi_device *device)
610
{
611
	int result = 0, state;
612
	struct acpi_power_resource *resource;
613

614
	if (!device)
615 616
		return -EINVAL;

617
	resource = acpi_driver_data(device);
618 619 620 621
	if (!resource)
		return -EINVAL;

	mutex_lock(&resource->resource_lock);
622

623
	result = acpi_power_get_state(device->handle, &state);
624
	if (result)
625
		goto unlock;
626

627 628
	if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
		result = __acpi_power_on(resource);
629

630
 unlock:
631
	mutex_unlock(&resource->resource_lock);
632 633

	return result;
634 635
}

636
int __init acpi_power_init(void)
L
Linus Torvalds 已提交
637 638
{
	INIT_LIST_HEAD(&acpi_power_resource_list);
639
	return acpi_bus_register_driver(&acpi_power_driver);
L
Linus Torvalds 已提交
640
}