ACPICA: Add repair for predefined methods that return nested packages
authorBob Moore <robert.moore@intel.com>
Fri, 24 Jul 2009 03:03:09 +0000 (11:03 +0800)
committerLen Brown <len.brown@intel.com>
Fri, 28 Aug 2009 23:40:38 +0000 (19:40 -0400)
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>
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nsrepair.c

index 908cfdd3b895e57425b92fa22cff7c55eeefdecd..f75a7a01b8754c99202f86e5c930b61239f05921 100644 (file)
@@ -278,6 +278,10 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
                      u32 package_index,
                      union acpi_operand_object **return_object_ptr);
 
+acpi_status
+acpi_ns_repair_package_list(struct acpi_predefined_data *data,
+                           union acpi_operand_object **obj_desc_ptr);
+
 /*
  * nssearch - Namespace searching and entry
  */
index e3f08dcb527524901c7cc60a57b55a0a338ff7d1..0091504df0745b8aa2a83f1769d74b1018464f64 100644 (file)
@@ -566,9 +566,35 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
        case ACPI_PTYPE2_COUNT:
 
                /*
-                * These types all return a single package that consists of a
-                * variable number of sub-packages.
+                * These types all return a single Package that consists of a
+                * variable number of sub-Packages.
+                *
+                * First, ensure that the first element is a sub-Package. If not,
+                * the BIOS may have incorrectly returned the object as a single
+                * package instead of a Package of Packages (a common error if
+                * there is only one entry). We may be able to repair this by
+                * wrapping the returned Package with a new outer Package.
                 */
+               if ((*elements)->common.type != ACPI_TYPE_PACKAGE) {
+
+                       /* Create the new outer package and populate it */
+
+                       status =
+                           acpi_ns_repair_package_list(data,
+                                                       return_object_ptr);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+
+                       /* Update locals to point to the new package (of 1 element) */
+
+                       return_object = *return_object_ptr;
+                       elements = return_object->package.elements;
+                       count = 1;
+               }
+
+               /* Validate each sub-Package in the parent Package */
+
                for (i = 0; i < count; i++) {
                        sub_package = *elements;
                        sub_elements = sub_package->package.elements;
index b64751eacc53d6eaebfd7ac752ab9cdb9e418019..db2b2a99c3a8130ba31dab24fd31a58116f5ec71 100644 (file)
@@ -149,3 +149,55 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
 
        return (AE_AML_OPERAND_TYPE);
 }
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_repair_package_list
+ *
+ * PARAMETERS:  Data                - Pointer to validation data structure
+ *              obj_desc_ptr        - Pointer to the object to repair. The new
+ *                                    package object is returned here,
+ *                                    overwriting the old object.
+ *
+ * RETURN:      Status, new object in *obj_desc_ptr
+ *
+ * DESCRIPTION: Repair a common problem with objects that are defined to return
+ *              a variable-length Package of Packages. If the variable-length
+ *              is one, some BIOS code mistakenly simply declares a single
+ *              Package instead of a Package with one sub-Package. This
+ *              function attempts to repair this error by wrapping a Package
+ *              object around the original Package, creating the correct
+ *              Package with one sub-Package.
+ *
+ *              Names that can be repaired in this manner include:
+ *              _ALR, _CSD, _HPX, _MLS, _PRT, _PSS, _TRT, TSS
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_repair_package_list(struct acpi_predefined_data *data,
+                           union acpi_operand_object **obj_desc_ptr)
+{
+       union acpi_operand_object *pkg_obj_desc;
+
+       /*
+        * Create the new outer package and populate it. The new package will
+        * have a single element, the lone subpackage.
+        */
+       pkg_obj_desc = acpi_ut_create_package_object(1);
+       if (!pkg_obj_desc) {
+               return (AE_NO_MEMORY);
+       }
+
+       pkg_obj_desc->package.elements[0] = *obj_desc_ptr;
+
+       /* Return the new object in the object pointer */
+
+       *obj_desc_ptr = pkg_obj_desc;
+       data->flags |= ACPI_OBJECT_REPAIRED;
+
+       ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+                             "Incorrectly formed Package, attempting repair"));
+
+       return (AE_OK);
+}