diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 69 |
1 files changed, 42 insertions, 27 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index d7a6bbbb834c..f2234db85da0 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/interrupt.h> | 39 | #include <linux/interrupt.h> |
40 | #include <linux/list.h> | 40 | #include <linux/list.h> |
41 | #include <linux/spinlock.h> | 41 | #include <linux/spinlock.h> |
42 | #include <linux/slab.h> | ||
42 | #include <asm/io.h> | 43 | #include <asm/io.h> |
43 | #include <acpi/acpi_bus.h> | 44 | #include <acpi/acpi_bus.h> |
44 | #include <acpi/acpi_drivers.h> | 45 | #include <acpi/acpi_drivers.h> |
@@ -76,8 +77,9 @@ enum ec_command { | |||
76 | enum { | 77 | enum { |
77 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ | 78 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
78 | EC_FLAGS_GPE_STORM, /* GPE storm detected */ | 79 | EC_FLAGS_GPE_STORM, /* GPE storm detected */ |
79 | EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and | 80 | EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and |
80 | * OpReg are installed */ | 81 | * OpReg are installed */ |
82 | EC_FLAGS_FROZEN, /* Transactions are suspended */ | ||
81 | }; | 83 | }; |
82 | 84 | ||
83 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ | 85 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ |
@@ -291,6 +293,10 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
291 | if (t->rdata) | 293 | if (t->rdata) |
292 | memset(t->rdata, 0, t->rlen); | 294 | memset(t->rdata, 0, t->rlen); |
293 | mutex_lock(&ec->lock); | 295 | mutex_lock(&ec->lock); |
296 | if (test_bit(EC_FLAGS_FROZEN, &ec->flags)) { | ||
297 | status = -EINVAL; | ||
298 | goto unlock; | ||
299 | } | ||
294 | if (ec->global_lock) { | 300 | if (ec->global_lock) { |
295 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); | 301 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); |
296 | if (ACPI_FAILURE(status)) { | 302 | if (ACPI_FAILURE(status)) { |
@@ -453,6 +459,32 @@ int ec_transaction(u8 command, | |||
453 | 459 | ||
454 | EXPORT_SYMBOL(ec_transaction); | 460 | EXPORT_SYMBOL(ec_transaction); |
455 | 461 | ||
462 | void acpi_ec_suspend_transactions(void) | ||
463 | { | ||
464 | struct acpi_ec *ec = first_ec; | ||
465 | |||
466 | if (!ec) | ||
467 | return; | ||
468 | |||
469 | mutex_lock(&ec->lock); | ||
470 | /* Prevent transactions from being carried out */ | ||
471 | set_bit(EC_FLAGS_FROZEN, &ec->flags); | ||
472 | mutex_unlock(&ec->lock); | ||
473 | } | ||
474 | |||
475 | void acpi_ec_resume_transactions(void) | ||
476 | { | ||
477 | struct acpi_ec *ec = first_ec; | ||
478 | |||
479 | if (!ec) | ||
480 | return; | ||
481 | |||
482 | mutex_lock(&ec->lock); | ||
483 | /* Allow transactions to be carried out again */ | ||
484 | clear_bit(EC_FLAGS_FROZEN, &ec->flags); | ||
485 | mutex_unlock(&ec->lock); | ||
486 | } | ||
487 | |||
456 | static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) | 488 | static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) |
457 | { | 489 | { |
458 | int result; | 490 | int result; |
@@ -597,12 +629,12 @@ static u32 acpi_ec_gpe_handler(void *data) | |||
597 | 629 | ||
598 | static acpi_status | 630 | static acpi_status |
599 | acpi_ec_space_handler(u32 function, acpi_physical_address address, | 631 | acpi_ec_space_handler(u32 function, acpi_physical_address address, |
600 | u32 bits, u64 *value, | 632 | u32 bits, u64 *value64, |
601 | void *handler_context, void *region_context) | 633 | void *handler_context, void *region_context) |
602 | { | 634 | { |
603 | struct acpi_ec *ec = handler_context; | 635 | struct acpi_ec *ec = handler_context; |
604 | int result = 0, i; | 636 | int result = 0, i, bytes = bits / 8; |
605 | u8 temp = 0; | 637 | u8 *value = (u8 *)value64; |
606 | 638 | ||
607 | if ((address > 0xFF) || !value || !handler_context) | 639 | if ((address > 0xFF) || !value || !handler_context) |
608 | return AE_BAD_PARAMETER; | 640 | return AE_BAD_PARAMETER; |
@@ -610,32 +642,15 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, | |||
610 | if (function != ACPI_READ && function != ACPI_WRITE) | 642 | if (function != ACPI_READ && function != ACPI_WRITE) |
611 | return AE_BAD_PARAMETER; | 643 | return AE_BAD_PARAMETER; |
612 | 644 | ||
613 | if (bits != 8 && acpi_strict) | 645 | if (EC_FLAGS_MSI || bits > 8) |
614 | return AE_BAD_PARAMETER; | ||
615 | |||
616 | if (EC_FLAGS_MSI) | ||
617 | acpi_ec_burst_enable(ec); | 646 | acpi_ec_burst_enable(ec); |
618 | 647 | ||
619 | if (function == ACPI_READ) { | 648 | for (i = 0; i < bytes; ++i, ++address, ++value) |
620 | result = acpi_ec_read(ec, address, &temp); | 649 | result = (function == ACPI_READ) ? |
621 | *value = temp; | 650 | acpi_ec_read(ec, address, value) : |
622 | } else { | 651 | acpi_ec_write(ec, address, *value); |
623 | temp = 0xff & (*value); | ||
624 | result = acpi_ec_write(ec, address, temp); | ||
625 | } | ||
626 | 652 | ||
627 | for (i = 8; unlikely(bits - i > 0); i += 8) { | 653 | if (EC_FLAGS_MSI || bits > 8) |
628 | ++address; | ||
629 | if (function == ACPI_READ) { | ||
630 | result = acpi_ec_read(ec, address, &temp); | ||
631 | (*value) |= ((u64)temp) << i; | ||
632 | } else { | ||
633 | temp = 0xff & ((*value) >> i); | ||
634 | result = acpi_ec_write(ec, address, temp); | ||
635 | } | ||
636 | } | ||
637 | |||
638 | if (EC_FLAGS_MSI) | ||
639 | acpi_ec_burst_disable(ec); | 654 | acpi_ec_burst_disable(ec); |
640 | 655 | ||
641 | switch (result) { | 656 | switch (result) { |