utils.c 23.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
L
Linus Torvalds 已提交
2 3 4 5 6 7 8 9 10
/*
 *  acpi_utils.c - ACPI Utility Functions ($Revision: 10 $)
 *
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 */

#include <linux/kernel.h>
#include <linux/module.h>
11
#include <linux/slab.h>
L
Linus Torvalds 已提交
12 13
#include <linux/init.h>
#include <linux/types.h>
14 15
#include <linux/hardirq.h>
#include <linux/acpi.h>
B
Bjørn Mork 已提交
16
#include <linux/dynamic_debug.h>
L
Linus Torvalds 已提交
17

18
#include "internal.h"
19
#include "sleep.h"
20

L
Linus Torvalds 已提交
21
#define _COMPONENT		ACPI_BUS_COMPONENT
22
ACPI_MODULE_NAME("utils");
L
Linus Torvalds 已提交
23 24 25 26

/* --------------------------------------------------------------------------
                            Object Evaluation Helpers
   -------------------------------------------------------------------------- */
27 28 29
static void
acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
{
L
Linus Torvalds 已提交
30
#ifdef ACPI_DEBUG_OUTPUT
31 32 33 34 35
	char prefix[80] = {'\0'};
	struct acpi_buffer buffer = {sizeof(prefix), prefix};
	acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
		(char *) prefix, p, acpi_format_exception(s)));
L
Linus Torvalds 已提交
36
#else
37
	return;
L
Linus Torvalds 已提交
38
#endif
39 40
}

L
Linus Torvalds 已提交
41
acpi_status
L
Len Brown 已提交
42 43
acpi_extract_package(union acpi_object *package,
		     struct acpi_buffer *format, struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
44
{
L
Len Brown 已提交
45 46 47 48 49 50 51
	u32 size_required = 0;
	u32 tail_offset = 0;
	char *format_string = NULL;
	u32 format_count = 0;
	u32 i = 0;
	u8 *head = NULL;
	u8 *tail = NULL;
L
Linus Torvalds 已提交
52 53


L
Len Brown 已提交
54 55
	if (!package || (package->type != ACPI_TYPE_PACKAGE)
	    || (package->package.count < 1)) {
56
		printk(KERN_WARNING PREFIX "Invalid package argument\n");
57
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
58 59 60
	}

	if (!format || !format->pointer || (format->length < 1)) {
61
		printk(KERN_WARNING PREFIX "Invalid format argument\n");
62
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
63 64 65
	}

	if (!buffer) {
66
		printk(KERN_WARNING PREFIX "Invalid buffer argument\n");
67
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
68 69
	}

L
Len Brown 已提交
70
	format_count = (format->length / sizeof(char)) - 1;
L
Linus Torvalds 已提交
71
	if (format_count > package->package.count) {
72 73 74
		printk(KERN_WARNING PREFIX "Format specifies more objects [%d]"
			      " than exist in package [%d].\n",
			      format_count, package->package.count);
75
		return AE_BAD_DATA;
L
Linus Torvalds 已提交
76 77
	}

78
	format_string = format->pointer;
L
Linus Torvalds 已提交
79 80 81 82

	/*
	 * Calculate size_required.
	 */
L
Len Brown 已提交
83
	for (i = 0; i < format_count; i++) {
L
Linus Torvalds 已提交
84 85 86 87 88 89 90 91

		union acpi_object *element = &(package->package.elements[i]);

		switch (element->type) {

		case ACPI_TYPE_INTEGER:
			switch (format_string[i]) {
			case 'N':
L
Lin Ming 已提交
92 93
				size_required += sizeof(u64);
				tail_offset += sizeof(u64);
L
Linus Torvalds 已提交
94 95
				break;
			case 'S':
L
Len Brown 已提交
96
				size_required +=
L
Lin Ming 已提交
97
				    sizeof(char *) + sizeof(u64) +
L
Len Brown 已提交
98 99
				    sizeof(char);
				tail_offset += sizeof(char *);
L
Linus Torvalds 已提交
100 101
				break;
			default:
102
				printk(KERN_WARNING PREFIX "Invalid package element"
103
					      " [%d]: got number, expecting"
104 105
					      " [%c]\n",
					      i, format_string[i]);
106
				return AE_BAD_DATA;
L
Linus Torvalds 已提交
107 108 109 110 111 112 113 114
				break;
			}
			break;

		case ACPI_TYPE_STRING:
		case ACPI_TYPE_BUFFER:
			switch (format_string[i]) {
			case 'S':
L
Len Brown 已提交
115 116 117 118 119
				size_required +=
				    sizeof(char *) +
				    (element->string.length * sizeof(char)) +
				    sizeof(char);
				tail_offset += sizeof(char *);
L
Linus Torvalds 已提交
120 121
				break;
			case 'B':
L
Len Brown 已提交
122
				size_required +=
123
				    sizeof(u8 *) + element->buffer.length;
L
Len Brown 已提交
124
				tail_offset += sizeof(u8 *);
L
Linus Torvalds 已提交
125 126
				break;
			default:
127
				printk(KERN_WARNING PREFIX "Invalid package element"
128
					      " [%d] got string/buffer,"
129
					      " expecting [%c]\n",
130
					      i, format_string[i]);
131
				return AE_BAD_DATA;
L
Linus Torvalds 已提交
132 133 134
				break;
			}
			break;
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
		case ACPI_TYPE_LOCAL_REFERENCE:
			switch (format_string[i]) {
			case 'R':
				size_required += sizeof(void *);
				tail_offset += sizeof(void *);
				break;
			default:
				printk(KERN_WARNING PREFIX "Invalid package element"
					      " [%d] got reference,"
					      " expecting [%c]\n",
					      i, format_string[i]);
				return AE_BAD_DATA;
				break;
			}
			break;
L
Linus Torvalds 已提交
150 151 152

		case ACPI_TYPE_PACKAGE:
		default:
L
Len Brown 已提交
153 154 155
			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					  "Found unsupported element at index=%d\n",
					  i));
L
Linus Torvalds 已提交
156
			/* TBD: handle nested packages... */
157
			return AE_SUPPORT;
L
Linus Torvalds 已提交
158 159 160 161 162 163 164
			break;
		}
	}

	/*
	 * Validate output buffer.
	 */
165
	if (buffer->length == ACPI_ALLOCATE_BUFFER) {
166
		buffer->pointer = ACPI_ALLOCATE_ZEROED(size_required);
167 168
		if (!buffer->pointer)
			return AE_NO_MEMORY;
L
Linus Torvalds 已提交
169
		buffer->length = size_required;
170 171 172 173 174 175 176 177
	} else {
		if (buffer->length < size_required) {
			buffer->length = size_required;
			return AE_BUFFER_OVERFLOW;
		} else if (buffer->length != size_required ||
			   !buffer->pointer) {
			return AE_BAD_PARAMETER;
		}
L
Linus Torvalds 已提交
178 179 180 181 182 183 184 185
	}

	head = buffer->pointer;
	tail = buffer->pointer + tail_offset;

	/*
	 * Extract package data.
	 */
L
Len Brown 已提交
186
	for (i = 0; i < format_count; i++) {
L
Linus Torvalds 已提交
187 188 189 190 191 192 193 194 195

		u8 **pointer = NULL;
		union acpi_object *element = &(package->package.elements[i]);

		switch (element->type) {

		case ACPI_TYPE_INTEGER:
			switch (format_string[i]) {
			case 'N':
L
Lin Ming 已提交
196
				*((u64 *) head) =
L
Len Brown 已提交
197
				    element->integer.value;
L
Lin Ming 已提交
198
				head += sizeof(u64);
L
Linus Torvalds 已提交
199 200
				break;
			case 'S':
L
Len Brown 已提交
201
				pointer = (u8 **) head;
L
Linus Torvalds 已提交
202
				*pointer = tail;
L
Lin Ming 已提交
203
				*((u64 *) tail) =
L
Len Brown 已提交
204
				    element->integer.value;
L
Lin Ming 已提交
205 206
				head += sizeof(u64 *);
				tail += sizeof(u64);
L
Linus Torvalds 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220
				/* NULL terminate string */
				*tail = (char)0;
				tail += sizeof(char);
				break;
			default:
				/* Should never get here */
				break;
			}
			break;

		case ACPI_TYPE_STRING:
		case ACPI_TYPE_BUFFER:
			switch (format_string[i]) {
			case 'S':
L
Len Brown 已提交
221
				pointer = (u8 **) head;
L
Linus Torvalds 已提交
222
				*pointer = tail;
L
Len Brown 已提交
223 224 225
				memcpy(tail, element->string.pointer,
				       element->string.length);
				head += sizeof(char *);
L
Linus Torvalds 已提交
226 227 228 229 230 231
				tail += element->string.length * sizeof(char);
				/* NULL terminate string */
				*tail = (char)0;
				tail += sizeof(char);
				break;
			case 'B':
L
Len Brown 已提交
232
				pointer = (u8 **) head;
L
Linus Torvalds 已提交
233
				*pointer = tail;
L
Len Brown 已提交
234 235 236
				memcpy(tail, element->buffer.pointer,
				       element->buffer.length);
				head += sizeof(u8 *);
237
				tail += element->buffer.length;
L
Linus Torvalds 已提交
238 239 240 241 242 243
				break;
			default:
				/* Should never get here */
				break;
			}
			break;
244 245 246 247 248 249 250 251 252 253 254 255
		case ACPI_TYPE_LOCAL_REFERENCE:
			switch (format_string[i]) {
			case 'R':
				*(void **)head =
				    (void *)element->reference.handle;
				head += sizeof(void *);
				break;
			default:
				/* Should never get here */
				break;
			}
			break;
L
Linus Torvalds 已提交
256 257 258 259 260 261 262 263
		case ACPI_TYPE_PACKAGE:
			/* TBD: handle nested packages... */
		default:
			/* Should never get here */
			break;
		}
	}

