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 | ||