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 int acpi_bus_check_device(struct acpi_device *device)
L
Linus Torvalds 已提交
454
{
L
Len Brown 已提交
455
	acpi_status status = 0;
L
Linus Torvalds 已提交
456 457 458 459
	struct acpi_device_status old_status;


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

	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;
470
		return 0;
L
Linus Torvalds 已提交
471 472 473 474
	}

	status = acpi_bus_get_status(device);
	if (ACPI_FAILURE(status))
475
		return -ENODEV;
L
Linus Torvalds 已提交
476 477

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

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

491
	return 0;
L
Linus Torvalds 已提交
492 493
}

L
Len Brown 已提交
494
static int acpi_bus_check_scope(struct acpi_device *device)
L
Linus Torvalds 已提交
495
{
L
Len Brown 已提交
496
	int result = 0;
L
Linus Torvalds 已提交
497 498

	if (!device)
499
		return -EINVAL;
L
Linus Torvalds 已提交
500 501

	/* Status Change? */
502
	result = acpi_bus_check_device(device);
L
Linus Torvalds 已提交
503
	if (result)
504
		return result;
L
Linus Torvalds 已提交
505 506 507 508 509 510

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

511
	return 0;
L
Linus Torvalds 已提交
512 513
}

514 515 516 517 518 519 520 521 522 523 524 525 526
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 已提交
527 528 529 530 531
/**
 * acpi_bus_notify
 * ---------------
 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
 */
L
Len Brown 已提交
532
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
L
Linus Torvalds 已提交
533
{
L
Len Brown 已提交
534 535
	int result = 0;
	struct acpi_device *device = NULL;
536
	struct acpi_driver *driver;
L
Linus Torvalds 已提交
537

538 539 540
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
			  type, handle));

541 542
	blocking_notifier_call_chain(&acpi_bus_notify_list,
		type, (void *)handle);
L
Linus Torvalds 已提交
543 544

	if (acpi_bus_get_device(handle, &device))
545
		return;
L
Linus Torvalds 已提交
546 547 548 549 550

	switch (type) {

	case ACPI_NOTIFY_BUS_CHECK:
		result = acpi_bus_check_scope(device);
551
		/*
L
Linus Torvalds 已提交
552
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
553
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
554 555 556 557
		 */
		break;

	case ACPI_NOTIFY_DEVICE_CHECK:
558
		result = acpi_bus_check_device(device);
559
		/*
L
Linus Torvalds 已提交
560
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
561
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
		 */
		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 已提交
590 591 592
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received unknown/unsupported notification [%08x]\n",
				  type));
L
Linus Torvalds 已提交
593 594 595
		break;
	}

596 597 598 599
	driver = device->driver;
	if (driver && driver->ops.notify &&
	    (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
		driver->ops.notify(device, type);
L
Linus Torvalds 已提交
600 601 602 603 604 605
}

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

L
Len Brown 已提交
606
static int __init acpi_bus_init_irq(void)
L
Linus Torvalds 已提交
607
{
L
Len Brown 已提交
608 609 610 611
	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 已提交
612 613


614
	/*
L
Linus Torvalds 已提交
615 616 617 618 619 620 621 622 623 624 625 626 627 628
	 * 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 已提交
629 630 631
	case ACPI_IRQ_MODEL_PLATFORM:
		message = "platform specific model";
		break;
L
Linus Torvalds 已提交
632 633
	default:
		printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
634
		return -ENODEV;
L
Linus Torvalds 已提交
635 636 637 638 639 640 641 642
	}

	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)) {
643
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
644
		return -ENODEV;
L
Linus Torvalds 已提交
645 646
	}

647
	return 0;
L
Linus Torvalds 已提交
648 649
}

650
u8 acpi_gbl_permanent_mmap;
651 652


L
Len Brown 已提交
653
void __init acpi_early_init(void)
L
Linus Torvalds 已提交
654
{
L
Len Brown 已提交
655
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
656 657

	if (acpi_disabled)
658
		return;
L
Linus Torvalds 已提交
659

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

L
Linus Torvalds 已提交
662 663 664 665
	/* enable workarounds, unless strict ACPI spec. compliance */
	if (!acpi_strict)
		acpi_gbl_enable_interpreter_slack = TRUE;

666 667 668 669 670 671 672 673 674
	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 已提交
675 676
	status = acpi_initialize_subsystem();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
677 678
		printk(KERN_ERR PREFIX
		       "Unable to initialize the ACPI Interpreter\n");
L
Linus Torvalds 已提交
679 680 681 682 683
		goto error0;
	}

	status = acpi_load_tables();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
684 685
		printk(KERN_ERR PREFIX
		       "Unable to load the System Description Tables\n");
L
Linus Torvalds 已提交
686 687 688 689 690 691
		goto error0;
	}

