diff options
-rw-r--r-- | drivers/acpi/ec.c | 325 | ||||
-rw-r--r-- | include/linux/acpi.h | 3 |
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 | ||
123 | static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); | 123 | static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); |
124 | static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event); | 124 | static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event); |
125 | static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data); | 125 | static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command, |
126 | static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data); | 126 | const u8 *wdata, unsigned wdata_len, |
127 | static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data); | 127 | u8 *rdata, unsigned rdata_len); |
128 | static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data); | 128 | static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command, |
129 | static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data); | 129 | const u8 *wdata, unsigned wdata_len, |
130 | static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data); | 130 | u8 *rdata, unsigned rdata_len); |
131 | static void acpi_ec_gpe_poll_query(void *ec_cxt); | 131 | static void acpi_ec_gpe_poll_query(void *ec_cxt); |
132 | static void acpi_ec_gpe_intr_query(void *ec_cxt); | 132 | static void acpi_ec_gpe_intr_query(void *ec_cxt); |
133 | static u32 acpi_ec_gpe_poll_handler(void *data); | 133 | static 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 | ||
305 | static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data) | 305 | static 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 | } | ||
314 | static 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 | } |
312 | static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data) | 322 | static 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 | } |
319 | static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data) | 327 | |
328 | static 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; |
360 | end_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 | ||
367 | static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data) | 364 | static 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 | |||
409 | end_nosem: | 394 | end_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 | ||
416 | static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data) | 401 | static 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 | |||
467 | static 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 | ||
433 | end: | ||
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 | ||
555 | EXPORT_SYMBOL(ec_write); | 482 | EXPORT_SYMBOL(ec_write); |
556 | 483 | ||
557 | static int acpi_ec_query(union acpi_ec *ec, u32 * data) | 484 | extern 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 | } | ||
564 | static 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); | ||
604 | end_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 | } |
610 | static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data) | ||
611 | { | ||
612 | int status = 0; | ||
613 | u32 glk; | ||
614 | 497 | ||
498 | EXPORT_SYMBOL(ec_transaction); | ||
615 | 499 | ||
616 | if (!ec || !data) | 500 | static 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 | ||
495 | extern int ec_read(u8 addr, u8 *val); | 495 | extern int ec_read(u8 addr, u8 *val); |
496 | extern int ec_write(u8 addr, u8 val); | 496 | extern int ec_write(u8 addr, u8 val); |
497 | extern 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 | ||