1//  APM BIOS support for the Bochs BIOS
2//  Copyright (C) 2004 Fabrice Bellard
3//
4//  Debugging extensions, 16-bit interface and extended power options
5//  Copyright (C) 2005 Struan Bartlett
6//
7//  This library is free software; you can redistribute it and/or
8//  modify it under the terms of the GNU Lesser General Public
9//  License as published by the Free Software Foundation; either
10//  version 2 of the License, or (at your option) any later version.
11//
12//  This library is distributed in the hope that it will be useful,
13//  but WITHOUT ANY WARRANTY; without even the implied warranty of
14//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15//  Lesser General Public License for more details.
16//
17//  You should have received a copy of the GNU Lesser General Public
18//  License along with this library; If not, see <http://www.gnu.org/licenses/>.
19
20#if defined(APM_REAL)
21#define APMSYM(s) apmreal_ ## s
22#elif defined(APM_PROT16)
23#define APMSYM(s) apm16_ ## s
24#elif defined(APM_PROT32)
25#define APMSYM(s) apm32_ ## s
26#else
27#error unsupported APM mode
28#endif
29
30APMSYM(out_str):
31  push eax
32  push ebx
33  mov ebx, eax
34APMSYM(out_str1):
35  SEG CS
36  mov al, byte ptr [bx]
37  cmp al, #0
38  je APMSYM(out_str2)
39  outb dx, al
40  inc ebx
41  jmp APMSYM(out_str1)
42APMSYM(out_str2):
43  pop ebx
44  pop eax
45  ret
46
47APMSYM(07_poweroff_str):
48  .ascii "Shutdown"
49  db 0
50APMSYM(07_suspend_str):
51  .ascii "Suspend"
52  db 0
53APMSYM(07_standby_str):
54  .ascii "Standby"
55  db 0
56
57#if DEBUG_APM
58APMSYM(put_str):
59  push edx
60  mov dx, #INFO_PORT
61  call APMSYM(out_str)
62  pop edx
63  ret
64
65; print the hex number in eax
66APMSYM(put_num):
67  push eax
68  push ebx
69  push ecx
70  push edx
71  mov ecx, eax
72  mov bx, #8
73  mov dx, #INFO_PORT
74APMSYM(put_num1):
75  mov eax, ecx
76  shr eax, #28
77  add al, #0x30
78  cmp al, #0x39
79  jbe APMSYM(put_num2)
80  add al, #0x27
81APMSYM(put_num2):
82  outb dx, al
83  shl ecx, #4
84  dec bx
85  jne APMSYM(put_num1)
86  pop edx
87  pop ecx
88  pop ebx
89  pop eax
90  ret
91
92APMSYM(put_reg):
93  outb dx, al
94  shr eax, #8
95  outb dx, al
96  shr eax, #8
97  outb dx, al
98  shr eax, #8
99  outb dx, al
100
101  mov eax,ebx
102  call APMSYM(put_num)
103
104  mov al, #0x3b
105  outb dx,al
106  mov al, #0x20
107  outb dx,al
108  ret
109
110APMSYM(put_regs):
111  push eax
112  push edx
113  push ebx
114  mov dx, #INFO_PORT
115
116  mov ebx, eax
117  mov eax, #0x3d584145 // 'EAX='
118  call APMSYM(put_reg)
119  pop ebx
120  push ebx
121  mov eax, #0x3d584245 // 'EBX='
122  call APMSYM(put_reg)
123  mov ebx, ecx
124  mov eax, #0x3d584345 // 'ECX='
125  call APMSYM(put_reg)
126  mov ebx, edx
127  mov eax, #0x3d584445 // 'EDX='
128  call APMSYM(put_reg)
129  mov ebx, esi
130  mov eax, #0x3d495345 // 'ESI='
131  call APMSYM(put_reg)
132  mov ebx, edi
133  mov eax, #0x3d494445 // 'EDI='
134  call APMSYM(put_reg)
135
136  mov al, #0x0a
137  outb dx, al
138  pop ebx
139  pop edx
140  pop eax
141  ret
142#endif
143
144#if defined(APM_PROT32)
145_apm32_entry:
146#endif
147#if defined(APM_PROT16)
148_apm16_entry:
149#endif
150  pushf
151
152#if defined(APM_REAL)
153_apmreal_entry:
154#endif
155
156#if DEBUG_APM
157  call APMSYM(put_regs)
158#endif
159
160#if defined(APM_REAL)
161;-----------------
162; APM installation check
163APMSYM(00):
164  cmp al, #0x00
165  jne APMSYM(01)
166
167  mov ah, #1 // APM major version
168  mov al, #2 // APM minor version
169
170  mov bh, #0x50 // 'P'
171  mov bl, #0x4d // 'M'
172
173  // bit 0 : 16 bit interface supported
174  // bit 1 : 32 bit interface supported
175  mov cx, #0x3
176  jmp APMSYM(ok)
177
178;-----------------
179; APM real mode interface connect
180APMSYM(01):
181  cmp al, #0x01
182  jne APMSYM(02)
183  jmp APMSYM(ok)
184
185;-----------------
186; APM 16 bit protected mode interface connect
187APMSYM(02):
188  cmp al, #0x02
189  jne APMSYM(03)
190
191  mov bx, #_apm16_entry
192
193  mov ax, #0xf000 // 16 bit code segment base
194  mov si, #0xfff0 // 16 bit code segment size
195  mov cx, #0xf000 // data segment address
196  mov di, #0xfff0 // data segment length
197  jmp APMSYM(ok)
198
199;-----------------
200; APM 32 bit protected mode interface connect
201APMSYM(03):
202  cmp al, #0x03
203  jne APMSYM(04)
204  mov ax, #0xf000 // 32 bit code segment base
205  mov ebx, #_apm32_entry
206  mov cx, #0xf000 // 16 bit code segment base
207  // 32 bit code segment size (low 16 bits)
208  // 16 bit code segment size (high 16 bits)
209  mov esi, #0xfff0fff0
210  mov dx, #0xf000 // data segment address
211  mov di, #0xfff0 // data segment length
212  jmp APMSYM(ok)
213#endif
214
215;-----------------
216; APM interface disconnect
217APMSYM(04):
218  cmp al, #0x04
219  jne APMSYM(05)
220  jmp APMSYM(ok)
221
222;-----------------
223; APM cpu idle
224APMSYM(05):
225  cmp al, #0x05
226  jne APMSYM(07)
227  pushf ; XEN
228  sti   ; XEN: OS calls us with ints disabled -- better re-enable here!
229  hlt
230  popf  ; XEN
231  jmp APMSYM(ok)
232
233;-----------------
234; APM Set Power State
235APMSYM(07):
236  cmp al, #0x07
237  jne APMSYM(08)
238
239  cmp bx, #1
240  jne APMSYM(ok)
241
242  cmp cx, #3
243  je APMSYM(07_poweroff)
244
245  cmp cx, #2
246  je APMSYM(07_suspend)
247
248  cmp cx, #1
249  je APMSYM(07_standby)
250
251  jne APMSYM(ok)
252
253APMSYM(07_poweroff):
254  // send power off event to emulator
255  cli
256  mov dx, #0x8900
257  mov ax, #APMSYM(07_poweroff_str)
258  call APMSYM(out_str)
259
260APMSYM(07_1):
261  hlt
262  jmp APMSYM(07_1)
263
264APMSYM(07_suspend):
265  push edx
266  mov dx, #0x8900
267  mov ax, #APMSYM(07_suspend_str)
268  call APMSYM(out_str)
269  pop edx
270  jmp APMSYM(ok)
271
272APMSYM(07_standby):
273  push edx
274  mov dx, #0x8900
275  mov ax, #APMSYM(07_standby_str)
276  call APMSYM(out_str)
277  pop edx
278  jmp APMSYM(ok)
279
280;-----------------
281; APM Enable / Disable
282APMSYM(08):
283  cmp al, #0x08
284  jne APMSYM(0a)
285
286  jmp APMSYM(ok)
287
288;-----------------
289; Get Power Status
290APMSYM(0a):
291  cmp al, #0x0a
292  jne APMSYM(0b)
293  mov bh, #0x01 // on line
294  // mov bh, #0x02 // battery
295  mov bl, #0xff // unknown battery status
296  // mov bl, #0x03 // charging
297  mov ch, #0x80 // no system battery
298  // mov ch, #0x8 // charging
299  mov cl, #0xff // unknown remaining time
300  // mov cl, #50
301  mov dx, #0xffff // unknown remaining time
302  mov si, #0      // zero battery
303  // mov si, #1      // one battery
304  jmp APMSYM(ok)
305
306;-----------------
307; Get PM Event
308APMSYM(0b):
309  cmp al, #0x0b
310  jne APMSYM(0e)
311  mov ah, #0x80 // no event pending
312  jmp APMSYM(error)
313
314;-----------------
315; APM Driver Version
316APMSYM(0e):
317  cmp al, #0x0e
318  jne APMSYM(0f)
319
320  mov ah, #1
321  mov al, #2
322
323  jmp APMSYM(ok)
324
325;-----------------
326; APM Engage / Disengage
327APMSYM(0f):
328  cmp al, #0x0f
329  jne APMSYM(10)
330
331  jmp APMSYM(ok)
332
333;-----------------
334; APM Get Capabilities
335APMSYM(10):
336  cmp al, #0x10
337  jne APMSYM(unimplemented)
338
339  mov bl, #0
340  mov cx, #0
341
342  jmp APMSYM(ok)
343
344;-----------------
345APMSYM(ok):
346  popf
347  clc
348#if defined(APM_REAL)
349  jmp iret_modify_cf
350#else
351  retf
352#endif
353APMSYM(unimplemented):
354APMSYM(error):
355  popf
356  stc
357#if defined(APM_REAL)
358  jmp iret_modify_cf
359#else
360  retf
361#endif
362
363#undef APM_PROT32
364#undef APM_PROT16
365#undef APM_REAL
366#undef APMSYM
367