Skip to contentSkip to conversation

Add a generic API for _OSC

PATCH In review Shaohua Li 4 participants 9 messages Oct 27, 2009 – Oct 28, 2009 ACPI

lore
Share & tools
lore

Shaohua Li

author
#0 lore raw

PATCH 1/3 Add a generic API for _OSC

Add an API to execute _OSC. A lot of devices can have this method, so add a generic API.

---
 drivers/acpi/bus.c   |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi.h |    9 ++++++
 2 files changed, 81 insertions(+)
drivers/acpi/bus.c +72 -0
Index: linux/drivers/acpi/bus.c
===================================================================
@@ -344,6 +344,78 @@ bool acpi_bus_can_wakeup(acpi_handle han
 
 EXPORT_SYMBOL(acpi_bus_can_wakeup);
 
+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;
+	u32 errors;
+
+	if (!context)
+		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	= context->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;
+
+	status = acpi_evaluate_object(handle, "_OSC", &input, &context->ret);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	/* return buffer should have the same length as cap buffer */
+	if (context->ret.length != context->cap.length)
+		return AE_NULL_OBJECT;
+
+	out_obj = context->ret.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		printk(KERN_DEBUG "_OSC evaluation returned wrong type\n");
+		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)
+			printk(KERN_DEBUG "_OSC request failed\n");
+		if (errors & OSC_INVALID_UUID_ERROR)
+			printk(KERN_DEBUG "_OSC invalid UUID\n");
+		if (errors & OSC_INVALID_REVISION_ERROR)
+			printk(KERN_DEBUG "_OSC invalid revision\n");
+		if (errors & OSC_CAPABILITIES_MASK_ERROR) {
+			if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
+			    & OSC_QUERY_ENABLE)
+				goto out_success;
+			printk(KERN_DEBUG
+			       "Firmware did not grant requested _OSC control\n");
+			status = AE_SUPPORT;
+			goto out_kfree;
+		}
+		status = AE_ERROR;
+		goto out_kfree;
+	}
+out_success:
+	return AE_OK;
+
+out_kfree:
+	kfree(context->ret.pointer);
+	context->ret.pointer = NULL;
+	return status;
+}
+EXPORT_SYMBOL(acpi_run_osc);
+
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
include/linux/acpi.h +9 -0
Index: linux/include/linux/acpi.h
===================================================================
@@ -253,6 +253,13 @@ void __init acpi_old_suspend_ordering(vo
 void __init acpi_s4_no_nvs(void);
 #endif /* CONFIG_PM_SLEEP */
 
+struct acpi_osc_context {
+	u8 *uuid;
+	int rev;
+	struct acpi_buffer cap; /* arg2/arg3 */
+	struct acpi_buffer ret; /* free by caller if success */
+};
+
 #define OSC_QUERY_TYPE			0
 #define OSC_SUPPORT_TYPE 		1
 #define OSC_CONTROL_TYPE		2
@@ -265,6 +272,8 @@ void __init acpi_s4_no_nvs(void);
 #define OSC_INVALID_REVISION_ERROR	8
 #define OSC_CAPABILITIES_MASK_ERROR	16
 
+acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
+
 /* _OSC DW1 Definition (OS Support Fields) */
 #define OSC_EXT_PCI_CONFIG_SUPPORT		1
 #define OSC_ACTIVE_STATE_PWR_SUPPORT 		2
Reviewed-by on v1 1/3
#1 lore raw

Looks good.

Quoted 125 lines · Shaohua Li

Add an API to execute _OSC. A lot of devices can have this method, so add a generic API.

---
 drivers/acpi/bus.c   |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi.h |    9 ++++++
 2 files changed, 81 insertions(+)

Index: linux/drivers/acpi/bus.c
===================================================================

drivers/acpi/bus.c +72 -0
@@ -344,6 +344,78 @@ bool acpi_bus_can_wakeup(acpi_handle han
 
 EXPORT_SYMBOL(acpi_bus_can_wakeup);
 
+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;
+	u32 errors;
+
+	if (!context)
+		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	= context->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;
+
+	status = acpi_evaluate_object(handle, "_OSC", &input, &context->ret);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	/* return buffer should have the same length as cap buffer */
+	if (context->ret.length != context->cap.length)
+		return AE_NULL_OBJECT;
+
+	out_obj = context->ret.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		printk(KERN_DEBUG "_OSC evaluation returned wrong type\n");
+		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)
+			printk(KERN_DEBUG "_OSC request failed\n");
+		if (errors & OSC_INVALID_UUID_ERROR)
+			printk(KERN_DEBUG "_OSC invalid UUID\n");
+		if (errors & OSC_INVALID_REVISION_ERROR)
+			printk(KERN_DEBUG "_OSC invalid revision\n");
+		if (errors & OSC_CAPABILITIES_MASK_ERROR) {
+			if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
+			    & OSC_QUERY_ENABLE)
+				goto out_success;
+			printk(KERN_DEBUG
+			       "Firmware did not grant requested _OSC control\n");
+			status = AE_SUPPORT;
+			goto out_kfree;
+		}
+		status = AE_ERROR;
+		goto out_kfree;
+	}
+out_success:
+	return AE_OK;
+
+out_kfree:
+	kfree(context->ret.pointer);
+	context->ret.pointer = NULL;
+	return status;
+}
+EXPORT_SYMBOL(acpi_run_osc);
+
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */

Index: linux/include/linux/acpi.h
===================================================================

include/linux/acpi.h +9 -1
@@ -253,6 +253,13 @@ void __init acpi_old_suspend_ordering(vo
 void __init acpi_s4_no_nvs(void);
 #endif /* CONFIG_PM_SLEEP */
 
+struct acpi_osc_context {
+	u8 *uuid;
+	int rev;
+	struct acpi_buffer cap; /* arg2/arg3 */
+	struct acpi_buffer ret; /* free by caller if success */
+};
+
 #define OSC_QUERY_TYPE			0
 #define OSC_SUPPORT_TYPE 		1
 #define OSC_CONTROL_TYPE		2
@@ -265,6 +272,8 @@ void __init acpi_s4_no_nvs(void);
 #define OSC_INVALID_REVISION_ERROR	8
 #define OSC_CAPABILITIES_MASK_ERROR	16
 
+acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
+
 /* _OSC DW1 Definition (OS Support Fields) */
 #define OSC_EXT_PCI_CONFIG_SUPPORT		1
 #define OSC_ACTIVE_STATE_PWR_SUPPORT 		2
--

To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#2 lore raw
In reply to Shaohua Li
Quoted 14 lines · Shaohua Li

Add an API to execute _OSC. A lot of devices can have this method, so add a generic API.

drivers/acpi/bus.c +11 -0
+	out_obj = context->ret.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		printk(KERN_DEBUG "_OSC evaluation returned wrong type\n");
+		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)
+			printk(KERN_DEBUG "_OSC request failed\n");

