utils.c 18.2 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_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>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  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/kernel.h>
#include <linux/module.h>
28
#include <linux/slab.h>
L
Linus Torvalds 已提交
29 30
#include <linux/init.h>
#include <linux/types.h>
31 32
#include <linux/hardirq.h>
#include <linux/acpi.h>
B
Bjørn Mork 已提交
33
#include <linux/dynamic_debug.h>
L
Linus Torvalds 已提交
34

35 36
#include "internal.h"

L
Linus Torvalds 已提交
37
#define _COMPONENT		ACPI_BUS_COMPONENT
38
ACPI_MODULE_NAME("utils");
L
Linus Torvalds 已提交
39 40 41 42

/* --------------------------------------------------------------------------
                            Object Evaluation Helpers
   -------------------------------------------------------------------------- */
43 44 45
static void
acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
{
L
Linus Torvalds 已提交
46
#ifdef ACPI_DEBUG_OUTPUT
47 48 49 50 51
	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 已提交
52
#else
53
	return;
L
Linus Torvalds 已提交
54
#endif
55 56
}

L
Linus Torvalds 已提交
57
acpi_status
L
Len Brown 已提交
58 59
acpi_extract_package(union acpi_object *package,
		     struct acpi_buffer *format, struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
60
{
L
Len Brown 已提交
61 62 63 64 65 66 67
	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 已提交
68 69


L
Len Brown 已提交
70 71
	if (!package || (package->type != ACPI_TYPE_PACKAGE)
	    || (package->package.count < 1)) {
72
		printk(KERN_WARNING PREFIX "Invalid package argument\n");
73
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
74 75 76
	}

	if (!format || !format->pointer || (format->length < 1)) {
77
		printk(KERN_WARNING PREFIX "Invalid format argument\n");
78
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
79 80 81
	}

	if (!buffer) {
82
		printk(KERN_WARNING PREFIX "Invalid buffer argument\n");
83
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
84 85
	}

L
Len Brown 已提交
86
	format_count = (format->length / sizeof(char)) - 1;
L
Linus Torvalds 已提交
87
	if (format_count > package->package.count) {
88 89 90
		printk(KERN_WARNING PREFIX "Format specifies more objects [%d]"
			      " than exist in package [%d].\n",
			      format_count, package->package.count);
91
		return AE_BAD_DATA;
L
Linus Torvalds 已提交
92 93
	}

94
	format_string = format->pointer;
L
Linus Torvalds 已提交
95 96 97 98

	/*
	 * Calculate size_required.
	 */
L
Len Brown 已提交
99
	for (i = 0; i < format_count; i++) {
L
Linus Torvalds 已提交
100 101 102 103 104 105 106 107

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

		switch (element->type) {

		case ACPI_TYPE_INTEGER:
			switch (format_string[i]) {
			case 'N':
L
Lin Ming 已提交
108 109
				size_required += sizeof(u64);
				tail_offset += sizeof(u64);
L
Linus Torvalds 已提交
110 111
				break;
			case 'S':
L
Len Brown 已提交
112
				size_required +=
L
Lin Ming 已提交
113
				    sizeof(char *) + sizeof(u64) +
L
Len Brown 已提交
114 115
				    sizeof(char);
				tail_offset += sizeof(char *);
L
Linus Torvalds 已提交
116 117
				break;
			default:
118
				printk(KERN_WARNING PREFIX "Invalid package element"
119
					      " [%d]: got number, expecting"
120 121
					      " [%c]\n",
					      i, format_string[i]);
122
				return AE_BAD_DATA;
L
Linus Torvalds 已提交
123 124 125 126 127 128 129 130
				break;
			}
			break;

		case ACPI_TYPE_STRING:
		case ACPI_TYPE_BUFFER:
			switch (format_string[i]) {
			case 'S':
L
Len Brown 已提交
131 132 133 134 135
				size_required +=
				    sizeof(char *) +
				    (element->string.length * sizeof(char)) +
				    sizeof(char);
				tail_offset += sizeof(char *);
L
Linus Torvalds 已提交
136 137
				break;
			case 'B':
L
Len Brown 已提交
138
				size_required +=
139
				    sizeof(u8 *) + element->buffer.length;
L
Len Brown 已提交
140
				tail_offset += sizeof(u8 *);
L
Linus Torvalds 已提交
141 142
				break;
			default:
143
				printk(KERN_WARNING PREFIX "Invalid package element"
144
					      " [%d] got string/buffer,"
145
					      " expecting [%c]\n",
146
					      i, format_string[i]);
147
				return AE_BAD_DATA;
L
Linus Torvalds 已提交
148 149 150
				break;
			}
			break;
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
		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 已提交
166 167 168

		case ACPI_TYPE_PACKAGE:
		default:
L
Len Brown 已提交
169 170 171
			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					  "Found unsupported element at index=%d\n",
					  i));
L
Linus Torvalds 已提交
172
			/* TBD: handle nested packages... */
173
			return AE_SUPPORT;
L
Linus Torvalds 已提交
174 175 176 177 178 179 180
			break;
		}
	}

	/*
	 * Validate output buffer.
	 */
