bus.c 25.8 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>
35
#include <linux/slab.h>
L
Linus Torvalds 已提交
36 37 38
#ifdef CONFIG_X86
#include <asm/mpspec.h>
#endif
39
#include <linux/pci.h>
L
Linus Torvalds 已提交
40 41
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
42
#include <linux/dmi.h>
L
Linus Torvalds 已提交
43

44 45
#include "internal.h"

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

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

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

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
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},
	{},
};


72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
static int set_copy_dsdt(const struct dmi_system_id *id)
{
	printk(KERN_NOTICE "%s detected - "
		"force copy of DSDT to local memory\n", id->ident);
	acpi_gbl_copy_dsdt_locally = 1;
	return 0;
}

static struct dmi_system_id dsdt_dmi_table[] __initdata = {
	/*
	 * Insyde BIOS on some TOSHIBA machines corrupt the DSDT.
	 * https://bugzilla.kernel.org/show_bug.cgi?id=14679
	 */
	{
	 .callback = set_copy_dsdt,
	 .ident = "TOSHIBA Satellite A505",
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
		DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A505"),
		},
	},
	{
	 .callback = set_copy_dsdt,
	 .ident = "TOSHIBA Satellite L505D",
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
		DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L505D"),
		},
	}
};

L
Linus Torvalds 已提交
103 104 105 106
/* --------------------------------------------------------------------------
                                Device Management
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
107
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
L
Linus Torvalds 已提交
108
{
L
Len Brown 已提交
109
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
110 111 112


	if (!device)
113
		return -EINVAL;
L
Linus Torvalds 已提交
114 115 116

	/* TBD: Support fixed-feature devices */

L
Len Brown 已提交
117
	status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
L
Linus Torvalds 已提交
118
	if (ACPI_FAILURE(status) || !*device) {
119 120
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
				  handle));
121
		return -ENODEV;
L
Linus Torvalds 已提交
122 123
	}

124
	return 0;
L
Linus Torvalds 已提交
125
}
L
Len Brown 已提交
126

L
Linus Torvalds 已提交
127 128
EXPORT_SYMBOL(acpi_bus_get_device);

129 130
acpi_status acpi_bus_get_status_handle(acpi_handle handle,
				       unsigned long long *sta)
L
Linus Torvalds 已提交
131
{
132
	acpi_status status;
L
Len Brown 已提交
133

134 135 136
	status = acpi_evaluate_integer(handle, "_STA", NULL, sta);
	if (ACPI_SUCCESS(status))
		return AE_OK;
L
Linus Torvalds 已提交
137

138 139 140 141
	if (status == AE_NOT_FOUND) {
		*sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
		       ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING;
		return AE_OK;
L
Linus Torvalds 已提交
142
	}
143 144
	return status;
}
L
Linus Torvalds 已提交
145

146 147 148 149 150 151 152 153 154 155
int acpi_bus_get_status(struct acpi_device *device)
{
	acpi_status status;
	unsigned long long sta;

	status = acpi_bus_get_status_handle(device->handle, &sta);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	STRUCT_TO_INT(device->status) = (int) sta;
L
Linus Torvalds 已提交
156 157

	if (device->status.functional && !device->status.present) {
158 159 160 161
		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 已提交
162 163
	}

L
Len Brown 已提交
164 165 166
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
			  device->pnp.bus_id,
			  (u32) STRUCT_TO_INT(device->status)));
167
	return 0;
L
Linus Torvalds 已提交
168
}
L
Len Brown 已提交
169
EXPORT_SYMBOL(acpi_bus_get_status);
L
Linus Torvalds 已提交
170

Z
Zhang Rui 已提交
171
void acpi_bus_private_data_handler(acpi_handle handle,
172
				   void *context)
Z
Zhang Rui 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
{
	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 已提交
196 197 198 199
/* --------------------------------------------------------------------------
                                 Power Management
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
200
int acpi_bus_get_power(acpi_handle handle, int *state)
L
Linus Torvalds 已提交
201
{
L
Len Brown 已提交
202 203 204
	int result = 0;
	acpi_status status = 0;
	struct acpi_device *device = NULL;
205
	unsigned long long psc = 0;
L
Linus Torvalds 已提交
206 207 208 209


	result = acpi_bus_get_device(handle, &device);
	if (result)
210
		return result;
L
Linus Torvalds 已提交
211 212 213 214 215 216 217 218 219

	*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 已提交
220
	} else {
L
Linus Torvalds 已提交
221
		/*
222
		 * Get the device's power state either directly (via _PSC) or
L
Linus Torvalds 已提交
223 224
		 * indirectly (via power resources).
		 */
225 226 227 228 229
		if (device->power.flags.power_resources) {
			result = acpi_power_get_inferred_state(device);
			if (result)
				return result;
		} else if (device->power.flags.explicit_get) {
L
Len Brown 已提交
230 231
			status = acpi_evaluate_integer(device->handle, "_PSC",
						       NULL, &psc);
L
Linus Torvalds 已提交
232
			if (ACPI_FAILURE(status))
233
				return -ENODEV;
L
Len Brown 已提交
234
			device->power.state = (int)psc;
L
Linus Torvalds 已提交
235 236 237 238 239 240
		}

		*state = device->power.state;
	}

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

243
	return 0;
L
Linus Torvalds 已提交
244 245
}

L
Len Brown 已提交
246
EXPORT_SYMBOL(acpi_bus_get_power);
L
Linus Torvalds 已提交
247

L
Len Brown 已提交
248
int acpi_bus_set_power(acpi_handle handle, int state)
L
Linus Torvalds 已提交
249
{
L
Len Brown 已提交
250 251 252 253
	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 已提交
254 255 256 257


	result = acpi_bus_get_device(handle, &device);
	if (result)
258
		return result;
L
Linus Torvalds 已提交
259 260

	if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
261
		return -EINVAL;
L
Linus Torvalds 已提交
262 263 264 265

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

	if (!device->flags.power_manageable) {
266
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
267
				kobject_name(&device->dev.kobj)));
268
		return -ENODEV;
L
Linus Torvalds 已提交
269
	}
270
	/*
271
	 * Get device's current power state
272
	 */
273 274 275 276 277 278 279 280 281 282 283 284 285
	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);
	}
286
	if ((state == device->power.state) && !device->flags.force_power_state) {
287 288 289
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
				  state));
		return 0;
L
Linus Torvalds 已提交
290
	}
291

L
Linus Torvalds 已提交
292
	if (!device->power.states[state].flags.valid) {
293
		printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
294
		return -ENODEV;
L
Linus Torvalds 已提交
295 296
	}
	if (device->parent && (state < device->parent->power.state)) {
297
		printk(KERN_WARNING PREFIX
298
			      "Cannot set device to a higher-powered"
299
			      " state than parent\n");
300
		return -ENODEV;
L
Linus Torvalds 已提交
301 302 303 304 305 306 307 308
	}

	/*
	 * 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.
309
	 */
L
Linus Torvalds 已提交
310 311 312 313 314 315 316
	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 已提交
317 318
			status = acpi_evaluate_object(device->handle,
						      object_name, NULL, NULL);
L
Linus Torvalds 已提交
319 320 321 322 323
			if (ACPI_FAILURE(status)) {
				result = -ENODEV;
				goto end;
			}
		}
L
Len Brown 已提交
324
	} else {
L
Linus Torvalds 已提交
325
		if (device->power.states[state].flags.explicit_set) {
L
Len Brown 已提交
326 327
			status = acpi_evaluate_object(device->handle,
						      object_name, NULL, NULL);
L
Linus Torvalds 已提交
328 329 330 331 332 333 334 335 336 337 338 339
			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 已提交
340
      end:
L
Linus Torvalds 已提交
341
	if (result)
342
		printk(KERN_WARNING PREFIX
L
Len Brown 已提交
343
			      "Device [%s] failed to transition to D%d\n",
344
			      device->pnp.bus_id, state);
345 346
	else {
		device->power.state = state;
L
Len Brown 已提交
347 348 349
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Device [%s] transitioned to D%d\n",
				  device->pnp.bus_id, state));
350
	}