drivers/acpi/bus.c bool acpi_bus_can_wakeup(acpi_handle han · line 402

Quoted 10 lines
drivers/acpi/bus.c +10 -0
+		if (errors & OSC_INVALID_UUID_ERROR)
+			printk(KERN_DEBUG "_OSC invalid UUID\n");
+		if (errors & OSC_INVALID_REVISION_ERROR)
+			printk(KERN_DEBUG "_OSC invalid revision\n");
+		if (errors & OSC_CAPABILITIES_MASK_ERROR) {
+			if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
+			    & OSC_QUERY_ENABLE)
+				goto out_success;
+			printk(KERN_DEBUG
+			       "Firmware did not grant requested _OSC control\n");

On all these printks, it would be very useful to have some indication of what the OS requested and which specific _OSC method we executed, e.g., an ACPI device name or a namespace path.

Bjorn

#3 lore raw
Quoted 21 lines · Bjorn Helgaas
Quoted 20 lines · Shaohua Li

Add an API to execute _OSC. A lot of devices can have this method, so add a generic API.

drivers/acpi/bus.c +17 -0
+	out_obj = context->ret.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		printk(KERN_DEBUG "_OSC evaluation returned wrong type\n");
+		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)
+			printk(KERN_DEBUG "_OSC request failed\n");
+		if (errors & OSC_INVALID_UUID_ERROR)
+			printk(KERN_DEBUG "_OSC invalid UUID\n");
+		if (errors & OSC_INVALID_REVISION_ERROR)
+			printk(KERN_DEBUG "_OSC invalid revision\n");
+		if (errors & OSC_CAPABILITIES_MASK_ERROR) {
+			if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
Quoted 9 lines

drivers/acpi/bus.c bool acpi_bus_can_wakeup(acpi_handle han · line 402

Quoted 4 lines
drivers/acpi/bus.c +4 -0
+			    & OSC_QUERY_ENABLE)
+				goto out_success;
+			printk(KERN_DEBUG
+			       "Firmware did not grant requested _OSC control\n");

On all these printks, it would be very useful to have some indication of what the OS requested and which specific _OSC method we executed, e.g., an ACPI device name or a namespace path.

I think the following printk is confusing and should be removed.

Quoted 2 lines

drivers/acpi/bus.c bool acpi_bus_can_wakeup(acpi_handle han · line 402

Quoted 2 lines
drivers/acpi/bus.c +2 -0
+			printk(KERN_DEBUG
+			       "Firmware did not grant requested _OSC control\n");

People might think something wrong is happening on OS or firmware. Actually I had been asked about this message several times.

Thanks,
Kenji Kaneshige

#4 lore raw
In reply to Shaohua Li

Hi Shaohua,

Could you also make it take a spec string as argument, not a prepared byte buffer?

Regards,
Alex.

Shaohua Li пишет:

Quoted 120 lines

Add an API to execute _OSC. A lot of devices can have this method, so add a generic API.

---
 drivers/acpi/bus.c   |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi.h |    9 ++++++
 2 files changed, 81 insertions(+)

Index: linux/drivers/acpi/bus.c
===================================================================

drivers/acpi/bus.c +72 -0
@@ -344,6 +344,78 @@ bool acpi_bus_can_wakeup(acpi_handle han
 
 EXPORT_SYMBOL(acpi_bus_can_wakeup);
 
+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;
+	u32 errors;
+
+	if (!context)
+		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	= context->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;
+
+	status = acpi_evaluate_object(handle, "_OSC", &input, &context->ret);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	/* return buffer should have the same length as cap buffer */
+	if (context->ret.length != context->cap.length)
+		return AE_NULL_OBJECT;
+
+	out_obj = context->ret.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		printk(KERN_DEBUG "_OSC evaluation returned wrong type\n");
+		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)
+			printk(KERN_DEBUG "_OSC request failed\n");
+		if (errors & OSC_INVALID_UUID_ERROR)
+			printk(KERN_DEBUG "_OSC invalid UUID\n");
+		if (errors & OSC_INVALID_REVISION_ERROR)
+			printk(KERN_DEBUG "_OSC invalid revision\n");
+		if (errors & OSC_CAPABILITIES_MASK_ERROR) {
+			if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
+			    & OSC_QUERY_ENABLE)
+				goto out_success;
+			printk(KERN_DEBUG
+			       "Firmware did not grant requested _OSC control\n");
+			status = AE_SUPPORT;
+			goto out_kfree;
+		}
+		status = AE_ERROR;
+		goto out_kfree;
+	}
+out_success:
+	return AE_OK;
+
+out_kfree:
+	kfree(context->ret.pointer);
+	context->ret.pointer = NULL;
+	return status;
+}
+EXPORT_SYMBOL(acpi_run_osc);
+
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */

Index: linux/include/linux/acpi.h
===================================================================