264
	return AE_OK;
L
Linus Torvalds 已提交
265 266
}

L
Len Brown 已提交
267
EXPORT_SYMBOL(acpi_extract_package);
L
Linus Torvalds 已提交
268 269

acpi_status
L
Len Brown 已提交
270 271
acpi_evaluate_integer(acpi_handle handle,
		      acpi_string pathname,
272
		      struct acpi_object_list *arguments, unsigned long long *data)
L
Linus Torvalds 已提交
273
{
L
Len Brown 已提交
274
	acpi_status status = AE_OK;
275
	union acpi_object element;
L
Len Brown 已提交
276
	struct acpi_buffer buffer = { 0, NULL };
L
Linus Torvalds 已提交
277 278

	if (!data)
279
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
280 281

	buffer.length = sizeof(union acpi_object);
282
	buffer.pointer = &element;
L
Linus Torvalds 已提交
283 284 285
	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
	if (ACPI_FAILURE(status)) {
		acpi_util_eval_error(handle, pathname, status);
286
		return status;
L
Linus Torvalds 已提交
287 288
	}

289
	if (element.type != ACPI_TYPE_INTEGER) {
L
Linus Torvalds 已提交
290
		acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
291
		return AE_BAD_DATA;
L
Linus Torvalds 已提交
292 293
	}

294
	*data = element.integer.value;
L
Linus Torvalds 已提交
295

296
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data));
L
Linus Torvalds 已提交
297

298
	return AE_OK;
L
Linus Torvalds 已提交
299 300
}

L
Len Brown 已提交
301
EXPORT_SYMBOL(acpi_evaluate_integer);
L
Linus Torvalds 已提交
302 303

acpi_status
L
Len Brown 已提交
304 305 306 307
acpi_evaluate_reference(acpi_handle handle,
			acpi_string pathname,
			struct acpi_object_list *arguments,
			struct acpi_handle_list *list)
