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