bus.c 20.9 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 453

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

static int
L
Len Brown 已提交
454
acpi_bus_check_device(struct acpi_device *device, int *status_changed)
L
Linus Torvalds 已提交
455
{
L
Len Brown 已提交
456
	acpi_status status = 0;
L
Linus Torvalds 已提交
457 458 459 460
	struct acpi_device_status old_status;


	if (!device)
461
		return -EINVAL;
L
Linus Torvalds 已提交
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477

	if (status_changed)
		*status_changed = 0;

	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;
		if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) {
			if (status_changed)
				*status_changed = 1;
		}
478
		return 0;
L
Linus Torvalds 已提交
479 480 481 482
	}

	status = acpi_bus_get_status(device);
	if (ACPI_FAILURE(status))
483
		return -ENODEV;
L
Linus Torvalds 已提交
484 485

	if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
486
		return 0;
L
Linus Torvalds 已提交
487 488 489

	if (status_changed)
		*status_changed = 1;
L
Len Brown 已提交
490

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

502
	return 0;
L
Linus Torvalds 已提交
503 504
}

L
Len Brown 已提交
505
static int acpi_bus_check_scope(struct acpi_device *device)
L
Linus Torvalds 已提交
506
{
L
Len Brown 已提交
507 508
	int result = 0;
	int status_changed = 0;
L
Linus Torvalds 已提交
509 510 511


	if (!device)
512
		return -EINVAL;
L
Linus Torvalds 已提交
513 514 515 516

	/* Status Change? */
	result = acpi_bus_check_device(device, &status_changed);
	if (result)
517
		return result;
L
Linus Torvalds 已提交
518 519

	if (!status_changed)
520
		return 0;
L
Linus Torvalds 已提交
521 522 523 524 525 526

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

527
	return 0;
L
Linus Torvalds 已提交
528 529
}

530 531 532 533 534 535 536 537 538 539 540 541 542
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 已提交
543 544 545 546 547
/**
 * acpi_bus_notify
 * ---------------
 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
 */
L
Len Brown 已提交
548
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
L
Linus Torvalds 已提交
549
{
L
Len Brown 已提交
550 551
	int result = 0;
	struct acpi_device *device = NULL;
552
	struct acpi_driver *driver;
L
Linus Torvalds 已提交
553

554 555 556
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
			  type, handle));

557 558
	blocking_notifier_call_chain(&acpi_bus_notify_list,
		type, (void *)handle);
L
Linus Torvalds 已提交
559 560

	if (acpi_bus_get_device(handle, &device))
561
		return;
L
Linus Torvalds 已提交
562 563 564 565 566

	switch (type) {

	case ACPI_NOTIFY_BUS_CHECK:
		result = acpi_bus_check_scope(device);
567
		/*
L
Linus Torvalds 已提交
568
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
569
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
570 571 572 573 574
		 */
		break;

	case ACPI_NOTIFY_DEVICE_CHECK:
		result = acpi_bus_check_device(device, NULL);
575
		/*
L
Linus Torvalds 已提交
576
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
577
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
		 */
		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 已提交
606 607 608
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received unknown/unsupported notification [%08x]\n",
				  type));
L
Linus Torvalds 已提交
609 610 611
		break;
	}

612 613 614 615
	driver = device->driver;
	if (driver && driver->ops.notify &&
	    (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
		driver->ops.notify(device, type);
L
Linus Torvalds 已提交
616 617 618 619 620 621
}

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

L
Len Brown 已提交
622
static int __init acpi_bus_init_irq(void)
L
Linus Torvalds 已提交
623
{
L
Len Brown 已提交
624 625 626 627
	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 已提交
628 629


630
	/*
L
Linus Torvalds 已提交
631 632 633 634 635 636 637 638 639 640 641 642 643 644
	 * 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 已提交
645 646 647
	case ACPI_IRQ_MODEL_PLATFORM:
		message = "platform specific model";
		break;
L
Linus Torvalds 已提交
648 649
	default:
		printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
650
		return -ENODEV;
L
Linus Torvalds 已提交
651 652 653 654 655 656 657 658
	}

	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)) {
659
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
660
		return -ENODEV;
L
Linus Torvalds 已提交
661 662
	}

663
	return 0;
L
Linus Torvalds 已提交
664 665
}

666
u8 acpi_gbl_permanent_mmap;
667 668


L
Len Brown 已提交
669
void __init acpi_early_init(void)
L
Linus Torvalds 已提交
670
{
L
Len Brown 已提交
671
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
672 673

	if (acpi_disabled)
674
		return;
L
Linus Torvalds 已提交
675

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

L
Linus Torvalds 已提交
678 679 680 681
	/* enable workarounds, unless strict ACPI spec. compliance */
	if (!acpi_strict)
		acpi_gbl_enable_interpreter_slack = TRUE;

682 683 684 685 686 687 688 689 690
	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 已提交
691 692
	status = acpi_initialize_subsystem();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
693 694
		printk(KERN_ERR PREFIX
		       "Unable to initialize the ACPI Interpreter\n");
L
Linus Torvalds 已提交
695 696 697 698 699
		goto error0;
	}

	status = acpi_load_tables();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
700 701
		printk(KERN_ERR PREFIX
		       "Unable to load the System Description Tables\n");
L
Linus Torvalds 已提交
702 703 704 705 706 707
		goto error0;
	}

#ifdef CONFIG_X86
	if (!acpi_ioapic) {
		/* compatible (0) means level (3) */
708 709 710 711
		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 已提交
712
		/* Set PIC-mode SCI trigger type */
713
		acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
714
					 (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
L
Linus Torvalds 已提交
715 716
	} else {
		/*
717
		 * now that acpi_gbl_FADT is initialized,
L
Linus Torvalds 已提交
718 719
		 * update it with result from INT_SRC_OVR parsing
		 */
720
		acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
L
Linus Torvalds 已提交
721 722 723
	}
#endif

L
Len Brown 已提交
724 725 726 727
	status =
	    acpi_enable_subsystem(~
				  (ACPI_NO_HARDWARE_INIT |
				   ACPI_NO_ACPI_ENABLE));
L
Linus Torvalds 已提交
728 729 730 731 732
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
		goto error0;
	}

733
	return;
L
Linus Torvalds 已提交
734

L
Len Brown 已提交
735
      error0:
L
Linus Torvalds 已提交
736
	disable_acpi();
737
	return;
L
Linus Torvalds 已提交
738 739
}

L
Len Brown 已提交
740
static int __init acpi_bus_init(void)
L
Linus Torvalds 已提交
741
{
L
Len Brown 已提交
742 743 744
	int result = 0;
	acpi_status status = AE_OK;
	extern acpi_status acpi_os_initialize1(void);
L
Linus Torvalds 已提交
745

746
	acpi_os_initialize1();
L
Linus Torvalds 已提交
747

L
Len Brown 已提交
748 749
	status =
	    acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
L
Linus Torvalds 已提交
750
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
751 752
		printk(KERN_ERR PREFIX
		       "Unable to start the ACPI Interpreter\n");
L
Linus Torvalds 已提交
753 754 755 756 757 758 759 760
		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).
	 *
761
	 * This is accomplished by looking for the ECDT table, and getting
L
Linus Torvalds 已提交
762 763 764 765 766 767 768 769 770 771 772
	 * 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;
	}

773 774 775 776 777 778
	/*
	 * 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 已提交
779 780
	printk(KERN_INFO PREFIX "Interpreter enabled\n");

781 782 783
	/* Initialize sleep structures */
	acpi_sleep_init();

L
Linus Torvalds 已提交
784 785 786 787 788 789 790 791 792 793
	/*
	 * 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 已提交
794 795 796
	status =
	    acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
					&acpi_bus_notify, NULL);
L
Linus Torvalds 已提交
797
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
798 799
		printk(KERN_ERR PREFIX
		       "Unable to register for device notifications\n");
L
Linus Torvalds 已提交
800 801 802 803 804 805 806 807
		goto error1;
	}

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

808
	return 0;
L
Linus Torvalds 已提交
809 810

	/* Mimic structured exception handling */
L
Len Brown 已提交
811
      error1:
L
Linus Torvalds 已提交
812
	acpi_terminate();
813
	return -ENODEV;
L
Linus Torvalds 已提交
814 815
}

816
struct kobject *acpi_kobj;
L
Linus Torvalds 已提交
817

L
Len Brown 已提交
818
static int __init acpi_init(void)
L
Linus Torvalds 已提交
819
{
L
Len Brown 已提交
820
	int result = 0;
L
Linus Torvalds 已提交
821 822 823 824


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

828
	acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
829
	if (!acpi_kobj) {
830
		printk(KERN_WARNING "%s: kset create error\n", __func__);
831 832
		acpi_kobj = NULL;
	}
L
Linus Torvalds 已提交
833

834
	init_acpi_device_notify();
L
Linus Torvalds 已提交
835 836 837
	result = acpi_bus_init();

	if (!result) {
838
		pci_mmcfg_late_init();
839 840
		if (!(pm_flags & PM_APM))
			pm_flags |= PM_ACPI;
L
Linus Torvalds 已提交
841
		else {
L
Len Brown 已提交
842 843
			printk(KERN_INFO PREFIX
			       "APM is already active, exiting\n");
L
Linus Torvalds 已提交
844 845 846 847 848
			disable_acpi();
			result = -ENODEV;
		}
	} else
		disable_acpi();
849 850 851 852

	if (acpi_disabled)
		return result;

853 854 855 856 857
	/*
	 * 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);
858 859

	acpi_scan_init();
860
	acpi_ec_init();
861
	acpi_power_init();
862
	acpi_system_init();
863
	acpi_debug_init();
864
	acpi_sleep_proc_init();
865
	acpi_wakeup_device_init();
866
	return result;
L
Linus Torvalds 已提交
867 868 869
}

subsys_initcall(acpi_init);