EXPORT_SYMBOL(acpi_bus_can_wakeup);
- status = acpi_evaluate_object(handle, "_OSC", &input, &context->ret);
++ 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;
+++ struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
++
++ 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;
++
- /* return buffer should have the same length as cap buffer */
- if (context->ret.length != context->cap.length)
+++ status = acpi_evaluate_object(handle, "_OSC", &input, &output);
++ if (ACPI_FAILURE(status))
++ return status;
++
- out_obj = context->ret.pointer;
- if (out_obj->type != ACPI_TYPE_BUFFER) {
+++ if (!output.length)
++ return AE_NULL_OBJECT;
++
- return AE_OK;
+++ out_obj = output.pointer;
+++ if (out_obj->type != ACPI_TYPE_BUFFER
+++ || out_obj->buffer.length != context->cap.length) {
++ 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:
- kfree(context->ret.pointer);
- context->ret.pointer = NULL;
+++ 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;
++
++ out_kfree:
+++ kfree(output.pointer);
+++ if (status != AE_OK)
+++ context->ret.pointer = NULL;
++ return status;
++ }
++ EXPORT_SYMBOL(acpi_run_osc);
++
++ 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 */
++ #ifdef CONFIG_ACPI_PROCESSOR_AGGREGATOR
++ capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT;
++ #endif
++ 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 */
++ }
++
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */