scan.c 42.6 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6
/*
 * scan.c - support for transforming the ACPI namespace into individual objects
 */

#include <linux/module.h>
#include <linux/init.h>
7
#include <linux/slab.h>
8
#include <linux/kernel.h>
Linus Torvalds's avatar
Linus Torvalds committed
9
#include <linux/acpi.h>
10 11
#include <linux/signal.h>
#include <linux/kthread.h>
12
#include <linux/dmi.h>
13
#include <linux/nls.h>
Linus Torvalds's avatar
Linus Torvalds committed
14 15 16

#include <acpi/acpi_drivers.h>

17 18
#include "internal.h"

Linus Torvalds's avatar
Linus Torvalds committed
19
#define _COMPONENT		ACPI_BUS_COMPONENT
20
ACPI_MODULE_NAME("scan");
Linus Torvalds's avatar
Linus Torvalds committed
21
#define STRUCT_TO_INT(s)	(*((int*)&s))
Len Brown's avatar
Len Brown committed
22
extern struct acpi_device *acpi_root;
Linus Torvalds's avatar
Linus Torvalds committed
23 24

#define ACPI_BUS_CLASS			"system_bus"
25
#define ACPI_BUS_HID			"LNXSYBUS"
Linus Torvalds's avatar
Linus Torvalds committed
26 27
#define ACPI_BUS_DEVICE_NAME		"System Bus"

28 29
#define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)

30
static const char *dummy_hid = "device";
31

Linus Torvalds's avatar
Linus Torvalds committed
32
static LIST_HEAD(acpi_device_list);
33
static LIST_HEAD(acpi_bus_id_list);
34
DEFINE_MUTEX(acpi_device_lock);
Linus Torvalds's avatar
Linus Torvalds committed
35 36
LIST_HEAD(acpi_wakeup_device_list);

37
struct acpi_device_bus_id{
38
	char bus_id[15];
39 40
	unsigned int instance_no;
	struct list_head node;
Linus Torvalds's avatar
Linus Torvalds committed
41
};
42 43 44 45 46 47

/*
 * Creates hid/cid(s) string needed for modalias and uevent
 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
 * char *modalias: "acpi:IBM0001:ACPI0001"
*/
48 49 50
static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
			   int size)
{
51
	int len;
52
	int count;
53
	struct acpi_hardware_id *id;
54

55 56 57
	if (list_empty(&acpi_dev->pnp.ids))
		return 0;

58
	len = snprintf(modalias, size, "acpi:");
59 60
	size -= len;

61 62
	list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
		count = snprintf(&modalias[len], size, "%s:", id->id);
63 64 65 66 67 68
		if (count < 0 || count >= size)
			return -EINVAL;
		len += count;
		size -= count;
	}

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
	modalias[len] = '\0';
	return len;
}

static ssize_t
acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	int len;

	/* Device has no HID and no CID or string is >1024 */
	len = create_modalias(acpi_dev, buf, 1024);
	if (len <= 0)
		return 0;
	buf[len++] = '\n';
	return len;
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);

87 88 89 90 91 92 93 94 95
/**
 * acpi_bus_hot_remove_device: hot-remove a device and its children
 * @context: struct acpi_eject_event pointer (freed in this func)
 *
 * Hot-remove a device and its children. This function frees up the
 * memory space passed by arg context, so that the caller may call
 * this function asynchronously through acpi_os_hotplug_execute().
 */
void acpi_bus_hot_remove_device(void *context)
Linus Torvalds's avatar
Linus Torvalds committed
96
{
97
	struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
98
	struct acpi_device *device;
99
	acpi_handle handle = ej_event->handle;
100
	acpi_handle temp;
Linus Torvalds's avatar
Linus Torvalds committed
101 102 103
	struct acpi_object_list arg_list;
	union acpi_object arg;
	acpi_status status = AE_OK;
104
	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
Linus Torvalds's avatar
Linus Torvalds committed
105

106
	if (acpi_bus_get_device(handle, &device))
107
		goto err_out;
108 109

	if (!device)
110
		goto err_out;
111 112

	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
113
		"Hot-removing device %s...\n", dev_name(&device->dev)));
114 115

	if (acpi_bus_trim(device, 1)) {
116 117
		printk(KERN_ERR PREFIX
				"Removing device failed\n");
118
		goto err_out;
119
	}
Linus Torvalds's avatar
Linus Torvalds committed
120

121 122 123
	/* device has been freed */
	device = NULL;

124 125 126
	/* power off device */
	status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
127 128
		printk(KERN_WARNING PREFIX
				"Power-off device failed\n");
129

130
	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
Linus Torvalds's avatar
Linus Torvalds committed
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
		arg_list.count = 1;
		arg_list.pointer = &arg;
		arg.type = ACPI_TYPE_INTEGER;
		arg.integer.value = 0;
		acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
	}

	arg_list.count = 1;
	arg_list.pointer = &arg;
	arg.type = ACPI_TYPE_INTEGER;
	arg.integer.value = 1;

	/*
	 * TBD: _EJD support.
	 */
	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
147 148 149 150 151 152
	if (ACPI_FAILURE(status)) {
		if (status != AE_NOT_FOUND)
			printk(KERN_WARNING PREFIX
					"Eject device failed\n");
		goto err_out;
	}
Linus Torvalds's avatar
Linus Torvalds committed
153

154 155
	kfree(context);
	return;
Linus Torvalds's avatar
Linus Torvalds committed
156

157 158 159 160 161
err_out:
	/* Inform firmware the hot-remove operation has completed w/ error */
	(void) acpi_evaluate_hotplug_ost(handle,
				ej_event->event, ost_code, NULL);
	kfree(context);
162
	return;
Linus Torvalds's avatar
Linus Torvalds committed
163
}
164
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
Linus Torvalds's avatar
Linus Torvalds committed
165 166

static ssize_t
167 168
acpi_eject_store(struct device *d, struct device_attribute *attr,
		const char *buf, size_t count)
Linus Torvalds's avatar
Linus Torvalds committed
169
{
Len Brown's avatar
Len Brown committed
170 171 172
	int ret = count;
	acpi_status status;
	acpi_object_type type = 0;
173
	struct acpi_device *acpi_device = to_acpi_device(d);
174
	struct acpi_eject_event *ej_event;
Linus Torvalds's avatar
Linus Torvalds committed
175 176 177 178 179

	if ((!count) || (buf[0] != '1')) {
		return -EINVAL;
	}
#ifndef FORCE_EJECT
180
	if (acpi_device->driver == NULL) {
Linus Torvalds's avatar
Linus Torvalds committed
181 182 183 184
		ret = -ENODEV;
		goto err;
	}
#endif
185 186
	status = acpi_get_type(acpi_device->handle, &type);
	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
Linus Torvalds's avatar
Linus Torvalds committed
187 188 189 190
		ret = -ENODEV;
		goto err;
	}

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
	if (!ej_event) {
		ret = -ENOMEM;
		goto err;
	}

	ej_event->handle = acpi_device->handle;
	if (acpi_device->flags.eject_pending) {
		/* event originated from ACPI eject notification */
		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
		acpi_device->flags.eject_pending = 0;
	} else {
		/* event originated from user */
		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
		(void) acpi_evaluate_hotplug_ost(ej_event->handle,
			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
	}

	acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event);
210
err:
Linus Torvalds's avatar
Linus Torvalds committed
211 212 213
	return ret;
}

214
static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
Linus Torvalds's avatar
Linus Torvalds committed
215

216 217 218
static ssize_t
acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
	struct acpi_device *acpi_dev = to_acpi_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
219

220
	return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
Linus Torvalds's avatar
Linus Torvalds committed
221
}
222
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
static ssize_t acpi_device_uid_show(struct device *dev,
				    struct device_attribute *attr, char *buf)
{
	struct acpi_device *acpi_dev = to_acpi_device(dev);