#ifdef CONFIG_X86
	if (!acpi_ioapic) {
		/* compatible (0) means level (3) */
692 693 694 695
		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 已提交
696
		/* Set PIC-mode SCI trigger type */
697
		acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
698
					 (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
L
Linus Torvalds 已提交
699 700
	} else {
		/*
701
		 * now that acpi_gbl_FADT is initialized,
L
Linus Torvalds 已提交
702 703
		 * update it with result from INT_SRC_OVR parsing
		 */
704
		acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
L
Linus Torvalds 已提交
705 706 707
	}
#endif

L
Len Brown 已提交
708 709 710 711
	status =
	    acpi_enable_subsystem(~
				  (ACPI_NO_HARDWARE_INIT |
				   ACPI_NO_ACPI_ENABLE));
L
Linus Torvalds 已提交
712 713 714 715 716
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
		goto error0;
	}

717
	return;
L
Linus Torvalds 已提交
718

L
Len Brown 已提交
719
      error0:
L
Linus Torvalds 已提交
720
	disable_acpi();
721
	return;
L
Linus Torvalds 已提交
722 723
}

L
Len Brown 已提交
724
static int __init acpi_bus_init(void)
L
Linus Torvalds 已提交
725
{
L
Len Brown 已提交
726 727 728
	int result = 0;
	acpi_status status = AE_OK;
	extern acpi_status acpi_os_initialize1(void);
L
Linus Torvalds 已提交
729

730
	acpi_os_initialize1();
L
Linus Torvalds 已提交
731

L
Len Brown 已提交
732 733
	status =
	    acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
L
Linus Torvalds 已提交
734
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
735 736
		printk(KERN_ERR PREFIX
		       "Unable to start the ACPI Interpreter\n");
L
Linus Torvalds 已提交
737 738 739 740 741 742 743 744
		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).
	 *
745
	 * This is accomplished by looking for the ECDT table, and getting
L
Linus Torvalds 已提交
746 747 748 749 750 751 752 753 754 755 756
	 * 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;
	}

757 758 759 760 761 762
	/*
	 * 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 已提交
763 764
	printk(KERN_INFO PREFIX "Interpreter enabled\n");

765 766 767
	/* Initialize sleep structures */
	acpi_sleep_init();

L
Linus Torvalds 已提交
768 769 770 771 772 773 774 775 776 777
	/*
	 * 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 已提交
778 779 780
	status =
	    acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
					&acpi_bus_notify, NULL);
L
Linus Torvalds 已提交
781
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
782 783
		printk(KERN_ERR PREFIX
		       "Unable to register for device notifications\n");
L
Linus Torvalds 已提交
784 785 786 787 788 789 790 791
		goto error1;
	}

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

792
	return 0;
L
Linus Torvalds 已提交
793 794

	/* Mimic structured exception handling */
L
Len Brown 已提交
795
      error1:
L
Linus Torvalds 已提交
796
	acpi_terminate();
797
	return -ENODEV;
L
Linus Torvalds 已提交
798 799
}

800
struct kobject *acpi_kobj;
L
Linus Torvalds 已提交
801

L
Len Brown 已提交
802
static int __init acpi_init(void)
L
Linus Torvalds 已提交
803
{
L
Len Brown 已提交
804
	int result = 0;
L
Linus Torvalds 已提交
805 806 807 808


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

812
	acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
813
	if (!acpi_kobj) {
814
		printk(KERN_WARNING "%s: kset create error\n", __func__);
815 816
		acpi_kobj = NULL;
	}
L
Linus Torvalds 已提交
817

818
	init_acpi_device_notify();
L
Linus Torvalds 已提交
819 820 821
	result = acpi_bus_init();

	if (!result) {
822
		pci_mmcfg_late_init();
823 824
		if (!(pm_flags & PM_APM))
			pm_flags |= PM_ACPI;
L
Linus Torvalds 已提交
825
		else {
L
Len Brown 已提交
826 827
			printk(KERN_INFO PREFIX
			       "APM is already active, exiting\n");
L
Linus Torvalds 已提交
828 829 830 831 832
			disable_acpi();
			result = -ENODEV;
		}
	} else
		disable_acpi();
833 834 835 836

	if (acpi_disabled)
		return result;

837 838 839 840 841
	/*
	 * 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);
842 843

	acpi_scan_init();
844
	acpi_ec_init();
845
	acpi_power_init();
846
	acpi_system_init();
847
	acpi_debug_init();
848
	acpi_sleep_proc_init();
849
	acpi_wakeup_device_init();
850
	return result;
L
Linus Torvalds 已提交
851 852 853
}

subsys_initcall(acpi_init);