diff options
author | Bob Moore <robert.moore@intel.com> | 2009-07-23 23:03:09 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-08-28 19:40:38 -0400 |
commit | e5f69d6ef7a6b0dbad8d4c00d83009960be02155 (patch) | |
tree | fac155941c084b22c566b4931c67ab098a1488ee /drivers/acpi/acpica | |
parent | b2deadd53c3630786e73746fb0ad8450f4e015bf (diff) |
ACPICA: Add repair for predefined methods that return nested packages
Fixes a problem where a predefined method is defined to return
a variable-length Package of sub-packages. If the length is one,
the BIOS code occasionally creates a simple single package with
no sub-packages. This code attempts to fix the problem by wrapping
a new package object around the existing package. ACPICA BZ 790.
http://acpica.org/bugzilla/show_bug.cgi?id=790
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica')
-rw-r--r-- | drivers/acpi/acpica/acnamesp.h | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/nspredef.c | 30 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsrepair.c | 52 |
3 files changed, 84 insertions, 2 deletions
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 908cfdd3b895..f75a7a01b875 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h | |||
@@ -278,6 +278,10 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, | |||
278 | u32 package_index, | 278 | u32 package_index, |
279 | union acpi_operand_object **return_object_ptr); | 279 | union acpi_operand_object **return_object_ptr); |
280 | 280 | ||
281 | acpi_status | ||
282 | acpi_ns_repair_package_list(struct acpi_predefined_data *data, | ||
283 | union acpi_operand_object **obj_desc_ptr); | ||
284 | |||
281 | /* | 285 | /* |
282 | * nssearch - Namespace searching and entry | 286 | * nssearch - Namespace searching and entry |
283 | */ | 287 | */ |
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index e3f08dcb5275..0091504df074 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c | |||
@@ -566,9 +566,35 @@ acpi_ns_check_package(struct acpi_predefined_data *data, | |||
566 | case ACPI_PTYPE2_COUNT: | 566 | case ACPI_PTYPE2_COUNT: |
567 | 567 | ||
568 | /* | 568 | /* |
569 | * These types all return a single package that consists of a | 569 | * These types all return a single Package that consists of a |
570 | * variable number of sub-packages. | 570 | * variable number of sub-Packages. |
571 | * | ||
572 | * First, ensure that the first element is a sub-Package. If not, | ||
573 | * the BIOS may have incorrectly returned the object as a single | ||
574 | * package instead of a Package of Packages (a common error if | ||
575 | * there is only one entry). We may be able to repair this by | ||
576 | * wrapping the returned Package with a new outer Package. | ||
571 | */ | 577 | */ |
578 | if ((*elements)->common.type != ACPI_TYPE_PACKAGE) { | ||
579 | |||
580 | /* Create the new outer package and populate it */ | ||
581 | |||
582 | status = | ||
583 | acpi_ns_repair_package_list(data, | ||
584 | return_object_ptr); | ||
585 | if (ACPI_FAILURE(status)) { | ||
586 | return (status); | ||
587 | } | ||
588 | |||
589 | /* Update locals to point to the new package (of 1 element) */ | ||
590 | |||
591 | return_object = *return_object_ptr; | ||
592 | elements = return_object->package.elements; | ||
593 | count = 1; | ||
594 | } | ||
595 | |||
596 | /* Validate each sub-Package in the parent Package */ | ||
597 | |||
572 | for (i = 0; i < count; i++) { | 598 | for (i = 0; i < count; i++) { |
573 | sub_package = *elements; | 599 | sub_package = *elements; |
574 | sub_elements = sub_package->package.elements; | 600 | sub_elements = sub_package->package.elements; |
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index b64751eacc53..db2b2a99c3a8 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c | |||
@@ -149,3 +149,55 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, | |||
149 | 149 | ||
150 | return (AE_AML_OPERAND_TYPE); | 150 | return (AE_AML_OPERAND_TYPE); |
151 | } | 151 | } |
152 | |||
153 | /******************************************************************************* | ||
154 | * | ||
155 | * FUNCTION: acpi_ns_repair_package_list | ||
156 | * | ||
157 | * PARAMETERS: Data - Pointer to validation data structure | ||
158 | * obj_desc_ptr - Pointer to the object to repair. The new | ||
159 | * package object is returned here, | ||
160 | * overwriting the old object. | ||
161 | * | ||
162 | * RETURN: Status, new object in *obj_desc_ptr | ||
163 | * | ||
164 | * DESCRIPTION: Repair a common problem with objects that are defined to return | ||
165 | * a variable-length Package of Packages. If the variable-length | ||
166 | * is one, some BIOS code mistakenly simply declares a single | ||
167 | * Package instead of a Package with one sub-Package. This | ||
168 | * function attempts to repair this error by wrapping a Package | ||
169 | * object around the original Package, creating the correct | ||
170 | * Package with one sub-Package. | ||
171 | * | ||
172 | * Names that can be repaired in this manner include: | ||
173 | * _ALR, _CSD, _HPX, _MLS, _PRT, _PSS, _TRT, TSS | ||
174 | * | ||
175 | ******************************************************************************/ | ||
176 | |||
177 | acpi_status | ||
178 | acpi_ns_repair_package_list(struct acpi_predefined_data *data, | ||
179 | union acpi_operand_object **obj_desc_ptr) | ||
180 | { | ||
181 | union acpi_operand_object *pkg_obj_desc; | ||
182 | |||
183 | /* | ||
184 | * Create the new outer package and populate it. The new package will | ||
185 | * have a single element, the lone subpackage. | ||
186 | */ | ||
187 | pkg_obj_desc = acpi_ut_create_package_object(1); | ||
188 | if (!pkg_obj_desc) { | ||
189 | return (AE_NO_MEMORY); | ||
190 | } | ||
191 | |||
192 | pkg_obj_desc->package.elements[0] = *obj_desc_ptr; | ||
193 | |||
194 | /* Return the new object in the object pointer */ | ||
195 | |||
196 | *obj_desc_ptr = pkg_obj_desc; | ||
197 | data->flags |= ACPI_OBJECT_REPAIRED; | ||
198 | |||
199 | ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | ||
200 | "Incorrectly formed Package, attempting repair")); | ||
201 | |||
202 | return (AE_OK); | ||
203 | } | ||