	return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id);
}
static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);

static ssize_t acpi_device_adr_show(struct device *dev,
				    struct device_attribute *attr, char *buf)
{
	struct acpi_device *acpi_dev = to_acpi_device(dev);

	return sprintf(buf, "0x%08x\n",
		       (unsigned int)(acpi_dev->pnp.bus_address));
}
static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);

243 244 245 246 247
static ssize_t
acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
	int result;
Linus Torvalds's avatar
Linus Torvalds committed
248

249
	result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
250
	if (result)
251
		goto end;
Linus Torvalds's avatar
Linus Torvalds committed
252

253 254
	result = sprintf(buf, "%s\n", (char*)path.pointer);
	kfree(path.pointer);
255
end:
256
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
257
}
258
static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
259

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
/* sysfs file that shows description text from the ACPI _STR method */
static ssize_t description_show(struct device *dev,
				struct device_attribute *attr,
				char *buf) {
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	int result;

	if (acpi_dev->pnp.str_obj == NULL)
		return 0;

	/*
	 * The _STR object contains a Unicode identifier for a device.
	 * We need to convert to utf-8 so it can be displayed.
	 */
	result = utf16s_to_utf8s(
		(wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
		acpi_dev->pnp.str_obj->buffer.length,
		UTF16_LITTLE_ENDIAN, buf,
		PAGE_SIZE);

	buf[result++] = '\n';

	return result;
}
static DEVICE_ATTR(description, 0444, description_show, NULL);

286
static int acpi_device_setup_files(struct acpi_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
287
{
288
	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
289 290
	acpi_status status;
	acpi_handle temp;
291
	int result = 0;
Linus Torvalds's avatar
Linus Torvalds committed
292 293

	/*
294
	 * Devices gotten from FADT don't have a "path" attribute
Linus Torvalds's avatar
Linus Torvalds committed
295
	 */
296
	if (dev->handle) {
297
		result = device_create_file(&dev->dev, &dev_attr_path);
298
		if (result)
299
			goto end;
Linus Torvalds's avatar
Linus Torvalds committed
300 301
	}

302 303 304 305
	if (!list_empty(&dev->pnp.ids)) {
		result = device_create_file(&dev->dev, &dev_attr_hid);
		if (result)
			goto end;
Linus Torvalds's avatar
Linus Torvalds committed
306

307 308 309 310
		result = device_create_file(&dev->dev, &dev_attr_modalias);
		if (result)
			goto end;
	}
311

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
	/*
	 * If device has _STR, 'description' file is created
	 */
	status = acpi_get_handle(dev->handle, "_STR", &temp);
	if (ACPI_SUCCESS(status)) {
		status = acpi_evaluate_object(dev->handle, "_STR",
					NULL, &buffer);
		if (ACPI_FAILURE(status))
			buffer.pointer = NULL;
		dev->pnp.str_obj = buffer.pointer;
		result = device_create_file(&dev->dev, &dev_attr_description);
		if (result)
			goto end;
	}

327 328 329 330 331
	if (dev->flags.bus_address)
		result = device_create_file(&dev->dev, &dev_attr_adr);
	if (dev->pnp.unique_id)
		result = device_create_file(&dev->dev, &dev_attr_uid);

332 333 334 335
        /*
         * If device has _EJ0, 'eject' file is created that is used to trigger
         * hot-removal function from userland.
         */
336 337
	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
	if (ACPI_SUCCESS(status))
338
		result = device_create_file(&dev->dev, &dev_attr_eject);
339
end:
340
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
341 342
}

343
static void acpi_device_remove_files(struct acpi_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
344
{
345 346
	acpi_status status;
	acpi_handle temp;
Linus Torvalds's avatar
Linus Torvalds committed
347

348
	/*
349 350 351 352 353 354 355 356 357
	 * If device has _STR, remove 'description' file
	 */
	status = acpi_get_handle(dev->handle, "_STR", &temp);
	if (ACPI_SUCCESS(status)) {
		kfree(dev->pnp.str_obj);
		device_remove_file(&dev->dev, &dev_attr_description);
	}
	/*
	 * If device has _EJ0, remove 'eject' file.
358 359 360 361
	 */
	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
	if (ACPI_SUCCESS(status))
		device_remove_file(&dev->dev, &dev_attr_eject);
Linus Torvalds's avatar
Linus Torvalds committed
362

363 364 365 366
	if (dev->pnp.unique_id)
		device_remove_file(&dev->dev, &dev_attr_uid);
	if (dev->flags.bus_address)
		device_remove_file(&dev->dev, &dev_attr_adr);
367 368
	device_remove_file(&dev->dev, &dev_attr_modalias);
	device_remove_file(&dev->dev, &dev_attr_hid);
369
	if (dev->handle)
370
		device_remove_file(&dev->dev, &dev_attr_path);
Linus Torvalds's avatar
Linus Torvalds committed
371 372
}
/* --------------------------------------------------------------------------
Zhang Rui's avatar
Zhang Rui committed
373
			ACPI Bus operations
Linus Torvalds's avatar
Linus Torvalds committed
374
   -------------------------------------------------------------------------- */
375 376 377 378 379

int acpi_match_device_ids(struct acpi_device *device,
			  const struct acpi_device_id *ids)
{
	const struct acpi_device_id *id;
380
	struct acpi_hardware_id *hwid;
381

382 383 384 385 386 387 388
	/*
	 * If the device is not present, it is unnecessary to load device
	 * driver for it.
	 */
	if (!device->status.present)
		return -ENODEV;

389 390 391
	for (id = ids; id->id[0]; id++)
		list_for_each_entry(hwid, &device->pnp.ids, list)
			if (!strcmp((char *) id->id, hwid->id))
392 393 394 395 396 397
				return 0;

	return -ENOENT;
}
EXPORT_SYMBOL(acpi_match_device_ids);

398 399 400 401 402 403 404 405 406 407
static void acpi_free_ids(struct acpi_device *device)
{
	struct acpi_hardware_id *id, *tmp;

	list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) {
		kfree(id->id);
		kfree(id);
	}
}

408
static void acpi_device_release(struct device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
409
{
410
	struct acpi_device *acpi_dev = to_acpi_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
411

412
	acpi_free_ids(acpi_dev);
413
	kfree(acpi_dev->pnp.unique_id);
414
	kfree(acpi_dev);
Linus Torvalds's avatar
Linus Torvalds committed
415 416
}

417
static int acpi_bus_match(struct device *dev, struct device_driver *drv)
Zhang Rui's avatar
Zhang Rui committed
418
{
419 420
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = to_acpi_driver(drv);
Linus Torvalds's avatar
Linus Torvalds committed
421

422
	return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
423
}
Linus Torvalds's avatar
Linus Torvalds committed
424

425
static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
Linus Torvalds's avatar
Linus Torvalds committed
426
{
427
	struct acpi_device *acpi_dev = to_acpi_device(dev);
428
	int len;
429

430 431 432
	if (list_empty(&acpi_dev->pnp.ids))
		return 0;

433 434 435 436 437 438 439
	if (add_uevent_var(env, "MODALIAS="))
		return -ENOMEM;
	len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
			      sizeof(env->buf) - env->buflen);
	if (len >= (sizeof(env->buf) - env->buflen))
		return -ENOMEM;
	env->buflen += len;
Zhang Rui's avatar
Zhang Rui committed
440
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
441 442
}

443 444 445 446 447 448 449 450 451 452 453
static void acpi_device_notify(acpi_handle handle, u32 event, void *data)
{
	struct acpi_device *device = data;

	device->driver->ops.notify(device, event);
}

static acpi_status acpi_device_notify_fixed(void *data)
{
	struct acpi_device *device = data;

454 455
	/* Fixed hardware devices have no handles */
	acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
456 457 458 459 460 461 462
	return AE_OK;
}

static int acpi_device_install_notify_handler(struct acpi_device *device)
{
	acpi_status status;

463
	if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
464 465 466 467
		status =
		    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
						     acpi_device_notify_fixed,
						     device);
468
	else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
		status =
		    acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
						     acpi_device_notify_fixed,
						     device);
	else
		status = acpi_install_notify_handler(device->handle,
						     ACPI_DEVICE_NOTIFY,
						     acpi_device_notify,
						     device);

	if (ACPI_FAILURE(status))
		return -EINVAL;
	return 0;
}

static void acpi_device_remove_notify_handler(struct acpi_device *device)
{
486
	if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
487 488
		acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
						acpi_device_notify_fixed);
489
	else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
490 491 492 493 494 495 496
		acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
						acpi_device_notify_fixed);
	else
		acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
					   acpi_device_notify);
}

497 498 499
static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
static int acpi_start_single_object(struct acpi_device *);
static int acpi_device_probe(struct device * dev)
Linus Torvalds's avatar
Linus Torvalds committed
500
{
501 502 503 504 505 506
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
	int ret;

	ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
	if (!ret) {
507 508
		if (acpi_dev->bus_ops.acpi_op_start)
			acpi_start_single_object(acpi_dev);
509 510 511 512 513 514 515 516 517 518 519

		if (acpi_drv->ops.notify) {
			ret = acpi_device_install_notify_handler(acpi_dev);
			if (ret) {
				if (acpi_drv->ops.remove)
					acpi_drv->ops.remove(acpi_dev,
						     acpi_dev->removal_type);
				return ret;
			}
		}

520 521 522 523 524 525 526
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			"Found driver [%s] for device [%s]\n",
			acpi_drv->name, acpi_dev->pnp.bus_id));
		get_device(dev);
	}
	return ret;
}
Linus Torvalds's avatar
Linus Torvalds committed
527

528 529 530 531 532 533
static int acpi_device_remove(struct device * dev)
{
	struct acpi_device *acpi_dev = to_acpi_device(dev);
	struct acpi_driver *acpi_drv = acpi_dev->driver;

	if (acpi_drv) {
534 535
		if (acpi_drv->ops.notify)
			acpi_device_remove_notify_handler(acpi_dev);
536
		if (acpi_drv->ops.remove)
537
			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
Linus Torvalds's avatar
Linus Torvalds committed
538
	}
539
	acpi_dev->driver = NULL;
540
	acpi_dev->driver_data = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
541

542
	put_device(dev);
Zhang Rui's avatar
Zhang Rui committed
543 544
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
545

546
struct bus_type acpi_bus_type = {
Zhang Rui's avatar
Zhang Rui committed
547
	.name		= "acpi",
548 549 550 551
	.match		= acpi_bus_match,
	.probe		= acpi_device_probe,
	.remove		= acpi_device_remove,
	.uevent		= acpi_device_uevent,
Zhang Rui's avatar
Zhang Rui committed
552 553
};

554
static int acpi_device_register(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
555
{
Len Brown's avatar
Len Brown committed
556
	int result;
557 558
	struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
	int found = 0;
559

Zhang Rui's avatar
Zhang Rui committed
560 561 562 563 564 565 566 567
	/*
	 * Linkage
	 * -------
	 * Link this device to its parent and siblings.
	 */
	INIT_LIST_HEAD(&device->children);
	INIT_LIST_HEAD(&device->node);
	INIT_LIST_HEAD(&device->wakeup_list);
568 569
	INIT_LIST_HEAD(&device->physical_node_list);
	mutex_init(&device->physical_node_lock);
Linus Torvalds's avatar
Linus Torvalds committed
570

571 572 573 574
	new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
	if (!new_bus_id) {
		printk(KERN_ERR PREFIX "Memory allocation error\n");
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
575
	}
576

577
	mutex_lock(&acpi_device_lock);
578 579 580 581 582
	/*
	 * Find suitable bus_id and instance number in acpi_bus_id_list
	 * If failed, create one and link it into acpi_bus_id_list
	 */
	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
583 584 585
		if (!strcmp(acpi_device_bus_id->bus_id,
			    acpi_device_hid(device))) {
			acpi_device_bus_id->instance_no++;
586 587 588 589
			found = 1;
			kfree(new_bus_id);
			break;
		}
Linus Torvalds's avatar
Linus Torvalds committed
590
	}
591
	if (!found) {
592
		acpi_device_bus_id = new_bus_id;
593
		strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
594 595
		acpi_device_bus_id->instance_no = 0;
		list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
Linus Torvalds's avatar
Linus Torvalds committed
596
	}
597
	dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
Linus Torvalds's avatar
Linus Torvalds committed
598

Len Brown's avatar
Len Brown committed
599
	if (device->parent)
Zhang Rui's avatar
Zhang Rui committed
600
		list_add_tail(&device->node, &device->parent->children);
Len Brown's avatar
Len Brown committed
601

Zhang Rui's avatar
Zhang Rui committed
602 603
	if (device->wakeup.flags.valid)
		list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
604
	mutex_unlock(&acpi_device_lock);
Linus Torvalds's avatar
Linus Torvalds committed
605

606
	if (device->parent)
607
		device->dev.parent = &device->parent->dev;
608 609
	device->dev.bus = &acpi_bus_type;
	device->dev.release = &acpi_device_release;
610
	result = device_register(&device->dev);
611
	if (result) {
612
		dev_err(&device->dev, "Error registering device\n");
613
		goto end;
Linus Torvalds's avatar
Linus Torvalds committed
614 615
	}

616
	result = acpi_device_setup_files(device);
617
	if (result)
618 619
		printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
		       dev_name(&device->dev));
Linus Torvalds's avatar
Linus Torvalds committed
620

621
	device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
Linus Torvalds's avatar
Linus Torvalds committed
622
	return 0;
623
end:
624
	mutex_lock(&acpi_device_lock);
Len Brown's avatar
Len Brown committed
625
	if (device->parent)
626 627
		list_del(&device->node);
	list_del(&device->wakeup_list);
628
	mutex_unlock(&acpi_device_lock);
629
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
630 631
}

Zhang Rui's avatar
Zhang Rui committed
632 633
static void acpi_device_unregister(struct acpi_device *device, int type)
{
634
	mutex_lock(&acpi_device_lock);
Len Brown's avatar
Len Brown committed
635
	if (device->parent)
Zhang Rui's avatar
Zhang Rui committed
636
		list_del(&device->node);
Linus Torvalds's avatar
Linus Torvalds committed
637

Zhang Rui's avatar
Zhang Rui committed
638
	list_del(&device->wakeup_list);
639
	mutex_unlock(&acpi_device_lock);
Linus Torvalds's avatar
Linus Torvalds committed
640

Zhang Rui's avatar
Zhang Rui committed
641
	acpi_detach_data(device->handle, acpi_bus_data_handler);
642

643
	acpi_device_remove_files(device);
644
	device_unregister(&device->dev);
Linus Torvalds's avatar
Linus Torvalds committed
645 646
}

Zhang Rui's avatar
Zhang Rui committed
647 648 649
/* --------------------------------------------------------------------------
                                 Driver Management
   -------------------------------------------------------------------------- */
Linus Torvalds's avatar
Linus Torvalds committed
650
/**
651 652 653 654
 * acpi_bus_driver_init - add a device to a driver
 * @device: the device to add and initialize
 * @driver: driver for the device
 *
655
 * Used to initialize a device via its device driver.  Called whenever a
656
 * driver is bound to a device.  Invokes the driver's add() ops.
Linus Torvalds's avatar
Linus Torvalds committed
657 658
 */
static int
Len Brown's avatar
Len Brown committed
659
acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
Linus Torvalds's avatar
Linus Torvalds committed
660
{
Len Brown's avatar
Len Brown committed
661
	int result = 0;
Linus Torvalds's avatar
Linus Torvalds committed
662 663

	if (!device || !driver)
664
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
665 666

	if (!driver->ops.add)
667
		return -ENOSYS;
Linus Torvalds's avatar
Linus Torvalds committed
668 669 670 671

	result = driver->ops.add(device);
	if (result) {
		device->driver = NULL;
672
		device->driver_data = NULL;
673
		return result;
Linus Torvalds's avatar
Linus Torvalds committed
674 675 676 677 678 679 680 681 682
	}

	device->driver = driver;

	/*
	 * TBD - Configuration Management: Assign resources to device based
	 * upon possible configuration and currently allocated resources.
	 */

Len Brown's avatar
Len Brown committed
683 684
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Driver successfully bound to device\n"));
685
	return 0;
686 687
}

688
static int acpi_start_single_object(struct acpi_device *device)
689 690 691 692 693 694
{
	int result = 0;
	struct acpi_driver *driver;


	if (!(driver = device->driver))
695
		return 0;
696

Linus Torvalds's avatar
Linus Torvalds committed
697 698 699 700 701 702
	if (driver->ops.start) {
		result = driver->ops.start(device);
		if (result && driver->ops.remove)
			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
	}

703
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
704 705
}

Zhang Rui's avatar
Zhang Rui committed
706 707 708 709 710 711 712 713 714
/**
 * acpi_bus_register_driver - register a driver with the ACPI bus
 * @driver: driver being registered
 *
 * Registers a driver with the ACPI bus.  Searches the namespace for all
 * devices that match the driver's criteria and binds.  Returns zero for
 * success or a negative error status for failure.
 */
int acpi_bus_register_driver(struct acpi_driver *driver)
Linus Torvalds's avatar
Linus Torvalds committed
715
{
716
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed
717

Zhang Rui's avatar
Zhang Rui committed
718 719
	if (acpi_disabled)
		return -ENODEV;
720 721 722
	driver->drv.name = driver->name;
	driver->drv.bus = &acpi_bus_type;
	driver->drv.owner = driver->owner;
Linus Torvalds's avatar
Linus Torvalds committed
723

724 725
	ret = driver_register(&driver->drv);
	return ret;
Zhang Rui's avatar
Zhang Rui committed
726
}
Linus Torvalds's avatar
Linus Torvalds committed
727

Zhang Rui's avatar
Zhang Rui committed
728 729 730 731 732 733 734 735 736 737 738
EXPORT_SYMBOL(acpi_bus_register_driver);

/**
 * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
 * @driver: driver to unregister
 *
 * Unregisters a driver with the ACPI bus.  Searches the namespace for all
 * devices that match the driver's criteria and unbinds.
 */
void acpi_bus_unregister_driver(struct acpi_driver *driver)
{
739
	driver_unregister(&driver->drv);
Zhang Rui's avatar
Zhang Rui committed
740 741 742 743 744 745 746
}

EXPORT_SYMBOL(acpi_bus_unregister_driver);

/* --------------------------------------------------------------------------
                                 Device Enumeration
   -------------------------------------------------------------------------- */
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
{
	acpi_status status;
	int ret;
	struct acpi_device *device;

	/*
	 * Fixed hardware devices do not appear in the namespace and do not
	 * have handles, but we fabricate acpi_devices for them, so we have
	 * to deal with them specially.
	 */
	if (handle == NULL)
		return acpi_root;

	do {
		status = acpi_get_parent(handle, &handle);
		if (status == AE_NULL_ENTRY)
			return NULL;
		if (ACPI_FAILURE(status))
			return acpi_root;

		ret = acpi_bus_get_device(handle, &device);
		if (ret == 0)
			return device;
	} while (1);
}

Zhang Rui's avatar
Zhang Rui committed
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
acpi_status
acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
{
	acpi_status status;
	acpi_handle tmp;
	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
	union acpi_object *obj;

	status = acpi_get_handle(handle, "_EJD", &tmp);
	if (ACPI_FAILURE(status))
		return status;

	status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
	if (ACPI_SUCCESS(status)) {
		obj = buffer.pointer;
789 790
		status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer,
					 ejd);
Zhang Rui's avatar
Zhang Rui committed
791 792 793 794 795 796
		kfree(buffer.pointer);
	}
	return status;
}
EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);

797
void acpi_bus_data_handler(acpi_handle handle, void *context)
Zhang Rui's avatar
Zhang Rui committed
798 799 800 801 802 803 804 805 806 807 808 809 810 811
{

	/* TBD */

	return;
}

static int acpi_bus_get_perf_flags(struct acpi_device *device)
{
	device->performance.state = ACPI_STATE_UNKNOWN;
	return 0;
}

static acpi_status
812 813
acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
					     struct acpi_device_wakeup *wakeup)
Zhang Rui's avatar
Zhang Rui committed
814
{
815 816
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *package = NULL;
Zhang Rui's avatar
Zhang Rui committed
817
	union acpi_object *element = NULL;
818 819
	acpi_status status;
	int i = 0;
Zhang Rui's avatar
Zhang Rui committed
820

821
	if (!wakeup)
Zhang Rui's avatar
Zhang Rui committed
822 823
		return AE_BAD_PARAMETER;

824 825 826 827 828 829 830 831 832 833 834 835 836 837
	/* _PRW */
	status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
	if (ACPI_FAILURE(status)) {
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
		return status;
	}

	package = (union acpi_object *)buffer.pointer;

	if (!package || (package->package.count < 2)) {
		status = AE_BAD_DATA;
		goto out;
	}

Zhang Rui's avatar
Zhang Rui committed
838
	element = &(package->package.elements[0]);
839 840 841 842
	if (!element) {
		status = AE_BAD_DATA;
		goto out;
	}
Zhang Rui's avatar
Zhang Rui committed
843 844 845 846
	if (element->type == ACPI_TYPE_PACKAGE) {
		if ((element->package.count < 2) ||
		    (element->package.elements[0].type !=
		     ACPI_TYPE_LOCAL_REFERENCE)
847 848 849 850 851
		    || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) {
			status = AE_BAD_DATA;
			goto out;
		}
		wakeup->gpe_device =
Zhang Rui's avatar
Zhang Rui committed
852
		    element->package.elements[0].reference.handle;
853
		wakeup->gpe_number =
Zhang Rui's avatar
Zhang Rui committed
854 855
		    (u32) element->package.elements[1].integer.value;
	} else if (element->type == ACPI_TYPE_INTEGER) {
856 857 858 859 860 861
		wakeup->gpe_device = NULL;
		wakeup->gpe_number = element->integer.value;
	} else {
		status = AE_BAD_DATA;
		goto out;
	}
Zhang Rui's avatar
Zhang Rui committed
862 863 864

	element = &(package->package.elements[1]);
	if (element->type != ACPI_TYPE_INTEGER) {
865 866
		status = AE_BAD_DATA;
		goto out;
Zhang Rui's avatar
Zhang Rui committed
867
	}
868
	wakeup->sleep_state = element->integer.value;
Zhang Rui's avatar
Zhang Rui committed
869 870

	if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
871 872
		status = AE_NO_MEMORY;
		goto out;
Zhang Rui's avatar
Zhang Rui committed
873
	}
874 875
	wakeup->resources.count = package->package.count - 2;
	for (i = 0; i < wakeup->resources.count; i++) {
Zhang Rui's avatar
Zhang Rui committed
876
		element = &(package->package.elements[i + 2]);
877 878 879 880
		if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
			status = AE_BAD_DATA;
			goto out;
		}
Zhang Rui's avatar
Zhang Rui committed
881

882
		wakeup->resources.handles[i] = element->reference.handle;
Linus Torvalds's avatar
Linus Torvalds committed
883
	}
