Distinguish between debug reports for unimplemented vs invalid calls.
[seabios.git] / 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 "farptr.h" // GET_VAR
10 #include "bregs.h" // struct bregs
11 #include "ioport.h" // outb
12 #include "util.h" // wait_irq
13 #include "config.h" // CONFIG_*
14 #include "biosvar.h" // GET_GLOBAL
15
16 static void
17 out_str(const char *str_cs)
18 {
19     if (CONFIG_COREBOOT) {
20         dprintf(1, "APM request '%s'\n", str_cs);
21         return;
22     }
23
24     u8 *s = (u8*)str_cs;
25     for (;;) {
26         u8 c = GET_GLOBAL(*s);
27         if (!c)
28             break;
29         outb(c, PORT_BIOS_APM);
30         s++;
31     }
32 }
33
34 // APM installation check
35 static void
36 handle_155300(struct bregs *regs)
37 {
38     regs->ah = 1; // APM major version
39     regs->al = 2; // APM minor version
40     regs->bh = 'P';
41     regs->bl = 'M';
42     // bit 0 : 16 bit interface supported
43     // bit 1 : 32 bit interface supported
44     regs->cx = 0x03;
45     set_success(regs);
46 }
47
48 // APM real mode interface connect
49 static void
50 handle_155301(struct bregs *regs)
51 {
52     set_success(regs);
53 }
54
55 // Assembler entry points defined in romlayout.S
56 extern void apm16protected_entry();
57 extern void apm32protected_entry();
58
59 // APM 16 bit protected mode interface connect
60 static void
61 handle_155302(struct bregs *regs)
62 {
63     regs->bx = (u32)apm16protected_entry;
64     regs->ax = SEG_BIOS; // 16 bit code segment base
65     regs->si = 0xfff0;   // 16 bit code segment size
66     regs->cx = SEG_BIOS; // data segment address
67     regs->di = 0xfff0;   // data segment length
68     set_success(regs);
69 }
70
71 // APM 32 bit protected mode interface connect
72 static void
73 handle_155303(struct bregs *regs)
74 {
75     regs->ax = SEG_BIOS; // 32 bit code segment base
76     regs->ebx = (u32)apm32protected_entry;
77     regs->cx = SEG_BIOS; // 16 bit code segment base
78     // 32 bit code segment size (low 16 bits)
79     // 16 bit code segment size (high 16 bits)
80     regs->esi = 0xfff0fff0;
81     regs->dx = SEG_BIOS; // data segment address
82     regs->di = 0xfff0; // data segment length
83     set_success(regs);
84 }
85
86 // APM interface disconnect
87 static void
88 handle_155304(struct bregs *regs)
89 {
90     set_success(regs);
91 }
92
93 // APM cpu idle
94 static void
95 handle_155305(struct bregs *regs)
96 {
97     wait_irq();
98     set_success(regs);
99 }
100
101 // APM cpu busy
102 static void
103 handle_155306(struct bregs *regs)
104 {
105     set_success(regs);
106 }
107
108 // APM Set Power State
109 static void
110 handle_155307(struct bregs *regs)
111 {
112     if (regs->bx != 1) {
113         set_success(regs);
114         return;
115     }
116     switch (regs->cx) {
117     case 1:
118         out_str("Standby");
119         break;
120     case 2:
121         out_str("Suspend");
122         break;
123     case 3:
124         irq_disable();
125         out_str("Shutdown");
126         for (;;)
127             hlt();
128         break;
129     }
130     set_success(regs);
131 }
132
133 static void
134 handle_155308(struct bregs *regs)
135 {
136     set_success(regs);
137 }
138
139 // Get Power Status
140 static void
141 handle_15530a(struct bregs *regs)
142 {
143     regs->bh = 0x01; // on line
144     regs->bl = 0xff; // unknown battery status
145     regs->ch = 0x80; // no system battery
146     regs->cl = 0xff; // unknown remaining time
147     regs->dx = 0xffff; // unknown remaining time
148     regs->si = 0x00; // zero battery
149     set_success(regs);
150 }
151
152 #define RET_ENOEVENT 0x80
153
154 // Get PM Event
155 static void
156 handle_15530b(struct bregs *regs)
157 {
158     set_code_invalid_silent(regs, RET_ENOEVENT);
159 }
160
161 // APM Driver Version
162 static void
163 handle_15530e(struct bregs *regs)
164 {
165     regs->ah = 1;
166     regs->al = 2;
167     set_success(regs);
168 }
169
170 // APM Engage / Disengage
171 static void
172 handle_15530f(struct bregs *regs)
173 {
174     set_success(regs);
175 }
176
177 // APM Get Capabilities
178 static void
179 handle_155310(struct bregs *regs)
180 {
181     regs->bl = 0;
182     regs->cx = 0;
183     set_success(regs);
184 }
185
186 static void
187 handle_1553XX(struct bregs *regs)
188 {
189     set_unimplemented(regs);
190 }
191
192 void VISIBLE16
193 handle_1553(struct bregs *regs)
194 {
195     if (! CONFIG_APMBIOS) {
196         set_code_invalid(regs, RET_EUNSUPPORTED);
197         return;
198     }
199
200     //debug_stub(regs);
201     switch (regs->al) {
202     case 0x00: handle_155300(regs); break;
203     case 0x01: handle_155301(regs); break;
204     case 0x02: handle_155302(regs); break;
205     case 0x03: handle_155303(regs); break;
206     case 0x04: handle_155304(regs); break;
207     case 0x05: handle_155305(regs); break;
208     case 0x06: handle_155306(regs); break;
209     case 0x07: handle_155307(regs); break;
210     case 0x08: handle_155308(regs); break;
211     case 0x0a: handle_15530a(regs); break;
212     case 0x0b: handle_15530b(regs); break;
213     case 0x0e: handle_15530e(regs); break;
214     case 0x0f: handle_15530f(regs); break;
215     case 0x10: handle_155310(regs); break;
216     default:   handle_1553XX(regs); break;
217     }
218 }