aboutsummaryrefslogtreecommitdiff
path: root/com32/modules/poweroff.c
blob: 41e501e9362f406e12a79d7b02ade24b9be16706 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* ----------------------------------------------------------------------- *
 *
 *   Copyright 2013 Sebastian Herbszt - All Rights Reserved
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 *   Boston MA 02110-1301, USA; either version 2 of the License, or
 *   (at your option) any later version; incorporated herein by reference.
 *
 * ----------------------------------------------------------------------- */

/*
 * poweroff.c
 *
 * APM poweroff module
 */

#include <stdio.h>
#include <string.h>
#include <com32.h>

int main(int argc __unused, char *argv[] __unused)
{
	com32sys_t inregs, outregs;

	memset(&inregs, 0, sizeof inregs);

	inregs.eax.l = 0x5300; /* APM Installation Check (00h) */
	inregs.ebx.l = 0; /* APM BIOS (0000h) */
	__intcall(0x15, &inregs, &outregs);

	if (outregs.eflags.l & EFLAGS_CF) {
		printf("APM not present.\n");
		return 1;
	}

	if ((outregs.ebx.l & 0xffff) != 0x504d) { /* signature 'PM' */
		printf("APM not present.\n");
		return 1;
	}

	if ((outregs.eax.l & 0xffff) < 0x101) { /* Need version 1.1+ */
		printf("APM 1.1+ not supported.\n");
		return 1;
	}

	if ((outregs.ecx.l & 0x8) == 0x8) { /* bit 3 APM BIOS Power Management disabled */
		printf("Power management disabled.\n");
		return 1;
	}

	memset(&inregs, 0, sizeof inregs);
	inregs.eax.l = 0x5301; /* APM Real Mode Interface Connect (01h) */
	inregs.ebx.l = 0; /* APM BIOS (0000h) */
	__intcall(0x15, &inregs, &outregs);

	if (outregs.eflags.l & EFLAGS_CF) {
		printf("APM RM interface connect failed.\n");
		return 1;
	}

	memset(&inregs, 0, sizeof inregs);
	inregs.eax.l = 0x530e; /* APM Driver Version (0Eh) */
	inregs.ebx.l = 0; /* APM BIOS (0000h) */
	inregs.ecx.l = 0x101; /* APM Driver version 1.1 */
	__intcall(0x15, &inregs, &outregs);

	if (outregs.eflags.l & EFLAGS_CF) {
		printf("APM 1.1+ not supported.\n");
		return 1;
	}

	if ((outregs.ecx.l & 0xffff) < 0x101) { /* APM Connection version */
		printf("APM 1.1+ not supported.\n");
		return 1;
	}

	memset(&inregs, 0, sizeof inregs);
	inregs.eax.l = 0x5307; /* Set Power State (07h) */
	inregs.ebx.l = 1; /* All devices power managed by the APM BIOS */
	inregs.ecx.l = 3; /* Power state off */
	__intcall(0x15, &inregs, &outregs);

	if (outregs.eflags.l & EFLAGS_CF) {
		printf("Power off failed.\n");
		return 1;
	}

	return 0;
}