include/linux/acpi.h +9 -1
@@ -253,6 +253,13 @@ void __init acpi_old_suspend_ordering(vo
 void __init acpi_s4_no_nvs(void);
 #endif /* CONFIG_PM_SLEEP */
 
+struct acpi_osc_context {
+	u8 *uuid;
+	int rev;
+	struct acpi_buffer cap; /* arg2/arg3 */
+	struct acpi_buffer ret; /* free by caller if success */
+};
+
 #define OSC_QUERY_TYPE			0
 #define OSC_SUPPORT_TYPE 		1
 #define OSC_CONTROL_TYPE		2
@@ -265,6 +272,8 @@ void __init acpi_s4_no_nvs(void);
 #define OSC_INVALID_REVISION_ERROR	8
 #define OSC_CAPABILITIES_MASK_ERROR	16
 
+acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
+
 /* _OSC DW1 Definition (OS Support Fields) */
 #define OSC_EXT_PCI_CONFIG_SUPPORT		1
 #define OSC_ACTIVE_STATE_PWR_SUPPORT 		2
--
Quoted 4 lines

To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author
#5 lore raw
Quoted 4 lines · Alexey Starikovskiy

Hi Shaohua,

Could you also make it take a spec string as argument, not a prepared byte buffer?

Hi,
did you mean take the uuid string as an argument of the API? We can add a function to convert a uuid string to binary, but I didn't see any benefit to take the string as argument.

Thanks,
Shaohua

#6 lore raw

Shaohua Li пишет:

Quoted 7 lines · Alexey Starikovskiy
Quoted 6 lines

Hi Shaohua,

Could you also make it take a spec string as argument, not a prepared byte buffer?

Quoted 8 lines

Hi,
did you mean take the uuid string as an argument of the API? We can add a function to convert a uuid string to binary, but I didn't see any benefit to take the string as argument.

Thanks,
Shaohua

Hi,
Well, right now you are programming in machine codes. If you make mistake, no one will notice, even yourself.
Programming languages were invented to make programs look more readable by humans, so that they can see mistakes more easily.
For the same reason ACPI specification declares UUIDs as strings, while having them in AML as byte arrays.
Function to convert UUID to byte array already exists, you just need to use it...

Regards,
Alex.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author
#7 lore raw
Quoted 16 lines · Alexey Starikovskiy

Shaohua Li пишет:

Quoted 7 lines · Alexey Starikovskiy
Quoted 6 lines

Hi Shaohua,

Could you also make it take a spec string as argument, not a prepared byte buffer?

Quoted 8 lines

Hi,
did you mean take the uuid string as an argument of the API? We can add a function to convert a uuid string to binary, but I didn't see any benefit to take the string as argument.

Thanks,
Shaohua

Quoted 9 lines

Hi,
Well, right now you are programming in machine codes. If you make mistake, no one will notice, even yourself.
Programming languages were invented to make programs look more readable by humans, so that they can see mistakes more easily.
For the same reason ACPI specification declares UUIDs as strings, while having them in AML as byte arrays.
Function to convert UUID to byte array already exists, you just need to use it...

frankly even you use UUID string, it's easy to make mistakes. The string is too long. BTW, which function can convert UUID to byte array?

Thanks,
Shaohua
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#8 lore raw

Shaohua Li пишет:

Quoted 32 lines · Alexey Starikovskiy
Quoted 21 lines

Shaohua Li пишет:

Quoted 9 lines · Alexey Starikovskiy
Quoted 8 lines

Hi Shaohua,

Could you also make it take a spec string as argument, not a prepared byte buffer?

Quoted 9 lines

Hi,
did you mean take the uuid string as an argument of the API? We can add a function to convert a uuid string to binary, but I didn't see any benefit to take the string as argument.

Thanks,
Shaohua

Quoted 10 lines

Hi,
Well, right now you are programming in machine codes. If you make mistake, no one will notice, even yourself.
Programming languages were invented to make programs look more readable by humans, so that they can see mistakes more easily.
For the same reason ACPI specification declares UUIDs as strings, while having them in AML as byte arrays.
Function to convert UUID to byte array already exists, you just need to use it...

Quoted 2 lines

frankly even you use UUID string, it's easy to make mistakes. The string is too long.

Copy-paste is already invented too :)

Quoted 2 lines

BTW, which function can convert UUID to byte array?

aslopcodes.c:633 OpcDoUuId().

Regards,
Alex.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html