bus.c 20.5 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
/*
 *  acpi_bus.c - ACPI Bus Driver ($Revision: 80 $)
 *
 *  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.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
28
#include <linux/kernel.h>
L
Linus Torvalds 已提交
29 30 31 32 33
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/proc_fs.h>
34
#include <linux/acpi.h>
L
Linus Torvalds 已提交
35 36 37
#ifdef CONFIG_X86
#include <asm/mpspec.h>
#endif
38
#include <linux/pci.h>
L
Linus Torvalds 已提交
39 40 41
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>

42 43
#include "internal.h"

L
Linus Torvalds 已提交
44
#define _COMPONENT		ACPI_BUS_COMPONENT
45
ACPI_MODULE_NAME("bus");
L
Linus Torvalds 已提交
46

L
Len Brown 已提交
47 48
struct acpi_device *acpi_root;
struct proc_dir_entry *acpi_root_dir;
L
Linus Torvalds 已提交
49 50 51 52
EXPORT_SYMBOL(acpi_root_dir);

#define STRUCT_TO_INT(s)	(*((int*)&s))

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
static int set_power_nocheck(const struct dmi_system_id *id)
{
	printk(KERN_NOTICE PREFIX "%s detected - "
		"disable power check in power transistion\n", id->ident);
	acpi_power_nocheck = 1;
	return 0;
}
static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
	{
	set_power_nocheck, "HP Pavilion 05", {
	DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
	DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
	DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
	{},
};


L
Linus Torvalds 已提交
70 71 72 73
/* --------------------------------------------------------------------------
                                Device Management
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
74
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
L
Linus Torvalds 已提交
75
{
L
Len Brown 已提交
76
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
77 78 79


	if (!device)
80
		return -EINVAL;
L
Linus Torvalds 已提交
81 82 83

	/* TBD: Support fixed-feature devices */

L
Len Brown 已提交
84
	status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
L
Linus Torvalds 已提交
85
	if (ACPI_FAILURE(status) || !*device) {
86 87
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
				  handle));
88
		return -ENODEV;
L
Linus Torvalds 已提交
89 90
	}

91
	return 0;
L
Linus Torvalds 已提交
92
}
L
Len Brown 已提交
93

L
Linus Torvalds 已提交
94 95
EXPORT_SYMBOL(acpi_bus_get_device);

L
Len Brown 已提交
96
int acpi_bus_get_status(struct acpi_device *device)
L
Linus Torvalds 已提交
97
{
L
Len Brown 已提交
98
	acpi_status status = AE_OK;
99
	unsigned long long sta = 0;
L
Len Brown 已提交
100

L
Linus Torvalds 已提交
101 102

	if (!device)
103
		return -EINVAL;
L
Linus Torvalds 已提交
104 105 106 107 108

	/*
	 * Evaluate _STA if present.
	 */
	if (device->flags.dynamic_status) {
L
Len Brown 已提交
109 110
		status =
		    acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
L
Linus Torvalds 已提交
111
		if (ACPI_FAILURE(status))
112
			return -ENODEV;
L
Len Brown 已提交
113
		STRUCT_TO_INT(device->status) = (int)sta;
L
Linus Torvalds 已提交
114 115 116
	}

	/*
117 118 119 120
	 * According to ACPI spec some device can be present and functional
	 * even if the parent is not present but functional.
	 * In such conditions the child device should not inherit the status
	 * from the parent.
L
Linus Torvalds 已提交
121 122
	 */
	else
123 124 125
		STRUCT_TO_INT(device->status) =
		    ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
		    ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING;
L
Linus Torvalds 已提交
126 127

	if (device->status.functional && !device->status.present) {
128 129 130 131
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
		       "functional but not present;\n",
			device->pnp.bus_id,
			(u32) STRUCT_TO_INT(device->status)));
L
Linus Torvalds 已提交
132 133
	}

L
Len Brown 已提交
134 135 136
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
			  device->pnp.bus_id,
			  (u32) STRUCT_TO_INT(device->status)));
L
Linus Torvalds 已提交
137

138
	return 0;
L
Linus Torvalds 已提交
139 140
}