181
	if (buffer->length == ACPI_ALLOCATE_BUFFER) {
182
		buffer->pointer = ACPI_ALLOCATE_ZEROED(size_required);
183 184
		if (!buffer->pointer)
			return AE_NO_MEMORY;
L
Linus Torvalds 已提交
185
		buffer->length = size_required;
186 187 188 189 190 191 192 193
	} 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 已提交
194 195 196 197 198 199 200 201
	}

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

	/*
	 * Extract package data.
	 */
L
Len Brown 已提交
202
	for (i = 0; i < format_count; i++) {
L
Linus Torvalds 已提交
203 204 205 206 207

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

		if (!element) {
208
			return AE_BAD_DATA;
L
Linus Torvalds 已提交
209 210 211 212 213 214 215
		}

		switch (element->type) {

		case ACPI_TYPE_INTEGER:
			switch (format_string[i]) {
			case 'N':
L
Lin Ming 已提交
216
				*((u64 *) head) =
L
Len Brown 已提交
217
				    element->integer.value;
L
Lin Ming 已提交
218
				head += sizeof(u64);
L
Linus Torvalds 已提交
219 220
				break;
			case 'S':
L
Len Brown 已提交
221
				pointer = (u8 **) head;
L
Linus Torvalds 已提交
222
				*pointer = tail;
L
Lin Ming 已提交
223
				*((u64 *) tail) =
L
Len Brown 已提交
224
				    element->integer.value;
L
Lin Ming 已提交
225 226
				head += sizeof(u64 *);
				tail += sizeof(u64);
L
Linus Torvalds 已提交
227 228 229 230 231 232 233 234 235 236 237 238 239 240
				/* 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 已提交
241
				pointer = (u8 **) head;
L
Linus Torvalds 已提交
242
				*pointer = tail;
L
Len Brown 已提交
243 244 245
				memcpy(tail, element->string.pointer,
				       element->string.length);
				head += sizeof(char *);
L
Linus Torvalds 已提交
246 247 248 249 250 251
				tail += element->string.length * sizeof(char);
				/* NULL terminate string */
				*tail = (char)0;
				tail += sizeof(char);
				break;
			case 'B':
L
Len Brown 已提交
252
				pointer = (u8 **) head;
L
Linus Torvalds 已提交
253
				*pointer = tail;
L
Len Brown 已提交
254 255 256
				memcpy(tail, element->buffer.pointer,
				       element->buffer.length);
				head += sizeof(u8 *);
257
				tail += element->buffer.length;
L
Linus Torvalds 已提交
258 259 260 261 262 263
				break;
			default:
				/* Should never get here */
				break;
			}
			break;
264 265 266 267 268 269 270 271 272 273 274 275
		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 已提交
276 277 278 279 280 281 282 283
		case ACPI_TYPE_PACKAGE:
			/* TBD: handle nested packages... */
		default:
			/* Should never get here */
			break;
		}
	}

284
	return AE_OK;
L
Linus Torvalds 已提交
285 286
}

L
Len Brown 已提交
287
EXPORT_SYMBOL(acpi_extract_package);
L
Linus Torvalds 已提交
288 289

acpi_status
L
Len Brown 已提交
290 291
acpi_evaluate_integer(acpi_handle handle,
		      acpi_string pathname,
292
		      struct acpi_object_list *arguments, unsigned long long *data)
L
Linus Torvalds 已提交
293
{
L
Len Brown 已提交
294
	acpi_status status = AE_OK;
295
	union acpi_object element;
L
Len Brown 已提交
296
	struct acpi_buffer buffer = { 0, NULL };
L
Linus Torvalds 已提交
297 298

	if (!data)
299
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
300 301

	buffer.length = sizeof(union acpi_object);
302
	buffer.pointer = &element;
L
Linus Torvalds 已提交
303 304 305
	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
	if (ACPI_FAILURE(status)) {
		acpi_util_eval_error(handle, pathname, status);
306
		return status;
L
Linus Torvalds 已提交
307 308
	}

309
	if (element.type != ACPI_TYPE_INTEGER) {
L
Linus Torvalds 已提交
310
		acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
311
		return AE_BAD_DATA;
L
Linus Torvalds 已提交
312 313
	}

314
	*data = element.integer.value;
L
Linus Torvalds 已提交
315

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

318
	return AE_OK;
L
Linus Torvalds 已提交
319 320
}

L
Len Brown 已提交
321
EXPORT_SYMBOL(acpi_evaluate_integer);
L
Linus Torvalds 已提交
322 323

