162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- *
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *   Copyright (C) 1991, 1992 Linus Torvalds
562306a36Sopenharmony_ci *   Copyright 2007 rPath, Inc. - All Rights Reserved
662306a36Sopenharmony_ci *   Copyright 2009 Intel Corporation; author H. Peter Anvin
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *   Original APM BIOS checking by Stephen Rothwell, May 1994
962306a36Sopenharmony_ci *   (sfr@canb.auug.org.au)
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * ----------------------------------------------------------------------- */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * Get APM BIOS information
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "boot.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciint query_apm_bios(void)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct biosregs ireg, oreg;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	/* APM BIOS installation check */
2462306a36Sopenharmony_ci	initregs(&ireg);
2562306a36Sopenharmony_ci	ireg.ah = 0x53;
2662306a36Sopenharmony_ci	intcall(0x15, &ireg, &oreg);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (oreg.flags & X86_EFLAGS_CF)
2962306a36Sopenharmony_ci		return -1;		/* No APM BIOS */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	if (oreg.bx != 0x504d)		/* "PM" signature */
3262306a36Sopenharmony_ci		return -1;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (!(oreg.cx & 0x02))		/* 32 bits supported? */
3562306a36Sopenharmony_ci		return -1;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	/* Disconnect first, just in case */
3862306a36Sopenharmony_ci	ireg.al = 0x04;
3962306a36Sopenharmony_ci	intcall(0x15, &ireg, NULL);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/* 32-bit connect */
4262306a36Sopenharmony_ci	ireg.al = 0x03;
4362306a36Sopenharmony_ci	intcall(0x15, &ireg, &oreg);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	boot_params.apm_bios_info.cseg        = oreg.ax;
4662306a36Sopenharmony_ci	boot_params.apm_bios_info.offset      = oreg.ebx;
4762306a36Sopenharmony_ci	boot_params.apm_bios_info.cseg_16     = oreg.cx;
4862306a36Sopenharmony_ci	boot_params.apm_bios_info.dseg        = oreg.dx;
4962306a36Sopenharmony_ci	boot_params.apm_bios_info.cseg_len    = oreg.si;
5062306a36Sopenharmony_ci	boot_params.apm_bios_info.cseg_16_len = oreg.hsi;
5162306a36Sopenharmony_ci	boot_params.apm_bios_info.dseg_len    = oreg.di;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (oreg.flags & X86_EFLAGS_CF)
5462306a36Sopenharmony_ci		return -1;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/* Redo the installation check as the 32-bit connect;
5762306a36Sopenharmony_ci	   some BIOSes return different flags this way... */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	ireg.al = 0x00;
6062306a36Sopenharmony_ci	intcall(0x15, &ireg, &oreg);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) {
6362306a36Sopenharmony_ci		/* Failure with 32-bit connect, try to disconnect and ignore */
6462306a36Sopenharmony_ci		ireg.al = 0x04;
6562306a36Sopenharmony_ci		intcall(0x15, &ireg, NULL);
6662306a36Sopenharmony_ci		return -1;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	boot_params.apm_bios_info.version = oreg.ax;
7062306a36Sopenharmony_ci	boot_params.apm_bios_info.flags   = oreg.cx;
7162306a36Sopenharmony_ci	return 0;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
74