diff options
| author | Len Brown <len.brown@intel.com> | 2006-12-16 00:32:42 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2006-12-16 00:32:42 -0500 |
| commit | 678f2b7df24c34f90fee264fa3a8069bca9c99ad (patch) | |
| tree | 5569d1a0b1efb603ad9576c7af0a46a36dae531d | |
| parent | d1998ef38a13c4e74c69df55ccd38b0440c429b2 (diff) | |
| parent | 6ccedb10e39c34a4cb68f6c8dae67ecdd3e0b138 (diff) | |
Pull ec into test branch
| -rw-r--r-- | drivers/acpi/ec.c | 343 |
1 files changed, 153 insertions, 190 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e6d4b084dca2..d713f769b72d 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
| @@ -45,35 +45,34 @@ ACPI_MODULE_NAME("acpi_ec") | |||
| 45 | #define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" | 45 | #define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" |
| 46 | #define ACPI_EC_DEVICE_NAME "Embedded Controller" | 46 | #define ACPI_EC_DEVICE_NAME "Embedded Controller" |
| 47 | #define ACPI_EC_FILE_INFO "info" | 47 | #define ACPI_EC_FILE_INFO "info" |
| 48 | 48 | #undef PREFIX | |
| 49 | #define PREFIX "ACPI: EC: " | ||
| 49 | /* EC status register */ | 50 | /* EC status register */ |
| 50 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ | 51 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ |
| 51 | #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ | 52 | #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ |
| 52 | #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ | 53 | #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ |
| 53 | #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ | 54 | #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ |
| 54 | |||
| 55 | /* EC commands */ | 55 | /* EC commands */ |
| 56 | #define ACPI_EC_COMMAND_READ 0x80 | 56 | enum ec_command { |
| 57 | #define ACPI_EC_COMMAND_WRITE 0x81 | 57 | ACPI_EC_COMMAND_READ = 0x80, |
| 58 | #define ACPI_EC_BURST_ENABLE 0x82 | 58 | ACPI_EC_COMMAND_WRITE = 0x81, |
| 59 | #define ACPI_EC_BURST_DISABLE 0x83 | 59 | ACPI_EC_BURST_ENABLE = 0x82, |
| 60 | #define ACPI_EC_COMMAND_QUERY 0x84 | 60 | ACPI_EC_BURST_DISABLE = 0x83, |
| 61 | 61 | ACPI_EC_COMMAND_QUERY = 0x84, | |
| 62 | }; | ||
| 62 | /* EC events */ | 63 | /* EC events */ |
| 63 | enum { | 64 | enum ec_event { |
| 64 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ | 65 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ |
| 65 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ | 66 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ |
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | #define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ | 69 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ |
| 69 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ | 70 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ |
| 70 | #define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ | ||
| 71 | #define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ | ||
| 72 | 71 | ||
| 73 | enum { | 72 | static enum ec_mode { |
| 74 | EC_INTR = 1, /* Output buffer full */ | 73 | EC_INTR = 1, /* Output buffer full */ |
| 75 | EC_POLL, /* Input buffer empty */ | 74 | EC_POLL, /* Input buffer empty */ |
| 76 | }; | 75 | } acpi_ec_mode = EC_INTR; |
| 77 | 76 | ||
| 78 | static int acpi_ec_remove(struct acpi_device *device, int type); | 77 | static int acpi_ec_remove(struct acpi_device *device, int type); |
| 79 | static int acpi_ec_start(struct acpi_device *device); | 78 | static int acpi_ec_start(struct acpi_device *device); |
| @@ -96,19 +95,18 @@ static struct acpi_driver acpi_ec_driver = { | |||
| 96 | struct acpi_ec { | 95 | struct acpi_ec { |
| 97 | acpi_handle handle; | 96 | acpi_handle handle; |
| 98 | unsigned long uid; | 97 | unsigned long uid; |
| 99 | unsigned long gpe_bit; | 98 | unsigned long gpe; |
| 100 | unsigned long command_addr; | 99 | unsigned long command_addr; |
| 101 | unsigned long data_addr; | 100 | unsigned long data_addr; |
| 102 | unsigned long global_lock; | 101 | unsigned long global_lock; |
| 103 | struct semaphore sem; | 102 | struct mutex lock; |
| 104 | unsigned int expect_event; | 103 | atomic_t query_pending; |
| 105 | atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ | 104 | atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ |
| 106 | wait_queue_head_t wait; | 105 | wait_queue_head_t wait; |
| 107 | } *ec_ecdt; | 106 | } *ec_ecdt; |
| 108 | 107 | ||
| 109 | /* External interfaces use first EC only, so remember */ | 108 | /* External interfaces use first EC only, so remember */ |
| 110 | static struct acpi_device *first_ec; | 109 | static struct acpi_device *first_ec; |
| 111 | static int acpi_ec_mode = EC_INTR; | ||
| 112 | 110 | ||
| 113 | /* -------------------------------------------------------------------------- | 111 | /* -------------------------------------------------------------------------- |
| 114 | Transaction Management | 112 | Transaction Management |
| @@ -134,54 +132,41 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | |||
| 134 | outb(data, ec->data_addr); | 132 | outb(data, ec->data_addr); |
| 135 | } | 133 | } |
| 136 | 134 | ||
| 137 | static int acpi_ec_check_status(u8 status, u8 event) | 135 | static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) |
| 138 | { | 136 | { |
| 139 | switch (event) { | 137 | u8 status = acpi_ec_read_status(ec); |
| 140 | case ACPI_EC_EVENT_OBF_1: | 138 | |
| 139 | if (event == ACPI_EC_EVENT_OBF_1) { | ||
| 141 | if (status & ACPI_EC_FLAG_OBF) | 140 | if (status & ACPI_EC_FLAG_OBF) |
| 142 | return 1; | 141 | return 1; |
| 143 | break; | 142 | } else if (event == ACPI_EC_EVENT_IBF_0) { |
| 144 | case ACPI_EC_EVENT_IBF_0: | ||
| 145 | if (!(status & ACPI_EC_FLAG_IBF)) | 143 | if (!(status & ACPI_EC_FLAG_IBF)) |
| 146 | return 1; | 144 | return 1; |
| 147 | break; | ||
| 148 | default: | ||
| 149 | break; | ||
| 150 | } | 145 | } |
| 151 | 146 | ||
| 152 | return 0; | 147 | return 0; |
| 153 | } | 148 | } |
| 154 | 149 | ||
| 155 | static int acpi_ec_wait(struct acpi_ec *ec, u8 event) | 150 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event) |
| 156 | { | 151 | { |
| 157 | int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0; | 152 | if (acpi_ec_mode == EC_POLL) { |
| 158 | long time_left; | 153 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
| 159 | 154 | while (time_before(jiffies, delay)) { | |
| 160 | ec->expect_event = event; | 155 | if (acpi_ec_check_status(ec, event)) |
| 161 | if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { | ||
| 162 | ec->expect_event = 0; | ||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | do { | ||
| 167 | if (acpi_ec_mode == EC_POLL) { | ||
| 168 | udelay(ACPI_EC_UDELAY); | ||
| 169 | } else { | ||
| 170 | time_left = wait_event_timeout(ec->wait, | ||
| 171 | !ec->expect_event, | ||
| 172 | msecs_to_jiffies(ACPI_EC_DELAY)); | ||
| 173 | if (time_left > 0) { | ||
| 174 | ec->expect_event = 0; | ||
| 175 | return 0; | 156 | return 0; |
| 176 | } | ||
| 177 | } | 157 | } |
| 178 | if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { | 158 | } else { |
| 179 | ec->expect_event = 0; | 159 | if (wait_event_timeout(ec->wait, |
| 160 | acpi_ec_check_status(ec, event), | ||
| 161 | msecs_to_jiffies(ACPI_EC_DELAY)) || | ||
| 162 | acpi_ec_check_status(ec, event)) { | ||
| 180 | return 0; | 163 | return 0; |
| 164 | } else { | ||
| 165 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," | ||
| 166 | " status = %d, expect_event = %d\n", | ||
| 167 | acpi_ec_read_status(ec), event); | ||
| 181 | } | 168 | } |
| 182 | } while (--i > 0); | 169 | } |
| 183 | |||
| 184 | ec->expect_event = 0; | ||
| 185 | 170 | ||
| 186 | return -ETIME; | 171 | return -ETIME; |
| 187 | } | 172 | } |
| @@ -196,7 +181,6 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec) | |||
| 196 | u8 tmp = 0; | 181 | u8 tmp = 0; |
| 197 | u8 status = 0; | 182 | u8 status = 0; |
| 198 | 183 | ||
| 199 | |||
| 200 | status = acpi_ec_read_status(ec); | 184 | status = acpi_ec_read_status(ec); |
| 201 | if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) { | 185 | if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) { |
| 202 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); | 186 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); |
| @@ -212,7 +196,7 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec) | |||
| 212 | 196 | ||
| 213 | atomic_set(&ec->leaving_burst, 0); | 197 | atomic_set(&ec->leaving_burst, 0); |
| 214 | return 0; | 198 | return 0; |
| 215 | end: | 199 | end: |
| 216 | ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode")); | 200 | ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode")); |
| 217 | return -1; | 201 | return -1; |
| 218 | } | 202 | } |
| @@ -221,58 +205,68 @@ int acpi_ec_leave_burst_mode(struct acpi_ec *ec) | |||
| 221 | { | 205 | { |
| 222 | u8 status = 0; | 206 | u8 status = 0; |
| 223 | 207 | ||
| 224 | |||
| 225 | status = acpi_ec_read_status(ec); | 208 | status = acpi_ec_read_status(ec); |
| 226 | if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){ | 209 | if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) { |
| 227 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); | 2 | |