L
Len Brown 已提交
141
EXPORT_SYMBOL(acpi_bus_get_status);
L
Linus Torvalds 已提交
142

Z
Zhang Rui 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
void acpi_bus_private_data_handler(acpi_handle handle,
				   u32 function, void *context)
{
	return;
}
EXPORT_SYMBOL(acpi_bus_private_data_handler);

int acpi_bus_get_private_data(acpi_handle handle, void **data)
{
	acpi_status status = AE_OK;

	if (!*data)
		return -EINVAL;

	status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
	if (ACPI_FAILURE(status) || !*data) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
				handle));
		return -ENODEV;
	}

	return 0;
}
EXPORT_SYMBOL(acpi_bus_get_private_data);

L
Linus Torvalds 已提交
168 169 170 171
/* --------------------------------------------------------------------------
                                 Power Management
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
172
int acpi_bus_get_power(acpi_handle handle, int *state)
L
Linus Torvalds 已提交
173
{
L
Len Brown 已提交
174 175 176
	int result = 0;
	acpi_status status = 0;
	struct acpi_device *device = NULL;
177
	unsigned long long psc = 0;
L
Linus Torvalds 已提交
178 179 180 181


	result = acpi_bus_get_device(handle, &device);
	if (result)
182
		return result;
L
Linus Torvalds 已提交
183 184 185 186 187 188 189 190 191

	*state = ACPI_STATE_UNKNOWN;

	if (!device->flags.power_manageable) {
		/* TBD: Non-recursive algorithm for walking up hierarchy */
		if (device->parent)
			*state = device->parent->power.state;
		else
			*state = ACPI_STATE_D0;
L
Len Brown 已提交
192
	} else {
L
Linus Torvalds 已提交
193
		/*
194
		 * Get the device's power state either directly (via _PSC) or
L
Linus Torvalds 已提交
195 196 197
		 * indirectly (via power resources).
		 */
		if (device->power.flags.explicit_get) {
L
Len Brown 已提交
198 199
			status = acpi_evaluate_integer(device->handle, "_PSC",
						       NULL, &psc);
L
Linus Torvalds 已提交
200
			if (ACPI_FAILURE(status))
201
				return -ENODEV;
L
Len Brown 已提交
202 203
			device->power.state = (int)psc;
		} else if (device->power.flags.power_resources) {
L
Linus Torvalds 已提交
204 205
			result = acpi_power_get_inferred_state(device);
			if (result)
206
				return result;
L
Linus Torvalds 已提交
207 208 209 210 211 212
		}

		*state = device->power.state;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
L
Len Brown 已提交
213
			  device->pnp.bus_id, device->power.state));
L
Linus Torvalds 已提交
214

215
	return 0;
L
Linus Torvalds 已提交
216 217
}

L
Len Brown 已提交
218
EXPORT_SYMBOL(acpi_bus_get_power);
L
Linus Torvalds 已提交
219

L
Len Brown 已提交
220
int acpi_bus_set_power(acpi_handle handle, int state)
L
Linus Torvalds 已提交
221
{
L
Len Brown 已提交
222 223 224 225
	int result = 0;
	acpi_status status = AE_OK;
	struct acpi_device *device = NULL;
	char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
L
Linus Torvalds 已提交
226 227 228 229


	result = acpi_bus_get_device(handle, &device);
	if (result)
230
		return result;
L
Linus Torvalds 已提交
231 232

	if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
233
		return -EINVAL;
L
Linus Torvalds 已提交
234 235 236 237

	/* Make sure this is a valid target state */

	if (!device->flags.power_manageable) {
238
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
239
				kobject_name(&device->dev.kobj)));
240
		return -ENODEV;
L
Linus Torvalds 已提交
241
	}
242
	/*
243
	 * Get device's current power state
244
	 */
245 246 247 248 249 250 251 252 253 254 255 256 257
	if (!acpi_power_nocheck) {
		/*
		 * Maybe the incorrect power state is returned on the bogus
		 * bios, which is different with the real power state.
		 * For example: the bios returns D0 state and the real power
		 * state is D3. OS expects to set the device to D0 state. In
		 * such case if OS uses the power state returned by the BIOS,
		 * the device can't be transisted to the correct power state.
		 * So if the acpi_power_nocheck is set, it is unnecessary to
		 * get the power state by calling acpi_bus_get_power.
		 */
		acpi_bus_get_power(device->handle, &device->power.state);
	}
