H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 1 | /* -*- linux-c -*- ------------------------------------------------------- * |
| 2 | * |
| 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
| 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
| 5 | * |
| 6 | * Original APM BIOS checking by Stephen Rothwell, May 1994 |
| 7 | * (sfr@canb.auug.org.au) |
| 8 | * |
| 9 | * This file is part of the Linux kernel, and is made available under |
| 10 | * the terms of the GNU General Public License version 2. |
| 11 | * |
| 12 | * ----------------------------------------------------------------------- */ |
| 13 | |
| 14 | /* |
| 15 | * arch/i386/boot/apm.c |
| 16 | * |
| 17 | * Get APM BIOS information |
| 18 | */ |
| 19 | |
| 20 | #include "boot.h" |
| 21 | |
| 22 | #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) |
| 23 | |
| 24 | int query_apm_bios(void) |
| 25 | { |
| 26 | u16 ax, bx, cx, dx, di; |
| 27 | u32 ebx, esi; |
| 28 | u8 err; |
| 29 | |
| 30 | /* APM BIOS installation check */ |
| 31 | ax = 0x5300; |
| 32 | bx = cx = 0; |
| 33 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0" |
| 34 | : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx) |
| 35 | : : "esi", "edi"); |
| 36 | |
| 37 | if (err) |
| 38 | return -1; /* No APM BIOS */ |
| 39 | |
| 40 | if (bx != 0x504d) /* "PM" signature */ |
| 41 | return -1; |
| 42 | |
Mikael Pettersson | 1514ab0 | 2007-07-24 00:25:59 +0200 | [diff] [blame] | 43 | if (!(cx & 0x02)) /* 32 bits supported? */ |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 44 | return -1; |
| 45 | |
| 46 | /* Disconnect first, just in case */ |
| 47 | ax = 0x5304; |
H. Peter Anvin | 1a13286 | 2007-07-23 15:37:14 -0700 | [diff] [blame] | 48 | bx = 0; |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 49 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp" |
H. Peter Anvin | 1a13286 | 2007-07-23 15:37:14 -0700 | [diff] [blame] | 50 | : "+a" (ax), "+b" (bx) |
| 51 | : : "ecx", "edx", "esi", "edi"); |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 52 | |
| 53 | /* Paranoia */ |
| 54 | ebx = esi = 0; |
| 55 | cx = dx = di = 0; |
| 56 | |
| 57 | /* 32-bit connect */ |
| 58 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6" |
| 59 | : "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx), |
| 60 | "+S" (esi), "+D" (di), "=m" (err) |
| 61 | : "a" (0x5303)); |
| 62 | |
| 63 | boot_params.apm_bios_info.cseg = ax; |
| 64 | boot_params.apm_bios_info.offset = ebx; |
| 65 | boot_params.apm_bios_info.cseg_16 = cx; |
| 66 | boot_params.apm_bios_info.dseg = dx; |
| 67 | boot_params.apm_bios_info.cseg_len = (u16)esi; |
| 68 | boot_params.apm_bios_info.cseg_16_len = esi >> 16; |
| 69 | boot_params.apm_bios_info.dseg_len = di; |
| 70 | |
| 71 | if (err) |
| 72 | return -1; |
| 73 | |
| 74 | /* Redo the installation check as the 32-bit connect; |
| 75 | some BIOSes return different flags this way... */ |
| 76 | |
| 77 | ax = 0x5300; |
| 78 | bx = cx = 0; |
| 79 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0" |
| 80 | : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx) |
| 81 | : : "esi", "edi"); |
| 82 | |
| 83 | if (err || bx != 0x504d) { |
| 84 | /* Failure with 32-bit connect, try to disconect and ignore */ |
| 85 | ax = 0x5304; |
| 86 | bx = 0; |
| 87 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp" |
| 88 | : "+a" (ax), "+b" (bx) |
| 89 | : : "ecx", "edx", "esi", "edi"); |
| 90 | return -1; |
| 91 | } |
| 92 | |
| 93 | boot_params.apm_bios_info.version = ax; |
| 94 | boot_params.apm_bios_info.flags = cx; |
| 95 | return 0; |
| 96 | } |
| 97 | |
| 98 | #endif |