Zhang Rui's avatar
Zhang Rui committed
884

Lin Ming's avatar
Lin Ming committed
885
	acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
886

887 888 889 890
 out:
	kfree(buffer.pointer);

	return status;
Linus Torvalds's avatar
Linus Torvalds committed
891 892
}

893
static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
894
{
895 896 897 898 899 900
	struct acpi_device_id button_device_ids[] = {
		{"PNP0C0D", 0},
		{"PNP0C0C", 0},
		{"PNP0C0E", 0},
		{"", 0},
	};
901 902 903
	acpi_status status;
	acpi_event_status event_status;

904
	device->wakeup.flags.notifier_present = 0;
905 906 907 908

	/* Power button, Lid switch always enable wakeup */
	if (!acpi_match_device_ids(device, button_device_ids)) {
		device->wakeup.flags.run_wake = 1;
909
		device_set_wakeup_capable(&device->dev, true);
910 911 912
		return;
	}

913 914 915
	status = acpi_get_gpe_status(device->wakeup.gpe_device,
					device->wakeup.gpe_number,
						&event_status);
916 917 918 919 920
	if (status == AE_OK)
		device->wakeup.flags.run_wake =
				!!(event_status & ACPI_EVENT_FLAG_HANDLE);
}

921
static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
922
{
923
	acpi_handle temp;
924 925
	acpi_status status = 0;
	int psw_error;
926

927 928 929 930 931
	/* Presence of _PRW indicates wake capable */
	status = acpi_get_handle(device->handle, "_PRW", &temp);
	if (ACPI_FAILURE(status))
		return;

932 933
	status = acpi_bus_extract_wakeup_device_power_package(device->handle,
							      &device->wakeup);
Zhang Rui's avatar
Zhang Rui committed
934 935
	if (ACPI_FAILURE(status)) {
		ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
936
		return;
Zhang Rui's avatar
Zhang Rui committed
937
	}
Linus Torvalds's avatar
Linus Torvalds committed
938

Zhang Rui's avatar
Zhang Rui committed
939
	device->wakeup.flags.valid = 1;
940
	device->wakeup.prepare_count = 0;
941
	acpi_bus_set_run_wake_flags(device);
942 943 944 945 946 947
	/* Call _PSW/_DSW object to disable its ability to wake the sleeping
	 * system for the ACPI device with the _PRW object.
	 * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
	 * So it is necessary to call _DSW object first. Only when it is not
	 * present will the _PSW object used.
	 */
948 949 950 951
	psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
	if (psw_error)
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				"error in _DSW or _PSW evaluation\n"));
Linus Torvalds's avatar
Linus Torvalds committed
952 953
}

954 955
static void acpi_bus_add_power_resource(acpi_handle handle);

Zhang Rui's avatar
Zhang Rui committed
956
static int acpi_bus_get_power_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
957
{
Zhang Rui's avatar
Zhang Rui committed
958 959 960
	acpi_status status = 0;
	acpi_handle handle = NULL;
	u32 i = 0;
Bjorn Helgaas's avatar
Bjorn Helgaas committed
961

Len Brown's avatar
Len Brown committed
962

Zhang Rui's avatar
Zhang Rui committed
963 964 965 966 967 968 969 970 971
	/*
	 * Power Management Flags
	 */
	status = acpi_get_handle(device->handle, "_PSC", &handle);
	if (ACPI_SUCCESS(status))
		device->power.flags.explicit_get = 1;
	status = acpi_get_handle(device->handle, "_IRC", &handle);
	if (ACPI_SUCCESS(status))
		device->power.flags.inrush_current = 1;
Linus Torvalds's avatar
Linus Torvalds committed
972

Zhang Rui's avatar
Zhang Rui committed
973 974 975
	/*
	 * Enumerate supported power management states
	 */
976
	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
Zhang Rui's avatar
Zhang Rui committed
977 978
		struct acpi_device_power_state *ps = &device->power.states[i];
		char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
Linus Torvalds's avatar
Linus Torvalds committed
979

Zhang Rui's avatar
Zhang Rui committed
980 981 982 983
		/* Evaluate "_PRx" to se if power resources are referenced */
		acpi_evaluate_reference(device->handle, object_name, NULL,
					&ps->resources);
		if (ps->resources.count) {
984 985
			int j;

Zhang Rui's avatar
Zhang Rui committed
986
			device->power.flags.power_resources = 1;
987 988
			for (j = 0; j < ps->resources.count; j++)
				acpi_bus_add_power_resource(ps->resources.handles[j]);
Linus Torvalds's avatar
Linus Torvalds committed
989 990
		}

Zhang Rui's avatar
Zhang Rui committed
991 992 993
		/* Evaluate "_PSx" to see if we can do explicit sets */
		object_name[2] = 'S';
		status = acpi_get_handle(device->handle, object_name, &handle);
994
		if (ACPI_SUCCESS(status))
Zhang Rui's avatar
Zhang Rui committed
995
			ps->flags.explicit_set = 1;
Linus Torvalds's avatar
Linus Torvalds committed
996

997 998 999 1000 1001 1002
		/*
		 * State is valid if there are means to put the device into it.
		 * D3hot is only valid if _PR3 present.
		 */
		if (ps->resources.count ||
		    (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT))
Zhang Rui's avatar
Zhang Rui committed
1003
			ps->flags.valid = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1004

Zhang Rui's avatar
Zhang Rui committed
1005 1006 1007
		ps->power = -1;	/* Unknown - driver assigned */
		ps->latency = -1;	/* Unknown - driver assigned */
	}
Linus Torvalds's avatar
Linus Torvalds committed
1008

Zhang Rui's avatar
Zhang Rui committed
1009 1010 1011 1012 1013
	/* Set defaults for D0 and D3 states (always valid) */
	device->power.states[ACPI_STATE_D0].flags.valid = 1;
	device->power.states[ACPI_STATE_D0].power = 100;
	device->power.states[ACPI_STATE_D3].flags.valid = 1;
	device->power.states[ACPI_STATE_D3].power = 0;
1014

1015 1016 1017 1018
	/* Set D3cold's explicit_set flag if _PS3 exists. */
	if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set)
		device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1;

1019
	acpi_bus_init_power(device);
1020

Zhang Rui's avatar
Zhang Rui committed
1021 1022
	return 0;
}
1023