258
	if ((state == device->power.state) && !device->flags.force_power_state) {
259 260 261
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
				  state));
		return 0;
L
Linus Torvalds 已提交
262
	}
263

L
Linus Torvalds 已提交
264
	if (!device->power.states[state].flags.valid) {
265
		printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
266
		return -ENODEV;
L
Linus Torvalds 已提交
267 268
	}
	if (device->parent && (state < device->parent->power.state)) {
269
		printk(KERN_WARNING PREFIX
270
			      "Cannot set device to a higher-powered"
271
			      " state than parent\n");
272
		return -ENODEV;
L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280
	}

	/*
	 * Transition Power
	 * ----------------
	 * On transitions to a high-powered state we first apply power (via
	 * power resources) then evalute _PSx.  Conversly for transitions to
	 * a lower-powered state.
281
	 */
L
Linus Torvalds 已提交
282 283 284 285 286 287 288
	if (state < device->power.state) {
		if (device->power.flags.power_resources) {
			result = acpi_power_transition(device, state);
			if (result)
				goto end;
		}
		if (device->power.states[state].flags.explicit_set) {
L
Len Brown 已提交
289 290
			status = acpi_evaluate_object(device->handle,
						      object_name, NULL, NULL);
L
Linus Torvalds 已提交
291 292 293 294 295
			if (ACPI_FAILURE(status)) {
				result = -ENODEV;
				goto end;
			}
		}
L
Len Brown 已提交
296
	} else {
L
Linus Torvalds 已提交
297
		if (device->power.states[state].flags.explicit_set) {
L
Len Brown 已提交
298 299
			status = acpi_evaluate_object(device->handle,
						      object_name, NULL, NULL);
L
Linus Torvalds 已提交
300 301 302 303 304 305 306 307 308 309 310 311
			if (ACPI_FAILURE(status)) {
				result = -ENODEV;
				goto end;
			}
		}
		if (device->power.flags.power_resources) {
			result = acpi_power_transition(device, state);
			if (result)
				goto end;
		}
	}

L
Len Brown 已提交
312
      end:
L
Linus Torvalds 已提交
313
	if (result)
314
		printk(KERN_WARNING PREFIX
L
Len Brown 已提交
315
			      "Device [%s] failed to transition to D%d\n",
316
			      device->pnp.bus_id, state);
317 318
	else {
		device->power.state = state;
L
Len Brown 已提交
319 320 321
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Device [%s] transitioned to D%d\n",
				  device->pnp.bus_id, state));
322
	}
L
Linus Torvalds 已提交
323

324
	return result;
L
Linus Torvalds 已提交
325 326
}

L
Len Brown 已提交
327
EXPORT_SYMBOL(acpi_bus_set_power);
L
Linus Torvalds 已提交
328

329 330 331 332 333 334 335 336 337 338 339
bool acpi_bus_power_manageable(acpi_handle handle)
{
	struct acpi_device *device;
	int result;

	result = acpi_bus_get_device(handle, &device);
	return result ? false : device->flags.power_manageable;
}

EXPORT_SYMBOL(acpi_bus_power_manageable);

340 341 342 343 344 345 346 347 348 349 350
bool acpi_bus_can_wakeup(acpi_handle handle)
{
	struct acpi_device *device;
	int result;

	result = acpi_bus_get_device(handle, &device);
	return result ? false : device->wakeup.flags.valid;
}

EXPORT_SYMBOL(acpi_bus_can_wakeup);

L
Linus Torvalds 已提交
351 352 353 354
/* --------------------------------------------------------------------------
                                Event Management
   -------------------------------------------------------------------------- */

355
#ifdef CONFIG_ACPI_PROC_EVENT
L
Linus Torvalds 已提交
356 357 358 359 360
static DEFINE_SPINLOCK(acpi_bus_event_lock);