L
Linus Torvalds 已提交
308
{
L
Len Brown 已提交
309 310 311 312 313
	acpi_status status = AE_OK;
	union acpi_object *package = NULL;
	union acpi_object *element = NULL;
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	u32 i = 0;
L
Linus Torvalds 已提交
314 315 316


	if (!list) {
317
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
318 319 320 321 322 323 324 325
	}

	/* Evaluate object. */

	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
	if (ACPI_FAILURE(status))
		goto end;

326
	package = buffer.pointer;
L
Linus Torvalds 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344

	if ((buffer.length == 0) || !package) {
		status = AE_BAD_DATA;
		acpi_util_eval_error(handle, pathname, status);
		goto end;
	}
	if (package->type != ACPI_TYPE_PACKAGE) {
		status = AE_BAD_DATA;
		acpi_util_eval_error(handle, pathname, status);
		goto end;
	}
	if (!package->package.count) {
		status = AE_BAD_DATA;
		acpi_util_eval_error(handle, pathname, status);
		goto end;
	}

	if (package->package.count > ACPI_MAX_HANDLES) {
345
		kfree(package);
346
		return AE_NO_MEMORY;
L
Linus Torvalds 已提交
347 348 349 350 351 352 353 354 355
	}
	list->count = package->package.count;

	/* Extract package data. */

	for (i = 0; i < list->count; i++) {

		element = &(package->package.elements[i]);

356
		if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
L
Linus Torvalds 已提交
357 358 359 360 361
			status = AE_BAD_DATA;
			acpi_util_eval_error(handle, pathname, status);
			break;
		}

362 363
		if (!element->reference.handle) {
			status = AE_NULL_ENTRY;
364
			acpi_util_eval_error(handle, pathname, status);
365 366
			break;
		}
L
Linus Torvalds 已提交
367 368 369 370
		/* Get the  acpi_handle. */

		list->handles[i] = element->reference.handle;
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n",
L
Len Brown 已提交
371
				  list->handles[i]));
L
Linus Torvalds 已提交
372 373
	}

L
Len Brown 已提交
374
      end:
L
Linus Torvalds 已提交
375 376 377 378 379
	if (ACPI_FAILURE(status)) {
		list->count = 0;
		//kfree(list->handles);
	}

380
	kfree(buffer.pointer);
L
Linus Torvalds 已提交
381

382
	return status;
L
Linus Torvalds 已提交
383 384
}

L
Len Brown 已提交
385
EXPORT_SYMBOL(acpi_evaluate_reference);
M
Matthew Garrett 已提交
386 387

acpi_status
388
acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld)
M
Matthew Garrett 已提交
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
{
	acpi_status status;
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *output;

	status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer);

	if (ACPI_FAILURE(status))
		return status;

	output = buffer.pointer;

	if (!output || output->type != ACPI_TYPE_PACKAGE
	    || !output->package.count
	    || output->package.elements[0].type != ACPI_TYPE_BUFFER
404
	    || output->package.elements[0].buffer.length < ACPI_PLD_REV1_BUFFER_SIZE) {
M
Matthew Garrett 已提交
405 406 407 408
		status = AE_TYPE;
		goto out;
	}

409 410 411 412 413
	status = acpi_decode_pld_buffer(
			output->package.elements[0].buffer.pointer,
			output->package.elements[0].buffer.length,
			pld);

M
Matthew Garrett 已提交
414 415 416 417 418
out:
	kfree(buffer.pointer);
	return status;
}
EXPORT_SYMBOL(acpi_get_physical_device_location);
419 420

/**
421
 * acpi_evaluate_ost: Evaluate _OST for hotplug operations
422 423 424 425 426 427 428 429 430 431
 * @handle: ACPI device handle
 * @source_event: source event code
 * @status_code: status code
 * @status_buf: optional detailed information (NULL if none)
 *
 * Evaluate _OST for hotplug operations. All ACPI hotplug handlers
 * must call this function when evaluating _OST for hotplug operations.
 * When the platform does not support _OST, this function has no effect.
 */
