1/*
2 * Copyright 2006, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "apm.h"
8#include "bios.h"
9
10#include <boot/kernel_args.h>
11#include <boot/platform.h>
12#include <boot/stage2.h>
13
14
15//#define TRACE_APM
16#ifdef TRACE_APM
17#	define TRACE(x) dprintf x
18#else
19#	define TRACE(x) ;
20#endif
21
22
23status_t
24apm_init(void)
25{
26	// check if APM is available
27
28	struct bios_regs regs;
29	regs.eax = BIOS_APM_CHECK;
30	regs.ebx = 0;
31	call_bios(0x15, &regs);
32
33	if ((regs.flags & CARRY_FLAG) != 0
34		|| (regs.ebx & 0xffff) != 'PM') {
35		dprintf("No APM available.\n");
36		return B_ERROR;
37	}
38
39	const apm_info &info = gKernelArgs.platform_args.apm;
40	gKernelArgs.platform_args.apm.version = regs.eax & 0xffff;
41	gKernelArgs.platform_args.apm.flags = regs.ecx & 0xffff;
42
43	dprintf("APM version %d.%d available, flags %x.\n",
44		(info.version >> 8) & 0xf, info.version & 0xf, info.flags);
45
46	if ((info.version & 0xf) < 2) {
47		// 32-bit protected mode interface was not available before 1.2
48		return B_ERROR;
49	}
50
51	// there can always be one connection, so make sure we're
52	// the one - and disconnect
53
54	regs.eax = BIOS_APM_DISCONNECT;
55	regs.ebx = 0;
56	call_bios(0x15, &regs);
57		// We don't care if this fails - there might not have been
58		// any connection before.
59
60	// try to connect to the 32-bit interface
61
62	regs.eax = BIOS_APM_CONNECT_32_BIT;
63	regs.ebx = 0;
64	call_bios(0x15, &regs);
65	if ((regs.flags & CARRY_FLAG) != 0) {
66		// reset the version, so that the kernel won't try to use APM
67		gKernelArgs.platform_args.apm.version = 0;
68		return B_ERROR;
69	}
70
71	gKernelArgs.platform_args.apm.code32_segment_base = regs.eax & 0xffff;
72	gKernelArgs.platform_args.apm.code32_segment_offset = regs.ebx;
73	gKernelArgs.platform_args.apm.code32_segment_length = regs.esi & 0xffff;
74
75	gKernelArgs.platform_args.apm.code16_segment_base = regs.ecx & 0xffff;
76	gKernelArgs.platform_args.apm.code16_segment_length = regs.esi >> 16;
77
78	gKernelArgs.platform_args.apm.data_segment_base = regs.edx & 0xffff;
79	gKernelArgs.platform_args.apm.data_segment_length = regs.edi & 0xffff;
80
81	TRACE(("  code32: 0x%x, 0x%lx, length 0x%x\n",
82		info.code32_segment_base, info.code32_segment_offset, info.code32_segment_length));
83	TRACE(("  code16: 0x%x, length 0x%x\n",
84		info.code16_segment_base, info.code16_segment_length));
85	TRACE(("  data: 0x%x, length 0x%x\n",
86		info.data_segment_base, info.data_segment_length));
87
88	return B_OK;
89}
90