197873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
296ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
396ae6ea0SThomas Gleixner *
496ae6ea0SThomas Gleixner * Copyright (C) 1991, 1992 Linus Torvalds
596ae6ea0SThomas Gleixner * Copyright 2007 rPath, Inc. - All Rights Reserved
6d54ea252SH. Peter Anvin * Copyright 2009 Intel Corporation; author H. Peter Anvin
796ae6ea0SThomas Gleixner *
896ae6ea0SThomas Gleixner * Original APM BIOS checking by Stephen Rothwell, May 1994
996ae6ea0SThomas Gleixner * (sfr@canb.auug.org.au)
1096ae6ea0SThomas Gleixner *
1196ae6ea0SThomas Gleixner * ----------------------------------------------------------------------- */
1296ae6ea0SThomas Gleixner
1396ae6ea0SThomas Gleixner /*
1496ae6ea0SThomas Gleixner * Get APM BIOS information
1596ae6ea0SThomas Gleixner */
1696ae6ea0SThomas Gleixner
1796ae6ea0SThomas Gleixner #include "boot.h"
1896ae6ea0SThomas Gleixner
query_apm_bios(void)1996ae6ea0SThomas Gleixner int query_apm_bios(void)
2096ae6ea0SThomas Gleixner {
21d54ea252SH. Peter Anvin struct biosregs ireg, oreg;
2296ae6ea0SThomas Gleixner
2396ae6ea0SThomas Gleixner /* APM BIOS installation check */
24d54ea252SH. Peter Anvin initregs(&ireg);
25d54ea252SH. Peter Anvin ireg.ah = 0x53;
26d54ea252SH. Peter Anvin intcall(0x15, &ireg, &oreg);
2796ae6ea0SThomas Gleixner
28d54ea252SH. Peter Anvin if (oreg.flags & X86_EFLAGS_CF)
2996ae6ea0SThomas Gleixner return -1; /* No APM BIOS */
3096ae6ea0SThomas Gleixner
31d54ea252SH. Peter Anvin if (oreg.bx != 0x504d) /* "PM" signature */
3296ae6ea0SThomas Gleixner return -1;
3396ae6ea0SThomas Gleixner
34d54ea252SH. Peter Anvin if (!(oreg.cx & 0x02)) /* 32 bits supported? */
3596ae6ea0SThomas Gleixner return -1;
3696ae6ea0SThomas Gleixner
3796ae6ea0SThomas Gleixner /* Disconnect first, just in case */
38d54ea252SH. Peter Anvin ireg.al = 0x04;
39d54ea252SH. Peter Anvin intcall(0x15, &ireg, NULL);
4096ae6ea0SThomas Gleixner
4196ae6ea0SThomas Gleixner /* 32-bit connect */
42d54ea252SH. Peter Anvin ireg.al = 0x03;
43d54ea252SH. Peter Anvin intcall(0x15, &ireg, &oreg);
4496ae6ea0SThomas Gleixner
45d54ea252SH. Peter Anvin boot_params.apm_bios_info.cseg = oreg.ax;
46d54ea252SH. Peter Anvin boot_params.apm_bios_info.offset = oreg.ebx;
47d54ea252SH. Peter Anvin boot_params.apm_bios_info.cseg_16 = oreg.cx;
48d54ea252SH. Peter Anvin boot_params.apm_bios_info.dseg = oreg.dx;
49d54ea252SH. Peter Anvin boot_params.apm_bios_info.cseg_len = oreg.si;
50d54ea252SH. Peter Anvin boot_params.apm_bios_info.cseg_16_len = oreg.hsi;
51d54ea252SH. Peter Anvin boot_params.apm_bios_info.dseg_len = oreg.di;
5296ae6ea0SThomas Gleixner
53d54ea252SH. Peter Anvin if (oreg.flags & X86_EFLAGS_CF)
5496ae6ea0SThomas Gleixner return -1;
5596ae6ea0SThomas Gleixner
5696ae6ea0SThomas Gleixner /* Redo the installation check as the 32-bit connect;
5796ae6ea0SThomas Gleixner some BIOSes return different flags this way... */
5896ae6ea0SThomas Gleixner
59d54ea252SH. Peter Anvin ireg.al = 0x00;
60d54ea252SH. Peter Anvin intcall(0x15, &ireg, &oreg);
6196ae6ea0SThomas Gleixner
62d54ea252SH. Peter Anvin if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) {
63*023f270bSGeert Uytterhoeven /* Failure with 32-bit connect, try to disconnect and ignore */
64d54ea252SH. Peter Anvin ireg.al = 0x04;
65d54ea252SH. Peter Anvin intcall(0x15, &ireg, NULL);
6696ae6ea0SThomas Gleixner return -1;
6796ae6ea0SThomas Gleixner }
6896ae6ea0SThomas Gleixner
69d54ea252SH. Peter Anvin boot_params.apm_bios_info.version = oreg.ax;
70d54ea252SH. Peter Anvin boot_params.apm_bios_info.flags = oreg.cx;
7196ae6ea0SThomas Gleixner return 0;
7296ae6ea0SThomas Gleixner }
7396ae6ea0SThomas Gleixner
74