aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
authorLennart Poettering <mzxreary@0pointer.de>2006-09-05 12:12:24 -0400
committerLen Brown <len.brown@intel.com>2006-10-14 00:49:52 -0400
commitd7a76e4cb3b4469b1eccb6204c053e3ebcd4c196 (patch)
treedb53dad0c84af4741a3888f96bb297ab328db78b /drivers/acpi/ec.c
parentb4bd8c66435a8cdf8c90334fb3b517a23ff2ab95 (diff)
ACPI: consolidate functions in acpi ec driver
Unify the following functions: acpi_ec_poll_read() acpi_ec_poll_write() acpi_ec_poll_query() acpi_ec_intr_read() acpi_ec_intr_write() acpi_ec_intr_query() into: acpi_ec_poll_transaction() acpi_ec_intr_transaction() These new functions take as arguments an ACPI EC command, a few bytes to write to the EC data register and a buffer for a few bytes to read from the EC data register. The old _read(), _write(), _query() are just special cases of these functions. Then unified the code in acpi_ec_poll_transaction() and acpi_ec_intr_transaction() a little more. Both functions are now just wrappers around the new acpi_ec_transaction_unlocked() function. The latter contains the EC access logic, the two original function now just do their special way of locking and call the the new function for the actual work. This saves a lot of very similar code. The primary reason for doing this, however, is that my driver for MSI 270 laptops needs to issue some non-standard EC commands in a safe way. Due to this I added a new exported function similar to ec_write()/ec_write() which is called ec_transaction() and is essentially just a wrapper around acpi_ec_{poll,intr}_transaction(). Signed-off-by: Lennart Poettering <mzxreary@0pointer.de> Acked-by: Luming Yu <luming.yu@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c325
1 files changed, 95 insertions, 230 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e5d796362854..a0dcbad97c45 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -122,12 +122,12 @@ union acpi_ec {
122 122
123static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); 123static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event);
124static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event); 124static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event);
125static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data); 125static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command,
126static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data); 126 const u8 *wdata, unsigned wdata_len,
127static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data); 127 u8 *rdata, unsigned rdata_len);
128static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data); 128static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command,
129static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data); 129 const u8 *wdata, unsigned wdata_len,
130static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data); 130 u8 *rdata, unsigned rdata_len);
131static void acpi_ec_gpe_poll_query(void *ec_cxt); 131static void acpi_ec_gpe_poll_query(void *ec_cxt);
132static void acpi_ec_gpe_intr_query(void *ec_cxt); 132static void acpi_ec_gpe_intr_query(void *ec_cxt);
133static u32 acpi_ec_gpe_poll_handler(void *data); 133static u32 acpi_ec_gpe_poll_handler(void *data);
@@ -302,110 +302,95 @@ end:
302} 302}
303#endif /* ACPI_FUTURE_USAGE */ 303#endif /* ACPI_FUTURE_USAGE */
304 304
305static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data) 305static int acpi_ec_transaction(union acpi_ec *ec, u8 command,
306 const u8 *wdata, unsigned wdata_len,
307 u8 *rdata, unsigned rdata_len)
306{ 308{
307 if (acpi_ec_poll_mode) 309 if (acpi_ec_poll_mode)
308 return acpi_ec_poll_read(ec, address, data); 310 return acpi_ec_poll_transaction(ec, command, wdata, wdata_len, rdata, rdata_len);
309 else 311 else
310 return acpi_ec_intr_read(ec, address, data); 312 return acpi_ec_intr_transaction(ec, command, wdata, wdata_len, rdata, rdata_len);
313}
314static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data)
315{
316 int result;
317 u8 d;
318 result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, &address, 1, &d, 1);
319 *data = d;
320 return result;
311} 321}
312static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data) 322static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data)
313{ 323{
314 if (acpi_ec_poll_mode) 324 u8 wdata[2] = { address, data };
315 return acpi_ec_poll_write(ec, address, data); 325 return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, wdata, 2, NULL, 0);
316 else
317 return acpi_ec_intr_write(ec, address, data);
318} 326}
319static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data) 327
328static int acpi_ec_transaction_unlocked(union acpi_ec *ec, u8 command,
329 const u8 *wdata, unsigned wdata_len,
330 u8 *rdata, unsigned rdata_len)
320{ 331{
321 acpi_status status = AE_OK; 332 int result;
322 int result = 0;
323 u32 glk = 0;
324 333
334 acpi_hw_low_level_write(8, command, &ec->common.command_addr);
325 335
326 if (!ec || !data) 336 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
327 return -EINVAL; 337 if (result)
338 return result;
328 339
329 *data = 0; 340 for (; wdata_len > 0; wdata_len --) {
330 341
331 if (ec->common.global_lock) { 342 acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr);
332 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
333 if (ACPI_FAILURE(status))
334 return -ENODEV;
335 }
336 343
337 if (down_interruptible(&ec->poll.sem)) { 344 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
338 result = -ERESTARTSYS; 345 if (result)
339 goto end_nosem; 346 return result;
340 } 347 }
341
342 acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
343 &ec->common.command_addr);
344 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
345 if (result)
346 goto end;
347 348
348 acpi_hw_low_level_write(8, address, &ec->common.data_addr);
349 result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
350 if (result)
351 goto end;
352 349
353 acpi_hw_low_level_read(8, data, &ec->common.data_addr); 350 for (; rdata_len > 0; rdata_len --) {
351 u32 d;
354 352
355 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", 353 result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
356 *data, address)); 354 if (result)
355 return result;
357 356
358 end: 357 acpi_hw_low_level_read(8, &d, &ec->common.data_addr);
359 up(&ec->poll.sem); 358 *(rdata++) = (u8) d;
360end_nosem: 359 }
361 if (ec->common.global_lock)
362 acpi_release_global_lock(glk);
363 360
364 return result; 361 return 0;
365} 362}
366 363
367static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data) 364static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command,
365 const u8 *wdata, unsigned wdata_len,
366 u8 *rdata, unsigned rdata_len)
368{ 367{
369 int result = 0;
370 acpi_status status = AE_OK; 368 acpi_status status = AE_OK;
369 int result;
371 u32 glk = 0; 370 u32 glk = 0;
372 371
373 372 if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
374 if (!ec)
375 return -EINVAL; 373 return -EINVAL;
376 374
375 if (rdata)
376 memset(rdata, 0, rdata_len);
377
377 if (ec->common.global_lock) { 378 if (ec->common.global_lock) {
378 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); 379 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
379 if (ACPI_FAILURE(status)) 380 if (ACPI_FAILURE(status))
380 return -ENODEV; 381 return -ENODEV;
381 } 382 }
382 383
383 if (down_interruptible(&ec->poll.sem)) { 384 if (down_interruptible(&ec->poll.sem)) {
384 result = -ERESTARTSYS; 385 result = -ERESTARTSYS;
385 goto end_nosem; 386 goto end_nosem;
386 } 387 }
387
388 acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
389 &ec->common.command_addr);
390 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
391 if (result)
392 goto end;
393 388
394 acpi_hw_low_level_write(8, address, &ec->common.data_addr); 389 result = acpi_ec_transaction_unlocked(ec, command,
395 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); 390 wdata, wdata_len,
396 if (result) 391 rdata, rdata_len);
397 goto end;
398
399 acpi_hw_low_level_write(8, data, &ec->common.data_addr);
400 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
401 if (result)
402 goto end;
403
404 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
405 data, address));
406
407 end:
408 up(&ec->poll.sem); 392 up(&ec->poll.sem);
393
409end_nosem: 394end_nosem:
410 if (ec->common.global_lock) 395 if (ec->common.global_lock)
411 acpi_release_global_lock(glk); 396 acpi_release_global_lock(glk);
@@ -413,16 +398,18 @@ end_nosem:
413 return result; 398 return result;
414} 399}
415 400
416static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data) 401static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command,
402 const u8 *wdata, unsigned wdata_len,
403 u8 *rdata, unsigned rdata_len)
417{ 404{
418 int status = 0; 405 int status;
419 u32 glk; 406 u32 glk;
420 407
421 408 if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
422 if (!ec || !data)
423 return -EINVAL; 409 return -EINVAL;
424 410
425 *data = 0; 411 if (rdata)
412 memset(rdata, 0, rdata_len);
426 413
427 if (ec->common.global_lock) { 414 if (ec->common.global_lock) {
428 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); 415 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
@@ -438,72 +425,12 @@ static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
438 printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); 425 printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
439 goto end; 426 goto end;
440 } 427 }
441 acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
442 &ec->common.command_addr);
443 status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
444 if (status) {
445 printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
446 }
447
448 acpi_hw_low_level_write(8, address, &ec->common.data_addr);
449 status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
450 if (status) {
451 printk(KERN_DEBUG PREFIX "read EC, OB not full\n");
452 goto end;
453 }
454 acpi_hw_low_level_read(8, data, &ec->common.data_addr);
455 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
456 *data, address));
457
458 end:
459 up(&ec->intr.sem);
460
461 if (ec->common.global_lock)
462 acpi_release_global_lock(glk);
463
464 return status;
465}
466
467static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
468{
469 int status = 0;
470 u32 glk;
471
472
473 if (!ec)
474 return -EINVAL;
475
476 if (ec->common.global_lock) {
477 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
478 if (ACPI_FAILURE(status))
479 return -ENODEV;
480 }
481
482 WARN_ON(in_interrupt());
483 down(&ec->intr.sem);
484
485 status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
486 if (status) {
487 printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
488 }
489 acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
490 &ec->common.command_addr);
491 status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
492 if (status) {
493 printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
494 }
495
496 acpi_hw_low_level_write(8, address, &ec->common.data_addr);
497 status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
498 if (status) {
499 printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
500 }
501 428
502 acpi_hw_low_level_write(8, data, &ec->common.data_addr); 429 status = acpi_ec_transaction_unlocked(ec, command,
503 430 wdata, wdata_len,
504 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", 431 rdata, rdata_len);
505 data, address));
506 432
433end:
507 up(&ec->intr.sem); 434 up(&ec->intr.sem);
508 435
509 if (ec->common.global_lock) 436 if (ec->common.global_lock)
@@ -554,106 +481,44 @@ int ec_write(u8 addr, u8 val)
554 481
555EXPORT_SYMBOL(ec_write); 482EXPORT_SYMBOL(ec_write);
556 483
557static int acpi_ec_query(union acpi_ec *ec, u32 * data) 484extern int ec_transaction(u8 command,
558{ 485 const u8 *wdata, unsigned wdata_len,
559 if (acpi_ec_poll_mode) 486 u8 *rdata, unsigned rdata_len)
560 return acpi_ec_poll_query(ec, data);
561 else
562 return acpi_ec_intr_query(ec, data);
563}
564static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
565{ 487{
566 int result = 0; 488 union acpi_ec *ec;
567 acpi_status status = AE_OK;
568 u32 glk = 0;
569
570
571 if (!ec || !data)
572 return -EINVAL;
573
574 *data = 0;
575
576 if (ec->common.global_lock) {
577 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
578 if (ACPI_FAILURE(status))
579 return -ENODEV;
580 }
581
582 /*
583 * Query the EC to find out which _Qxx method we need to evaluate.
584 * Note that successful completion of the query causes the ACPI_EC_SCI
585 * bit to be cleared (and thus clearing the interrupt source).
586 */
587 if (down_interruptible(&ec->poll.sem)) {
588 result = -ERESTARTSYS;
589 goto end_nosem;
590 }
591
592 acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
593 &ec->common.command_addr);
594 result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
595 if (result)
596 goto end;
597 489
598 acpi_hw_low_level_read(8, data, &ec->common.data_addr); 490 if (!first_ec)
599 if (!*data) 491 return -ENODEV;
600 result = -ENODATA;
601 492
602 end: 493 ec = acpi_driver_data(first_ec);
603 up(&ec->poll.sem);
604end_nosem:
605 if (ec->common.global_lock)
606 acpi_release_global_lock(glk);
607 494
608 return result; 495 return acpi_ec_transaction(ec, command, wdata, wdata_len, rdata, rdata_len);
609} 496}
610static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
611{
612 int status = 0;
613 u32 glk;
614 497
498EXPORT_SYMBOL(ec_transaction);
615 499
616 if (!ec || !data) 500static int acpi_ec_query(union acpi_ec *ec, u32 * data) {
617 return -EINVAL; 501 int result;
618 *data = 0; 502 u8 d;
619 503
620 if (ec->common.global_lock) { 504 if (!ec || !data)
621 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); 505 return -EINVAL;
622 if (ACPI_FAILURE(status))
623 return -ENODEV;
624 }
625 506
626 down(&ec->intr.sem); 507 /*
508 * Query the EC to find out which _Qxx method we need to evaluate.
509 * Note that successful completion of the query causes the ACPI_EC_SCI
510 * bit to be cleared (and thus clearing the interrupt source).
511 */
627 512
628 status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); 513 result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
629 if (status) { 514 if (result)
630 printk(KERN_DEBUG PREFIX "query EC, IB not empty\n"); 515 return result;
631 goto end;
632 }
633 /*
634 * Query the EC to find out which _Qxx method we need to evaluate.
635 * Note that successful completion of the query causes the ACPI_EC_SCI
636 * bit to be cleared (and thus clearing the interrupt source).
637 */
638 acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
639 &ec->common.command_addr);
640 status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
641 if (status) {
642 printk(KERN_DEBUG PREFIX "query EC, OB not full\n");
643 goto end;
644 }
645
646 acpi_hw_low_level_read(8, data, &ec->common.data_addr);
647 if (!*data)
648 status = -ENODATA;
649 516
650 end: 517 if (!d)
651 up(&ec->intr.sem); 518 return -ENODATA;
652 519
653 if (ec->common.global_lock) 520 *data = d;
654 acpi_release_global_lock(glk); 521 return 0;
655
656 return status;
657} 522}
658 523
659/* -------------------------------------------------------------------------- 524/* --------------------------------------------------------------------------