aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/ec.c325
-rw-r--r--include/linux/acpi.h3
2 files changed, 98 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/* --------------------------------------------------------------------------
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 88b5dfd8ee12..2b0c955590fe 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -494,6 +494,9 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
494 494
495extern int ec_read(u8 addr, u8 *val); 495extern int ec_read(u8 addr, u8 *val);
496extern int ec_write(u8 addr, u8 val); 496extern int ec_write(u8 addr, u8 val);
497extern int ec_transaction(u8 command,
498 const u8 *wdata, unsigned wdata_len,
499 u8 *rdata, unsigned rdata_len);
497 500
498#endif /*CONFIG_ACPI_EC*/ 501#endif /*CONFIG_ACPI_EC*/
499 502