18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- *
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *   Copyright (C) 1991, 1992 Linus Torvalds
58c2ecf20Sopenharmony_ci *   Copyright 2007 rPath, Inc. - All Rights Reserved
68c2ecf20Sopenharmony_ci *   Copyright 2009 Intel Corporation; author H. Peter Anvin
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *   Original APM BIOS checking by Stephen Rothwell, May 1994
98c2ecf20Sopenharmony_ci *   (sfr@canb.auug.org.au)
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * ----------------------------------------------------------------------- */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * Get APM BIOS information
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "boot.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciint query_apm_bios(void)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct biosregs ireg, oreg;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	/* APM BIOS installation check */
248c2ecf20Sopenharmony_ci	initregs(&ireg);
258c2ecf20Sopenharmony_ci	ireg.ah = 0x53;
268c2ecf20Sopenharmony_ci	intcall(0x15, &ireg, &oreg);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	if (oreg.flags & X86_EFLAGS_CF)
298c2ecf20Sopenharmony_ci		return -1;		/* No APM BIOS */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	if (oreg.bx != 0x504d)		/* "PM" signature */
328c2ecf20Sopenharmony_ci		return -1;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (!(oreg.cx & 0x02))		/* 32 bits supported? */
358c2ecf20Sopenharmony_ci		return -1;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* Disconnect first, just in case */
388c2ecf20Sopenharmony_ci	ireg.al = 0x04;
398c2ecf20Sopenharmony_ci	intcall(0x15, &ireg, NULL);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	/* 32-bit connect */
428c2ecf20Sopenharmony_ci	ireg.al = 0x03;
438c2ecf20Sopenharmony_ci	intcall(0x15, &ireg, &oreg);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.cseg        = oreg.ax;
468c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.offset      = oreg.ebx;
478c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.cseg_16     = oreg.cx;
488c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.dseg        = oreg.dx;
498c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.cseg_len    = oreg.si;
508c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.cseg_16_len = oreg.hsi;
518c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.dseg_len    = oreg.di;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (oreg.flags & X86_EFLAGS_CF)
548c2ecf20Sopenharmony_ci		return -1;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/* Redo the installation check as the 32-bit connect;
578c2ecf20Sopenharmony_ci	   some BIOSes return different flags this way... */
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	ireg.al = 0x00;
608c2ecf20Sopenharmony_ci	intcall(0x15, &ireg, &oreg);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) {
638c2ecf20Sopenharmony_ci		/* Failure with 32-bit connect, try to disconnect and ignore */
648c2ecf20Sopenharmony_ci		ireg.al = 0x04;
658c2ecf20Sopenharmony_ci		intcall(0x15, &ireg, NULL);
668c2ecf20Sopenharmony_ci		return -1;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.version = oreg.ax;
708c2ecf20Sopenharmony_ci	boot_params.apm_bios_info.flags   = oreg.cx;
718c2ecf20Sopenharmony_ci	return 0;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
74