Commit 451566f4 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Len Brown

[ACPI] Enable EC Burst Mode

Fixes several Embedded Controller issues, including
button failure and battery status AE_TIME failure.

http://bugzilla.kernel.org/show_bug.cgi?id=3851

Based on patch by: Andi Kleen <ak@suse.de>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
Signed-off-by: default avatarLuming Yu <luming.yu@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent b913100d
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <asm/io.h> #include <asm/io.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
...@@ -49,17 +50,19 @@ ACPI_MODULE_NAME ("acpi_ec") ...@@ -49,17 +50,19 @@ ACPI_MODULE_NAME ("acpi_ec")
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */ #define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */
#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */ #define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ #define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */
#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_COMMAND_READ 0x80 #define ACPI_EC_COMMAND_READ 0x80
#define ACPI_EC_COMMAND_WRITE 0x81 #define ACPI_EC_COMMAND_WRITE 0x81
#define ACPI_EC_BURST_ENABLE 0x82
#define ACPI_EC_BURST_DISABLE 0x83
#define ACPI_EC_COMMAND_QUERY 0x84 #define ACPI_EC_COMMAND_QUERY 0x84
static int acpi_ec_add (struct acpi_device *device); static int acpi_ec_add (struct acpi_device *device);
...@@ -87,7 +90,11 @@ struct acpi_ec { ...@@ -87,7 +90,11 @@ struct acpi_ec {
struct acpi_generic_address command_addr; struct acpi_generic_address command_addr;
struct acpi_generic_address data_addr; struct acpi_generic_address data_addr;
unsigned long global_lock; unsigned long global_lock;
spinlock_t lock; unsigned int expect_event;
atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort*/
atomic_t pending_gpe;
struct semaphore sem;
wait_queue_head_t wait;
}; };
/* If we find an EC via the ECDT, we need to keep a ptr to its context */ /* If we find an EC via the ECDT, we need to keep a ptr to its context */
...@@ -100,59 +107,138 @@ static struct acpi_device *first_ec; ...@@ -100,59 +107,138 @@ static struct acpi_device *first_ec;
Transaction Management Transaction Management
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static int static inline u32 acpi_ec_read_status(struct acpi_ec *ec)
acpi_ec_wait (
struct acpi_ec *ec,
u8 event)
{ {
u32 acpi_ec_status = 0; u32 status = 0;
u32 i = ACPI_EC_UDELAY_COUNT;
if (!ec) acpi_hw_low_level_read(8, &status, &ec->status_addr);
return -EINVAL; return status;
}
static int acpi_ec_wait(struct acpi_ec *ec, unsigned int event)
{
int result = 0;
ACPI_FUNCTION_TRACE("acpi_ec_wait");
/* Poll the EC status register waiting for the event to occur. */ ec->expect_event = event;
smp_mb();
result = wait_event_interruptible_timeout(ec->wait,
!ec->expect_event,
msecs_to_jiffies(ACPI_EC_DELAY));
ec->expect_event = 0;
smp_mb();
if (result < 0){
ACPI_DEBUG_PRINT((ACPI_DB_ERROR," result = %d ", result));
return_VALUE(result);
}
/*
* Verify that the event in question has actually happened by
* querying EC status. Do the check even if operation timed-out
* to make sure that we did not miss interrupt.
*/
switch (event) { switch (event) {
case ACPI_EC_EVENT_OBF: case ACPI_EC_EVENT_OBF:
do { if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr); return_VALUE(0);
if (acpi_ec_status & ACPI_EC_FLAG_OBF)
return 0;
udelay(ACPI_EC_UDELAY);
} while (--i>0);
break; break;
case ACPI_EC_EVENT_IBE: case ACPI_EC_EVENT_IBE:
do { if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr); return_VALUE(0);
if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
return 0;
udelay(ACPI_EC_UDELAY);
} while (--i>0);
break; break;
default:
return -EINVAL;
} }
return -ETIME; return_VALUE(-ETIME);
} }
static int
acpi_ec_enter_burst_mode (
struct acpi_ec *ec)
{
u32 tmp = 0;
int status = 0;
ACPI_FUNCTION_TRACE("acpi_ec_enter_burst_mode");
status = acpi_ec_read_status(ec);
if (status != -EINVAL &&
!(status & ACPI_EC_FLAG_BURST)){
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"entering burst mode \n"));
acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (status){
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR," status = %d\n", status));
return_VALUE(-EINVAL);
}
acpi_hw_low_level_read(8, &tmp, &ec->data_addr);
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
if(tmp != 0x90 ) {/* Burst ACK byte*/
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Ack failed \n"));
return_VALUE(-EINVAL);
}
} else
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in burst mode \n"));
atomic_set(&ec->leaving_burst , 0);
return_VALUE(0);
}
static int
acpi_ec_leave_burst_mode (
struct acpi_ec *ec)
{
int status =0;
ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode");
atomic_set(&ec->leaving_burst , 1);
status = acpi_ec_read_status(ec);
if (status != -EINVAL &&
(status & ACPI_EC_FLAG_BURST)){
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n"));
acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->command_addr);
status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
if (status){
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->wait fail\n"));
return_VALUE(-EINVAL);
}
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
status = acpi_ec_read_status(ec);
if (status != -EINVAL &&
(status & ACPI_EC_FLAG_BURST)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->status fail\n"));
return_VALUE(-EINVAL);
}
}else
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in Non-burst mode \n"));
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n"));
return_VALUE(0);
}
static int static int
acpi_ec_read ( acpi_ec_read (
struct acpi_ec *ec, struct acpi_ec *ec,
u8 address, u8 address,
u32 *data) u32 *data)
{ {
acpi_status status = AE_OK; int status = 0;
int result = 0; u32 glk;
unsigned long flags = 0;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_read"); ACPI_FUNCTION_TRACE("acpi_ec_read");
if (!ec || !data) if (!ec || !data)
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
retry:
*data = 0; *data = 0;
if (ec->global_lock) { if (ec->global_lock) {
...@@ -160,32 +246,50 @@ acpi_ec_read ( ...@@ -160,32 +246,50 @@ acpi_ec_read (
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
} }
spin_lock_irqsave(&ec->lock, flags); WARN_ON(in_interrupt());
down(&ec->sem);
if(acpi_ec_enter_burst_mode(ec))
goto end;
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if (result) acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
if (status) {
goto end; goto end;
}
acpi_hw_low_level_write(8, address, &ec->data_addr); acpi_hw_low_level_write(8, address, &ec->data_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); status= acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (result) if (status){
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto end; goto end;
}
acpi_hw_low_level_read(8, data, &ec->data_addr); acpi_hw_low_level_read(8, data, &ec->data_addr);
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
*data, address)); *data, address));
end: end:
spin_unlock_irqrestore(&ec->lock, flags); acpi_ec_leave_burst_mode(ec);
up(&ec->sem);
if (ec->global_lock) if (ec->global_lock)
acpi_release_global_lock(glk); acpi_release_global_lock(glk);
return_VALUE(result); if(atomic_read(&ec->leaving_burst) == 2){
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
while(!atomic_read(&ec->pending_gpe)){
msleep(1);
}
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto retry;
}
return_VALUE(status);
} }
...@@ -195,49 +299,80 @@ acpi_ec_write ( ...@@ -195,49 +299,80 @@ acpi_ec_write (
u8 address, u8 address,
u8 data) u8 data)
{ {
int result = 0; int status = 0;
acpi_status status = AE_OK; u32 glk;
unsigned long flags = 0; u32 tmp;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_write"); ACPI_FUNCTION_TRACE("acpi_ec_write");
if (!ec) if (!ec)
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
retry:
if (ec->global_lock) { if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
} }
spin_lock_irqsave(&ec->lock, flags); WARN_ON(in_interrupt());
down(&ec->sem);
if(acpi_ec_enter_burst_mode(ec))
goto end;
status = acpi_ec_read_status(ec);
if (status != -EINVAL &&
!(status & ACPI_EC_FLAG_BURST)){
acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (status)
goto end;
acpi_hw_low_level_read(8, &tmp, &ec->data_addr);
if(tmp != 0x90 ) /* Burst ACK byte*/
goto end;
}
/*Now we are in burst mode*/
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if (result) acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
if (status){
goto end; goto end;
}
acpi_hw_low_level_write(8, address, &ec->data_addr); acpi_hw_low_level_write(8, address, &ec->data_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if (result) if (status){
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto end; goto end;
}
acpi_hw_low_level_write(8, data, &ec->data_addr); acpi_hw_low_level_write(8, data, &ec->data_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
if (result) acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
if (status)
goto end; goto end;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
data, address)); data, address));
end: end:
spin_unlock_irqrestore(&ec->lock, flags); acpi_ec_leave_burst_mode(ec);
up(&ec->sem);
if (ec->global_lock) if (ec->global_lock)
acpi_release_global_lock(glk); acpi_release_global_lock(glk);
return_VALUE(result); if(atomic_read(&ec->leaving_burst) == 2){
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
while(!atomic_read(&ec->pending_gpe)){
msleep(1);
}
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto retry;
}
return_VALUE(status);
} }
/* /*
...@@ -289,16 +424,14 @@ acpi_ec_query ( ...@@ -289,16 +424,14 @@ acpi_ec_query (
struct acpi_ec *ec, struct acpi_ec *ec,
u32 *data) u32 *data)
{ {
int result = 0; int status = 0;
acpi_status status = AE_OK; u32 glk;
unsigned long flags = 0;
u32 glk = 0;
ACPI_FUNCTION_TRACE("acpi_ec_query"); ACPI_FUNCTION_TRACE("acpi_ec_query");
if (!ec || !data) if (!ec || !data)
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
retry:
*data = 0; *data = 0;
if (ec->global_lock) { if (ec->global_lock) {
...@@ -307,29 +440,43 @@ acpi_ec_query ( ...@@ -307,29 +440,43 @@ acpi_ec_query (
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
} }
down(&ec->sem);
if(acpi_ec_enter_burst_mode(ec))
goto end;
/* /*
* Query the EC to find out which _Qxx method we need to evaluate. * Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI * Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source). * bit to be cleared (and thus clearing the interrupt source).
*/ */
spin_lock_irqsave(&ec->lock, flags);
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
if (result) if (status){
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto end; goto end;
}
acpi_hw_low_level_read(8, data, &ec->data_addr); acpi_hw_low_level_read(8, data, &ec->data_addr);
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
if (!*data) if (!*data)
result = -ENODATA; status = -ENODATA;
end: end:
spin_unlock_irqrestore(&ec->lock, flags); acpi_ec_leave_burst_mode(ec);
up(&ec->sem);
if (ec->global_lock) if (ec->global_lock)
acpi_release_global_lock(glk); acpi_release_global_lock(glk);
return_VALUE(result); if(atomic_read(&ec->leaving_burst) == 2){
ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
while(!atomic_read(&ec->pending_gpe)){
msleep(1);
}
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto retry;
}
return_VALUE(status);
} }
...@@ -347,42 +494,29 @@ acpi_ec_gpe_query ( ...@@ -347,42 +494,29 @@ acpi_ec_gpe_query (
void *ec_cxt) void *ec_cxt)
{ {
struct acpi_ec *ec = (struct acpi_ec *) ec_cxt; struct acpi_ec *ec = (struct acpi_ec *) ec_cxt;
u32 value = 0; u32 value;
unsigned long flags = 0; int result = -ENODATA;
static char object_name[5] = {'_','Q','0','0','\0'}; static char object_name[5] = {'_','Q','0','0','\0'};
const char hex[] = {'0','1','2','3','4','5','6','7', const char hex[] = {'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'}; '8','9','A','B','C','D','E','F'};
ACPI_FUNCTION_TRACE("acpi_ec_gpe_query"); ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
if (!ec_cxt) if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
goto end; result = acpi_ec_query(ec, &value);
spin_lock_irqsave(&ec->lock, flags); if (result)
acpi_hw_low_level_read(8, &value, &ec->command_addr);
spin_unlock_irqrestore(&ec->lock, flags);
/* TBD: Implement asynch events!
* NOTE: All we care about are EC-SCI's. Other EC events are
* handled via polling (yuck!). This is because some systems
* treat EC-SCIs as level (versus EDGE!) triggered, preventing
* a purely interrupt-driven approach (grumble, grumble).
*/
if (!(value & ACPI_EC_FLAG_SCI))
goto end; goto end;
if (acpi_ec_query(ec, &value))
goto end;
object_name[2] = hex[((value >> 4) & 0x0F)]; object_name[2] = hex[((value >> 4) & 0x0F)];
object_name[3] = hex[(value & 0x0F)]; object_name[3] = hex[(value & 0x0F)];
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
acpi_evaluate_object(ec->handle, object_name, NULL, NULL); acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
atomic_dec(&ec->pending_gpe);
end: end:
acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); return;
} }
static u32 static u32
...@@ -390,6 +524,7 @@ acpi_ec_gpe_handler ( ...@@ -390,6 +524,7 @@ acpi_ec_gpe_handler (
void *data) void *data)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
u32 value;
struct acpi_ec *ec = (struct acpi_ec *) data; struct acpi_ec *ec = (struct acpi_ec *) data;
if (!ec) if (!ec)
...@@ -397,13 +532,39 @@ acpi_ec_gpe_handler ( ...@@ -397,13 +532,39 @@ acpi_ec_gpe_handler (
acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, value = acpi_ec_read_status(ec);
acpi_ec_gpe_query, ec);
if (status == AE_OK) if((value & ACPI_EC_FLAG_IBF) &&
return ACPI_INTERRUPT_HANDLED; !(value & ACPI_EC_FLAG_BURST) &&
else (atomic_read(&ec->leaving_burst) == 0)) {
return ACPI_INTERRUPT_NOT_HANDLED; /*
* the embedded controller disables
* burst mode for any reason other
* than the burst disable command
* to process critical event.
*/
atomic_set(&ec->leaving_burst , 2); /* block current pending transaction
and retry */
wake_up(&ec->wait);
}else {
if ((ec->expect_event == ACPI_EC_EVENT_OBF &&
(value & ACPI_EC_FLAG_OBF)) ||
(ec->expect_event == ACPI_EC_EVENT_IBE &&
!(value & ACPI_EC_FLAG_IBF))) {
ec->expect_event = 0;
wake_up(&ec->wait);
}
}
if (value & ACPI_EC_FLAG_SCI){
atomic_add(1, &ec->pending_gpe) ;
status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
acpi_ec_gpe_query, ec);
}
return status == AE_OK ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
...@@ -421,10 +582,8 @@ acpi_ec_space_setup ( ...@@ -421,10 +582,8 @@ acpi_ec_space_setup (
* The EC object is in the handler context and is needed * The EC object is in the handler context and is needed
* when calling the acpi_ec_space_handler. * when calling the acpi_ec_space_handler.
*/ */
if(function == ACPI_REGION_DEACTIVATE) *return_context = (function != ACPI_REGION_DEACTIVATE) ?
*return_context = NULL; handler_context : NULL;
else
*return_context = handler_context;
return AE_OK; return AE_OK;
} }
...@@ -555,7 +714,7 @@ static int ...@@ -555,7 +714,7 @@ static int
acpi_ec_add_fs ( acpi_ec_add_fs (
struct acpi_device *device) struct acpi_device *device)
{ {
struct proc_dir_entry *entry = NULL; struct proc_dir_entry *entry;
ACPI_FUNCTION_TRACE("acpi_ec_add_fs"); ACPI_FUNCTION_TRACE("acpi_ec_add_fs");
...@@ -606,9 +765,9 @@ static int ...@@ -606,9 +765,9 @@ static int
acpi_ec_add ( acpi_ec_add (
struct acpi_device *device) struct acpi_device *device)
{ {
int result = 0; int result;
acpi_status status = AE_OK; acpi_status status;
struct acpi_ec *ec = NULL; struct acpi_ec *ec;
unsigned long uid; unsigned long uid;
ACPI_FUNCTION_TRACE("acpi_ec_add"); ACPI_FUNCTION_TRACE("acpi_ec_add");
...@@ -623,7 +782,10 @@ acpi_ec_add ( ...@@ -623,7 +782,10 @@ acpi_ec_add (
ec->handle = device->handle; ec->handle = device->handle;
ec->uid = -1; ec->uid = -1;
spin_lock_init(&ec->lock); atomic_set(&ec->pending_gpe, 0);
atomic_set(&ec->leaving_burst , 1);
init_MUTEX(&ec->sem);
init_waitqueue_head(&ec->wait);
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS); strcpy(acpi_device_class(device), ACPI_EC_CLASS);
acpi_driver_data(device) = ec; acpi_driver_data(device) = ec;
...@@ -637,7 +799,7 @@ acpi_ec_add ( ...@@ -637,7 +799,7 @@ acpi_ec_add (
if (ec_ecdt && ec_ecdt->uid == uid) { if (ec_ecdt && ec_ecdt->uid == uid) {
acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler);
kfree(ec_ecdt); kfree(ec_ecdt);
...@@ -677,7 +839,7 @@ acpi_ec_remove ( ...@@ -677,7 +839,7 @@ acpi_ec_remove (
struct acpi_device *device, struct acpi_device *device,
int type) int type)
{ {
struct acpi_ec *ec = NULL; struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_remove"); ACPI_FUNCTION_TRACE("acpi_ec_remove");
...@@ -732,8 +894,8 @@ static int ...@@ -732,8 +894,8 @@ static int
acpi_ec_start ( acpi_ec_start (
struct acpi_device *device) struct acpi_device *device)
{ {
acpi_status status = AE_OK; acpi_status status;
struct acpi_ec *ec = NULL; struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_start"); ACPI_FUNCTION_TRACE("acpi_ec_start");
...@@ -789,8 +951,8 @@ acpi_ec_stop ( ...@@ -789,8 +951,8 @@ acpi_ec_stop (
struct acpi_device *device, struct acpi_device *device,
int type) int type)
{ {
acpi_status status = AE_OK; acpi_status status;
struct acpi_ec *ec = NULL; struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_stop"); ACPI_FUNCTION_TRACE("acpi_ec_stop");
...@@ -832,7 +994,6 @@ acpi_fake_ecdt_callback ( ...@@ -832,7 +994,6 @@ acpi_fake_ecdt_callback (
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit); status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return status; return status;
spin_lock_init(&ec_ecdt->lock);
ec_ecdt->global_lock = TRUE; ec_ecdt->global_lock = TRUE;
ec_ecdt->handle = handle; ec_ecdt->handle = handle;
...@@ -890,7 +1051,7 @@ acpi_ec_get_real_ecdt(void) ...@@ -890,7 +1051,7 @@ acpi_ec_get_real_ecdt(void)
acpi_status status; acpi_status status;
struct acpi_table_ecdt *ecdt_ptr; struct acpi_table_ecdt *ecdt_ptr;
status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
(struct acpi_table_header **) &ecdt_ptr); (struct acpi_table_header **) &ecdt_ptr);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
...@@ -905,11 +1066,12 @@ acpi_ec_get_real_ecdt(void) ...@@ -905,11 +1066,12 @@ acpi_ec_get_real_ecdt(void)
return -ENOMEM; return -ENOMEM;
memset(ec_ecdt, 0, sizeof(struct acpi_ec)); memset(ec_ecdt, 0, sizeof(struct acpi_ec));
init_MUTEX(&ec_ecdt->sem);
init_waitqueue_head(&ec_ecdt->wait);
ec_ecdt->command_addr = ecdt_ptr->ec_control; ec_ecdt->command_addr = ecdt_ptr->ec_control;
ec_ecdt->status_addr = ecdt_ptr->ec_control; ec_ecdt->status_addr = ecdt_ptr->ec_control;
ec_ecdt->data_addr = ecdt_ptr->ec_data; ec_ecdt->data_addr = ecdt_ptr->ec_data;
ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
spin_lock_init(&ec_ecdt->lock);
/* use the GL just to be safe */ /* use the GL just to be safe */
ec_ecdt->global_lock = TRUE; ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid; ec_ecdt->uid = ecdt_ptr->uid;
...@@ -978,7 +1140,7 @@ acpi_ec_ecdt_probe (void) ...@@ -978,7 +1140,7 @@ acpi_ec_ecdt_probe (void)
static int __init acpi_ec_init (void) static int __init acpi_ec_init (void)
{ {
int result = 0; int result;
ACPI_FUNCTION_TRACE("acpi_ec_init"); ACPI_FUNCTION_TRACE("acpi_ec_init");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment