diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index d411017f8c06..7222a18a0319 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -26,6 +26,9 @@ | |||
26 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 26 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
27 | */ | 27 | */ |
28 | 28 | ||
29 | /* Uncomment next line to get verbose print outs*/ | ||
30 | /* #define DEBUG */ | ||
31 | |||
29 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 33 | #include <linux/module.h> |
31 | #include <linux/init.h> | 34 | #include <linux/init.h> |
@@ -47,9 +50,6 @@ | |||
47 | #undef PREFIX | 50 | #undef PREFIX |
48 | #define PREFIX "ACPI: EC: " | 51 | #define PREFIX "ACPI: EC: " |
49 | 52 | ||
50 | /* Uncomment next line to get verbose print outs*/ | ||
51 | /* #define DEBUG */ | ||
52 | |||
53 | /* EC status register */ | 53 | /* EC status register */ |
54 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ | 54 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ |
55 | #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ | 55 | #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ |
@@ -82,6 +82,7 @@ enum { | |||
82 | EC_FLAGS_ADDRESS, /* Address is being written */ | 82 | EC_FLAGS_ADDRESS, /* Address is being written */ |
83 | EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */ | 83 | EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */ |
84 | EC_FLAGS_WDATA, /* Data is being written */ | 84 | EC_FLAGS_WDATA, /* Data is being written */ |
85 | EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */ | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | static int acpi_ec_remove(struct acpi_device *device, int type); | 88 | static int acpi_ec_remove(struct acpi_device *device, int type); |
@@ -138,26 +139,26 @@ static struct acpi_ec { | |||
138 | static inline u8 acpi_ec_read_status(struct acpi_ec *ec) | 139 | static inline u8 acpi_ec_read_status(struct acpi_ec *ec) |
139 | { | 140 | { |
140 | u8 x = inb(ec->command_addr); | 141 | u8 x = inb(ec->command_addr); |
141 | pr_debug(PREFIX "---> status = 0x%2x\n", x); | 142 | pr_debug(PREFIX "---> status = 0x%2.2x\n", x); |
142 | return x; | 143 | return x; |
143 | } | 144 | } |
144 | 145 | ||
145 | static inline u8 acpi_ec_read_data(struct acpi_ec *ec) | 146 | static inline u8 acpi_ec_read_data(struct acpi_ec *ec) |
146 | { | 147 | { |
147 | u8 x = inb(ec->data_addr); | 148 | u8 x = inb(ec->data_addr); |
148 | pr_debug(PREFIX "---> data = 0x%2x\n", x); | 149 | pr_debug(PREFIX "---> data = 0x%2.2x\n", x); |
149 | return inb(ec->data_addr); | 150 | return inb(ec->data_addr); |
150 | } | 151 | } |
151 | 152 | ||
152 | static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) | 153 | static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) |
153 | { | 154 | { |
154 | pr_debug(PREFIX "<--- command = 0x%2x\n", command); | 155 | pr_debug(PREFIX "<--- command = 0x%2.2x\n", command); |
155 | outb(command, ec->command_addr); | 156 | outb(command, ec->command_addr); |
156 | } | 157 | } |
157 | 158 | ||
158 | static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | 159 | static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) |
159 | { | 160 | { |
160 | pr_debug(PREFIX "<--- data = 0x%2x\n", data); | 161 | pr_debug(PREFIX "<--- data = 0x%2.2x\n", data); |
161 | outb(data, ec->data_addr); | 162 | outb(data, ec->data_addr); |
162 | } | 163 | } |
163 | 164 | ||
@@ -179,6 +180,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) | |||
179 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) | 180 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) |
180 | { | 181 | { |
181 | int ret = 0; | 182 | int ret = 0; |
183 | |||
184 | if (unlikely(event == ACPI_EC_EVENT_OBF_1 && | ||
185 | test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags))) | ||
186 | force_poll = 1; | ||
182 | if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) && | 187 | if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) && |
183 | test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags))) | 188 | test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags))) |
184 | force_poll = 1; | 189 | force_poll = 1; |
@@ -192,7 +197,12 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) | |||
192 | goto end; | 197 | goto end; |
193 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 198 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
194 | if (acpi_ec_check_status(ec, event)) { | 199 | if (acpi_ec_check_status(ec, event)) { |
195 | if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { | 200 | if (event == ACPI_EC_EVENT_OBF_1) { |
201 | /* miss OBF_1 GPE, don't expect it */ | ||
202 | pr_info(PREFIX "missing OBF confirmation, " | ||
203 | "don't expect it any longer.\n"); | ||
204 | set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags); | ||
205 | } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { | ||
196 | /* miss address GPE, don't expect it anymore */ | 206 | /* miss address GPE, don't expect it anymore */ |
197 | pr_info(PREFIX "missing address confirmation, " | 207 | pr_info(PREFIX "missing address confirmation, " |
198 | "don't expect it any longer.\n"); | 208 | "don't expect it any longer.\n"); |
@@ -563,7 +573,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, | |||
563 | void *handler_context, void *region_context) | 573 | void *handler_context, void *region_context) |
564 | { | 574 | { |
565 | struct acpi_ec *ec = handler_context; | 575 | struct acpi_ec *ec = handler_context; |
566 | int result = 0, i = 0; | 576 | int result = 0, i; |
567 | u8 temp = 0; | 577 | u8 temp = 0; |
568 | 578 | ||
569 | if ((address > 0xFF) || !value || !handler_context) | 579 | if ((address > 0xFF) || !value || !handler_context) |
@@ -575,7 +585,18 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, | |||
575 | if (bits != 8 && acpi_strict) | 585 | if (bits != 8 && acpi_strict) |
576 | return AE_BAD_PARAMETER; | 586 | return AE_BAD_PARAMETER; |
577 | 587 | ||
578 | while (bits - i > 0) { | 588 | acpi_ec_burst_enable(ec); |
589 | |||
590 | if (function == ACPI_READ) { | ||
591 | result = acpi_ec_read(ec, address, &temp); | ||
592 | *value = temp; | ||
593 | } else { | ||
594 | temp = 0xff & (*value); | ||
595 | result = acpi_ec_write(ec, address, temp); | ||
596 | } | ||
597 | |||
598 | for (i = 8; unlikely(bits - i > 0); i += 8) { | ||
599 | ++address; | ||
579 | if (function == ACPI_READ) { | 600 | if (function == ACPI_READ) { |
580 | result = acpi_ec_read(ec, address, &temp); | 601 | result = acpi_ec_read(ec, address, &temp); |
581 | (*value) |= ((acpi_integer)temp) << i; | 602 | (*value) |= ((acpi_integer)temp) << i; |
@@ -583,10 +604,10 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, | |||
583 | temp = 0xff & ((*value) >> i); | 604 | temp = 0xff & ((*value) >> i); |
584 | result = acpi_ec_write(ec, address, temp); | 605 | result = acpi_ec_write(ec, address, temp); |
585 | } | 606 | } |
586 | i += 8; | ||
587 | ++address; | ||
588 | } | 607 | } |
589 | 608 | ||
609 | acpi_ec_burst_disable(ec); | ||
610 | |||
590 | switch (result) { | 611 | switch (result) { |
591 | case -EINVAL: | 612 | case -EINVAL: |
592 | return AE_BAD_PARAMETER; | 613 | return AE_BAD_PARAMETER; |
@@ -892,6 +913,17 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
892 | return 0; | 913 | return 0; |
893 | } | 914 | } |
894 | 915 | ||
916 | int __init acpi_boot_ec_enable(void) | ||
917 | { | ||
918 | if (!boot_ec || boot_ec->handlers_installed) | ||
919 | return 0; | ||
920 | if (!ec_install_handlers(boot_ec)) { | ||
921 | first_ec = boot_ec; | ||
922 | return 0; | ||
923 | } | ||
924 | return -EFAULT; | ||
925 | } | ||
926 | |||
895 | int __init acpi_ec_ecdt_probe(void) | 927 | int __init acpi_ec_ecdt_probe(void) |
896 | { | 928 | { |
897 | int ret; | 929 | int ret; |
@@ -924,9 +956,10 @@ int __init acpi_ec_ecdt_probe(void) | |||
924 | goto error; | 956 | goto error; |
925 | /* We really need to limit this workaround, the only ASUS, | 957 | /* We really need to limit this workaround, the only ASUS, |
926 | * which needs it, has fake EC._INI method, so use it as flag. | 958 | * which needs it, has fake EC._INI method, so use it as flag. |
959 | * Keep boot_ec struct as it will be needed soon. | ||
927 | */ | 960 | */ |
928 | if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x))) | 961 | if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x))) |
929 | goto error; | 962 | return -ENODEV; |
930 | } | 963 | } |
931 | 964 | ||
932 | ret = ec_install_handlers(boot_ec); | 965 | ret = ec_install_handlers(boot_ec); |