diff options
Diffstat (limited to 'arch/x86/kernel/apm_32.c')
| -rw-r--r-- | arch/x86/kernel/apm_32.c | 250 |
1 files changed, 146 insertions, 104 deletions
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 266ec6c18b6c..c1941be9fb17 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c | |||
| @@ -301,7 +301,7 @@ extern int (*console_blank_hook)(int); | |||
| 301 | */ | 301 | */ |
| 302 | #define APM_ZERO_SEGS | 302 | #define APM_ZERO_SEGS |
| 303 | 303 | ||
| 304 | #include "apm.h" | 304 | #include <asm/apm.h> |
| 305 | 305 | ||
| 306 | /* | 306 | /* |
| 307 | * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend. | 307 | * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend. |
| @@ -466,7 +466,7 @@ static const lookup_t error_table[] = { | |||
| 466 | * @err: APM BIOS return code | 466 | * @err: APM BIOS return code |
| 467 | * | 467 | * |
| 468 | * Write a meaningful log entry to the kernel log in the event of | 468 | * Write a meaningful log entry to the kernel log in the event of |
| 469 | * an APM error. | 469 | * an APM error. Note that this also handles (negative) kernel errors. |
| 470 | */ | 470 | */ |
| 471 | 471 | ||
| 472 | static void apm_error(char *str, int err) | 472 | static void apm_error(char *str, int err) |
| @@ -478,43 +478,14 @@ static void apm_error(char *str, int err) | |||
| 478 | break; | 478 | break; |
| 479 | if (i < ERROR_COUNT) | 479 | if (i < ERROR_COUNT) |
| 480 | printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg); | 480 | printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg); |
| 481 | else if (err < 0) | ||
| 482 | printk(KERN_NOTICE "apm: %s: linux error code %i\n", str, err); | ||
| 481 | else | 483 | else |
| 482 | printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n", | 484 | printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n", |
| 483 | str, err); | 485 | str, err); |
| 484 | } | 486 | } |
| 485 | 487 | ||
| 486 | /* | 488 | /* |
| 487 | * Lock APM functionality to physical CPU 0 | ||
| 488 | */ | ||
| 489 | |||
| 490 | #ifdef CONFIG_SMP | ||
| 491 | |||
| 492 | static cpumask_t apm_save_cpus(void) | ||
| 493 | { | ||
| 494 | cpumask_t x = current->cpus_allowed; | ||
| 495 | /* Some bioses don't like being called from CPU != 0 */ | ||
| 496 | set_cpus_allowed(current, cpumask_of_cpu(0)); | ||
| 497 | BUG_ON(smp_processor_id() != 0); | ||
| 498 | return x; | ||
| 499 | } | ||
| 500 | |||
| 501 | static inline void apm_restore_cpus(cpumask_t mask) | ||
| 502 | { | ||
| 503 | set_cpus_allowed(current, mask); | ||
| 504 | } | ||
| 505 | |||
| 506 | #else | ||
| 507 | |||
| 508 | /* | ||
| 509 | * No CPU lockdown needed on a uniprocessor | ||
| 510 | */ | ||
| 511 | |||
| 512 | #define apm_save_cpus() (current->cpus_allowed) | ||
| 513 | #define apm_restore_cpus(x) (void)(x) | ||
| 514 | |||
| 515 | #endif | ||
| 516 | |||
| 517 | /* | ||
| 518 | * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and | 489 | * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and |
| 519 | * apm_info.allow_ints, we are being really paranoid here! Not only | 490 | * apm_info.allow_ints, we are being really paranoid here! Not only |
| 520 | * are interrupts disabled, but all the segment registers (except SS) | 491 | * are interrupts disabled, but all the segment registers (except SS) |
| @@ -568,16 +539,23 @@ static inline void apm_irq_restore(unsigned long flags) | |||
| 568 | # define APM_DO_RESTORE_SEGS | 539 | # define APM_DO_RESTORE_SEGS |
| 569 | #endif | 540 | #endif |
| 570 | 541 | ||
| 542 | struct apm_bios_call { | ||
| 543 | u32 func; | ||
| 544 | /* In and out */ | ||
| 545 | u32 ebx; | ||
| 546 | u32 ecx; | ||
| 547 | /* Out only */ | ||
| 548 | u32 eax; | ||
| 549 | u32 edx; | ||
| 550 | u32 esi; | ||
| 551 | |||
| 552 | /* Error: -ENOMEM, or bits 8-15 of eax */ | ||
| 553 | int err; | ||
| 554 | }; | ||
| 555 | |||
| 571 | /** | 556 | /** |
| 572 | * apm_bios_call - Make an APM BIOS 32bit call | 557 | * __apm_bios_call - Make an APM BIOS 32bit call |
| 573 | * @func: APM function to execute | 558 | * @_call: pointer to struct apm_bios_call. |
| 574 | * @ebx_in: EBX register for call entry | ||
| 575 | * @ecx_in: ECX register for call entry | ||
| 576 | * @eax: EAX register return | ||
| 577 | * @ebx: EBX register return | ||
| 578 | * @ecx: ECX register return | ||
| 579 | * @edx: EDX register return | ||
| 580 | * @esi: ESI register return | ||
| 581 | * | 559 | * |
| 582 | * Make an APM call using the 32bit protected mode interface. The | 560 | * Make an APM call using the 32bit protected mode interface. The |
| 583 | * caller is responsible for knowing if APM BIOS is configured and | 561 | * caller is responsible for knowing if APM BIOS is configured and |
| @@ -586,80 +564,142 @@ static inline void apm_irq_restore(unsigned long flags) | |||
| 586 | * flag is loaded into AL. If there is an error, then the error | 564 | * flag is loaded into AL. If there is an error, then the error |
| 587 | * code is returned in AH (bits 8-15 of eax) and this function | 565 | * code is returned in AH (bits 8-15 of eax) and this function |
| 588 | * returns non-zero. | 566 | * returns non-zero. |
| 567 | * | ||
| 568 | * Note: this makes the call on the current CPU. | ||
| 589 | */ | 569 | */ |
| 590 | 570 | static long __apm_bios_call(void *_call) | |
| 591 | static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, | ||
| 592 | u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi) | ||
| 593 | { | 571 | { |
| 594 | APM_DECL_SEGS | 572 | APM_DECL_SEGS |
| 595 | unsigned long flags; | 573 | unsigned long flags; |
| 596 | cpumask_t cpus; | ||
| 597 | int cpu; | 574 | int cpu; |
| 598 | struct desc_struct save_desc_40; | 575 | struct desc_struct save_desc_40; |
| 599 | struct desc_struct *gdt; | 576 | struct desc_struct *gdt; |
| 600 | 577 | struct apm_bios_call *call = _call; | |
| 601 | cpus = apm_save_cpus(); | ||
| 602 | 578 | ||
| 603 | cpu = get_cpu(); | 579 | cpu = get_cpu(); |
| 580 | BUG_ON(cpu != 0); | ||
| 604 | gdt = get_cpu_gdt_table(cpu); | 581 | gdt = get_cpu_gdt_table(cpu); |
| 605 | save_desc_40 = gdt[0x40 / 8]; | 582 | save_desc_40 = gdt[0x40 / 8]; |
| 606 | gdt[0x40 / 8] = bad_bios_desc; | 583 | gdt[0x40 / 8] = bad_bios_desc; |
| 607 | 584 | ||
| 608 | apm_irq_save(flags); | 585 | apm_irq_save(flags); |
| 609 | APM_DO_SAVE_SEGS; | 586 | APM_DO_SAVE_SEGS; |
| 610 | apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi); | 587 | apm_bios_call_asm(call->func, call->ebx, call->ecx, |
| 588 | &call->eax, &call->ebx, &call->ecx, &call->edx, | ||
| 589 | &call->esi); | ||
| 611 | APM_DO_RESTORE_SEGS; | 590 | APM_DO_RESTORE_SEGS; |
| 612 | apm_irq_restore(flags); | 591 | apm_irq_restore(flags); |
| 613 | gdt[0x40 / 8] = save_desc_40; | 592 | gdt[0x40 / 8] = save_desc_40; |
| 614 | put_cpu(); | 593 | put_cpu(); |
| 615 | apm_restore_cpus(cpus); | ||
| 616 | 594 | ||
| 617 | return *eax & 0xff; | 595 | return call->eax & 0xff; |
| 596 | } | ||
| 597 | |||
| 598 | /* Run __apm_bios_call or __apm_bios_call_simple on CPU 0 */ | ||
| 599 | static int on_cpu0(long (*fn)(void *), struct apm_bios_call *call) | ||
| 600 | { | ||
| 601 | int ret; | ||
| 602 | |||
| 603 | /* Don't bother with work_on_cpu in the common case, so we don't | ||
| 604 | * have to worry about OOM or overhead. */ | ||
| 605 | if (get_cpu() == 0) { | ||
| 606 | ret = fn(call); | ||
| 607 | put_cpu(); | ||
| 608 | } else { | ||
| 609 | put_cpu(); | ||
| 610 | ret = work_on_cpu(0, fn, call); | ||
| 611 | } | ||
| 612 | |||
| 613 | /* work_on_cpu can fail with -ENOMEM */ | ||
| 614 | if (ret < 0) | ||
| 615 | call->err = ret; | ||
| 616 | else | ||
| 617 | call->err = (call->eax >> 8) & 0xff; | ||
| 618 | |||
| 619 | return ret; | ||
| 618 | } | 620 | } |
| 619 | 621 | ||
| 620 | /** | 622 | /** |
| 621 | * apm_bios_call_simple - make a simple APM BIOS 32bit call | 623 | * apm_bios_call - Make an APM BIOS 32bit call (on CPU 0) |
| 622 | * @func: APM function to invoke | 624 | * @call: the apm_bios_call registers. |
| 623 | * @ebx_in: EBX register value for BIOS call | 625 | * |
| 624 | * @ecx_in: ECX register value for BIOS call | 626 | * If there is an error, it is returned in @call.err. |
| 625 | * @eax: EAX register on return from the BIOS call | 627 | */ |
| 628 | static int apm_bios_call(struct apm_bios_call *call) | ||
| 629 | { | ||
| 630 | return on_cpu0(__apm_bios_call, call); | ||
| 631 | } | ||
| 632 | |||
| 633 | /** | ||
| 634 | * __apm_bios_call_simple - Make an APM BIOS 32bit call (on CPU 0) | ||
| 635 | * @_call: pointer to struct apm_bios_call. | ||
| 626 | * | 636 | * |
| 627 | * Make a BIOS call that returns one value only, or just status. | 637 | * Make a BIOS call that returns one value only, or just status. |
| 628 | * If there is an error, then the error code is returned in AH | 638 | * If there is an error, then the error code is returned in AH |
| 629 | * (bits 8-15 of eax) and this function returns non-zero. This is | 639 | * (bits 8-15 of eax) and this function returns non-zero (it can |
| 630 | * used for simpler BIOS operations. This call may hold interrupts | 640 | * also return -ENOMEM). This is used for simpler BIOS operations. |
| 631 | * off for a long time on some laptops. | 641 | * This call may hold interrupts off for a long time on some laptops. |
| 642 | * | ||
| 643 | * Note: this makes the call on the current CPU. | ||
| 632 | */ | 644 | */ |
| 633 | 645 | static long __apm_bios_call_simple(void *_call) | |
| 634 | static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) | ||
| 635 | { | 646 | { |
| 636 | u8 error; | 647 | u8 error; |
| 637 | APM_DECL_SEGS | 648 | APM_DECL_SEGS |
| 638 | unsigned long flags; | 649 | unsigned long flags; |
| 639 | cpumask_t cpus; | ||
| 640 | int cpu; | 650 | int cpu; |
| 641 | struct desc_struct save_desc_40; | 651 | struct desc_struct save_desc_40; |
| 642 | struct desc_struct *gdt; | 652 | struct desc_struct *gdt; |
| 643 | 653 | struct apm_bios_call *call = _call; | |
| 644 | cpus = apm_save_cpus(); | ||
| 645 | 654 | ||
| 646 | cpu = get_cpu(); | 655 | cpu = get_cpu(); |
| 656 | BUG_ON(cpu != 0); | ||
| 647 | gdt = get_cpu_gdt_table(cpu); | 657 | gdt = get_cpu_gdt_table(cpu); |
| 648 | save_desc_40 = gdt[0x40 / 8]; | 658 | save_desc_40 = gdt[0x40 / 8]; |
| 649 | gdt[0x40 / 8] = bad_bios_desc; | 659 | gdt[0x40 / 8] = bad_bios_desc; |
| 650 | 660 | ||
| 651 | apm_irq_save(flags); | 661 | apm_irq_save(flags); |
| 652 | APM_DO_SAVE_SEGS; | 662 | APM_DO_SAVE_SEGS; |
| 653 | error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax); | 663 | error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx, |
| 664 | &call->eax); | ||
| 654 | APM_DO_RESTORE_SEGS; | 665 | APM_DO_RESTORE_SEGS; |
| 655 | apm_irq_restore(flags); | 666 | apm_irq_restore(flags); |
| 656 | gdt[0x40 / 8] = save_desc_40; | 667 | gdt[0x40 / 8] = save_desc_40; |
| 657 | put_cpu(); | 668 | put_cpu(); |
| 658 | apm_restore_cpus(cpus); | ||
| 659 | return error; | 669 | return error; |
| 660 | } | 670 | } |
| 661 | 671 | ||
| 662 | /** | 672 | /** |
| 673 | * apm_bios_call_simple - make a simple APM BIOS 32bit call | ||
| 674 | * @func: APM function to invoke | ||
| 675 | * @ebx_in: EBX register value for BIOS call | ||
| 676 | * @ecx_in: ECX register value for BIOS call | ||
| 677 | * @eax: EAX register on return from the BIOS call | ||
| 678 | * @err: bits | ||
| 679 | * | ||
| 680 | * Make a BIOS call that returns one value only, or just status. | ||
| 681 | * If there is an error, then the error code is returned in @err | ||
| 682 | * and this function returns non-zero. This is used for simpler | ||
| 683 | * BIOS operations. This call may hold interrupts off for a long | ||
| 684 | * time on some laptops. | ||
| 685 | */ | ||
| 686 | static int apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax, | ||
| 687 | int *err) | ||
| 688 | { | ||
| 689 | struct apm_bios_call call; | ||
| 690 | int ret; | ||
| 691 | |||
| 692 | call.func = func; | ||
| 693 | call.ebx = ebx_in; | ||
| 694 | call.ecx = ecx_in; | ||
| 695 | |||
| 696 | ret = on_cpu0(__apm_bios_call_simple, &call); | ||
| 697 | *eax = call.eax; | ||
| 698 | *err = call.err; | ||
| 699 | return ret; | ||
| 700 | } | ||
| 701 | |||
| 702 | /** | ||
| 663 | * apm_driver_version - APM driver version | 703 | * apm_driver_version - APM driver version |
| 664 | * @val: loaded with the APM version on return | 704 | * @val: loaded with the APM version on return |
| 665 | * | 705 | * |
| @@ -678,9 +718,10 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) | |||
| 678 | static int apm_driver_version(u_short *val) | 718 | static int apm_driver_version(u_short *val) |
| 679 | { | 719 | { |
| 680 | u32 eax; | 720 | u32 eax; |
| 721 | int err; | ||
| 681 | 722 | ||
| 682 | if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax)) | 723 | if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax, &err)) |
| 683 | return (eax >> 8) & 0xff; | 724 | return err; |
| 684 | *val = eax; | 725 | *val = eax; |
| 685 | return APM_SUCCESS; | 726 | return APM_SUCCESS; |
| 686 | } | 727 | } |
| @@ -701,22 +742,21 @@ static int apm_driver_version(u_short *val) | |||
| 701 | * that APM 1.2 is in use. If no messges are pending the value 0x80 | 742 | * that APM 1.2 is in use. If no messges are pending the value 0x80 |
| 702 | * is returned (No power management events pending). | 743 | * is returned (No power management events pending). |
| 703 | */ | 744 | */ |
| 704 | |||
| 705 | static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info) | 745 | static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info) |
| 706 | { | 746 | { |
| 707 | u32 eax; | 747 | struct apm_bios_call call; |
| 708 | u32 ebx; | ||
| 709 | u32 ecx; | ||
| 710 | u32 dummy; | ||
| 711 | 748 | ||
| 712 | if (apm_bios_call(APM_FUNC_GET_EVENT, 0, 0, &eax, &ebx, &ecx, | 749 | call.func = APM_FUNC_GET_EVENT; |
| 713 | &dummy, &dummy)) | 750 | call.ebx = call.ecx = 0; |
| 714 | return (eax >> 8) & 0xff; | 751 | |
| 715 | *event = ebx; | 752 | if (apm_bios_call(&call)) |
| 753 | return call.err; | ||
| 754 | |||
| 755 | *event = call.ebx; | ||
| 716 | if (apm_info.connection_version < 0x0102) | 756 | if (apm_info.connection_version < 0x0102) |
| 717 | *info = ~0; /* indicate info not valid */ | 757 | *info = ~0; /* indicate info not valid */ |
| 718 | else | 758 | else |
| 719 | *info = ecx; | 759 | *info = call.ecx; |
| 720 | return APM_SUCCESS; | 760 | return APM_SUCCESS; |
| 721 | } | 761 | } |
| 722 | 762 | ||
| @@ -737,9 +777,10 @@ static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info) | |||
| 737 | static int set_power_state(u_short what, u_short state) | 777 | static int set_power_state(u_short what, u_short state) |
| 738 | { | 778 | { |
| 739 | u32 eax; | 779 | u32 eax; |
| 780 | int err; | ||
| 740 | 781 | ||
| 741 | if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax)) | 782 | if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax, &err)) |
| 742 | return (eax >> 8) & 0xff; | 783 | return err; |
| 743 | return APM_SUCCESS; | 784 | return APM_SUCCESS; |
| 744 | } | 785 | } |
| 745 | 786 | ||
| @@ -770,6 +811,7 @@ static int apm_do_idle(void) | |||
| 770 | u8 ret = 0; | 811 | u8 ret = 0; |
| 771 | int idled = 0; | 812 | int idled = 0; |
| 772 | int polling; | 813 | int polling; |
| 814 | int err; | ||
| 773 | 815 | ||
| 774 | polling = !!(current_thread_info()->status & TS_POLLING); | 816 | polling = !!(current_thread_info()->status & TS_POLLING); |
| 775 | if (polling) { | 817 | if (polling) { |
| @@ -782,7 +824,7 @@ static int apm_do_idle(void) | |||
| 782 | } | 824 | } |
| 783 | if (!need_resched()) { | 825 | if (!need_resched()) { |
| 784 | idled = 1; | 826 | idled = 1; |
| 785 | ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax); | 827 | ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax, &err); |
| 786 | } | 828 | } |
| 787 | if (polling) | 829 | if (polling) |
| 788 | current_thread_info()->status |= TS_POLLING; | 830 | current_thread_info()->status |= TS_POLLING; |
| @@ -797,8 +839,7 @@ static int apm_do_idle(void) | |||
| 797 | * Only report the failure the first 5 times. | 839 | * Only report the failure the first 5 times. |
| 798 | */ | 840 | */ |
| 799 | if (++t < 5) { | 841 | if (++t < 5) { |
| 800 | printk(KERN_DEBUG "apm_do_idle failed (%d)\n", | 842 | printk(KERN_DEBUG "apm_do_idle failed (%d)\n", err); |
| 801 | (eax >> 8) & 0xff); | ||
| 802 | t = jiffies; | 843 | t = jiffies; |
| 803 | } | 844 | } |
| 804 | return -1; | 845 | return -1; |
| @@ -816,9 +857,10 @@ static int apm_do_idle(void) | |||
| 816 | static void apm_do_busy(void) | 857 | static void apm_do_busy(void) |
| 817 | { | 858 | { |
| 818 | u32 dummy; | 859 | u32 dummy; |
| 860 | int err; | ||
| 819 | 861 | ||
| 820 | if (clock_slowed || ALWAYS_CALL_BUSY) { | 862 | if (clock_slowed || ALWAYS_CALL_BUSY) { |
| 821 | (void)apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy); | 863 | (void)apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy, &err); |
| 822 | clock_slowed = 0; | 864 | clock_slowed = 0; |
| 823 | } | 865 | } |
| 824 | } | 866 | } |
| @@ -937,7 +979,7 @@ static void apm_power_off(void) | |||
| 937 | 979 | ||
| 938 | /* Some bioses don't like being called from CPU != 0 */ | 980 | /* Some bioses don't like being called from CPU != 0 */ |
| 939 | if (apm_info.realmode_power_off) { | 981 | if (apm_info.realmode_power_off) { |
| 940 | (void)apm_save_cpus(); | 982 | set_cpus_allowed_ptr(current, cpumask_of(0)); |
| 941 | machine_real_restart(po_bios_call, sizeof(po_bios_call)); | 983 | machine_real_restart(po_bios_call, sizeof(po_bios_call)); |
| 942 | } else { | 984 | } else { |
| 943 | (void)set_system_power_state(APM_STATE_OFF); | 985 | (void)set_system_power_state(APM_STATE_OFF); |
| @@ -956,12 +998,13 @@ static void apm_power_off(void) | |||
| 956 | static int apm_enable_power_management(int enable) | 998 | static int apm_enable_power_management(int enable) |
| 957 | { | 999 | { |
| 958 | u32 eax; | 1000 | u32 eax; |
| 1001 | int err; | ||
| 959 | 1002 | ||
| 960 | if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED)) | 1003 | if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED)) |
| 961 | return APM_NOT_ENGAGED; | 1004 | return APM_NOT_ENGAGED; |
| 962 | if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL, | 1005 | if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL, |
| 963 | enable, &eax)) | 1006 | enable, &eax, &err)) |
| 964 | return (eax >> 8) & 0xff; | 1007 | return err; |
| 965 | if (enable) | 1008 | if (enable) |
| 966 | apm_info.bios.flags &= ~APM_BIOS_DISABLED; | 1009 | apm_info.bios.flags &= ~APM_BIOS_DISABLED; |
| 967 | else | 1010 | else |
| @@ -986,24 +1029,23 @@ static int apm_enable_power_management(int enable) | |||
| 986 | 1029 | ||
| 987 | static int apm_get_power_status(u_short *status, u_short *bat, u_short *life) | 1030 | static int apm_get_power_status(u_short *status, u_short *bat, u_short *life) |
| 988 | { | 1031 | { |
| 989 | u32 eax; | 1032 | struct apm_bios_call call; |
| 990 | u32 ebx; | 1033 | |
| 991 | u32 ecx; | 1034 | call.func = APM_FUNC_GET_STATUS; |
| 992 | u32 edx; | 1035 | call.ebx = APM_DEVICE_ALL; |
| 993 | u32 dummy; | 1036 | call.ecx = 0; |
| 994 | 1037 | ||
| 995 | if (apm_info.get_power_status_broken) | 1038 | if (apm_info.get_power_status_broken) |
| 996 | return APM_32_UNSUPPORTED; | 1039 | return APM_32_UNSUPPORTED; |
| 997 | if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0, | 1040 | if (apm_bios_call(&call)) |
| 998 | &eax, &ebx, &ecx, &edx, &dummy)) | 1041 | return call.err; |
| 999 | return (eax >> 8) & 0xff; | 1042 | *status = call.ebx; |
| 1000 | *status = ebx; | 1043 | *bat = call.ecx; |
| 1001 | *bat = ecx; | ||
| 1002 | if (apm_info.get_power_status_swabinminutes) { | 1044 | if (apm_info.get_power_status_swabinminutes) { |
| 1003 | *life = swab16((u16)edx); | 1045 | *life = swab16((u16)call.edx); |
| 1004 | *life |= 0x8000; | 1046 | *life |= 0x8000; |
| 1005 | } else | 1047 | } else |
| 1006 | *life = edx; | 1048 | *life = call.edx; |
| 1007 | return APM_SUCCESS; | 1049 | return APM_SUCCESS; |
| 1008 | } | 1050 | } |
| 1009 | 1051 | ||
| @@ -1048,12 +1090,14 @@ static int apm_get_battery_status(u_short which, u_short *status, | |||
| 1048 | static int apm_engage_power_management(u_short device, int enable) | 1090 | static int apm_engage_power_management(u_short device, int enable) |
| 1049 | { | 1091 | { |
| 1050 | u32 eax; | 1092 | u32 eax; |
| 1093 | int err; | ||
| 1051 | 1094 | ||
| 1052 | if ((enable == 0) && (device == APM_DEVICE_ALL) | 1095 | if ((enable == 0) && (device == APM_DEVICE_ALL) |
| 1053 | && (apm_info.bios.flags & APM_BIOS_DISABLED)) | 1096 | && (apm_info.bios.flags & APM_BIOS_DISABLED)) |
| 1054 | return APM_DISABLED; | 1097 | return APM_DISABLED; |
| 1055 | if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax)) | 1098 | if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, |
| 1056 | return (eax >> 8) & 0xff; | 1099 | &eax, &err)) |
| 1100 | return err; | ||
| 1057 | if (device == APM_DEVICE_ALL) { | 1101 | if (device == APM_DEVICE_ALL) { |
| 1058 | if (enable) | 1102 | if (enable) |
| 1059 | apm_info.bios.flags &= ~APM_BIOS_DISENGAGED; | 1103 | apm_info.bios.flags &= ~APM_BIOS_DISENGAGED; |
| @@ -1682,16 +1726,14 @@ static int apm(void *unused) | |||
| 1682 | char *power_stat; | 1726 | char *power_stat; |
| 1683 | char *bat_stat; | 1727 | char *bat_stat; |
| 1684 | 1728 | ||
| 1685 | #ifdef CONFIG_SMP | ||
| 1686 | /* 2002/08/01 - WT | 1729 | /* 2002/08/01 - WT |
| 1687 | * This is to avoid random crashes at boot time during initialization | 1730 | * This is to avoid random crashes at boot time during initialization |
| 1688 | * on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D. | 1731 | * on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D. |
| 1689 | * Some bioses don't like being called from CPU != 0. | 1732 | * Some bioses don't like being called from CPU != 0. |
| 1690 | * Method suggested by Ingo Molnar. | 1733 | * Method suggested by Ingo Molnar. |
| 1691 | */ | 1734 | */ |
| 1692 | set_cpus_allowed(current, cpumask_of_cpu(0)); | 1735 | set_cpus_allowed_ptr(current, cpumask_of(0)); |
| 1693 | BUG_ON(smp_processor_id() != 0); | 1736 | BUG_ON(smp_processor_id() != 0); |
| 1694 | #endif | ||
| 1695 | 1737 | ||
| 1696 | if (apm_info.connection_version == 0) { | 1738 | if (apm_info.connection_version == 0) { |
| 1697 | apm_info.connection_version = apm_info.bios.version; | 1739 | apm_info.connection_version = apm_info.bios.version; |