acpi_status
432 433
acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
		  struct acpi_buffer *status_buf)
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
{
	union acpi_object params[3] = {
		{.type = ACPI_TYPE_INTEGER,},
		{.type = ACPI_TYPE_INTEGER,},
		{.type = ACPI_TYPE_BUFFER,}
	};
	struct acpi_object_list arg_list = {3, params};

	params[0].integer.value = source_event;
	params[1].integer.value = status_code;
	if (status_buf != NULL) {
		params[2].buffer.pointer = status_buf->pointer;
		params[2].buffer.length = status_buf->length;
	} else {
		params[2].buffer.pointer = NULL;
		params[2].buffer.length = 0;
	}

452
	return acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
453
}
454
EXPORT_SYMBOL(acpi_evaluate_ost);
455

B
Bjørn Mork 已提交
456 457
/**
 * acpi_handle_path: Return the object path of handle
458
 * @handle: ACPI device handle
B
Bjørn Mork 已提交
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
 *
 * Caller must free the returned buffer
 */
static char *acpi_handle_path(acpi_handle handle)
{
	struct acpi_buffer buffer = {
		.length = ACPI_ALLOCATE_BUFFER,
		.pointer = NULL
	};

	if (in_interrupt() ||
	    acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK)
		return NULL;
	return buffer.pointer;
}

475 476
/**
 * acpi_handle_printk: Print message with ACPI prefix and object path
477 478 479
 * @level: log level
 * @handle: ACPI device handle
 * @fmt: format string
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
 *
 * This function is called through acpi_handle_<level> macros and prints
 * a message with ACPI prefix and object path.  This function acquires
 * the global namespace mutex to obtain an object path.  In interrupt
 * context, it shows the object path as <n/a>.
 */
void
acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
{
	struct va_format vaf;
	va_list args;
	const char *path;

	va_start(args, fmt);
	vaf.fmt = fmt;
	vaf.va = &args;

B
Bjørn Mork 已提交
497 498
	path = acpi_handle_path(handle);
	printk("%sACPI: %s: %pV", level, path ? path : "<n/a>" , &vaf);
499 500

	va_end(args);
B
Bjørn Mork 已提交
501
	kfree(path);
502 503
}
EXPORT_SYMBOL(acpi_handle_printk);
504

B
Bjørn Mork 已提交
505 506 507
#if defined(CONFIG_DYNAMIC_DEBUG)
/**
 * __acpi_handle_debug: pr_debug with ACPI prefix and object path
508 509 510
 * @descriptor: Dynamic Debug descriptor
 * @handle: ACPI device handle
 * @fmt: format string
B
Bjørn Mork 已提交
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
 *
 * This function is called through acpi_handle_debug macro and debug
 * prints a message with ACPI prefix and object path. This function
 * acquires the global namespace mutex to obtain an object path.  In
 * interrupt context, it shows the object path as <n/a>.
 */
void
__acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle,
		    const char *fmt, ...)
{
	struct va_format vaf;
	va_list args;
	const char *path;

	va_start(args, fmt);
	vaf.fmt = fmt;
	vaf.va = &args;

	path = acpi_handle_path(handle);
	__dynamic_pr_debug(descriptor, "ACPI: %s: %pV", path ? path : "<n/a>", &vaf);

	va_end(args);
	kfree(path);
}
EXPORT_SYMBOL(__acpi_handle_debug);
#endif

538 539 540 541 542 543 544 545 546 547 548 549 550 551
/**
 * acpi_has_method: Check whether @handle has a method named @name
 * @handle: ACPI device handle
 * @name: name of object or method
 *
 * Check whether @handle has a method named @name.
 */
bool acpi_has_method(acpi_handle handle, char *name)
{
	acpi_handle tmp;

	return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp));
}
EXPORT_SYMBOL(acpi_has_method);
552 553 554 555 556 557 558 559 560 561 562 563

acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
				       u64 arg)
{
	union acpi_object obj = { .type = ACPI_TYPE_INTEGER };
	struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, };

	obj.integer.value = arg;

	return acpi_evaluate_object(handle, method, &arg_list, NULL);
}
EXPORT_SYMBOL(acpi_execute_simple_method);
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 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606

/**
 * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations
 * @handle: ACPI device handle
 *
 * Evaluate device's _EJ0 method for hotplug operations.
 */
