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 |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 6 | * |
| 7 | * Original APM BIOS checking by Stephen Rothwell, May 1994 |
| 8 | * (sfr@canb.auug.org.au) |
| 9 | * |
| 10 | * This file is part of the Linux kernel, and is made available under |
| 11 | * the terms of the GNU General Public License version 2. |
| 12 | * |
| 13 | * ----------------------------------------------------------------------- */ |
| 14 | |
| 15 | /* |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 16 | * Get APM BIOS information |
| 17 | */ |
| 18 | |
| 19 | #include "boot.h" |
| 20 | |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 21 | int query_apm_bios(void) |
| 22 | { |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 23 | struct biosregs ireg, oreg; |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 24 | |
| 25 | /* APM BIOS installation check */ |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 26 | initregs(&ireg); |
| 27 | ireg.ah = 0x53; |
| 28 | intcall(0x15, &ireg, &oreg); |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 29 | |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 30 | if (oreg.flags & X86_EFLAGS_CF) |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 31 | return -1; /* No APM BIOS */ |
| 32 | |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 33 | if (oreg.bx != 0x504d) /* "PM" signature */ |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 34 | return -1; |
| 35 | |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 36 | if (!(oreg.cx & 0x02)) /* 32 bits supported? */ |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 37 | return -1; |
| 38 | |
| 39 | /* Disconnect first, just in case */ |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 40 | ireg.al = 0x04; |
| 41 | intcall(0x15, &ireg, NULL); |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 42 | |
| 43 | /* 32-bit connect */ |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 44 | ireg.al = 0x03; |
| 45 | intcall(0x15, &ireg, &oreg); |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 46 | |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 47 | boot_params.apm_bios_info.cseg = oreg.ax; |
| 48 | boot_params.apm_bios_info.offset = oreg.ebx; |
| 49 | boot_params.apm_bios_info.cseg_16 = oreg.cx; |
| 50 | boot_params.apm_bios_info.dseg = oreg.dx; |
| 51 | boot_params.apm_bios_info.cseg_len = oreg.si; |
| 52 | boot_params.apm_bios_info.cseg_16_len = oreg.hsi; |
| 53 | boot_params.apm_bios_info.dseg_len = oreg.di; |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 54 | |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 55 | if (oreg.flags & X86_EFLAGS_CF) |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 56 | return -1; |
| 57 | |
| 58 | /* Redo the installation check as the 32-bit connect; |
| 59 | some BIOSes return different flags this way... */ |
| 60 | |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 61 | ireg.al = 0x00; |
| 62 | intcall(0x15, &ireg, &oreg); |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 63 | |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 64 | if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) { |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 65 | /* Failure with 32-bit connect, try to disconect and ignore */ |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 66 | ireg.al = 0x04; |
| 67 | intcall(0x15, &ireg, NULL); |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 68 | return -1; |
| 69 | } |
| 70 | |
H. Peter Anvin | d54ea25 | 2009-04-01 18:14:26 -0700 | [diff] [blame] | 71 | boot_params.apm_bios_info.version = oreg.ax; |
| 72 | boot_params.apm_bios_info.flags = oreg.cx; |
H. Peter Anvin | 49df18f | 2007-07-11 12:18:43 -0700 | [diff] [blame] | 73 | return 0; |
| 74 | } |
| 75 | |