3 * Advanced Power Management BIOS library.
4 * (C) 2009-2012 Jonathan Campbell.
5 * Hackipedia DOS library.
7 * This code is licensed under the LGPL.
8 * <insert LGPL legal text here>
10 * Compiles for intended target environments:
11 * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
13 * This library is intended for DOS programs that want to communicate with the APM
14 * BIOS interface on PC systems made since about 1994. Note that on systems built
15 * since 1999 you may want to use the ACPI BIOS instead, however that interface is
16 * quite a bit more complex. */
19 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
29 #include <hw/dos/dos.h>
30 #include <hw/apm/apm.h>
31 #include <hw/8254/8254.h> /* 8254 timer */
32 #include <hw/8259/8259.h> /* 8259 PIC */
34 struct apm_bios_ctx *apm_bios = NULL;
36 #if TARGET_MSDOS == 32
37 static void apm_bios_rm_call(struct dpmi_realmode_call *rc) {
42 mov edi,rc ; we trust Watcom has left ES == DS
48 void apm_bios_free() {
49 if (apm_bios) free(apm_bios);
53 int apm_bios_probe() { /* 8.8 version */
56 apm_bios = (struct apm_bios_ctx*)malloc(sizeof(*apm_bios));
57 if (apm_bios == NULL) return 0;
58 memset(apm_bios,0,sizeof(*apm_bios));
60 apm_bios->version_want = 0x102;
61 apm_bios->major_neg = 1;
62 apm_bios->minor_neg = 0;
64 #if TARGET_MSDOS == 32
66 struct dpmi_realmode_call rc={0};
67 rc.eax = 0x5300; /* AH=0x53 A=0x00 */
68 apm_bios_rm_call(&rc);
69 if (!(rc.flags & 1)) { /* CF=0 */
70 apm_bios->major = (rc.eax >> 8) & 0xFF;
71 apm_bios->minor = (rc.eax & 0xFF);
72 apm_bios->signature = (rc.ebx & 0xFFFF);
73 apm_bios->flags = (rc.ecx & 0xFFFF);
83 #if defined(__LARGE__) || defined(__COMPACT__)
85 mov si,seg apm_bios ; we need DS = segment of apm_bios variable
87 lds si,apm_bios ; DS:SI = apm_bios
91 mov byte ptr [si+0],ah
92 mov byte ptr [si+1],al
93 mov word ptr [si+2],bx
94 mov word ptr [si+4],cx
95 #if defined(__LARGE__) || defined(__COMPACT__)
102 return (apm_bios->signature == APM_PM_SIG);
105 void apm_bios_update_capabilities() {
106 apm_bios->capabilities = 0;
107 apm_bios->batteries = 0;
109 #if TARGET_MSDOS == 32
111 struct dpmi_realmode_call rc={0};
113 apm_bios_rm_call(&rc);
114 if (!(rc.flags & 1)) { /* CF=0 */
115 apm_bios->capabilities = rc.ecx & 0xFFFF;
116 apm_bios->batteries = rc.ebx & 0xFF;
121 unsigned char bat=0,err=0;
122 unsigned short cap=0;
135 apm_bios->capabilities = cap;
136 apm_bios->batteries = bat;
142 /* FIXME: For the protected mode calls, this code needs to save AX, BX, CX, (E)SI, and (E)DI
143 * which contain all the info needed for protected mode selectors */
144 int apm_bios_connect(int n) {
147 if (apm_bios == NULL)
149 if (n < APM_CONNECT_NONE || n > APM_CONNECT_32_PM)
151 if (n == APM_CONNECT_NONE)
152 n = 0x04; /* AH=0x04 disconnect function */
154 /* NTS: for now, only the real-mode interface */
155 if (n == APM_CONNECT_16_PM || n == APM_CONNECT_32_PM)
156 return 0; /* anything but real mode not supported */
158 #if TARGET_MSDOS == 32
160 struct dpmi_realmode_call rc={0};
161 rc.eax = 0x5300+n; /* AH=0x53 A=0x01-0x04 */
162 apm_bios_rm_call(&rc);
163 if (rc.flags & 1) { /* CF=1 */
164 err = (rc.eax >> 8) & 0xFF;
179 /* translate "n" back to enum */
180 if (n == 0x04) n = APM_CONNECT_NONE;
182 /* success: BIOS returns success, or disconnect (AH=4) command says "not connected" */
183 if (err == 0x00 || (err == 0x03 && n == 0x04)) {
184 apm_bios->connection = n;
186 else if (err == 0x02) { /* err code 2 real mode interface connected */
187 apm_bios->connection = APM_CONNECT_REALMODE;
189 else if (err == 0x05) { /* err code 5 16-bit prot mode interface connected */
190 apm_bios->connection = APM_CONNECT_16_PM;
192 else if (err == 0x07) { /* err code 2 32-bit prot mode interface connected */
193 apm_bios->connection = APM_CONNECT_32_PM;
196 /* if transitioning to an interface, negotiate a newer API */
197 if (err == 0x00 && n > APM_CONNECT_NONE) {
198 unsigned int neg_ver = apm_bios->version_want;
199 unsigned short ww = 0;
201 apm_bios->major_neg = 1;
202 apm_bios->minor_neg = 0;
203 if (apm_bios->major == 1 && apm_bios->minor != 0 && neg_ver >= 0x101 && neg_ver <= 0x1FF) {
204 #if TARGET_MSDOS == 32
206 struct dpmi_realmode_call rc={0};
209 apm_bios_rm_call(&rc);
210 if (!(rc.flags & 1)) { /* CF=0 */
211 ww = rc.eax & 0xFFFF;
226 if (ww >= 0x101 && ww <= 0x1FF) {
227 apm_bios->major_neg = ww >> 8;
228 apm_bios->minor_neg = ww & 0xFF;
233 if (n > APM_CONNECT_NONE && apm_bios->connection == APM_CONNECT_NONE)
234 apm_bios_update_capabilities();
236 apm_bios->last_error = err;
237 return (apm_bios->connection == n);
240 int apm_bios_cpu_busy() {
243 #if TARGET_MSDOS == 32
245 struct dpmi_realmode_call rc={0};
247 apm_bios_rm_call(&rc);
248 if (rc.flags & 1) { /* CF=1 */
249 err = (rc.eax >> 8) & 0xFF;
265 int apm_bios_cpu_idle() {
268 #if TARGET_MSDOS == 32
270 struct dpmi_realmode_call rc={0};
272 apm_bios_rm_call(&rc);
273 if (rc.flags & 1) { /* CF=1 */
274 err = (rc.eax >> 8) & 0xFF;
290 signed long apm_bios_pm_evnet() {
291 unsigned short ev=0,info=0;
293 #if TARGET_MSDOS == 32
295 struct dpmi_realmode_call rc={0};
297 apm_bios_rm_call(&rc);
298 if (!(rc.flags & 1)) { /* CF=0 */
299 ev = rc.ebx & 0xFFFF;
300 info = rc.ecx & 0xFFFF;
314 return (ev == 0 ? -1LL : (unsigned long)ev);
317 void apm_bios_update_status() {
318 #if TARGET_MSDOS == 32
320 struct dpmi_realmode_call rc={0};
322 apm_bios_rm_call(&rc);
323 if (!(rc.flags & 1)) { /* CF=0 */
324 apm_bios->status_ac = (rc.ebx >> 8) & 0xFF;
325 apm_bios->status_battery = (rc.ebx & 0xFF);
326 apm_bios->status_battery_flag = (rc.ecx >> 8) & 0xFF;
327 apm_bios->status_battery_life = (rc.ecx & 0xFF);
328 apm_bios->status_battery_time = rc.edx & 0xFFFF;
333 unsigned short b=0,c=0,d=0;
345 apm_bios->status_ac = (b >> 8) & 0xFF;
346 apm_bios->status_battery = (b & 0xFF);
347 apm_bios->status_battery_flag = (c >> 8) & 0xFF;
348 apm_bios->status_battery_life = (c & 0xFF);
349 apm_bios->status_battery_time = d & 0xFFFF;
354 int apm_bios_power_state(unsigned short state) {
357 #if TARGET_MSDOS == 32
359 struct dpmi_realmode_call rc={0};
363 apm_bios_rm_call(&rc);
364 if (rc.flags & 1) { /* CF=0 */
365 err = (rc.eax >> 8) & 0xFF;