acpi_status acpi_evaluate_ej0(acpi_handle handle)
{
	acpi_status status;

	status = acpi_execute_simple_method(handle, "_EJ0", 1);
	if (status == AE_NOT_FOUND)
		acpi_handle_warn(handle, "No _EJ0 support for device\n");
	else if (ACPI_FAILURE(status))
		acpi_handle_warn(handle, "Eject failed (0x%x)\n", status);

	return status;
}

/**
 * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device
 * @handle: ACPI device handle
 * @lock: lock device if non-zero, otherwise unlock device
 *
 * Evaluate device's _LCK method if present to lock/unlock device
 */
acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
{
	acpi_status status;

	status = acpi_execute_simple_method(handle, "_LCK", !!lock);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
		if (lock)
			acpi_handle_warn(handle,
				"Locking device failed (0x%x)\n", status);
		else
			acpi_handle_warn(handle,
				"Unlocking device failed (0x%x)\n", status);
	}

	return status;
}
607

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
/**
 * acpi_evaluate_reg: Evaluate _REG method to register OpRegion presence
 * @handle: ACPI device handle
 * @space_id: ACPI address space id to register OpRegion presence for
 * @function: Parameter to pass to _REG one of ACPI_REG_CONNECT or
 *            ACPI_REG_DISCONNECT
 *
 * Evaluate device's _REG method to register OpRegion presence.
 */
acpi_status acpi_evaluate_reg(acpi_handle handle, u8 space_id, u32 function)
{
	struct acpi_object_list arg_list;
	union acpi_object params[2];

	params[0].type = ACPI_TYPE_INTEGER;
	params[0].integer.value = space_id;
	params[1].type = ACPI_TYPE_INTEGER;
	params[1].integer.value = function;
	arg_list.count = 2;
	arg_list.pointer = params;

	return acpi_evaluate_object(handle, "_REG", &arg_list, NULL);
}
EXPORT_SYMBOL(acpi_evaluate_reg);

633 634 635
/**
 * acpi_evaluate_dsm - evaluate device's _DSM method
 * @handle: ACPI device handle
636
 * @guid: GUID of requested functions, should be 16 bytes
637 638 639 640
 * @rev: revision number of requested function
 * @func: requested function number
 * @argv4: the function specific parameter
 *
641
 * Evaluate device's _DSM method with specified GUID, revision id and
642 643 644 645 646 647
 * function number. Caller needs to free the returned object.
 *
 * Though ACPI defines the fourth parameter for _DSM should be a package,
 * some old BIOSes do expect a buffer or an integer etc.
 */
union acpi_object *
648
acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func,
649 650 651 652 653 654 655 656 657 658 659 660
		  union acpi_object *argv4)
{
	acpi_status ret;
	struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
	union acpi_object params[4];
	struct acpi_object_list input = {
		.count = 4,
		.pointer = params,
	};

	params[0].type = ACPI_TYPE_BUFFER;
	params[0].buffer.length = 16;
661
	params[0].buffer.pointer = (u8 *)guid;
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
	params[1].type = ACPI_TYPE_INTEGER;
	params[1].integer.value = rev;
	params[2].type = ACPI_TYPE_INTEGER;
	params[2].integer.value = func;
	if (argv4) {
		params[3] = *argv4;
	} else {
		params[3].type = ACPI_TYPE_PACKAGE;
		params[3].package.count = 0;
		params[3].package.elements = NULL;
	}

	ret = acpi_evaluate_object(handle, "_DSM", &input, &buf);
	if (ACPI_SUCCESS(ret))
		return (union acpi_object *)buf.pointer;

	if (ret != AE_NOT_FOUND)
		acpi_handle_warn(handle,
				"failed to evaluate _DSM (0x%x)\n", ret);

	return NULL;
}
EXPORT_SYMBOL(acpi_evaluate_dsm);

/**
 * acpi_check_dsm - check if _DSM method supports requested functions.
 * @handle: ACPI device handle
689
 * @guid: GUID of requested functions, should be 16 bytes at least
690 691 692 693 694 695 696
 * @rev: revision number of requested functions
 * @funcs: bitmap of requested functions
 *
 * Evaluate device's _DSM method to check whether it supports requested
 * functions. Currently only support 64 functions at maximum, should be
 * enough for now.
 */