L
Linus Torvalds 已提交
351

352
	return result;
L
Linus Torvalds 已提交
353 354
}

L
Len Brown 已提交
355
EXPORT_SYMBOL(acpi_bus_set_power);
L
Linus Torvalds 已提交
356

357 358 359 360 361 362 363 364 365 366 367
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);

368 369 370 371 372 373 374 375 376 377 378
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);

S
Shaohua Li 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
static void acpi_print_osc_error(acpi_handle handle,
	struct acpi_osc_context *context, char *error)
{
	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
	int i;

	if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer)))
		printk(KERN_DEBUG "%s\n", error);
	else {
		printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error);
		kfree(buffer.pointer);
	}
	printk(KERN_DEBUG"_OSC request data:");
	for (i = 0; i < context->cap.length; i += sizeof(u32))
		printk("%x ", *((u32 *)(context->cap.pointer + i)));
	printk("\n");
}

static u8 hex_val(unsigned char c)
{
	return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
}

static acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
{
	int i;
	static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21,
		24, 26, 28, 30, 32, 34};

	if (strlen(str) != 36)
		return AE_BAD_PARAMETER;
	for (i = 0; i < 36; i++) {
		if (i == 8 || i == 13 || i == 18 || i == 23) {
			if (str[i] != '-')
				return AE_BAD_PARAMETER;
		} else if (!isxdigit(str[i]))
			return AE_BAD_PARAMETER;
	}
	for (i = 0; i < 16; i++) {
		uuid[i] = hex_val(str[opc_map_to_uuid[i]]) << 4;
		uuid[i] |= hex_val(str[opc_map_to_uuid[i] + 1]);
	}
	return AE_OK;
}

acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
{
	acpi_status status;
	struct acpi_object_list input;
	union acpi_object in_params[4];
	union acpi_object *out_obj;
	u8 uuid[16];
	u32 errors;
432
	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
S
Shaohua Li 已提交
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454

	if (!context)
		return AE_ERROR;
	if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid)))
		return AE_ERROR;
	context->ret.length = ACPI_ALLOCATE_BUFFER;
	context->ret.pointer = NULL;

	/* Setting up input parameters */
	input.count = 4;
	input.pointer = in_params;
	in_params[0].type 		= ACPI_TYPE_BUFFER;
	in_params[0].buffer.length 	= 16;
	in_params[0].buffer.pointer	= uuid;
	in_params[1].type 		= ACPI_TYPE_INTEGER;
	in_params[1].integer.value 	= context->rev;
	in_params[2].type 		= ACPI_TYPE_INTEGER;
	in_params[2].integer.value	= context->cap.length/sizeof(u32);
	in_params[3].type		= ACPI_TYPE_BUFFER;
	in_params[3].buffer.length 	= context->cap.length;
	in_params[3].buffer.pointer 	= context->cap.pointer;

455
	status = acpi_evaluate_object(handle, "_OSC", &input, &output);
S
Shaohua Li 已提交
456 457 458
	if (ACPI_FAILURE(status))
		return status;

459
	if (!output.length)
S
Shaohua Li 已提交
460 461
		return AE_NULL_OBJECT;

