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
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
41
#include <linux/dmi.h>
L
Linus Torvalds 已提交
42

43 44
#include "internal.h"

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

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

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

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
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 已提交
71 72 73 74
/* --------------------------------------------------------------------------
                                Device Management
   -------------------------------------------------------------------------- */

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


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

	/* TBD: Support fixed-feature devices */

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

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

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

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

L
Linus Torvalds 已提交
102 103

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

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

	/*
118 119 120 121
	 * 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 已提交
122 123
	 */
	else
124 125 126
		STRUCT_TO_INT(device->status) =
		    ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
		    ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING;
L
Linus Torvalds 已提交
127 128

	if (device->status.functional && !device->status.present) {
129 130 131 132
		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 已提交
133 134
	}

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

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

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

Z
Zhang Rui 已提交
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
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 已提交
169 170 171 172
/* --------------------------------------------------------------------------
                                 Power Management
   -------------------------------------------------------------------------- */

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


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

	*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 已提交
193
	} else {
L
Linus Torvalds 已提交
194
		/*
195
		 * Get the device's power state either directly (via _PSC) or
L
Linus Torvalds 已提交
196 197 198
		 * indirectly (via power resources).
		 */
		if (device->power.flags.explicit_get) {
L
Len Brown 已提交
199 200
			status = acpi_evaluate_integer(device->handle, "_PSC",
						       NULL, &psc);
L
Linus Torvalds 已提交
201
			if (ACPI_FAILURE(status))
202
				return -ENODEV;
L
Len Brown 已提交
203 204
			device->power.state = (int)psc;
		} else if (device->power.flags.power_resources) {
L
Linus Torvalds 已提交
205 206
			result = acpi_power_get_inferred_state(device);
			if (result)
207
				return result;
L
Linus Torvalds 已提交
208 209 210 211 212 213
		}

		*state = device->power.state;
	}

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

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

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

L
Len Brown 已提交
221
int acpi_bus_set_power(acpi_handle handle, int state)
L
Linus Torvalds 已提交
222
{
L
Len Brown 已提交
223 224 225 226
	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 已提交
227 228 229 230


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

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

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

	if (!device->flags.power_manageable) {
239
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
240
				kobject_name(&device->dev.kobj)));
241
		return -ENODEV;
L
Linus Torvalds 已提交
242
	}
243
	/*
244
	 * Get device's current power state
245
	 */
246 247 248 249 250 251 252 253 254 255 256 257 258
	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);
	}
259
	if ((state == device->power.state) && !device->flags.force_power_state) {
260 261 262
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
				  state));
		return 0;
L
Linus Torvalds 已提交
263
	}
264

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

	/*
	 * 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.
282
	 */
L
Linus Torvalds 已提交
283 284 285 286 287 288 289
	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 已提交
290 291
			status = acpi_evaluate_object(device->handle,
						      object_name, NULL, NULL);
L
Linus Torvalds 已提交
292 293 294 295 296
			if (ACPI_FAILURE(status)) {
				result = -ENODEV;
				goto end;
			}
		}
L
Len Brown 已提交
297
	} else {
L
Linus Torvalds 已提交
298
		if (device->power.states[state].flags.explicit_set) {
L
Len Brown 已提交
299 300
			status = acpi_evaluate_object(device->handle,
						      object_name, NULL, NULL);
L
Linus Torvalds 已提交
301 302 303 304 305 306 307 308 309 310 311 312
			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 已提交
313
      end:
L
Linus Torvalds 已提交
314
	if (result)
315
		printk(KERN_WARNING PREFIX
L
Len Brown 已提交
316
			      "Device [%s] failed to transition to D%d\n",
317
			      device->pnp.bus_id, state);
318 319
	else {
		device->power.state = state;
L
Len Brown 已提交
320 321 322
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Device [%s] transitioned to D%d\n",
				  device->pnp.bus_id, state));
323
	}
L
Linus Torvalds 已提交
324

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

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

330 331 332 333 334 335 336 337 338 339 340
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);

341 342 343 344 345 346 347 348 349 350 351
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 已提交
352 353 354 355
/* --------------------------------------------------------------------------
                                Event Management
   -------------------------------------------------------------------------- */

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

LIST_HEAD(acpi_bus_event_list);
DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);

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

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

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

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

