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