462 463 464
	out_obj = output.pointer;
	if (out_obj->type != ACPI_TYPE_BUFFER
		|| out_obj->buffer.length != context->cap.length) {
S
Shaohua Li 已提交
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
		acpi_print_osc_error(handle, context,
			"_OSC evaluation returned wrong type");
		status = AE_TYPE;
		goto out_kfree;
	}
	/* Need to ignore the bit0 in result code */
	errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
	if (errors) {
		if (errors & OSC_REQUEST_ERROR)
			acpi_print_osc_error(handle, context,
				"_OSC request failed");
		if (errors & OSC_INVALID_UUID_ERROR)
			acpi_print_osc_error(handle, context,
				"_OSC invalid UUID");
		if (errors & OSC_INVALID_REVISION_ERROR)
			acpi_print_osc_error(handle, context,
				"_OSC invalid revision");
		if (errors & OSC_CAPABILITIES_MASK_ERROR) {
			if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
			    & OSC_QUERY_ENABLE)
				goto out_success;
			status = AE_SUPPORT;
			goto out_kfree;
		}
		status = AE_ERROR;
		goto out_kfree;
	}
out_success:
493 494 495 496 497 498 499 500 501
	context->ret.length = out_obj->buffer.length;
	context->ret.pointer = kmalloc(context->ret.length, GFP_KERNEL);
	if (!context->ret.pointer) {
		status =  AE_NO_MEMORY;
		goto out_kfree;
	}
	memcpy(context->ret.pointer, out_obj->buffer.pointer,
		context->ret.length);
	status =  AE_OK;
S
Shaohua Li 已提交
502 503

out_kfree:
504 505 506
	kfree(output.pointer);
	if (status != AE_OK)
		context->ret.pointer = NULL;
S
Shaohua Li 已提交
507 508 509 510
	return status;
}
EXPORT_SYMBOL(acpi_run_osc);

S
Shaohua Li 已提交
511 512 513 514 515 516 517 518 519 520 521 522 523 524
static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
static void acpi_bus_osc_support(void)
{
	u32 capbuf[2];
	struct acpi_osc_context context = {
		.uuid_str = sb_uuid_str,
		.rev = 1,
		.cap.length = 8,
		.cap.pointer = capbuf,
	};
	acpi_handle handle;

	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
	capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */
525 526
#if defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR) ||\
			defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR_MODULE)
S
Shaohua Li 已提交
527 528
	capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT;
#endif
529 530 531 532

#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
	capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT;
#endif
S
Shaohua Li 已提交
533 534 535 536 537 538 539
	if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
		return;
	if (ACPI_SUCCESS(acpi_run_osc(handle, &context)))
		kfree(context.ret.pointer);
	/* do we need to check the returned cap? Sounds no */
}

L
Linus Torvalds 已提交
540 541 542 543
/* --------------------------------------------------------------------------
                                Event Management
   -------------------------------------------------------------------------- */

544
#ifdef CONFIG_ACPI_PROC_EVENT
L
Linus Torvalds 已提交
545 546 547 548 549
static DEFINE_SPINLOCK(acpi_bus_event_lock);

LIST_HEAD(acpi_bus_event_list);
DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);

L
Len Brown 已提交
550
extern int event_is_open;
L
Linus Torvalds 已提交
551

552
int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
L
Linus Torvalds 已提交
553
{
554
	struct acpi_bus_event *event;
L
Len Brown 已提交
555
	unsigned long flags = 0;
L
Linus Torvalds 已提交
556 557 558

	/* drop event on the floor if no one's listening */
	if (!event_is_open)
559
		return 0;
L
Linus Torvalds 已提交
560 561 562

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

565 566
	strcpy(event->device_class, device_class);
	strcpy(event->bus_id, bus_id);
L
Linus Torvalds 已提交
567 568 569 570 571 572 573 574 575
	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);

576
	return 0;
577 578 579 580 581 582 583 584 585 586 587

}

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 已提交
588
}
L
Len Brown 已提交
589

590
EXPORT_SYMBOL(acpi_bus_generate_proc_event);
L
Linus Torvalds 已提交
591

