diff options
Diffstat (limited to 'drivers/acpi/ec.c')
| -rw-r--r-- | drivers/acpi/ec.c | 420 |
1 files changed, 288 insertions, 132 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index fdf143b405be..8e665f2e3138 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
| 32 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
| 33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
| 34 | #include <linux/interrupt.h> | ||
| 34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
| 35 | #include <acpi/acpi_bus.h> | 36 | #include <acpi/acpi_bus.h> |
| 36 | #include <acpi/acpi_drivers.h> | 37 | #include <acpi/acpi_drivers.h> |
| @@ -49,17 +50,19 @@ ACPI_MODULE_NAME ("acpi_ec") | |||
| 49 | 50 | ||
| 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 */ |
| 53 | #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ | ||
| 52 | #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ | 54 | #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ |
| 53 | 55 | ||
| 54 | #define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */ | 56 | #define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */ |
| 55 | #define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */ | 57 | #define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */ |
| 56 | 58 | ||
| 57 | #define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ | 59 | #define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ |
| 58 | #define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ | ||
| 59 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ | 60 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ |
| 60 | 61 | ||
| 61 | #define ACPI_EC_COMMAND_READ 0x80 | 62 | #define ACPI_EC_COMMAND_READ 0x80 |
| 62 | #define ACPI_EC_COMMAND_WRITE 0x81 | 63 | #define ACPI_EC_COMMAND_WRITE 0x81 |
| 64 | #define ACPI_EC_BURST_ENABLE 0x82 | ||
| 65 | #define ACPI_EC_BURST_DISABLE 0x83 | ||
| 63 | #define ACPI_EC_COMMAND_QUERY 0x84 | 66 | #define ACPI_EC_COMMAND_QUERY 0x84 |
| 64 | 67 | ||
| 65 | static int acpi_ec_add (struct acpi_device *device); | 68 | static int acpi_ec_add (struct acpi_device *device); |
| @@ -87,7 +90,11 @@ struct acpi_ec { | |||
| 87 | struct acpi_generic_address command_addr; | 90 | struct acpi_generic_address command_addr; |
| 88 | struct acpi_generic_address data_addr; | 91 | struct acpi_generic_address data_addr; |
| 89 | unsigned long global_lock; | 92 | unsigned long global_lock; |
| 90 | spinlock_t lock; | 93 | unsigned int expect_event; |
| 94 | atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort*/ | ||
| 95 | atomic_t pending_gpe; | ||
| 96 | struct semaphore sem; | ||
| 97 | wait_queue_head_t wait; | ||
| 91 | }; | 98 | }; |
| 92 | 99 | ||
| 93 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ | 100 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ |
| @@ -100,42 +107,122 @@ static struct acpi_device *first_ec; | |||
| 100 | Transaction Management | 107 | Transaction Management |
| 101 | -------------------------------------------------------------------------- */ | 108 | -------------------------------------------------------------------------- */ |
| 102 | 109 | ||
| 103 | static int | 110 | static inline u32 acpi_ec_read_status(struct acpi_ec *ec) |
| 104 | acpi_ec_wait ( | ||
| 105 | struct acpi_ec *ec, | ||
| 106 | u8 event) | ||
| 107 | { | 111 | { |
| 108 | u32 acpi_ec_status = 0; | 112 | u32 status = 0; |
| 109 | u32 i = ACPI_EC_UDELAY_COUNT; | ||
| 110 | 113 | ||
| 111 | if (!ec) | 114 | acpi_hw_low_level_read(8, &status, &ec->status_addr); |
| 112 | return -EINVAL; | 115 | return status; |
| 116 | } | ||
| 117 | |||
| 118 | static int acpi_ec_wait(struct acpi_ec *ec, unsigned int event) | ||
| 119 | { | ||
| 120 | int result = 0; | ||
| 121 | |||
| 122 | ACPI_FUNCTION_TRACE("acpi_ec_wait"); | ||
| 113 | 123 | ||
| 114 | /* Poll the EC status register waiting for the event to occur. */ | 124 | ec->expect_event = event; |
| 125 | smp_mb(); | ||
| 126 | |||
| 127 | result = wait_event_interruptible_timeout(ec->wait, | ||
| 128 | !ec->expect_event, | ||
| 129 | msecs_to_jiffies(ACPI_EC_DELAY)); | ||
| 130 | |||
| 131 | ec->expect_event = 0; | ||
| 132 | smp_mb(); | ||
| 133 | |||
| 134 | if (result < 0){ | ||
| 135 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR," result = %d ", result)); | ||
| 136 | return_VALUE(result); | ||
| 137 | } | ||
| 138 | |||
| 139 | /* | ||
| 140 | * Verify that the event in question has actually happened by | ||
| 141 | * querying EC status. Do the check even if operation timed-out | ||
| 142 | * to make sure that we did not miss interrupt. | ||
| 143 | */ | ||
| 115 | switch (event) { | 144 | switch (event) { |
| 116 | case ACPI_EC_EVENT_OBF: | 145 | case ACPI_EC_EVENT_OBF: |
| 117 | do { | 146 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) |
| 118 | acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr); | 147 | return_VALUE(0); |
| 119 | if (acpi_ec_status & ACPI_EC_FLAG_OBF) | ||
| 120 | return 0; | ||
| 121 | udelay(ACPI_EC_UDELAY); | ||
| 122 | } while (--i>0); | ||
| 123 | break; | 148 | break; |
| 149 | |||
| 124 | case ACPI_EC_EVENT_IBE: | 150 | case ACPI_EC_EVENT_IBE: |
| 125 | do { | 151 | if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) |
| 126 | acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr); | 152 | return_VALUE(0); |
| 127 | if (!(acpi_ec_status & ACPI_EC_FLAG_IBF)) | ||
| 128 | return 0; | ||
| 129 | udelay(ACPI_EC_UDELAY); | ||
| 130 | } while (--i>0); | ||
| 131 | break; | 153 | break; |
| 132 | default: | ||
| 133 | return -EINVAL; | ||
| 134 | } | 154 | } |
| 135 | 155 | ||
| 136 | return -ETIME; | 156 | return_VALUE(-ETIME); |
| 157 | } | ||
| 158 | |||
| 159 | |||
| 160 | |||
| 161 | static int | ||
| 162 | acpi_ec_enter_burst_mode ( | ||
| 163 | struct acpi_ec *ec) | ||
| 164 | { | ||
| 165 | u32 tmp = 0; | ||
| 166 | int status = 0; | ||
| 167 | |||
| 168 | ACPI_FUNCTION_TRACE("acpi_ec_enter_burst_mode"); | ||
| 169 | |||
| 170 | status = acpi_ec_read_status(ec); | ||
| 171 | if (status != -EINVAL && | ||
| 172 | !(status & ACPI_EC_FLAG_BURST)){ | ||
| 173 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"entering burst mode \n")); | ||
| 174 | acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr); | ||
| 175 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); | ||
| 176 | if (status){ | ||
| 177 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 178 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR," status = %d\n", status)); | ||
| 179 | return_VALUE(-EINVAL); | ||
| 180 | } | ||
| 181 | acpi_hw_low_level_read(8, &tmp, &ec->data_addr); | ||
| 182 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 183 | if(tmp != 0x90 ) {/* Burst ACK byte*/ | ||
| 184 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Ack failed \n")); | ||
| 185 | return_VALUE(-EINVAL); | ||
| 186 | } | ||
| 187 | } else | ||
| 188 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in burst mode \n")); | ||
| 189 | atomic_set(&ec->leaving_burst , 0); | ||
| 190 | return_VALUE(0); | ||
| 137 | } | 191 | } |
| 138 | 192 | ||
| 193 | static int | ||
| 194 | acpi_ec_leave_burst_mode ( | ||
| 195 | struct acpi_ec *ec) | ||
| 196 | { | ||
| 197 | int status =0; | ||
| 198 | |||
| 199 | ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode"); | ||
| 200 | |||
| 201 | atomic_set(&ec->leaving_burst , 1); | ||
| 202 | status = acpi_ec_read_status(ec); | ||
| 203 | if (status != -EINVAL && | ||
| 204 | (status & ACPI_EC_FLAG_BURST)){ | ||
| 205 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n")); | ||
| 206 | acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->command_addr); | ||
| 207 | status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); | ||
| 208 | if (status){ | ||
| 209 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 210 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->wait fail\n")); | ||
| 211 | return_VALUE(-EINVAL); | ||
| 212 | } | ||
| 213 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 214 | status = acpi_ec_read_status(ec); | ||
| 215 | if (status != -EINVAL && | ||
| 216 | (status & ACPI_EC_FLAG_BURST)) { | ||
| 217 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->status fail\n")); | ||
| 218 | return_VALUE(-EINVAL); | ||
| 219 | } | ||
| 220 | }else | ||
| 221 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in Non-burst mode \n")); | ||
| 222 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n")); | ||
| 223 | |||
| 224 | return_VALUE(0); | ||
| 225 | } | ||
| 139 | 226 | ||
| 140 | static int | 227 | static int |
| 141 | acpi_ec_read ( | 228 | acpi_ec_read ( |
| @@ -143,16 +230,15 @@ acpi_ec_read ( | |||
| 143 | u8 address, | 230 | u8 address, |
| 144 | u32 *data) | 231 | u32 *data) |
| 145 | { | 232 | { |
| 146 | acpi_status status = AE_OK; | 233 | int status = 0; |
| 147 | int result = 0; | 234 | u32 glk; |
| 148 | unsigned long flags = 0; | ||
| 149 | u32 glk = 0; | ||
| 150 | 235 | ||
| 151 | ACPI_FUNCTION_TRACE("acpi_ec_read"); | 236 | ACPI_FUNCTION_TRACE("acpi_ec_read"); |
| 152 | 237 | ||
| 153 | if (!ec || !data) | 238 | if (!ec || !data) |
| 154 | return_VALUE(-EINVAL); | 239 | return_VALUE(-EINVAL); |
| 155 | 240 | ||
| 241 | retry: | ||
| 156 | *data = 0; | 242 | *data = 0; |
| 157 | 243 | ||
| 158 | if (ec->global_lock) { | 244 | if (ec->global_lock) { |
| @@ -160,32 +246,50 @@ acpi_ec_read ( | |||
| 160 | if (ACPI_FAILURE(status)) | 246 | if (ACPI_FAILURE(status)) |
| 161 | return_VALUE(-ENODEV); | 247 | return_VALUE(-ENODEV); |
| 162 | } | 248 | } |
| 163 | 249 | ||
| 164 | spin_lock_irqsave(&ec->lock, flags); | 250 | WARN_ON(in_interrupt()); |
| 251 | down(&ec->sem); | ||
| 252 | |||
| 253 | if(acpi_ec_enter_burst_mode(ec)) | ||
| 254 | goto end; | ||
| 165 | 255 | ||
| 166 | acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr); | 256 | acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr); |
| 167 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); | 257 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); |
| 168 | if (result) | 258 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); |
| 259 | if (status) { | ||
| 169 | goto end; | 260 | goto end; |
| 261 | } | ||
| 170 | 262 | ||
| 171 | acpi_hw_low_level_write(8, address, &ec->data_addr); | 263 | acpi_hw_low_level_write(8, address, &ec->data_addr); |
| 172 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); | 264 | status= acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); |
| 173 | if (result) | 265 | if (status){ |
| 266 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 174 | goto end; | 267 | goto end; |
| 175 | 268 | } | |
| 176 | 269 | ||
| 177 | acpi_hw_low_level_read(8, data, &ec->data_addr); | 270 | acpi_hw_low_level_read(8, data, &ec->data_addr); |
| 271 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 178 | 272 | ||
| 179 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", | 273 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", |
| 180 | *data, address)); | 274 | *data, address)); |
| 181 | 275 | ||
| 182 | end: | 276 | end: |
| 183 | spin_unlock_irqrestore(&ec->lock, flags); | 277 | acpi_ec_leave_burst_mode(ec); |
| 278 | up(&ec->sem); | ||
| 184 | 279 | ||
| 185 | if (ec->global_lock) | 280 | if (ec->global_lock) |
| 186 | acpi_release_global_lock(glk); | 281 | acpi_release_global_lock(glk); |
| 187 | 282 | ||
| 188 | return_VALUE(result); | 283 | if(atomic_read(&ec->leaving_burst) == 2){ |
| 284 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); | ||
| 285 | while(atomic_read(&ec->pending_gpe)){ | ||
| 286 | msleep(1); | ||
| 287 | } | ||
| 288 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 289 | goto retry; | ||
| 290 | } | ||
| 291 | |||
| 292 | return_VALUE(status); | ||
| 189 | } | 293 | } |
| 190 | 294 | ||
| 191 | 295 | ||
| @@ -195,49 +299,80 @@ acpi_ec_write ( | |||
| 195 | u8 address, | 299 | u8 address, |
| 196 | u8 data) | 300 | u8 data) |
| 197 | { | 301 | { |
| 198 | int result = 0; | 302 | int status = 0; |
| 199 | acpi_status status = AE_OK; | 303 | u32 glk; |
| 200 | unsigned long flags = 0; | 304 | u32 tmp; |
| 201 | u32 glk = 0; | ||
| 202 | 305 | ||
| 203 | ACPI_FUNCTION_TRACE("acpi_ec_write"); | 306 | ACPI_FUNCTION_TRACE("acpi_ec_write"); |
| 204 | 307 | ||
| 205 | if (!ec) | 308 | if (!ec) |
| 206 | return_VALUE(-EINVAL); | 309 | return_VALUE(-EINVAL); |
| 207 | 310 | retry: | |
| 208 | if (ec->global_lock) { | 311 | if (ec->global_lock) { |
| 209 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); | 312 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); |
| 210 | if (ACPI_FAILURE(status)) | 313 | if (ACPI_FAILURE(status)) |
| 211 | return_VALUE(-ENODEV); | 314 | return_VALUE(-ENODEV); |
| 212 | } | 315 | } |
| 213 | 316 | ||
| 214 | spin_lock_irqsave(&ec->lock, flags); | 317 | WARN_ON(in_interrupt()); |
| 318 | down(&ec->sem); | ||
| 319 | |||
| 320 | if(acpi_ec_enter_burst_mode(ec)) | ||
| 321 | goto end; | ||
| 322 | |||
| 323 | status = acpi_ec_read_status(ec); | ||
| 324 | if (status != -EINVAL && | ||
| 325 | !(status & ACPI_EC_FLAG_BURST)){ | ||
| 326 | acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr); | ||
| 327 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); | ||
| 328 | if (status) | ||
| 329 | goto end; | ||
| 330 | acpi_hw_low_level_read(8, &tmp, &ec->data_addr); | ||
| 331 | if(tmp != 0x90 ) /* Burst ACK byte*/ | ||
| 332 | goto end; | ||
| 333 | } | ||
| 334 | /*Now we are in burst mode*/ | ||
| 215 | 335 | ||
| 216 | acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr); | 336 | acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr); |
| 217 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); | 337 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); |
| 218 | if (result) | 338 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); |
| 339 | if (status){ | ||
| 219 | goto end; | 340 | goto end; |
| 341 | } | ||
| 220 | 342 | ||
| 221 | acpi_hw_low_level_write(8, address, &ec->data_addr); | 343 | acpi_hw_low_level_write(8, address, &ec->data_addr); |
| 222 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); | 344 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); |
| 223 | if (result) | 345 | if (status){ |
| 346 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 224 | goto end; | 347 | goto end; |
| 348 | } | ||
| 225 | 349 | ||
| 226 | acpi_hw_low_level_write(8, data, &ec->data_addr); | 350 | acpi_hw_low_level_write(8, data, &ec->data_addr); |
| 227 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); | 351 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); |
| 228 | if (result) | 352 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); |
| 353 | if (status) | ||
| 229 | goto end; | 354 | goto end; |
| 230 | 355 | ||
| 231 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", | 356 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", |
| 232 | data, address)); | 357 | data, address)); |
| 233 | 358 | ||
| 234 | end: | 359 | end: |
| 235 | spin_unlock_irqrestore(&ec->lock, flags); | 360 | acpi_ec_leave_burst_mode(ec); |
| 361 | up(&ec->sem); | ||
| 236 | 362 | ||
| 237 | if (ec->global_lock) | 363 | if (ec->global_lock) |
| 238 | acpi_release_global_lock(glk); | 364 | acpi_release_global_lock(glk); |
| 239 | 365 | ||
| 240 | return_VALUE(result); | 366 | if(atomic_read(&ec->leaving_burst) == 2){ |
| 367 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); | ||
| 368 | while(atomic_read(&ec->pending_gpe)){ | ||
| 369 | msleep(1); | ||
| 370 | } | ||
| 371 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 372 | goto retry; | ||
| 373 | } | ||
| 374 | |||
| 375 | return_VALUE(status); | ||
| 241 | } | 376 | } |
| 242 | 377 | ||
| 243 | /* | 378 | /* |
| @@ -289,16 +424,13 @@ acpi_ec_query ( | |||
| 289 | struct acpi_ec *ec, | 424 | struct acpi_ec *ec, |
| 290 | u32 *data) | 425 | u32 *data) |
| 291 | { | 426 | { |
| 292 | int result = 0; | 427 | int status = 0; |
| 293 | acpi_status status = AE_OK; | 428 | u32 glk; |
| 294 | unsigned long flags = 0; | ||
| 295 | u32 glk = 0; | ||
| 296 | 429 | ||
| 297 | ACPI_FUNCTION_TRACE("acpi_ec_query"); | 430 | ACPI_FUNCTION_TRACE("acpi_ec_query"); |
| 298 | 431 | ||
| 299 | if (!ec || !data) | 432 | if (!ec || !data) |
| 300 | return_VALUE(-EINVAL); | 433 | return_VALUE(-EINVAL); |
| 301 | |||
| 302 | *data = 0; | 434 | *data = 0; |
| 303 | 435 | ||
| 304 | if (ec->global_lock) { | 436 | if (ec->global_lock) { |
| @@ -307,29 +439,39 @@ acpi_ec_query ( | |||
| 307 | return_VALUE(-ENODEV); | 439 | return_VALUE(-ENODEV); |
| 308 | } | 440 | } |
| 309 | 441 | ||
| 442 | down(&ec->sem); | ||
| 443 | if(acpi_ec_enter_burst_mode(ec)) | ||
| 444 | goto end; | ||
| 310 | /* | 445 | /* |
| 311 | * Query the EC to find out which _Qxx method we need to evaluate. | 446 | * Query the EC to find out which _Qxx method we need to evaluate. |
| 312 | * Note that successful completion of the query causes the ACPI_EC_SCI | 447 | * Note that successful completion of the query causes the ACPI_EC_SCI |
| 313 | * bit to be cleared (and thus clearing the interrupt source). | 448 | * bit to be cleared (and thus clearing the interrupt source). |
| 314 | */ | 449 | */ |
| 315 | spin_lock_irqsave(&ec->lock, flags); | ||
| 316 | |||
| 317 | acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr); | 450 | acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr); |
| 318 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); | 451 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); |
| 319 | if (result) | 452 | if (status){ |
| 453 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 320 | goto end; | 454 | goto end; |
| 321 | 455 | } | |
| 456 | |||
| 322 | acpi_hw_low_level_read(8, data, &ec->data_addr); | 457 | acpi_hw_low_level_read(8, data, &ec->data_addr); |
| 458 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 323 | if (!*data) | 459 | if (!*data) |
| 324 | result = -ENODATA; | 460 | status = -ENODATA; |
| 325 | 461 | ||
| 326 | end: | 462 | end: |
| 327 | spin_unlock_irqrestore(&ec->lock, flags); | 463 | acpi_ec_leave_burst_mode(ec); |
| 464 | up(&ec->sem); | ||
| 328 | 465 | ||
| 329 | if (ec->global_lock) | 466 | if (ec->global_lock) |
| 330 | acpi_release_global_lock(glk); | 467 | acpi_release_global_lock(glk); |
| 331 | 468 | ||
| 332 | return_VALUE(result); | 469 | if(atomic_read(&ec->leaving_burst) == 2){ |
| 470 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); | ||
| 471 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 472 | status = -ENODATA; | ||
| 473 | } | ||
| 474 | return_VALUE(status); | ||
| 333 | } | 475 | } |
| 334 | 476 | ||
| 335 | 477 | ||
| @@ -347,42 +489,29 @@ acpi_ec_gpe_query ( | |||
| 347 | void *ec_cxt) | 489 | void *ec_cxt) |
| 348 | { | 490 | { |
| 349 | struct acpi_ec *ec = (struct acpi_ec *) ec_cxt; | 491 | struct acpi_ec *ec = (struct acpi_ec *) ec_cxt; |
| 350 | u32 value = 0; | 492 | u32 value; |
| 351 | unsigned long flags = 0; | 493 | int result = -ENODATA; |
| 352 | static char object_name[5] = {'_','Q','0','0','\0'}; | 494 | static char object_name[5] = {'_','Q','0','0','\0'}; |
| 353 | const char hex[] = {'0','1','2','3','4','5','6','7', | 495 | const char hex[] = {'0','1','2','3','4','5','6','7', |
| 354 | '8','9','A','B','C','D','E','F'}; | 496 | '8','9','A','B','C','D','E','F'}; |
| 355 | 497 | ||
| 356 | ACPI_FUNCTION_TRACE("acpi_ec_gpe_query"); | 498 | ACPI_FUNCTION_TRACE("acpi_ec_gpe_query"); |
| 357 | 499 | ||
| 358 | if (!ec_cxt) | 500 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) |
| 359 | goto end; | 501 | result = acpi_ec_query(ec, &value); |
| 360 | |||
| 361 | spin_lock_irqsave(&ec->lock, flags); | ||
| 362 | acpi_hw_low_level_read(8, &value, &ec->command_addr); | ||
| 363 | spin_unlock_irqrestore(&ec->lock, flags); | ||
| 364 | 502 | ||
| 365 | /* TBD: Implement asynch events! | 503 | if (result) |
| 366 | * NOTE: All we care about are EC-SCI's. Other EC events are | ||
| 367 | * handled via polling (yuck!). This is because some systems | ||
| 368 | * treat EC-SCIs as level (versus EDGE!) triggered, preventing | ||
| 369 | * a purely interrupt-driven approach (grumble, grumble). | ||
| 370 | */ | ||
| 371 | if (!(value & ACPI_EC_FLAG_SCI)) | ||
| 372 | goto end; | 504 | goto end; |
| 373 | 505 | ||
| 374 | if (acpi_ec_query(ec, &value)) | ||
| 375 | goto end; | ||
| 376 | |||
| 377 | object_name[2] = hex[((value >> 4) & 0x0F)]; | 506 | object_name[2] = hex[((value >> 4) & 0x0F)]; |
| 378 | object_name[3] = hex[(value & 0x0F)]; | 507 | object_name[3] = hex[(value & 0x0F)]; |
| 379 | 508 | ||
| 380 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); | 509 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); |
| 381 | 510 | ||
| 382 | acpi_evaluate_object(ec->handle, object_name, NULL, NULL); | 511 | acpi_evaluate_object(ec->handle, object_name, NULL, NULL); |
| 383 | 512 | end: | |
| 384 | end: | 513 | atomic_dec(&ec->pending_gpe); |
| 385 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | 514 | return; |
| 386 | } | 515 | } |
| 387 | 516 | ||
| 388 | static u32 | 517 | static u32 |
| @@ -390,6 +519,7 @@ acpi_ec_gpe_handler ( | |||
| 390 | void *data) | 519 | void *data) |
| 391 | { | 520 | { |
| 392 | acpi_status status = AE_OK; | 521 | acpi_status status = AE_OK; |
| 522 | u32 value; | ||
| 393 | struct acpi_ec *ec = (struct acpi_ec *) data; | 523 | struct acpi_ec *ec = (struct acpi_ec *) data; |
| 394 | 524 | ||
| 395 | if (!ec) | 525 | if (!ec) |
| @@ -397,13 +527,41 @@ acpi_ec_gpe_handler ( | |||
| 397 | 527 | ||
| 398 | acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); | 528 | acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); |
| 399 | 529 | ||
| 400 | status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, | 530 | value = acpi_ec_read_status(ec); |
| 401 | acpi_ec_gpe_query, ec); | ||
| 402 | 531 | ||
| 403 | if (status == AE_OK) | 532 | if((value & ACPI_EC_FLAG_IBF) && |
| 404 | return ACPI_INTERRUPT_HANDLED; | 533 | !(value & ACPI_EC_FLAG_BURST) && |
| 405 | else | 534 | (atomic_read(&ec->leaving_burst) == 0)) { |
| 406 | return ACPI_INTERRUPT_NOT_HANDLED; | 535 | /* |
| 536 | * the embedded controller disables | ||
| 537 | * burst mode for any reason other | ||
| 538 | * than the burst disable command | ||
| 539 | * to process critical event. | ||
| 540 | */ | ||
| 541 | atomic_set(&ec->leaving_burst , 2); /* block current pending transaction | ||
| 542 | and retry */ | ||
| 543 | wake_up(&ec->wait); | ||
| 544 | }else { | ||
| 545 | if ((ec->expect_event == ACPI_EC_EVENT_OBF && | ||
| 546 | (value & ACPI_EC_FLAG_OBF)) || | ||
| 547 | (ec->expect_event == ACPI_EC_EVENT_IBE && | ||
| 548 | !(value & ACPI_EC_FLAG_IBF))) { | ||
| 549 | ec->expect_event = 0; | ||
| 550 | wake_up(&ec->wait); | ||
| 551 | return ACPI_INTERRUPT_HANDLED; | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | if (value & ACPI_EC_FLAG_SCI){ | ||
| 556 | atomic_add(1, &ec->pending_gpe) ; | ||
| 557 | status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, | ||
| 558 | acpi_ec_gpe_query, ec); | ||
| 559 | return status == AE_OK ? | ||
| 560 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; | ||
| 561 | } | ||
| 562 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR); | ||
| 563 | return status == AE_OK ? | ||
| 564 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; | ||
| 407 | } | 565 | } |
| 408 | 566 | ||
| 409 | /* -------------------------------------------------------------------------- | 567 | /* -------------------------------------------------------------------------- |
| @@ -421,10 +579,8 @@ acpi_ec_space_setup ( | |||
| 421 | * The EC object is in the handler context and is needed | 579 | * The EC object is in the handler context and is needed |
| 422 | * when calling the acpi_ec_space_handler. | 580 | * when calling the acpi_ec_space_handler. |
| 423 | */ | 581 | */ |
| 424 | if(function == ACPI_REGION_DEACTIVATE) | 582 | *return_context = (function != ACPI_REGION_DEACTIVATE) ? |
| 425 | *return_context = NULL; | 583 | handler_context : NULL; |
| 426 | else | ||
| 427 | *return_context = handler_context; | ||
| 428 | 584 | ||
| 429 | return AE_OK; | 585 | return AE_OK; |
| 430 | } | 586 | } |
| @@ -441,7 +597,7 @@ acpi_ec_space_handler ( | |||
| 441 | { | 597 | { |
| 442 | int result = 0; | 598 | int result = 0; |
| 443 | struct acpi_ec *ec = NULL; | 599 | struct acpi_ec *ec = NULL; |
| 444 | u32 temp = 0; | 600 | u64 temp = *value; |
| 445 | acpi_integer f_v = 0; | 601 | acpi_integer f_v = 0; |
| 446 | int i = 0; | 602 | int i = 0; |
| 447 | 603 | ||
| @@ -450,10 +606,9 @@ acpi_ec_space_handler ( | |||
| 450 | if ((address > 0xFF) || !value || !handler_context) | 606 | if ((address > 0xFF) || !value || !handler_context) |
| 451 | return_VALUE(AE_BAD_PARAMETER); | 607 | return_VALUE(AE_BAD_PARAMETER); |
| 452 | 608 | ||
| 453 | if(bit_width != 8) { | 609 | if (bit_width != 8 && acpi_strict) { |
| 454 | printk(KERN_WARNING PREFIX "acpi_ec_space_handler: bit_width should be 8\n"); | 610 | printk(KERN_WARNING PREFIX "acpi_ec_space_handler: bit_width should be 8\n"); |
| 455 | if (acpi_strict) | 611 | return_VALUE(AE_BAD_PARAMETER); |
| 456 | return_VALUE(AE_BAD_PARAMETER); | ||
| 457 | } | 612 | } |
| 458 | 613 | ||
| 459 | ec = (struct acpi_ec *) handler_context; | 614 | ec = (struct acpi_ec *) handler_context; |
| @@ -461,11 +616,11 @@ acpi_ec_space_handler ( | |||
| 461 | next_byte: | 616 | next_byte: |
| 462 | switch (function) { | 617 | switch (function) { |
| 463 | case ACPI_READ: | 618 | case ACPI_READ: |
| 464 | result = acpi_ec_read(ec, (u8) address, &temp); | 619 | temp = 0; |
| 465 | *value = (acpi_integer) temp; | 620 | result = acpi_ec_read(ec, (u8) address, (u32 *)&temp); |
| 466 | break; | 621 | break; |
| 467 | case ACPI_WRITE: | 622 | case ACPI_WRITE: |
| 468 | result = acpi_ec_write(ec, (u8) address, (u8) *value); | 623 | result = acpi_ec_write(ec, (u8) address, (u8) temp); |
| 469 | break; | 624 | break; |
| 470 | default: | 625 | default: |
| 471 | result = -EINVAL; | 626 | result = -EINVAL; |
| @@ -474,19 +629,18 @@ next_byte: | |||
| 474 | } | 629 | } |
| 475 | 630 | ||
| 476 | bit_width -= 8; | 631 | bit_width -= 8; |
| 477 | if(bit_width){ | 632 | if (bit_width) { |
| 478 | 633 | if (function == ACPI_READ) | |
| 479 | if(function == ACPI_READ) | 634 | f_v |= temp << 8 * i; |
| 480 | f_v |= (acpi_integer) (*value) << 8*i; | 635 | if (function == ACPI_WRITE) |
| 481 | if(function == ACPI_WRITE) | 636 | temp >>= 8; |
| 482 | (*value) >>=8; | ||
| 483 | i++; | 637 | i++; |
| 638 | address++; | ||
| 484 | goto next_byte; | 639 | goto next_byte; |
| 485 | } | 640 | } |
| 486 | 641 | ||
| 487 | 642 | if (function == ACPI_READ) { | |
| 488 | if(function == ACPI_READ){ | 643 | f_v |= temp << 8 * i; |
| 489 | f_v |= (acpi_integer) (*value) << 8*i; | ||
| 490 | *value = f_v; | 644 | *value = f_v; |
| 491 | } | 645 | } |
| 492 | 646 | ||
| @@ -505,8 +659,6 @@ out: | |||
| 505 | default: | 659 | default: |
| 506 | return_VALUE(AE_OK); | 660 | return_VALUE(AE_OK); |
| 507 | } | 661 | } |
| 508 | |||
| 509 | |||
| 510 | } | 662 | } |
| 511 | 663 | ||
| 512 | 664 | ||
| @@ -533,6 +685,7 @@ acpi_ec_read_info (struct seq_file *seq, void *offset) | |||
| 533 | (u32) ec->status_addr.address, (u32) ec->data_addr.address); | 685 | (u32) ec->status_addr.address, (u32) ec->data_addr.address); |
| 534 | seq_printf(seq, "use global lock: %s\n", | 686 | seq_printf(seq, "use global lock: %s\n", |
| 535 | ec->global_lock?"yes":"no"); | 687 | ec->global_lock?"yes":"no"); |
| 688 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
| 536 | 689 | ||
| 537 | end: | 690 | end: |
| 538 | return_VALUE(0); | 691 | return_VALUE(0); |
| @@ -555,7 +708,7 @@ static int | |||
| 555 | acpi_ec_add_fs ( | 708 | acpi_ec_add_fs ( |
| 556 | struct acpi_device *device) | 709 | struct acpi_device *device) |
| 557 | { | 710 | { |
| 558 | struct proc_dir_entry *entry = NULL; | 711 | struct proc_dir_entry *entry; |
| 559 | 712 | ||
| 560 | ACPI_FUNCTION_TRACE("acpi_ec_add_fs"); | 713 | ACPI_FUNCTION_TRACE("acpi_ec_add_fs"); |
| 561 | 714 | ||
| @@ -606,9 +759,9 @@ static int | |||
| 606 | acpi_ec_add ( | 759 | acpi_ec_add ( |
| 607 | struct acpi_device *device) | 760 | struct acpi_device *device) |
| 608 | { | 761 | { |
| 609 | int result = 0; | 762 | int result; |
| 610 | acpi_status status = AE_OK; | 763 | acpi_status status; |
| 611 | struct acpi_ec *ec = NULL; | 764 | struct acpi_ec *ec; |
| 612 | unsigned long uid; | 765 | unsigned long uid; |
| 613 | 766 | ||
| 614 | ACPI_FUNCTION_TRACE("acpi_ec_add"); | 767 | ACPI_FUNCTION_TRACE("acpi_ec_add"); |
| @@ -623,7 +776,10 @@ acpi_ec_add ( | |||
| 623 | 776 | ||
| 624 | ec->handle = device->handle; | 777 | ec->handle = device->handle; |
| 625 | ec->uid = -1; | 778 | ec->uid = -1; |
| 626 | spin_lock_init(&ec->lock); | 779 | atomic_set(&ec->pending_gpe, 0); |
| 780 | atomic_set(&ec->leaving_burst , 1); | ||
| 781 | init_MUTEX(&ec->sem); | ||
| 782 | init_waitqueue_head(&ec->wait); | ||
| 627 | strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); | 783 | strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); |
| 628 | strcpy(acpi_device_class(device), ACPI_EC_CLASS); | 784 | strcpy(acpi_device_class(device), ACPI_EC_CLASS); |
| 629 | acpi_driver_data(device) = ec; | 785 | acpi_driver_data(device) = ec; |
| @@ -637,7 +793,7 @@ acpi_ec_add ( | |||
| 637 | if (ec_ecdt && ec_ecdt->uid == uid) { | 793 | if (ec_ecdt && ec_ecdt->uid == uid) { |
| 638 | acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, | 794 | acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, |
| 639 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); | 795 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); |
| 640 | 796 | ||
| 641 | acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); | 797 | acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); |
| 642 | 798 | ||
| 643 | kfree(ec_ecdt); | 799 | kfree(ec_ecdt); |
| @@ -677,7 +833,7 @@ acpi_ec_remove ( | |||
| 677 | struct acpi_device *device, | 833 | struct acpi_device *device, |
| 678 | int type) | 834 | int type) |
| 679 | { | 835 | { |
| 680 | struct acpi_ec *ec = NULL; | 836 | struct acpi_ec *ec; |
| 681 | 837 | ||
| 682 | ACPI_FUNCTION_TRACE("acpi_ec_remove"); | 838 | ACPI_FUNCTION_TRACE("acpi_ec_remove"); |
| 683 | 839 | ||
| @@ -732,8 +888,8 @@ static int | |||
| 732 | acpi_ec_start ( | 888 | acpi_ec_start ( |
| 733 | struct acpi_device *device) | 889 | struct acpi_device *device) |
| 734 | { | 890 | { |
| 735 | acpi_status status = AE_OK; | 891 | acpi_status status; |
| 736 | struct acpi_ec *ec = NULL; | 892 | struct acpi_ec *ec; |
| 737 | 893 | ||
| 738 | ACPI_FUNCTION_TRACE("acpi_ec_start"); | 894 | ACPI_FUNCTION_TRACE("acpi_ec_start"); |
| 739 | 895 | ||
| @@ -789,8 +945,8 @@ acpi_ec_stop ( | |||
| 789 | struct acpi_device *device, | 945 | struct acpi_device *device, |
| 790 | int type) | 946 | int type) |
| 791 | { | 947 | { |
| 792 | acpi_status status = AE_OK; | 948 | acpi_status status; |
| 793 | struct acpi_ec *ec = NULL; | 949 | struct acpi_ec *ec; |
| 794 | 950 | ||
| 795 | ACPI_FUNCTION_TRACE("acpi_ec_stop"); | 951 | ACPI_FUNCTION_TRACE("acpi_ec_stop"); |
| 796 | 952 | ||
| @@ -832,7 +988,6 @@ acpi_fake_ecdt_callback ( | |||
| 832 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit); | 988 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit); |
| 833 | if (ACPI_FAILURE(status)) | 989 | if (ACPI_FAILURE(status)) |
| 834 | return status; | 990 | return status; |
| 835 | spin_lock_init(&ec_ecdt->lock); | ||
| 836 | ec_ecdt->global_lock = TRUE; | 991 | ec_ecdt->global_lock = TRUE; |
| 837 | ec_ecdt->handle = handle; | 992 | ec_ecdt->handle = handle; |
| 838 | 993 | ||
| @@ -890,7 +1045,7 @@ acpi_ec_get_real_ecdt(void) | |||
| 890 | acpi_status status; | 1045 | acpi_status status; |
| 891 | struct acpi_table_ecdt *ecdt_ptr; | 1046 | struct acpi_table_ecdt *ecdt_ptr; |
| 892 | 1047 | ||
| 893 | status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, | 1048 | status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, |
| 894 | (struct acpi_table_header **) &ecdt_ptr); | 1049 | (struct acpi_table_header **) &ecdt_ptr); |
| 895 | if (ACPI_FAILURE(status)) | 1050 | if (ACPI_FAILURE(status)) |
| 896 | return -ENODEV; | 1051 | return -ENODEV; |
| @@ -905,11 +1060,12 @@ acpi_ec_get_real_ecdt(void) | |||
| 905 | return -ENOMEM; | 1060 | return -ENOMEM; |
| 906 | memset(ec_ecdt, 0, sizeof(struct acpi_ec)); | 1061 | memset(ec_ecdt, 0, sizeof(struct acpi_ec)); |
| 907 | 1062 | ||
| 1063 | init_MUTEX(&ec_ecdt->sem); | ||
| 1064 | init_waitqueue_head(&ec_ecdt->wait); | ||
| 908 | ec_ecdt->command_addr = ecdt_ptr->ec_control; | 1065 | ec_ecdt->command_addr = ecdt_ptr->ec_control; |
| 909 | ec_ecdt->status_addr = ecdt_ptr->ec_control; | 1066 | ec_ecdt->status_addr = ecdt_ptr->ec_control; |
| 910 | ec_ecdt->data_addr = ecdt_ptr->ec_data; | 1067 | ec_ecdt->data_addr = ecdt_ptr->ec_data; |
| 911 | ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; | 1068 | ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; |
| 912 | spin_lock_init(&ec_ecdt->lock); | ||
| 913 | /* use the GL just to be safe */ | 1069 | /* use the GL just to be safe */ |
| 914 | ec_ecdt->global_lock = TRUE; | 1070 | ec_ecdt->global_lock = TRUE; |
| 915 | ec_ecdt->uid = ecdt_ptr->uid; | 1071 | ec_ecdt->uid = ecdt_ptr->uid; |
| @@ -978,7 +1134,7 @@ error: | |||
| 978 | 1134 | ||
| 979 | static int __init acpi_ec_init (void) | 1135 | static int __init acpi_ec_init (void) |
| 980 | { | 1136 | { |
| 981 | int result = 0; | 1137 | int result; |
| 982 | 1138 | ||
| 983 | ACPI_FUNCTION_TRACE("acpi_ec_init"); | 1139 | ACPI_FUNCTION_TRACE("acpi_ec_init"); |
| 984 | 1140 | ||
