V4L/DVB (9582): Add a EM28XX_NODECODER option to the list of available decoders
[safe/jmp/linux-2.6] / drivers / acpi / tables / tbutils.c
index 1da64b4..0cc92ef 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,8 +49,67 @@ ACPI_MODULE_NAME("tbutils")
 
 /* Local prototypes */
 static acpi_physical_address
-acpi_tb_get_root_table_entry(u8 * table_entry,
-                            acpi_native_uint table_entry_size);
+acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_check_xsdt
+ *
+ * PARAMETERS:  address                    - Pointer to the XSDT
+ *
+ * RETURN:      status
+ *             AE_OK - XSDT is okay
+ *             AE_NO_MEMORY - can't map XSDT
+ *             AE_INVALID_TABLE_LENGTH - invalid table length
+ *             AE_NULL_ENTRY - XSDT has NULL entry
+ *
+ * DESCRIPTION: validate XSDT
+******************************************************************************/
+
+static acpi_status
+acpi_tb_check_xsdt(acpi_physical_address address)
+{
+       struct acpi_table_header *table;
+       u32 length;
+       u64 xsdt_entry_address;
+       u8 *table_entry;
+       u32 table_count;
+       int i;
+
+       table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+       if (!table)
+               return AE_NO_MEMORY;
+
+       length = table->length;
+       acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+       if (length < sizeof(struct acpi_table_header))
+               return AE_INVALID_TABLE_LENGTH;
+
+       table = acpi_os_map_memory(address, length);
+       if (!table)
+               return AE_NO_MEMORY;
+
+       /* Calculate the number of tables described in XSDT */
+       table_count =
+               (u32) ((table->length -
+               sizeof(struct acpi_table_header)) / sizeof(u64));
+       table_entry =
+               ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+       for (i = 0; i < table_count; i++) {
+               ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
+               if (!xsdt_entry_address) {
+                       /* XSDT has NULL entry */
+                       break;
+               }
+               table_entry += sizeof(u64);
+       }
+       acpi_os_unmap_memory(table, length);
+
+       if (i < table_count)
+               return AE_NULL_ENTRY;
+       else
+               return AE_OK;
+}
 
 /*******************************************************************************
  *
@@ -153,7 +212,7 @@ acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
 
        if (checksum) {
                ACPI_WARNING((AE_INFO,
-                             "Incorrect checksum in table [%4.4s] -  %2.2X, should be %2.2X",
+                             "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
                              table->signature, table->checksum,
                              (u8) (table->checksum - checksum)));
 
@@ -179,7 +238,7 @@ acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
  *
  ******************************************************************************/
 
-u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
+u8 acpi_tb_checksum(u8 *buffer, u32 length)
 {
        u8 sum = 0;
        u8 *end = buffer + length;
@@ -209,7 +268,7 @@ u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
 
 void
 acpi_tb_install_table(acpi_physical_address address,
-                     u8 flags, char *signature, acpi_native_uint table_index)
+                     u8 flags, char *signature, u32 table_index)
 {
        struct acpi_table_header *table;
 
@@ -277,8 +336,7 @@ acpi_tb_install_table(acpi_physical_address address,
  ******************************************************************************/
 
 static acpi_physical_address
-acpi_tb_get_root_table_entry(u8 * table_entry,
-                            acpi_native_uint table_entry_size)
+acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
 {
        u64 address64;
 
@@ -336,11 +394,12 @@ acpi_status __init
 acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
 {
        struct acpi_table_rsdp *rsdp;
-       acpi_native_uint table_entry_size;
-       acpi_native_uint i;
+       u32 table_entry_size;
+       u32 i;
        u32 table_count;
        struct acpi_table_header *table;
        acpi_physical_address address;
+       acpi_physical_address uninitialized_var(rsdt_address);
        u32 length;
        u8 *table_entry;
        acpi_status status;
@@ -369,6 +428,8 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
                 */
                address = (acpi_physical_address) rsdp->xsdt_physical_address;
                table_entry_size = sizeof(u64);
+               rsdt_address = (acpi_physical_address)
+                                       rsdp->rsdt_physical_address;
        } else {
                /* Root table is an RSDT (32-bit physical addresses) */
 
@@ -382,6 +443,15 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
         */
        acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
 
+       if (table_entry_size == sizeof(u64)) {
+               if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) {
+                       /* XSDT has NULL entry, RSDT is used */
+                       address = rsdt_address;
+                       table_entry_size = sizeof(u32);
+                       ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry, "
+                                       "using RSDT"));
+               }
+       }
        /* Map the RSDT/XSDT table header to get the full table length */
 
        table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));