xref: /haiku/src/system/boot/platform/bios_ia32/apm.cpp (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
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 
23 status_t
24 apm_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