| 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 |  |