L
Len Brown 已提交
592
int acpi_bus_receive_event(struct acpi_bus_event *event)
L
Linus Torvalds 已提交
593
{
L
Len Brown 已提交
594 595
	unsigned long flags = 0;
	struct acpi_bus_event *entry = NULL;
L
Linus Torvalds 已提交
596 597 598 599 600

	DECLARE_WAITQUEUE(wait, current);


	if (!event)
601
		return -EINVAL;
L
Linus Torvalds 已提交
602 603 604 605 606 607 608 609 610 611 612 613 614

	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))
615
			return -ERESTARTSYS;
L
Linus Torvalds 已提交
616 617 618
	}

	spin_lock_irqsave(&acpi_bus_event_lock, flags);
619 620 621
	if (!list_empty(&acpi_bus_event_list)) {
		entry = list_entry(acpi_bus_event_list.next,
				   struct acpi_bus_event, node);
L
Linus Torvalds 已提交
622
		list_del(&entry->node);
623
	}
L
Linus Torvalds 已提交
624 625 626
	spin_unlock_irqrestore(&acpi_bus_event_lock, flags);

	if (!entry)
627
		return -ENODEV;
L
Linus Torvalds 已提交
628 629 630 631 632

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

	kfree(entry);

633
	return 0;
L
Linus Torvalds 已提交
634 635
}

636
#endif	/* CONFIG_ACPI_PROC_EVENT */
L
Linus Torvalds 已提交
637 638 639 640 641

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

642
static void acpi_bus_check_device(acpi_handle handle)
L
Linus Torvalds 已提交
643
{
644
	struct acpi_device *device;
645
	acpi_status status;
L
Linus Torvalds 已提交
646 647
	struct acpi_device_status old_status;

648 649
	if (acpi_bus_get_device(handle, &device))
		return;
L
Linus Torvalds 已提交
650
	if (!device)
651
		return;
L
Linus Torvalds 已提交
652 653 654 655 656 657 658 659 660

	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;
661
		return;
L
Linus Torvalds 已提交
662 663 664 665
	}

	status = acpi_bus_get_status(device);
	if (ACPI_FAILURE(status))
666
		return;
L
Linus Torvalds 已提交
667 668

	if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
669
		return;
L
Linus Torvalds 已提交
670 671 672 673 674 675 676

	/*
	 * 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 已提交
677
	} else if (!(device->status.present) && (old_status.present)) {
L
Linus Torvalds 已提交
678 679 680 681 682
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
		/* TBD: Handle device removal */
	}
}

683
static void acpi_bus_check_scope(acpi_handle handle)
L
Linus Torvalds 已提交
684 685
{
	/* Status Change? */
686
	acpi_bus_check_device(handle);
L
Linus Torvalds 已提交
687 688 689 690 691 692 693

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

694 695 696 697 698 699 700 701 702 703 704 705 706
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 已提交
707 708 709 710 711
/**
 * acpi_bus_notify
 * ---------------
 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
 */
L
Len Brown 已提交
712
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
L
Linus Torvalds 已提交
713
{
L
Len Brown 已提交
714
	struct acpi_device *device = NULL;
715
	struct acpi_driver *driver;
L
Linus Torvalds 已提交
716

717 718 719
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
			  type, handle));

720 721
	blocking_notifier_call_chain(&acpi_bus_notify_list,
		type, (void *)handle);
L
Linus Torvalds 已提交
722 723 724 725

	switch (type) {

	case ACPI_NOTIFY_BUS_CHECK:
726
		acpi_bus_check_scope(handle);
727
		/*
L
Linus Torvalds 已提交
728
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
729
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
730 731 732 733
		 */
		break;

	case ACPI_NOTIFY_DEVICE_CHECK:
734
		acpi_bus_check_device(handle);
735
		/*
L
Linus Torvalds 已提交
736
		 * TBD: We'll need to outsource certain events to non-ACPI
L
Len Brown 已提交
737
		 *      drivers via the device manager (device.c).
L
Linus Torvalds 已提交
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
		 */
		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 已提交
766 767 768
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received unknown/unsupported notification [%08x]\n",
				  type));