Len Brown's avatar
Len Brown committed
1024
static int acpi_bus_get_flags(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
1025
{
Len Brown's avatar
Len Brown committed
1026 1027
	acpi_status status = AE_OK;
	acpi_handle temp = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049


	/* Presence of _STA indicates 'dynamic_status' */
	status = acpi_get_handle(device->handle, "_STA", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.dynamic_status = 1;

	/* Presence of _RMV indicates 'removable' */
	status = acpi_get_handle(device->handle, "_RMV", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.removable = 1;

	/* Presence of _EJD|_EJ0 indicates 'ejectable' */
	status = acpi_get_handle(device->handle, "_EJD", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.ejectable = 1;
	else {
		status = acpi_get_handle(device->handle, "_EJ0", &temp);
		if (ACPI_SUCCESS(status))
			device->flags.ejectable = 1;
	}

1050 1051 1052 1053
	/* Power resources cannot be power manageable. */
	if (device->device_type == ACPI_BUS_TYPE_POWER)
		return 0;

Linus Torvalds's avatar
Linus Torvalds committed
1054 1055 1056 1057 1058 1059 1060
	/* Presence of _PS0|_PR0 indicates 'power manageable' */
	status = acpi_get_handle(device->handle, "_PS0", &temp);
	if (ACPI_FAILURE(status))
		status = acpi_get_handle(device->handle, "_PR0", &temp);
	if (ACPI_SUCCESS(status))
		device->flags.power_manageable = 1;

Joe Perches's avatar
Joe Perches committed
1061
	/* TBD: Performance management */
Linus Torvalds's avatar
Linus Torvalds committed
1062

1063
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1064 1065
}

1066
static void acpi_device_get_busid(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
1067
{
Len Brown's avatar
Len Brown committed
1068 1069 1070
	char bus_id[5] = { '?', 0 };
	struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
	int i = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1071 1072 1073 1074 1075 1076 1077

	/*
	 * Bus ID
	 * ------
	 * The device's Bus ID is simply the object name.
	 * TBD: Shouldn't this value be unique (within the ACPI namespace)?
	 */
1078
	if (ACPI_IS_ROOT_DEVICE(device)) {
Linus Torvalds's avatar
Linus Torvalds committed
1079
		strcpy(device->pnp.bus_id, "ACPI");
1080 1081 1082 1083
		return;
	}

	switch (device->device_type) {
Linus Torvalds's avatar
Linus Torvalds committed
1084 1085 1086 1087 1088 1089 1090
	case ACPI_BUS_TYPE_POWER_BUTTON:
		strcpy(device->pnp.bus_id, "PWRF");
		break;
	case ACPI_BUS_TYPE_SLEEP_BUTTON:
		strcpy(device->pnp.bus_id, "SLPF");
		break;
	default:
1091
		acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
Linus Torvalds's avatar
Linus Torvalds committed
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
		/* Clean up trailing underscores (if any) */
		for (i = 3; i > 1; i--) {
			if (bus_id[i] == '_')
				bus_id[i] = '\0';
			else
				break;
		}
		strcpy(device->pnp.bus_id, bus_id);
		break;
	}
}

1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
/*
 * acpi_bay_match - see if a device is an ejectable driver bay
 *
 * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
 * then we can safely call it an ejectable drive bay
 */
static int acpi_bay_match(struct acpi_device *device){
	acpi_status status;
	acpi_handle handle;
	acpi_handle tmp;
	acpi_handle phandle;

	handle = device->handle;

	status = acpi_get_handle(handle, "_EJ0", &tmp);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
		(ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
		(ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
		(ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
		return 0;

	if (acpi_get_parent(handle, &phandle))
		return -ENODEV;

        if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
                (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
                (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
                (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
                return 0;

	return -ENODEV;
}

1140 1141 1142 1143 1144 1145 1146 1147 1148
/*
 * acpi_dock_match - see if a device has a _DCK method
 */
static int acpi_dock_match(struct acpi_device *device)
{
	acpi_handle tmp;
	return acpi_get_handle(device->handle, "_DCK", &tmp);
}

1149
const char *acpi_device_hid(struct acpi_device *device)
1150
{
1151
	struct acpi_hardware_id *hid;
1152

1153 1154 1155
	if (list_empty(&device->pnp.ids))
		return dummy_hid;

1156 1157 1158 1159
	hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
	return hid->id;
}
EXPORT_SYMBOL(acpi_device_hid);
1160

1161 1162 1163
static void acpi_add_id(struct acpi_device *device, const char *dev_id)
{
	struct acpi_hardware_id *id;
1164

1165 1166 1167
	id = kmalloc(sizeof(*id), GFP_KERNEL);
	if (!id)
		return;
1168

Thomas Meyer's avatar
Thomas Meyer committed
1169
	id->id = kstrdup(dev_id, GFP_KERNEL);
1170 1171 1172
	if (!id->id) {
		kfree(id);
		return;
1173 1174
	}

1175
	list_add_tail(&id->list, &device->pnp.ids);
1176 1177
}

1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
/*
 * Old IBM workstations have a DSDT bug wherein the SMBus object
 * lacks the SMBUS01 HID and the methods do not have the necessary "_"
 * prefix.  Work around this.
 */
static int acpi_ibm_smbus_match(struct acpi_device *device)
{
	acpi_handle h_dummy;
	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
	int result;

	if (!dmi_name_in_vendors("IBM"))
		return -ENODEV;

	/* Look for SMBS object */
	result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
	if (result)
		return result;

	if (strcmp("SMBS", path.pointer)) {
		result = -ENODEV;
		goto out;
	}

	/* Does it have the necessary (but misnamed) methods? */
	result = -ENODEV;
	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
	    ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
	    ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
		result = 0;
out:
	kfree(path.pointer);
	return result;
}

1213
static void acpi_device_set_id(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
1214
{
Len Brown's avatar
Len Brown committed
1215
	acpi_status status;
1216 1217
	struct acpi_device_info *info;
	struct acpica_device_id_list *cid_list;
1218
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
1219

1220
	switch (device->device_type) {
Linus Torvalds's avatar
Linus Torvalds committed
1221
	case ACPI_BUS_TYPE_DEVICE:
1222
		if (ACPI_IS_ROOT_DEVICE(device)) {
1223
			acpi_add_id(device, ACPI_SYSTEM_HID);
1224 1225 1226
			break;
		}

1227
		status = acpi_get_object_info(device->handle, &info);
Linus Torvalds's avatar
Linus Torvalds committed
1228
		if (ACPI_FAILURE(status)) {
1229
			printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
1230 1231 1232 1233
			return;
		}

		if (info->valid & ACPI_VALID_HID)
1234 1235
			acpi_add_id(device, info->hardware_id.string);
		if (info->valid & ACPI_VALID_CID) {
1236
			cid_list = &info->compatible_id_list;
1237 1238 1239
			for (i = 0; i < cid_list->count; i++)
				acpi_add_id(device, cid_list->ids[i].string);
		}
Linus Torvalds's avatar
Linus Torvalds committed
1240 1241 1242 1243
		if (info->valid & ACPI_VALID_ADR) {
			device->pnp.bus_address = info->address;
			device->flags.bus_address = 1;
		}
1244 1245 1246
		if (info->valid & ACPI_VALID_UID)
			device->pnp.unique_id = kstrdup(info->unique_id.string,
							GFP_KERNEL);
1247

1248 1249
		kfree(info);

1250 1251 1252 1253
		/*
		 * Some devices don't reliably have _HIDs & _CIDs, so add
		 * synthetic HIDs to make sure drivers can find them.
		 */
1254
		if (acpi_is_video_device(device))
1255
			acpi_add_id(device, ACPI_VIDEO_HID);
1256
		else if (ACPI_SUCCESS(acpi_bay_match(device)))
1257
			acpi_add_id(device, ACPI_BAY_HID);
1258
		else if (ACPI_SUCCESS(acpi_dock_match(device)))
1259
			acpi_add_id(device, ACPI_DOCK_HID);
1260 1261
		else if (!acpi_ibm_smbus_match(device))
			acpi_add_id(device, ACPI_SMBUS_IBM_HID);
1262 1263 1264 1265 1266 1267
		else if (!acpi_device_hid(device) &&
			 ACPI_IS_ROOT_DEVICE(device->parent)) {
			acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
			strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
			strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
		}
1268

Linus Torvalds's avatar
Linus Torvalds committed
1269 1270
		break;
	case ACPI_BUS_TYPE_POWER:
1271
		acpi_add_id(device, ACPI_POWER_HID);
Linus Torvalds's avatar
Linus Torvalds committed
1272 1273
		break;
	case ACPI_BUS_TYPE_PROCESSOR:
1274
		acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
Linus Torvalds's avatar
Linus Torvalds committed
1275 1276
		break;
	case ACPI_BUS_TYPE_THERMAL:
1277
		acpi_add_id(device, ACPI_THERMAL_HID);
Linus Torvalds's avatar
Linus Torvalds committed
1278 1279
		break;
	case ACPI_BUS_TYPE_POWER_BUTTON:
1280
		acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
Linus Torvalds's avatar
Linus Torvalds committed
1281 1282
		break;
	case ACPI_BUS_TYPE_SLEEP_BUTTON:
1283
		acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
Linus Torvalds's avatar
Linus Torvalds committed
1284 1285 1286 1287
		break;
	}
}

1288
static int acpi_device_set_context(struct acpi_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
1289
{
1290 1291
	acpi_status status;

Linus Torvalds's avatar
Linus Torvalds committed
1292 1293 1294 1295
	/*
	 * Context
	 * -------
	 * Attach this 'struct acpi_device' to the ACPI object.  This makes
1296 1297
	 * resolutions from handle->device very efficient.  Fixed hardware
	 * devices have no handles, so we skip them.
Linus Torvalds's avatar
Linus Torvalds committed
1298
	 */
1299 1300
	if (!device->handle)
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1301

1302 1303 1304 1305 1306 1307 1308
	status = acpi_attach_data(device->handle,
				  acpi_bus_data_handler, device);
	if (ACPI_SUCCESS(status))
		return 0;

	printk(KERN_ERR PREFIX "Error attaching device data\n");
	return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
1309 1310
}

Len Brown's avatar
Len Brown committed
1311
static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
Linus Torvalds's avatar
Linus Torvalds committed
1312 1313
{
	if (!dev)
1314
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
1315

1316
	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
1317
	device_release_driver(&dev->dev);
Linus Torvalds's avatar
Linus Torvalds committed
1318 1319

	if (!rmdevice)
1320
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1321

1322 1323 1324
	/*
	 * unbind _ADR-Based Devices when hot removal
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1325 1326 1327 1328 1329 1330
	if (dev->flags.bus_address) {
		if ((dev->parent) && (dev->parent->ops.unbind))
			dev->parent->ops.unbind(dev);
	}
	acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);

1331
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1332 1333
}

1334 1335
static int acpi_add_single_object(struct acpi_device **child,
				  acpi_handle handle, int type,
1336
				  unsigned long long sta,
1337
				  struct acpi_bus_ops *ops)
Linus Torvalds's avatar
Linus Torvalds committed
1338
{
1339 1340
	int result;
	struct acpi_device *device;
1341
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
Linus Torvalds's avatar
Linus Torvalds committed
1342

1343
	device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
1344
	if (!device) {
1345
		printk(KERN_ERR PREFIX "Memory allocation error\n");
1346
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
1347 1348
	}

1349
	INIT_LIST_HEAD(&device->pnp.ids);
1350
	device->device_type = type;
Linus Torvalds's avatar
Linus Torvalds committed
1351
	device->handle = handle;
1352
	device->parent = acpi_bus_get_parent(handle);
1353
	device->bus_ops = *ops; /* workround for not call .start */
1354
	STRUCT_TO_INT(device->status) = sta;
1355

1356
	acpi_device_get_busid(device);
Linus Torvalds's avatar
Linus Torvalds committed
1357 1358 1359 1360

	/*
	 * Flags
	 * -----
1361 1362
	 * Note that we only look for object handles -- cannot evaluate objects
	 * until we know the device is present and properly initialized.
Linus Torvalds's avatar
Linus Torvalds committed
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
	 */
	result = acpi_bus_get_flags(device);
	if (result)
		goto end;

	/*
	 * Initialize Device
	 * -----------------
	 * TBD: Synch with Core's enumeration/initialization process.
	 */
1373
	acpi_device_set_id(device);
Linus Torvalds's avatar
Linus Torvalds committed
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384

	/*
	 * Power Management
	 * ----------------
	 */
	if (device->flags.power_manageable) {
		result = acpi_bus_get_power_flags(device);
		if (result)
			goto end;
	}

Len Brown's avatar
Len Brown committed
1385
	/*
Linus Torvalds's avatar
Linus Torvalds committed
1386 1387 1388
	 * Wakeup device management
	 *-----------------------
	 */
1389
	acpi_bus_get_wakeup_device_flags(device);
Linus Torvalds's avatar
Linus Torvalds committed
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400

	/*
	 * Performance Management
	 * ----------------------
	 */
	if (device->flags.performance_manageable) {
		result = acpi_bus_get_perf_flags(device);
		if (result)
			goto end;
	}

1401
	if ((result = acpi_device_set_context(device)))
1402
		goto end;
Linus Torvalds's avatar
Linus Torvalds committed
1403

1404
	result = acpi_device_register(device);
Linus Torvalds's avatar
Linus Torvalds committed
1405 1406

	/*
1407
	 * Bind _ADR-Based Devices when hot add
Linus Torvalds's avatar
Linus Torvalds committed
1408 1409 1410 1411 1412 1413
	 */
	if (device->flags.bus_address) {
		if (device->parent && device->parent->ops.bind)
			device->parent->ops.bind(device);
	}

1414
end:
1415 1416 1417 1418 1419 1420 1421 1422
	if (!result) {
		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			"Adding %s [%s] parent %s\n", dev_name(&device->dev),
			 (char *) buffer.pointer,
			 device->parent ? dev_name(&device->parent->dev) :
					  "(null)"));
		kfree(buffer.pointer);
Linus Torvalds's avatar
Linus Torvalds committed
1423
		*child = device;
1424
	} else
1425
		acpi_device_release(&device->dev);
Linus Torvalds's avatar
Linus Torvalds committed
1426

1427
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
1428 1429
}

1430 1431 1432
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
			  ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING)

1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
static void acpi_bus_add_power_resource(acpi_handle handle)
{
	struct acpi_bus_ops ops = {
		.acpi_op_add = 1,
		.acpi_op_start = 1,
	};
	struct acpi_device *device = NULL;

	acpi_bus_get_device(handle, &device);
	if (!device)
		acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER,
					ACPI_STA_DEFAULT, &ops);
}

1447 1448
static int acpi_bus_type_and_status(acpi_handle handle, int *type,
				    unsigned long long *sta)
Linus Torvalds's avatar
Linus Torvalds committed
1449
{
1450 1451
	acpi_status status;
	acpi_object_type acpi_type;
Linus Torvalds's avatar
Linus Torvalds committed
1452

1453
	status = acpi_get_type(handle, &acpi_type);
1454
	if (ACPI_FAILURE(status))
1455
		return -ENODEV;
Len Brown's avatar
Len Brown committed
1456

1457
	switch (acpi_type) {
1458 1459
	case ACPI_TYPE_ANY:		/* for ACPI_ROOT_OBJECT */
	case ACPI_TYPE_DEVICE:
1460 1461 1462 1463
		*type = ACPI_BUS_TYPE_DEVICE;
		status = acpi_bus_get_status_handle(handle, sta);
		if (ACPI_FAILURE(status))
			return -ENODEV;
1464 1465
		break;
	case ACPI_TYPE_PROCESSOR:
1466 1467 1468 1469
		*type = ACPI_BUS_TYPE_PROCESSOR;
		status = acpi_bus_get_status_handle(handle, sta);
		if (ACPI_FAILURE(status))
			return -ENODEV;
1470 1471
		break;
	case ACPI_TYPE_THERMAL:
1472 1473
		*type = ACPI_BUS_TYPE_THERMAL;
		*sta = ACPI_STA_DEFAULT;
1474 1475
		break;
	case ACPI_TYPE_POWER:
1476 1477
		*type = ACPI_BUS_TYPE_POWER;
		*sta = ACPI_STA_DEFAULT;
1478 1479
		break;
	default:
1480
		return -ENODEV;
1481
	}
Linus Torvalds's avatar
Linus Torvalds committed
1482

1483 1484 1485 1486 1487 1488 1489 1490 1491
	return 0;
}

static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
				      void *context, void **return_value)
{
	struct acpi_bus_ops *ops = context;
	int type;
	unsigned long long sta;
1492 1493
	struct acpi_device *device;
	acpi_status status;
1494 1495 1496 1497 1498 1499 1500
	int result;

	result = acpi_bus_type_and_status(handle, &type, &sta);
	if (result)
		return AE_OK;

	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
1501
	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
1502 1503 1504 1505 1506 1507 1508
		struct acpi_device_wakeup wakeup;
		acpi_handle temp;

		status = acpi_get_handle(handle, "_PRW", &temp);
		if (ACPI_SUCCESS(status))
			acpi_bus_extract_wakeup_device_power_package(handle,
								     &wakeup);
1509
		return AE_CTRL_DEPTH;
1510
	}
1511

1512 1513 1514 1515 1516 1517 1518 1519
	/*
	 * We may already have an acpi_device from a previous enumeration.  If
	 * so, we needn't add it again, but we may still have to start it.
	 */
	device = NULL;
	acpi_bus_get_device(handle, &device);
	if (ops->acpi_op_add && !device)
		acpi_add_single_object(&device, handle, type, sta, ops);
Linus Torvalds's avatar
Linus Torvalds committed
1520

1521
	if (!device)
1522
		return AE_CTRL_DEPTH;
Linus Torvalds's avatar
Linus Torvalds committed
1523

1524 1525
	if (ops->acpi_op_start && !(ops->acpi_op_add)) {
		status = acpi_start_single_object(device);
Linus Torvalds's avatar
Linus Torvalds committed
1526
		if (ACPI_FAILURE(status))
1527 1528
			return AE_CTRL_DEPTH;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1529

1530 1531 1532 1533
	if (!*return_value)
		*return_value = device;
	return AE_OK;
}
1534

1535 1536 1537 1538 1539
static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
			 struct acpi_device **child)
{
	acpi_status status;
	void *device = NULL;
1540

1541 1542 1543
	status = acpi_bus_check_add(handle, 0, ops, &device);
	if (ACPI_SUCCESS(status))
		acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
1544
				    acpi_bus_check_add, NULL, ops, &device);
Linus Torvalds's avatar
Linus Torvalds committed
1545

1546 1547
	if (child)
		*child = device;
1548 1549 1550 1551 1552

	if (device)
		return 0;
	else
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
1553 1554
}

1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
/*
 * acpi_bus_add and acpi_bus_start
 *
 * scan a given ACPI tree and (probably recently hot-plugged)
 * create and add or starts found devices.
 *
 * If no devices were found -ENODEV is returned which does not
 * mean that this is a real error, there just have been no suitable
 * ACPI objects in the table trunk from which the kernel could create
 * a device and add/start an appropriate driver.
 */

1567
int
Len Brown's avatar
Len Brown committed
1568 1569
acpi_bus_add(struct acpi_device **child,
	     struct acpi_device *parent, acpi_handle handle, int type)
1570 1571 1572
{
	struct acpi_bus_ops ops;

1573 1574
	memset(&ops, 0, sizeof(ops));
	ops.acpi_op_add = 1;
1575

1576
	return acpi_bus_scan(handle, &ops, child);
1577 1578 1579
}
EXPORT_SYMBOL(acpi_bus_add);

Len Brown's avatar
Len Brown committed
1580
int acpi_bus_start(struct acpi_device *device)
1581 1582
{
	struct acpi_bus_ops ops;
1583
	int result;
1584

1585 1586 1587
	if (!device)
		return -EINVAL;

1588 1589
	memset(&ops, 0, sizeof(ops));
	ops.acpi_op_start = 1;
1590

1591 1592
	result = acpi_bus_scan(device->handle, &ops, NULL);

1593
	acpi_update_all_gpes();
1594 1595

	return result;
1596 1597
}
EXPORT_SYMBOL(acpi_bus_start);
Linus Torvalds's avatar
Linus Torvalds committed
1598

1599
int acpi_bus_trim(struct acpi_device *start, int rmdevice)
Linus Torvalds's avatar
Linus Torvalds committed
1600
{
Len Brown's avatar
Len Brown committed
1601 1602 1603 1604 1605 1606 1607 1608
	acpi_status status;
	struct acpi_device *parent, *child;
	acpi_handle phandle, chandle;
	acpi_object_type type;
	u32 level = 1;
	int err = 0;

	parent = start;
Linus Torvalds's avatar
Linus Torvalds committed
1609 1610 1611 1612 1613
	phandle = start->handle;
	child = chandle = NULL;

	while ((level > 0) && parent && (!err)) {
		status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
Len Brown's avatar
Len Brown committed
1614
					      chandle, &chandle);
Linus Torvalds's avatar
Linus Torvalds committed
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651

		/*
		 * If this scope is exhausted then move our way back up.
		 */
		if (ACPI_FAILURE(status)) {
			level--;
			chandle = phandle;
			acpi_get_parent(phandle, &phandle);
			child = parent;
			parent = parent->parent;

			if (level == 0)
				err = acpi_bus_remove(child, rmdevice);
			else
				err = acpi_bus_remove(child, 1);

			continue;
		}

		status = acpi_get_type(chandle, &type);
		if (ACPI_FAILURE(status)) {
			continue;
		}
		/*
		 * If there is a device corresponding to chandle then
		 * parse it (depth-first).
		 */
		if (acpi_bus_get_device(chandle, &child) == 0) {
			level++;
			phandle = chandle;
			chandle = NULL;
			parent = child;
		}
		continue;
	}
	return err;
}
1652 1653
EXPORT_SYMBOL_GPL(acpi_bus_trim);

1654
static int acpi_bus_scan_fixed(void)
Linus Torvalds's avatar
Linus Torvalds committed
1655
{
Len Brown's avatar
Len Brown committed
1656 1657
	int result = 0;
	struct acpi_device *device = NULL;
1658
	struct acpi_bus_ops ops;
Linus Torvalds's avatar
Linus Torvalds committed
1659

1660 1661 1662 1663
	memset(&ops, 0, sizeof(ops));
	ops.acpi_op_add = 1;
	ops.acpi_op_start = 1;

Linus Torvalds's avatar
Linus Torvalds committed
1664 1665 1666
	/*
	 * Enumerate all fixed-feature devices.
	 */
1667
	if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
1668
		result = acpi_add_single_object(&device, NULL,
1669
						ACPI_BUS_TYPE_POWER_BUTTON,
1670
						ACPI_STA_DEFAULT,
1671
						&ops);
1672
		device_init_wakeup(&device->dev, true);
1673
	}
Linus Torvalds's avatar
Linus Torvalds committed
1674

1675
	if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
1676
		result = acpi_add_single_object(&device, NULL,
1677
						ACPI_BUS_TYPE_SLEEP_BUTTON,
1678
						ACPI_STA_DEFAULT,
1679
						&ops);
1680
	}
Linus Torvalds's avatar
Linus Torvalds committed
1681

1682
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
1683 1684
}

1685
int __init acpi_scan_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
1686 1687
{
	int result;
1688
	struct acpi_bus_ops ops;
Linus Torvalds's avatar
Linus Torvalds committed
1689

1690 1691 1692
	memset(&ops, 0, sizeof(ops));
	ops.acpi_op_add = 1;
	ops.acpi_op_start = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1693

1694 1695 1696 1697 1698 1699
	result = bus_register(&acpi_bus_type);
	if (result) {
		/* We don't want to quit even if we failed to add suspend/resume */
		printk(KERN_ERR PREFIX "Could not register bus type\n");
	}

1700 1701
	acpi_power_init();

Linus Torvalds's avatar
Linus Torvalds committed
1702 1703 1704
	/*
	 * Enumerate devices in the ACPI namespace.
	 */
1705
	result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
1706

1707
	if (!result)
1708
		result = acpi_bus_scan_fixed();
Linus Torvalds's avatar
Linus Torvalds committed
1709 1710 1711

	if (result)
		acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
1712
	else
1713
		acpi_update_all_gpes();
Linus Torvalds's avatar
Linus Torvalds committed
1714

1715
	return result;
Linus Torvalds's avatar
Linus Torvalds committed
1716
}