LIST_HEAD(acpi_bus_event_list);
DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);

L
Len Brown 已提交
361
extern int event_is_open;
L
Linus Torvalds 已提交
362

363
int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
L
Linus Torvalds 已提交
364
{
365
	struct acpi_bus_event *event;
L
Len Brown 已提交
366
	unsigned long flags = 0;
L
Linus Torvalds 已提交
367 368 369

	/* drop event on the floor if no one's listening */
	if (!event_is_open)
370
		return 0;
L
Linus Torvalds 已提交
371 372 373

	event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
	if (!event)
374
		return -ENOMEM;
L
Linus Torvalds 已提交
375

376 377
	strcpy(event->device_class, device_class);
	strcpy(event->bus_id, bus_id);
L
Linus Torvalds 已提交
378 379 380 381 382 383 384 385 386
	event->type = type;
	event->data = data;

	spin_lock_irqsave(&acpi_bus_event_lock, flags);
	list_add_tail(&event->node, &acpi_bus_event_list);
	spin_unlock_irqrestore(&acpi_bus_event_lock, flags);

	wake_up_interruptible(&acpi_bus_event_queue);

387
	return 0;
388 389 390 391 392 393 394 395 396 397 398

}

EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);

int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
{
	if (!device)
		return -EINVAL;
	return acpi_bus_generate_proc_event4(device->pnp.device_class,
					     device->pnp.bus_id, type, data);
L
Linus Torvalds 已提交
399
}
L
Len Brown 已提交
400

401
EXPORT_SYMBOL(acpi_bus_generate_proc_event);
L
Linus Torvalds 已提交
402

L
Len Brown 已提交
403
int acpi_bus_receive_event(struct acpi_bus_event *event)
L
Linus Torvalds 已提交
404
{
L
Len Brown 已提交
405 406
	unsigned long flags = 0;
	struct acpi_bus_event *entry = NULL;
L
Linus Torvalds 已提交
407 408 409 410 411

	DECLARE_WAITQUEUE(wait, current);


	if (!event)
412
		return -EINVAL;
L
Linus Torvalds 已提交
413 414 415 416 417 418 419 420 421 422 423 424 425

	if (list_empty(&acpi_bus_event_list)) {

		set_current_state(TASK_INTERRUPTIBLE);
		add_wait_queue(&acpi_bus_event_queue, &wait);

		if (list_empty(&acpi_bus_event_list))
			schedule();

		remove_wait_queue(&acpi_bus_event_queue, &wait);
		set_current_state(TASK_RUNNING);

		if (signal_pending(current))
426
			return -ERESTARTSYS;
L
Linus Torvalds 已提交
427 428 429
	}

	spin_lock_irqsave(&acpi_bus_event_lock, flags);
430 431 432
	if (!list_empty(&acpi_bus_event_list)) {
		entry = list_entry(acpi_bus_event_list.next,
				   struct acpi_bus_event, node);
L
Linus Torvalds 已提交
433
		list_del(&entry->node);
434
	}
L
Linus Torvalds 已提交
435 436 437
	spin_unlock_irqrestore(&acpi_bus_event_lock, flags);

	if (!entry)
438
		return -ENODEV;
L
Linus Torvalds 已提交
439 440 441 442 443

	memcpy(event, entry, sizeof(struct acpi_bus_event));

	kfree(entry);

444
	return 0;
L
Linus Torvalds 已提交
445 446
}

447
#endif	/* CONFIG_ACPI_PROC_EVENT */
L
Linus Torvalds 已提交
448 449 450 451 452

/* --------------------------------------------------------------------------
                             Notification Handling
   -------------------------------------------------------------------------- */