L
Linus Torvalds 已提交
769 770 771
		break;
	}

772 773 774 775 776 777 778
	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 已提交
779 780 781 782 783 784
}

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

L
Len Brown 已提交
785
static int __init acpi_bus_init_irq(void)
L
Linus Torvalds 已提交
786
{
L
Len Brown 已提交
787 788 789 790
	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 已提交
791 792


793
	/*
L
Linus Torvalds 已提交
794 795 796 797 798 799 800 801 802 803 804 805 806 807
	 * 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 已提交
808 809 810
	case ACPI_IRQ_MODEL_PLATFORM:
		message = "platform specific model";
		break;
L
Linus Torvalds 已提交
811 812
	default:
		printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
813
		return -ENODEV;
L
Linus Torvalds 已提交
814 815 816 817 818 819 820 821
	}

	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)) {
822
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
823
		return -ENODEV;
L
Linus Torvalds 已提交
824 825
	}

826
	return 0;
L
Linus Torvalds 已提交
827 828
}

829
u8 acpi_gbl_permanent_mmap;
830 831


L
Len Brown 已提交
832
void __init acpi_early_init(void)
L
Linus Torvalds 已提交
833
{
L
Len Brown 已提交
834
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
835 836

	if (acpi_disabled)
837
		return;
L
Linus Torvalds 已提交
838

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

L
Linus Torvalds 已提交
841 842 843 844
	/* enable workarounds, unless strict ACPI spec. compliance */
	if (!acpi_strict)
		acpi_gbl_enable_interpreter_slack = TRUE;

845 846
	acpi_gbl_permanent_mmap = 1;

847 848 849 850 851 852
	/*
	 * If the machine falls into the DMI check table,
	 * DSDT will be copied to memory
	 */
	dmi_check_system(dsdt_dmi_table);

853 854 855 856 857 858 859
	status = acpi_reallocate_root_table();
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX
		       "Unable to reallocate ACPI tables\n");
		goto error0;
	}

L
Linus Torvalds 已提交
860 861
	status = acpi_initialize_subsystem();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
862 863
		printk(KERN_ERR PREFIX
		       "Unable to initialize the ACPI Interpreter\n");
L
Linus Torvalds 已提交
864 865 866 867 868
		goto error0;
	}

	status = acpi_load_tables();
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
869 870
		printk(KERN_ERR PREFIX
		       "Unable to load the System Description Tables\n");
L
Linus Torvalds 已提交
871 872 873 874 875 876
		goto error0;
	}

#ifdef CONFIG_X86
	if (!acpi_ioapic) {
		/* compatible (0) means level (3) */
877 878 879 880
		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 已提交
881
		/* Set PIC-mode SCI trigger type */
882
		acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
883
					 (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
L
Linus Torvalds 已提交
884 885
	} else {
		/*
886
		 * now that acpi_gbl_FADT is initialized,
L
Linus Torvalds 已提交
887 888
		 * update it with result from INT_SRC_OVR parsing
		 */
889
		acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
L
Linus Torvalds 已提交
890 891 892
	}
#endif

L
Len Brown 已提交
893 894 895 896
	status =
	    acpi_enable_subsystem(~
				  (ACPI_NO_HARDWARE_INIT |
				   ACPI_NO_ACPI_ENABLE));
L
Linus Torvalds 已提交
897 898 899 900 901
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
		goto error0;
	}

902
	return;
L
Linus Torvalds 已提交
903

L
Len Brown 已提交
904
      error0:
L
Linus Torvalds 已提交
905
	disable_acpi();
906
	return;
L
Linus Torvalds 已提交
907 908
}