697
bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs)
698 699 700 701 702
{
	int i;
	u64 mask = 0;
	union acpi_object *obj;

D
Dan Williams 已提交
703 704 705
	if (funcs == 0)
		return false;

706
	obj = acpi_evaluate_dsm(handle, guid, rev, 0, NULL);
707 708 709 710 711 712 713 714
	if (!obj)
		return false;

	/* For compatibility, old BIOSes may return an integer */
	if (obj->type == ACPI_TYPE_INTEGER)
		mask = obj->integer.value;
	else if (obj->type == ACPI_TYPE_BUFFER)
		for (i = 0; i < obj->buffer.length && i < 8; i++)
715
			mask |= (((u64)obj->buffer.pointer[i]) << (i * 8));
716 717 718 719
	ACPI_FREE(obj);

	/*
	 * Bit 0 indicates whether there's support for any functions other than
720
	 * function 0 for the specified GUID and revision.
721 722 723 724 725 726 727
	 */
	if ((mask & 0x1) && (mask & funcs) == funcs)
		return true;

	return false;
}
EXPORT_SYMBOL(acpi_check_dsm);
728

729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
/**
 * acpi_dev_hid_uid_match - Match device by supplied HID and UID
 * @adev: ACPI device to match.
 * @hid2: Hardware ID of the device.
 * @uid2: Unique ID of the device, pass NULL to not check _UID.
 *
 * Matches HID and UID in @adev with given @hid2 and @uid2.
 * Returns true if matches.
 */
bool acpi_dev_hid_uid_match(struct acpi_device *adev,
			    const char *hid2, const char *uid2)
{
	const char *hid1 = acpi_device_hid(adev);
	const char *uid1 = acpi_device_uid(adev);

	if (strcmp(hid1, hid2))
		return false;

	if (!uid2)
		return true;

	return uid1 && !strcmp(uid1, uid2);
}
EXPORT_SYMBOL(acpi_dev_hid_uid_match);

754
/**
755
 * acpi_dev_found - Detect presence of a given ACPI device in the namespace.
756 757 758 759 760 761 762 763 764 765 766
 * @hid: Hardware ID of the device.
 *
 * Return %true if the device was present at the moment of invocation.
 * Note that if the device is pluggable, it may since have disappeared.
 *
 * For this function to work, acpi_bus_scan() must have been executed
 * which happens in the subsys_initcall() subsection. Hence, do not
 * call from a subsys_initcall() or earlier (use acpi_get_devices()
 * instead). Calling from module_init() is fine (which is synonymous
 * with device_initcall()).
 */
767
bool acpi_dev_found(const char *hid)
768 769 770 771 772 773 774 775 776 777 778 779 780 781
{
	struct acpi_device_bus_id *acpi_device_bus_id;
	bool found = false;

	mutex_lock(&acpi_device_lock);
	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
		if (!strcmp(acpi_device_bus_id->bus_id, hid)) {
			found = true;
			break;
		}
	mutex_unlock(&acpi_device_lock);

	return found;
}
782
EXPORT_SYMBOL(acpi_dev_found);
783

784
struct acpi_dev_match_info {
785 786 787 788 789
	struct acpi_device_id hid[2];
	const char *uid;
	s64 hrv;
};

790
static int acpi_dev_match_cb(struct device *dev, const void *data)
791 792
{
	struct acpi_device *adev = to_acpi_device(dev);
793
	const struct acpi_dev_match_info *match = data;
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
	unsigned long long hrv;
	acpi_status status;

	if (acpi_match_device_ids(adev, match->hid))
		return 0;

	if (match->uid && (!adev->pnp.unique_id ||
	    strcmp(adev->pnp.unique_id, match->uid)))
		return 0;

	if (match->hrv == -1)
		return 1;

	status = acpi_evaluate_integer(adev->handle, "_HRV", NULL, &hrv);
	if (ACPI_FAILURE(status))
		return 0;

	return hrv == match->hrv;
}