453
static void acpi_bus_check_device(acpi_handle handle)
L
Linus Torvalds 已提交
454
{
455
	struct acpi_device *device;
456
	acpi_status status;
L
Linus Torvalds 已提交
457 458
	struct acpi_device_status old_status;

459 460
	if (acpi_bus_get_device(handle, &device))
		return;
L
Linus Torvalds 已提交
461
	if (!device)
462
		return;
L
Linus Torvalds 已提交
463 464 465 466 467 468 469 470 471

	old_status = device->status;

	/*
	 * Make sure this device's parent is present before we go about
	 * messing with the device.
	 */
	if (device->parent && !device->parent->status.present) {
		device->status = device->parent->status;
472
		return;
L
Linus Torvalds 已提交
473 474 475 476
	}

	status = acpi_bus_get_status(device);
	if (ACPI_FAILURE(status))
477
		return;
L
Linus Torvalds 已提交
478 479

	if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
480
		return;
L
Linus Torvalds 已提交
481 482 483 484 485 486 487

	/*
	 * Device Insertion/Removal
	 */
	if ((device->status.present) && !(old_status.present)) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n"));
		/* TBD: Handle device insertion */
L
Len Brown 已提交
488
	} else if (!(device->status.present) && (old_status.present)) {
L
Linus Torvalds 已提交
489 490 491 492 493
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
		/* TBD: Handle device removal */
	}
}

494
static void acpi_bus_check_scope(acpi_handle handle)
L
Linus Torvalds 已提交
495 496
{
	/* Status Change? */
497
	acpi_bus_check_device(handle);
L
Linus Torvalds 已提交
498 499 500 501 502 503 504

	/*
	 * TBD: Enumerate child devices within this device's scope and
	 *       run acpi_bus_check_device()'s on them.
	 */
}

505 506 507 508 509 510 511 512 513 514 515 516 517
static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
int register_acpi_bus_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
}
EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);

void unregister_acpi_bus_notifier(struct notifier_block *nb)
{
	blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
}
EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);

L
Linus Torvalds 已提交
518 519 520 521 522
/**
 * acpi_bus_notify
 * ---------------
 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
 */
L
Len Brown 已提交
523
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
L
Linus Torvalds 已提交
524
{
L
Len Brown 已提交
525
	struct acpi_device *device = NULL;
526
	struct acpi_driver *driver;
L
Linus Torvalds 已提交
527

528 529 530
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
			  type, handle));

531 532
	blocking_notifier_call_chain(&acpi_bus_notify_list,
		type, (void *)handle);
L
Linus Torvalds 已提交
533 534 535 536

	switch (type) {

	case ACPI_NOTIFY_BUS_CHECK:
537
		acpi_bus_check_scope(handle);
538
		/*
L
Linus Torvalds 已提交
539
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
540
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
541 542 543 544
		 */
		break;

	case ACPI_NOTIFY_DEVICE_CHECK:
545
		acpi_bus_check_device(handle);
546
		/*
L
Linus Torvalds 已提交
547
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
548
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
		 */
		break;

	case ACPI_NOTIFY_DEVICE_WAKE:
		/* TBD */
		break;

	case ACPI_NOTIFY_EJECT_REQUEST:
		/* TBD */
		break;

	case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
		/* TBD: Exactly what does 'light' mean? */
		break;

	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
		/* TBD */
		break;

	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
		/* TBD */
		break;

	case ACPI_NOTIFY_POWER_FAULT:
		/* TBD */
		break;

	default:
L
Len Brown 已提交
577 578 579
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received unknown/unsupported notification [%08x]\n",
				  type));
L
Linus Torvalds 已提交
580 581 582
		break;
	}

583 584 585 586 587 588 589
	acpi_bus_get_device(handle, &device);
	if (device) {
		driver = device->driver;
		if (driver && driver->ops.notify &&
		    (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
			driver->ops.notify(device, type);
	}
L
Linus Torvalds 已提交
590 591 592 593 594 595
}

/* --------------------------------------------------------------------------
                             Initialization/Cleanup
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
596
static int __init acpi_bus_init_irq(void)
L
Linus Torvalds 已提交
597
{
L
Len Brown 已提交
598 599 600 601
	acpi_status status = AE_OK;
	union acpi_object arg = { ACPI_TYPE_INTEGER };
	struct acpi_object_list arg_list = { 1, &arg };
	char *message = NULL;
L
Linus Torvalds 已提交
602 603


604
	/*
L
Linus Torvalds 已提交
605 606 607 608 609 610 611 612 613 614 615 616 617 618
	 * Let the system know what interrupt model we are using by
	 * evaluating the \_PIC object, if exists.
	 */

	switch (acpi_irq_model) {
	case ACPI_IRQ_MODEL_PIC:
		message = "PIC";
		break;
	case ACPI_IRQ_MODEL_IOAPIC:
		message = "IOAPIC";
		break;
	case ACPI_IRQ_MODEL_IOSAPIC:
		message = "IOSAPIC";
		break;
J
John Keller 已提交
619 620 621
	case ACPI_IRQ_MODEL_PLATFORM:
		message = "platform specific model";
		break;
L
Linus Torvalds 已提交
622 623
	default:
		printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
624
		return -ENODEV;
L
Linus Torvalds 已提交
625 626 627 628 629 630 631 632
	}

	printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);

	arg.integer.value = acpi_irq_model;

	status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