L
Len Brown 已提交
909
static int __init acpi_bus_init(void)
L
Linus Torvalds 已提交
910
{
L
Len Brown 已提交
911 912 913
	int result = 0;
	acpi_status status = AE_OK;
	extern acpi_status acpi_os_initialize1(void);
L
Linus Torvalds 已提交
914

915
	acpi_os_initialize1();
L
Linus Torvalds 已提交
916

L
Len Brown 已提交
917 918
	status =
	    acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
L
Linus Torvalds 已提交
919
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
920 921
		printk(KERN_ERR PREFIX
		       "Unable to start the ACPI Interpreter\n");
L
Linus Torvalds 已提交
922 923 924 925 926 927 928 929
		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).
	 *
930
	 * This is accomplished by looking for the ECDT table, and getting
L
Linus Torvalds 已提交
931 932 933 934 935
	 * the EC parameters out of that.
	 */
	status = acpi_ec_ecdt_probe();
	/* Ignore result. Not having an ECDT is not fatal. */

S
Shaohua Li 已提交
936 937
	acpi_bus_osc_support();

L
Linus Torvalds 已提交
938 939 940 941 942 943
	status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
	if (ACPI_FAILURE(status)) {
		printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
		goto error1;
	}

A
Alex Chiang 已提交
944 945
	acpi_early_processor_set_pdc();

946 947 948 949 950 951
	/*
	 * 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 已提交
952 953
	printk(KERN_INFO PREFIX "Interpreter enabled\n");

954 955 956
	/* Initialize sleep structures */
	acpi_sleep_init();

L
Linus Torvalds 已提交
957 958 959 960 961 962 963 964 965 966
	/*
	 * 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 已提交
967 968 969
	status =
	    acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
					&acpi_bus_notify, NULL);
L
Linus Torvalds 已提交
970
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
971 972
		printk(KERN_ERR PREFIX
		       "Unable to register for device notifications\n");
L
Linus Torvalds 已提交
973 974 975 976 977 978 979 980
		goto error1;
	}

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

981
	return 0;
L
Linus Torvalds 已提交
982 983

	/* Mimic structured exception handling */
L
Len Brown 已提交
984
      error1:
L
Linus Torvalds 已提交
985
	acpi_terminate();
986
	return -ENODEV;
L
Linus Torvalds 已提交
987 988
}

989
struct kobject *acpi_kobj;
L
Linus Torvalds 已提交
990

L
Len Brown 已提交
991
static int __init acpi_init(void)
L
Linus Torvalds 已提交
992
{
L
Len Brown 已提交
993
	int result = 0;
L
Linus Torvalds 已提交
994 995 996 997


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

1001
	acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
1002
	if (!acpi_kobj) {
1003
		printk(KERN_WARNING "%s: kset create error\n", __func__);
1004 1005
		acpi_kobj = NULL;
	}
L
Linus Torvalds 已提交
1006

1007
	init_acpi_device_notify();
L
Linus Torvalds 已提交
1008 1009 1010
	result = acpi_bus_init();

	if (!result) {
1011
		pci_mmcfg_late_init();
1012 1013
		if (!(pm_flags & PM_APM))
			pm_flags |= PM_ACPI;
L
Linus Torvalds 已提交
1014
		else {
L
Len Brown 已提交
1015 1016
			printk(KERN_INFO PREFIX
			       "APM is already active, exiting\n");
L
Linus Torvalds 已提交
1017 1018 1019 1020 1021
			disable_acpi();
			result = -ENODEV;
		}
	} else
		disable_acpi();
1022 1023 1024 1025

	if (acpi_disabled)
		return result;

1026 1027 1028 1029 1030
	/*
	 * 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);
1031 1032

	acpi_scan_init();
1033
	acpi_ec_init();
1034
	acpi_power_init();
1035
	acpi_system_init();
1036
	acpi_debug_init();
1037
	acpi_sleep_proc_init();
1038
	acpi_wakeup_device_init();
1039
	return result;
L
Linus Torvalds 已提交
1040 1041 1042
}

subsys_initcall(acpi_init);