/**
 * acpi_dev_present - Detect that a given ACPI device is present
 * @hid: Hardware ID of the device.
 * @uid: Unique ID of the device, pass NULL to not check _UID
 * @hrv: Hardware Revision of the device, pass -1 to not check _HRV
 *
 * Return %true if a matching device was present at the moment of invocation.
 * Note that if the device is pluggable, it may since have disappeared.
 *
 * Note that unlike acpi_dev_found() this function checks the status
 * of the device. So for devices which are present in the dsdt, but
 * which are disabled (their _STA callback returns 0) this function
 * will return false.
 *
 * For this function to work, acpi_bus_scan() must have been executed
 * which happens in the subsys_initcall() subsection. Hence, do not
 * call from a subsys_initcall() or earlier (use acpi_get_devices()
 * instead). Calling from module_init() is fine (which is synonymous
 * with device_initcall()).
 */
bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
{
836
	struct acpi_dev_match_info match = {};
837 838 839 840 841 842
	struct device *dev;

	strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id));
	match.uid = uid;
	match.hrv = hrv;

843
	dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
844
	put_device(dev);
845 846 847 848
	return !!dev;
}
EXPORT_SYMBOL(acpi_dev_present);

849
/**
850
 * acpi_dev_get_first_match_dev - Return the first match of ACPI device
851 852 853 854
 * @hid: Hardware ID of the device.
 * @uid: Unique ID of the device, pass NULL to not check _UID
 * @hrv: Hardware Revision of the device, pass -1 to not check _HRV
 *
855
 * Return the first match of ACPI device if a matching device was present
856 857
 * at the moment of invocation, or NULL otherwise.
 *
858 859
 * The caller is responsible to call put_device() on the returned device.
 *
860 861
 * See additional information in acpi_dev_present() as well.
 */
862 863 864 865 866 867 868 869 870 871 872
struct acpi_device *
acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
{
	struct acpi_dev_match_info match = {};
	struct device *dev;

	strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id));
	match.uid = uid;
	match.hrv = hrv;

	dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
873
	return dev ? to_acpi_device(dev) : NULL;
874 875 876
}
EXPORT_SYMBOL(acpi_dev_get_first_match_dev);

877 878 879 880 881 882 883 884 885 886 887 888 889 890
/*
 * acpi_backlight= handling, this is done here rather then in video_detect.c
 * because __setup cannot be used in modules.
 */
char acpi_video_backlight_string[16];
EXPORT_SYMBOL(acpi_video_backlight_string);

static int __init acpi_backlight(char *str)
{
	strlcpy(acpi_video_backlight_string, str,
		sizeof(acpi_video_backlight_string));
	return 1;
}
__setup("acpi_backlight=", acpi_backlight);
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926

/**
 * acpi_match_platform_list - Check if the system matches with a given list
 * @plat: pointer to acpi_platform_list table terminated by a NULL entry
 *
 * Return the matched index if the system is found in the platform list.
 * Otherwise, return a negative error code.
 */
int acpi_match_platform_list(const struct acpi_platform_list *plat)
{
	struct acpi_table_header hdr;
	int idx = 0;

	if (acpi_disabled)
		return -ENODEV;

	for (; plat->oem_id[0]; plat++, idx++) {
		if (ACPI_FAILURE(acpi_get_table_header(plat->table, 0, &hdr)))
			continue;

		if (strncmp(plat->oem_id, hdr.oem_id, ACPI_OEM_ID_SIZE))
			continue;

		if (strncmp(plat->oem_table_id, hdr.oem_table_id, ACPI_OEM_TABLE_ID_SIZE))
			continue;

		if ((plat->pred == all_versions) ||
		    (plat->pred == less_than_or_equal && hdr.oem_revision <= plat->oem_revision) ||
		    (plat->pred == greater_than_or_equal && hdr.oem_revision >= plat->oem_revision) ||
		    (plat->pred == equal && hdr.oem_revision == plat->oem_revision))
			return idx;
	}

	return -ENODEV;
}
EXPORT_SYMBOL(acpi_match_platform_list);