Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / src / apm.c
1 // Basic support for apmbios callbacks.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2005 Struan Bartlett
5 // Copyright (C) 2004 Fabrice Bellard
6 //
7 // This file may be distributed under the terms of the GNU LGPLv3 license.
8
9 #include "biosvar.h" // GET_GLOBAL
10 #include "bregs.h" // struct bregs
11 #include "config.h" // CONFIG_*
12 #include "output.h" // dprintf
13 #include "stacks.h" // yield_toirq
14 #include "util.h" // apm_shutdown
15 #include "x86.h" // outb
16
17 // APM installation check
18 static void
19 handle_155300(struct bregs *regs)
20 {
21     regs->ah = 1; // APM major version
22     regs->al = 2; // APM minor version
23     regs->bh = 'P';
24     regs->bl = 'M';
25     // bit 0 : 16 bit interface supported
26     // bit 1 : 32 bit interface supported
27     regs->cx = 0x03;
28     set_success(regs);
29 }
30
31 // APM real mode interface connect
32 static void
33 handle_155301(struct bregs *regs)
34 {
35     set_success(regs);
36 }
37
38 // APM 16 bit protected mode interface connect
39 static void
40 handle_155302(struct bregs *regs)
41 {
42     extern void entry_apm16(void);
43     regs->bx = (u32)entry_apm16;
44     regs->ax = SEG_BIOS; // 16 bit code segment base
45     regs->si = 0xfff0;   // 16 bit code segment size
46     regs->cx = SEG_BIOS; // data segment address
47     regs->di = 0xfff0;   // data segment length
48     set_success(regs);
49 }
50
51 // APM 32 bit protected mode interface connect
52 static void
53 handle_155303(struct bregs *regs)
54 {
55     extern void entry_apm32(void);
56     regs->ax = SEG_BIOS; // 32 bit code segment base
57     regs->ebx = (u32)entry_apm32;
58     regs->cx = SEG_BIOS; // 16 bit code segment base
59     // 32 bit code segment size (low 16 bits)
60     // 16 bit code segment size (high 16 bits)
61     regs->esi = 0xfff0fff0;
62     regs->dx = SEG_BIOS; // data segment address
63     regs->di = 0xfff0; // data segment length
64     set_success(regs);
65 }
66
67 // APM interface disconnect
68 static void
69 handle_155304(struct bregs *regs)
70 {
71     set_success(regs);
72 }
73
74 // APM cpu idle
75 static void
76 handle_155305(struct bregs *regs)
77 {
78     yield_toirq();
79     set_success(regs);
80 }
81
82 // APM cpu busy
83 static void
84 handle_155306(struct bregs *regs)
85 {
86     set_success(regs);
87 }
88
89 void
90 apm_shutdown(void)
91 {
92     u16 pm1a_cnt = GET_GLOBAL(acpi_pm1a_cnt);
93     if (pm1a_cnt)
94         outw(0x2000, pm1a_cnt);
95
96     irq_disable();
97     for (;;)
98         hlt();
99 }
100
101 // APM Set Power State
102 static void
103 handle_155307(struct bregs *regs)
104 {
105     if (regs->bx != 1) {
106         set_success(regs);
107         return;
108     }
109     switch (regs->cx) {
110     case 1:
111         dprintf(1, "APM standby request\n");
112         break;
113     case 2:
114         dprintf(1, "APM suspend request\n");
115         break;
116     case 3:
117         apm_shutdown();
118         break;
119     }
120     set_success(regs);
121 }
122
123 static void
124 handle_155308(struct bregs *regs)
125 {
126     set_success(regs);
127 }
128
129 // Get Power Status
130 static void
131 handle_15530a(struct bregs *regs)
132 {
133     regs->bh = 0x01; // on line
134     regs->bl = 0xff; // unknown battery status
135     regs->ch = 0x80; // no system battery
136     regs->cl = 0xff; // unknown remaining time
137     regs->dx = 0xffff; // unknown remaining time
138     regs->si = 0x00; // zero battery
139     set_success(regs);
140 }
141
142 #define RET_ENOEVENT 0x80
143
144 // Get PM Event
145 static void
146 handle_15530b(struct bregs *regs)
147 {
148     set_code_invalid_silent(regs, RET_ENOEVENT);
149 }
150
151 // APM Driver Version
152 static void
153 handle_15530e(struct bregs *regs)
154 {
155     regs->ah = 1;
156     regs->al = 2;
157     set_success(regs);
158 }
159
160 // APM Engage / Disengage
161 static void
162 handle_15530f(struct bregs *regs)
163 {
164     set_success(regs);
165 }
166
167 // APM Get Capabilities
168 static void
169 handle_155310(struct bregs *regs)
170 {
171     regs->bl = 0;
172     regs->cx = 0;
173     set_success(regs);
174 }
175
176 static void
177 handle_1553XX(struct bregs *regs)
178 {
179     set_unimplemented(regs);
180 }
181
182 void
183 handle_1553(struct bregs *regs)
184 {
185     if (! CONFIG_APMBIOS) {
186         set_code_invalid(regs, RET_EUNSUPPORTED);
187         return;
188     }
189
190     //debug_stub(regs);
191     switch (regs->al) {
192     case 0x00: handle_155300(regs); break;
193     case 0x01: handle_155301(regs); break;
194     case 0x02: handle_155302(regs); break;
195     case 0x03: handle_155303(regs); break;
196     case 0x04: handle_155304(regs); break;
197     case 0x05: handle_155305(regs); break;
198     case 0x06: handle_155306(regs); break;
199     case 0x07: handle_155307(regs); break;
200     case 0x08: handle_155308(regs); break;
201     case 0x0a: handle_15530a(regs); break;
202     case 0x0b: handle_15530b(regs); break;
203     case 0x0e: handle_15530e(regs); break;
204     case 0x0f: handle_15530f(regs); break;
205     case 0x10: handle_155310(regs); break;
206     default:   handle_1553XX(regs); break;
207     }
208 }
209
210 void VISIBLE16 VISIBLE32SEG
211 handle_apm(struct bregs *regs)
212 {
213     debug_enter(regs, DEBUG_HDL_apm);
214     handle_1553(regs);
215 }