Change license from GPLv3 to LGPLv3.
[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" // irq_enable
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     irq_enable();
98     hlt();
99     set_success(regs);
100 }
101
102 // APM cpu busy
103 static void
104 handle_155306(struct bregs *regs)
105 {
106     set_success(regs);
107 }
108
109 // APM Set Power State
110 static void
111 handle_155307(struct bregs *regs)
112 {
113     if (regs->bx != 1) {
114         set_success(regs);
115         return;
116     }
117     switch (regs->cx) {
118     case 1:
119         out_str("Standby");
120         break;
121     case 2:
122         out_str("Suspend");
123         break;
124     case 3:
125         irq_disable();
126         out_str("Shutdown");
127         for (;;)
128             hlt();
129         break;
130     }
131     set_success(regs);
132 }
133
134 static void
135 handle_155308(struct bregs *regs)
136 {
137     set_success(regs);
138 }
139
140 // Get Power Status
141 static void
142 handle_15530a(struct bregs *regs)
143 {
144     regs->bh = 0x01; // on line
145     regs->bl = 0xff; // unknown battery status
146     regs->ch = 0x80; // no system battery
147     regs->cl = 0xff; // unknown remaining time
148     regs->dx = 0xffff; // unknown remaining time
149     regs->si = 0x00; // zero battery
150     set_success(regs);
151 }
152
153 #define RET_ENOEVENT 0x80
154
155 // Get PM Event
156 static void
157 handle_15530b(struct bregs *regs)
158 {
159     set_code_fail_silent(regs, RET_ENOEVENT);
160 }
161
162 // APM Driver Version
163 static void
164 handle_15530e(struct bregs *regs)
165 {
166     regs->ah = 1;
167     regs->al = 2;
168     set_success(regs);
169 }
170
171 // APM Engage / Disengage
172 static void
173 handle_15530f(struct bregs *regs)
174 {
175     set_success(regs);
176 }
177
178 // APM Get Capabilities
179 static void
180 handle_155310(struct bregs *regs)
181 {
182     regs->bl = 0;
183     regs->cx = 0;
184     set_success(regs);
185 }
186
187 static void
188 handle_1553XX(struct bregs *regs)
189 {
190     set_fail(regs);
191 }
192
193 void VISIBLE16
194 handle_1553(struct bregs *regs)
195 {
196     if (! CONFIG_APMBIOS) {
197         set_code_fail(regs, RET_EUNSUPPORTED);
198         return;
199     }
200
201     //debug_stub(regs);
202     switch (regs->al) {
203     case 0x00: handle_155300(regs); break;
204     case 0x01: handle_155301(regs); break;
205     case 0x02: handle_155302(regs); break;
206     case 0x03: handle_155303(regs); break;
207     case 0x04: handle_155304(regs); break;
208     case 0x05: handle_155305(regs); break;
209     case 0x06: handle_155306(regs); break;
210     case 0x07: handle_155307(regs); break;
211     case 0x08: handle_155308(regs); break;
212     case 0x0a: handle_15530a(regs); break;
213     case 0x0b: handle_15530b(regs); break;
214     case 0x0e: handle_15530e(regs); break;
215     case 0x0f: handle_15530f(regs); break;
216     case 0x10: handle_155310(regs); break;
217     default:   handle_1553XX(regs); break;
218     }
219 }