acpi_status
L
Len Brown 已提交
324 325 326 327
acpi_evaluate_reference(acpi_handle handle,
			acpi_string pathname,
			struct acpi_object_list *arguments,
			struct acpi_handle_list *list)
L
Linus Torvalds 已提交
328
{
L
Len Brown 已提交
329 330 331 332 333
	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 已提交
334 335 336


	if (!list) {
337
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
338 339 340 341 342 343 344 345
	}

	/* Evaluate object. */

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

346
	package = buffer.pointer;
L
Linus Torvalds 已提交
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364

	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) {
365
		return AE_NO_MEMORY;
L
Linus Torvalds 已提交
366 367 368 369 370 371 372 373 374
	}
	list->count = package->package.count;

	/* Extract package data. */

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

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

375
		if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
L
Linus Torvalds 已提交
376 377 378 379 380
			status = AE_BAD_DATA;
			acpi_util_eval_error(handle, pathname, status);
			break;
		}

381 382
		if (!element->reference.handle) {
			status = AE_NULL_ENTRY;
383
			acpi_util_eval_error(handle, pathname, status);
384 385
			break;
		}
L
Linus Torvalds 已提交
386 387 388 389
		/* Get the  acpi_handle. */

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

L
Len Brown 已提交
393
      end:
L
Linus Torvalds 已提交
394 395 396 397 398
	if (ACPI_FAILURE(status)) {
		list->count = 0;
		//kfree(list->handles);
	}

399
	kfree(buffer.pointer);
L
Linus Torvalds 已提交
400

401
	return status;
L
Linus Torvalds 已提交
402 403
}

L
Len Brown 已提交
404
EXPORT_SYMBOL(acpi_evaluate_reference);
M
Matthew Garrett 已提交
405 406

acpi_status
407
acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld)
M
Matthew Garrett 已提交
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
{
	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
423
	    || output->package.elements[0].buffer.length < ACPI_PLD_REV1_BUFFER_SIZE) {
M
Matthew Garrett 已提交
424 425 426 427
		status = AE_TYPE;
		goto out;
	}

428 429 430 431 432
	status = acpi_decode_pld_buffer(
			output->package.elements[0].buffer.pointer,
			output->package.elements[0].buffer.length,
			pld);

M
Matthew Garrett 已提交
433 434 435 436 437
out:
	kfree(buffer.pointer);
	return status;
}
EXPORT_SYMBOL(acpi_get_physical_device_location);
438 439

/**
440
 * acpi_evaluate_ost: Evaluate _OST for hotplug operations
441 442 443 444 445 446 447 448 449 450
 * @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
451 452
acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
		  struct acpi_buffer *status_buf)
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
{
	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;
	}

471
	return acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
472
}
473
EXPORT_SYMBOL(acpi_evaluate_ost);
474

B
Bjørn Mork 已提交
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
/**
 * acpi_handle_path: Return the object path of handle
 *
 * 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;
}

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
/**
 * acpi_handle_printk: Print message with ACPI prefix and object path
 *
 * 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 已提交
512 513
	path = acpi_handle_path(handle);
	printk("%sACPI: %s: %pV", level, path ? path : "<n/a>" , &vaf);
514 515

	va_end(args);
B
Bjørn Mork 已提交
516
	kfree(path);
517 518
}
EXPORT_SYMBOL(acpi_handle_printk);
519

B
Bjørn Mork 已提交
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
#if defined(CONFIG_DYNAMIC_DEBUG)
/**
 * __acpi_handle_debug: pr_debug with ACPI prefix and object path
 *
 * 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

550 551 552 553 554 555 556 557 558 559 560 561 562 563
/**
 * 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);
564 565 566 567 568 569 570 571 572 573 574 575

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);
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 607 608 609 610 611 612 613 614 615 616 617 618

/**
 * 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;
}
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 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 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714

/**
 * acpi_evaluate_dsm - evaluate device's _DSM method
 * @handle: ACPI device handle
 * @uuid: UUID of requested functions, should be 16 bytes
 * @rev: revision number of requested function
 * @func: requested function number
 * @argv4: the function specific parameter
 *
 * Evaluate device's _DSM method with specified UUID, revision id and
 * 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 *
acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func,
		  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;
	params[0].buffer.pointer = (char *)uuid;
	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
 * @uuid: UUID of requested functions, should be 16 bytes at least
 * @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.
 */
bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
{
	int i;
	u64 mask = 0;
	union acpi_object *obj;

	if (funcs == 0)
		return false;

	obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL);
	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++)
			mask |= (((u8)obj->buffer.pointer[i]) << (i * 8));
	ACPI_FREE(obj);

	/*
	 * Bit 0 indicates whether there's support for any functions other than
	 * function 0 for the specified UUID and revision.
	 */
	if ((mask & 0x1) && (mask & funcs) == funcs)
		return true;

	return false;
}
EXPORT_SYMBOL(acpi_check_dsm);
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729

/*
 * 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);