377 378
	strcpy(event->device_class, device_class);
	strcpy(event->bus_id, bus_id);
L
Linus Torvalds 已提交
379 380 381 382 383 384 385 386 387
	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);

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

}

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 已提交
400
}
L
Len Brown 已提交
401

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

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

	DECLARE_WAITQUEUE(wait, current);


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

	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))
427
			return -ERESTARTSYS;
L
Linus Torvalds 已提交
428 429 430
	}

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

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

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

	kfree(entry);

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

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

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

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

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

	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;
473
		return;
L
Linus Torvalds 已提交
474 475 476 477
	}

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

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

	/*
	 * 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 已提交
489
	} else if (!(device->status.present) && (old_status.present)) {
L
Linus Torvalds 已提交
490 491 492 493 494
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
		/* TBD: Handle device removal */
	}
}

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

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

506 507 508 509 510 511 512 513 514 515 516 517 518
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 已提交
519 520 521 522 523
/**
 * acpi_bus_notify
 * ---------------
 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
 */
L
Len Brown 已提交
524
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
L
Linus Torvalds 已提交
525
{
L
Len Brown 已提交
526
	struct acpi_device *device = NULL;
527
	struct acpi_driver *driver;
L
Linus Torvalds 已提交
528

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

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

	switch (type) {

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

	case ACPI_NOTIFY_DEVICE_CHECK:
546
		acpi_bus_check_device(handle);
547
		/*
L
Linus Torvalds 已提交
548
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
549
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
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 577
		 */
		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 已提交
578 579 580
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received unknown/unsupported notification [%08x]\n",
				  type));
L
Linus Torvalds 已提交
581 582 583
		break;
	}

584 585 586 587 588 589 590
	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 已提交
591 592 593 594 595 596
}

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

L
Len Brown 已提交
597
static int __init acpi_bus_init_irq(void)
L
Linus Torvalds 已提交
598
{
L
Len Brown 已提交
599 600 601 602
	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 已提交
603 604


605
	/*
L
Linus Torvalds 已提交
606 607 608 609 610 611 612 613 614 615 616 617 618 619
	 * 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 已提交
620 621 622
	case ACPI_IRQ_MODEL_PLATFORM:
		message = "platform specific model";
		break;
L
Linus Torvalds 已提交
623 624
	default:
		printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
625
		return -ENODEV;
L
Linus Torvalds 已提交
626 627 628 629 630 631 632 633
	}

	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)) {
634
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
635
		return -ENODEV;
L
Linus Torvalds 已提交
636 637
	}

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

641
u8 acpi_gbl_permanent_mmap;
642 643


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

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

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

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

657 658 659 660 661 662 663 664 665
	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 已提交
666 667
	status = acpi_initialize_subsystem();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
668 669
		printk(KERN_ERR PREFIX
		       "Unable to initialize the ACPI Interpreter\n");
L
Linus Torvalds 已提交
670 671 672 673 674
		goto error0;
	}

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

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

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

708
	return;
L
Linus Torvalds 已提交
709

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

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

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

L
Len Brown 已提交
723 724
	status =
	    acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
L
Linus Torvalds 已提交
725
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
726 727
		printk(KERN_ERR PREFIX
		       "Unable to start the ACPI Interpreter\n");
L
Linus Torvalds 已提交
728 729 730 731 732 733 734 735
		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).
	 *
736
	 * This is accomplished by looking for the ECDT table, and getting
L
Linus Torvalds 已提交
737 738 739 740 741 742 743 744 745 746 747
	 * 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;
	}

748 749 750 751 752 753
	/*
	 * 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 已提交
754 755
	printk(KERN_INFO PREFIX "Interpreter enabled\n");

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

L
Linus Torvalds 已提交
759 760 761 762 763 764 765 766 767 768
	/*
	 * 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 已提交
769 770 771
	status =
	    acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
					&acpi_bus_notify, NULL);
L
Linus Torvalds 已提交
772
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
773 774
		printk(KERN_ERR PREFIX
		       "Unable to register for device notifications\n");
L
Linus Torvalds 已提交
775 776 777 778 779 780 781 782
		goto error1;
	}

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

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

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

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

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


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

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

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

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

	if (acpi_disabled)
		return result;

828 829 830 831 832
	/*
	 * 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);
833 834

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

subsys_initcall(acpi_init);