diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 56 |
1 files changed, 47 insertions, 9 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index f70796081c4c..baef28c1e630 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -119,6 +119,8 @@ static struct acpi_ec { | |||
119 | } *boot_ec, *first_ec; | 119 | } *boot_ec, *first_ec; |
120 | 120 | ||
121 | static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ | 121 | static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ |
122 | static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ | ||
123 | static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ | ||
122 | 124 | ||
123 | /* -------------------------------------------------------------------------- | 125 | /* -------------------------------------------------------------------------- |
124 | Transaction Management | 126 | Transaction Management |
@@ -232,10 +234,8 @@ static int ec_poll(struct acpi_ec *ec) | |||
232 | } | 234 | } |
233 | advance_transaction(ec, acpi_ec_read_status(ec)); | 235 | advance_transaction(ec, acpi_ec_read_status(ec)); |
234 | } while (time_before(jiffies, delay)); | 236 | } while (time_before(jiffies, delay)); |
235 | if (!ec->curr->irq_count || | 237 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) |
236 | (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) | ||
237 | break; | 238 | break; |
238 | /* try restart command if we get any false interrupts */ | ||
239 | pr_debug(PREFIX "controller reset, restart transaction\n"); | 239 | pr_debug(PREFIX "controller reset, restart transaction\n"); |
240 | spin_lock_irqsave(&ec->curr_lock, flags); | 240 | spin_lock_irqsave(&ec->curr_lock, flags); |
241 | start_transaction(ec); | 241 | start_transaction(ec); |
@@ -899,6 +899,44 @@ static const struct acpi_device_id ec_device_ids[] = { | |||
899 | {"", 0}, | 899 | {"", 0}, |
900 | }; | 900 | }; |
901 | 901 | ||
902 | /* Some BIOS do not survive early DSDT scan, skip it */ | ||
903 | static int ec_skip_dsdt_scan(const struct dmi_system_id *id) | ||
904 | { | ||
905 | EC_FLAGS_SKIP_DSDT_SCAN = 1; | ||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | /* ASUStek often supplies us with broken ECDT, validate it */ | ||
910 | static int ec_validate_ecdt(const struct dmi_system_id *id) | ||
911 | { | ||
912 | EC_FLAGS_VALIDATE_ECDT = 1; | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | /* MSI EC needs special treatment, enable it */ | ||
917 | static int ec_flag_msi(const struct dmi_system_id *id) | ||
918 | { | ||
919 | EC_FLAGS_MSI = 1; | ||
920 | EC_FLAGS_VALIDATE_ECDT = 1; | ||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static struct dmi_system_id __initdata ec_dmi_table[] = { | ||
925 | { | ||
926 | ec_skip_dsdt_scan, "Compal JFL92", { | ||
927 | DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), | ||
928 | DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL}, | ||
929 | { | ||
930 | ec_flag_msi, "MSI hardware", { | ||
931 | DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star"), | ||
932 | DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star") }, NULL}, | ||
933 | { | ||
934 | ec_validate_ecdt, "ASUS hardware", { | ||
935 | DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL}, | ||
936 | {}, | ||
937 | }; | ||
938 | |||
939 | |||
902 | int __init acpi_ec_ecdt_probe(void) | 940 | int __init acpi_ec_ecdt_probe(void) |
903 | { | 941 | { |
904 | acpi_status status; | 942 | acpi_status status; |
@@ -911,11 +949,7 @@ int __init acpi_ec_ecdt_probe(void) | |||
911 | /* | 949 | /* |
912 | * Generate a boot ec context | 950 | * Generate a boot ec context |
913 | */ | 951 | */ |
914 | if (dmi_name_in_vendors("Micro-Star") || | 952 | dmi_check_system(ec_dmi_table); |
915 | dmi_name_in_vendors("Notebook")) { | ||
916 | pr_info(PREFIX "Enabling special treatment for EC from MSI.\n"); | ||
917 | EC_FLAGS_MSI = 1; | ||
918 | } | ||
919 | status = acpi_get_table(ACPI_SIG_ECDT, 1, | 953 | status = acpi_get_table(ACPI_SIG_ECDT, 1, |
920 | (struct acpi_table_header **)&ecdt_ptr); | 954 | (struct acpi_table_header **)&ecdt_ptr); |
921 | if (ACPI_SUCCESS(status)) { | 955 | if (ACPI_SUCCESS(status)) { |
@@ -926,7 +960,7 @@ int __init acpi_ec_ecdt_probe(void) | |||
926 | boot_ec->handle = ACPI_ROOT_OBJECT; | 960 | boot_ec->handle = ACPI_ROOT_OBJECT; |
927 | acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); | 961 | acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); |
928 | /* Don't trust ECDT, which comes from ASUSTek */ | 962 | /* Don't trust ECDT, which comes from ASUSTek */ |
929 | if (!dmi_name_in_vendors("ASUS") && EC_FLAGS_MSI == 0) | 963 | if (!EC_FLAGS_VALIDATE_ECDT) |
930 | goto install; | 964 | goto install; |
931 | saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); | 965 | saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL); |
932 | if (!saved_ec) | 966 | if (!saved_ec) |
@@ -934,6 +968,10 @@ int __init acpi_ec_ecdt_probe(void) | |||
934 | memcpy(saved_ec, boot_ec, sizeof(struct acpi_ec)); | 968 | memcpy(saved_ec, boot_ec, sizeof(struct acpi_ec)); |
935 | /* fall through */ | 969 | /* fall through */ |
936 | } | 970 | } |
971 | |||
972 | if (EC_FLAGS_SKIP_DSDT_SCAN) | ||
973 | return -ENODEV; | ||
974 | |||
937 | /* This workaround is needed only on some broken machines, | 975 | /* This workaround is needed only on some broken machines, |
938 | * which require early EC, but fail to provide ECDT */ | 976 | * which require early EC, but fail to provide ECDT */ |
939 | printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); | 977 | printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); |