633
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
634
		return -ENODEV;
L
Linus Torvalds 已提交
635 636
	}

637
	return 0;
L
Linus Torvalds 已提交
638 639
}

640
u8 acpi_gbl_permanent_mmap;
641 642


L
Len Brown 已提交
643
void __init acpi_early_init(void)
L
Linus Torvalds 已提交
644
{
L
Len Brown 已提交
645
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
646 647

	if (acpi_disabled)
648
		return;
L
Linus Torvalds 已提交
649

B
Bob Moore 已提交
650 651
	printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);

L
Linus Torvalds 已提交
652 653 654 655
	/* enable workarounds, unless strict ACPI spec. compliance */
	if (!acpi_strict)
		acpi_gbl_enable_interpreter_slack = TRUE;

656 657 658 659 660 661 662 663 664
	acpi_gbl_permanent_mmap = 1;

	status = acpi_reallocate_root_table();
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX
		       "Unable to reallocate ACPI tables\n");
		goto error0;
	}

L
Linus Torvalds 已提交
665 666
	status = acpi_initialize_subsystem();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
667 668
		printk(KERN_ERR PREFIX
		       "Unable to initialize the ACPI Interpreter\n");
L
Linus Torvalds 已提交
669 670 671 672 673
		goto error0;
	}

	status = acpi_load_tables();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
674 675
		printk(KERN_ERR PREFIX
		       "Unable to load the System Description Tables\n");
L
Linus Torvalds 已提交
676 677 678 679 680 681
		goto error0;
	}

#ifdef CONFIG_X86
	if (!acpi_ioapic) {
		/* compatible (0) means level (3) */
682 683 684 685
		if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) {
			acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK;
			acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL;
		}
L
Linus Torvalds 已提交
686
		/* Set PIC-mode SCI trigger type */
687
		acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
688
					 (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
L
Linus Torvalds 已提交
689 690
	} else {
		/*
691
		 * now that acpi_gbl_FADT is initialized,
L
Linus Torvalds 已提交
692 693
		 * update it with result from INT_SRC_OVR parsing
		 */
694
		acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
L
Linus Torvalds 已提交
695 696 697
	}
#endif

L
Len Brown 已提交
698 699 700 701
	status =
	    acpi_enable_subsystem(~
				  (ACPI_NO_HARDWARE_INIT |
				   ACPI_NO_ACPI_ENABLE));
L
Linus Torvalds 已提交
702 703 704 705 706
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
		goto error0;
	}

707
	return;
L
Linus Torvalds 已提交
708

L
Len Brown 已提交
709
      error0:
L
Linus Torvalds 已提交
710
	disable_acpi();
711
	return;
L
Linus Torvalds 已提交
712 713
}

L
Len Brown 已提交
714
static int __init acpi_bus_init(void)
L
Linus Torvalds 已提交
715
{
L
Len Brown 已提交
716 717 718
	int result = 0;
	acpi_status status = AE_OK;
	extern acpi_status acpi_os_initialize1(void);
L
Linus Torvalds 已提交
719

720
	acpi_os_initialize1();
L
Linus Torvalds 已提交
721

L
Len Brown 已提交
722 723
	status =
	    acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
L
Linus Torvalds 已提交
724
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
725 726
		printk(KERN_ERR PREFIX
		       "Unable to start the ACPI Interpreter\n");
L
Linus Torvalds 已提交
727 728 729 730 731 732 733 734
		goto error1;
	}

	/*
	 * ACPI 2.0 requires the EC driver to be loaded and work before
	 * the EC device is found in the namespace (i.e. before acpi_initialize_objects()
	 * is called).
	 *
735
	 * This is accomplished by looking for the ECDT table, and getting
L
Linus Torvalds 已提交
736 737 738 739 740 741 742 743 744 745 746
	 * the EC parameters out of that.
	 */
	status = acpi_ec_ecdt_probe();
	/* Ignore result. Not having an ECDT is not fatal. */

	status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
		goto error1;
	}

747 748 749 750 751 752
	/*
	 * Maybe EC region is required at bus_scan/acpi_get_devices. So it
	 * is necessary to enable it as early as possible.
	 */
	acpi_boot_ec_enable();

L
Linus Torvalds 已提交
753 754
	printk(KERN_INFO PREFIX "Interpreter enabled\n");

755 756 757
	/* Initialize sleep structures */
	acpi_sleep_init();

L
Linus Torvalds 已提交
758 759 760 761 762 763 764 765 766 767
	/*
	 * Get the system interrupt model and evaluate \_PIC.
	 */
	result = acpi_bus_init_irq();
	if (result)
		goto error1;

	/*
	 * Register the for all standard device notifications.
	 */
L
Len Brown 已提交
768 769 770
	status =
	    acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
					&acpi_bus_notify, NULL);
L
Linus Torvalds 已提交
771
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
772 773
		printk(KERN_ERR PREFIX
		       "Unable to register for device notifications\n");
L
Linus Torvalds 已提交
774 775 776 777 778 779 780 781
		goto error1;
	}

	/*
	 * Create the top ACPI proc directory
	 */
	acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);

782
	return 0;
L
Linus Torvalds 已提交
783 784

	/* Mimic structured exception handling */
L
Len Brown 已提交
785
      error1:
L
Linus Torvalds 已提交
786
	acpi_terminate();
787
	return -ENODEV;
L
Linus Torvalds 已提交
788 789
}

790
struct kobject *acpi_kobj;
L
Linus Torvalds 已提交
791

L
Len Brown 已提交
792
static int __init acpi_init(void)
L
Linus Torvalds 已提交
793
{
L
Len Brown 已提交
794
	int result = 0;
L
Linus Torvalds 已提交
795 796 797 798


	if (acpi_disabled) {
		printk(KERN_INFO PREFIX "Interpreter disabled.\n");
799
		return -ENODEV;
L
Linus Torvalds 已提交
800 801
	}

802
	acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
803
	if (!acpi_kobj) {
804
		printk(KERN_WARNING "%s: kset create error\n", __func__);
805 806
		acpi_kobj = NULL;
	}
L
Linus Torvalds 已提交
807

808
	init_acpi_device_notify();
L
Linus Torvalds 已提交
809 810 811
	result = acpi_bus_init();

	if (!result) {
812
		pci_mmcfg_late_init();
813 814
		if (!(pm_flags & PM_APM))
			pm_flags |= PM_ACPI;
L
Linus Torvalds 已提交
815
		else {
L
Len Brown 已提交
816 817
			printk(KERN_INFO PREFIX
			       "APM is already active, exiting\n");
L
Linus Torvalds 已提交
818 819 820 821 822
			disable_acpi();
			result = -ENODEV;
		}
	} else
		disable_acpi();
823 824 825 826

	if (acpi_disabled)
		return result;

827 828 829 830 831
	/*
	 * If the laptop falls into the DMI check table, the power state check
	 * will be disabled in the course of device power transistion.
	 */
	dmi_check_system(power_nocheck_dmi_table);
832 833

	acpi_scan_init();
834
	acpi_ec_init();
835
	acpi_power_init();
836
	acpi_system_init();
837
	acpi_debug_init();
838
	acpi_sleep_proc_init();
839
	acpi_wakeup_device_init();
840
	return result;
L
Linus Torvalds 已提交
841 842 843
}

subsys_initcall(acpi_init);