blob: 8daf9583b811141a9780d4c63a4c356230a9c2ea [file] [log] [blame]
Kevin O'Connor95b2f782008-03-05 19:52:06 -05001// 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//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05007// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connor95b2f782008-03-05 19:52:06 -05008
Kevin O'Connor9521e262008-07-04 13:04:29 -04009#include "bregs.h" // struct bregs
Kevin O'Connor95b2f782008-03-05 19:52:06 -050010#include "ioport.h" // outb
Kevin O'Connor94c749c2012-05-28 11:44:02 -040011#include "util.h" // dprintf
Kevin O'Connor9521e262008-07-04 13:04:29 -040012#include "config.h" // CONFIG_*
Kevin O'Connor15157a32008-12-13 11:10:37 -050013#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor95b2f782008-03-05 19:52:06 -050014
15static void
16out_str(const char *str_cs)
17{
Kevin O'Connorf64f0db2008-05-18 02:42:58 -040018 if (CONFIG_COREBOOT) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -040019 dprintf(1, "APM request '%s'\n", str_cs);
Kevin O'Connorf64f0db2008-05-18 02:42:58 -040020 return;
21 }
22
Kevin O'Connor95b2f782008-03-05 19:52:06 -050023 u8 *s = (u8*)str_cs;
24 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -050025 u8 c = GET_GLOBAL(*s);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050026 if (!c)
27 break;
Kevin O'Connor2ad37442008-05-06 19:49:01 -040028 outb(c, PORT_BIOS_APM);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050029 s++;
30 }
31}
32
33// APM installation check
34static void
35handle_155300(struct bregs *regs)
36{
37 regs->ah = 1; // APM major version
38 regs->al = 2; // APM minor version
39 regs->bh = 'P';
40 regs->bl = 'M';
41 // bit 0 : 16 bit interface supported
42 // bit 1 : 32 bit interface supported
43 regs->cx = 0x03;
Kevin O'Connor6c781222008-03-09 12:19:23 -040044 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050045}
46
47// APM real mode interface connect
48static void
49handle_155301(struct bregs *regs)
50{
Kevin O'Connor6c781222008-03-09 12:19:23 -040051 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050052}
53
Kevin O'Connor44d65302008-03-08 11:34:46 -050054// Assembler entry points defined in romlayout.S
Kevin O'Connor47c8e312011-07-10 22:57:32 -040055extern void entry_apm16(void);
56extern void entry_apm32(void);
Kevin O'Connor44d65302008-03-08 11:34:46 -050057
Kevin O'Connor95b2f782008-03-05 19:52:06 -050058// APM 16 bit protected mode interface connect
59static void
60handle_155302(struct bregs *regs)
61{
Kevin O'Connor47c8e312011-07-10 22:57:32 -040062 regs->bx = (u32)entry_apm16;
Kevin O'Connor95b2f782008-03-05 19:52:06 -050063 regs->ax = SEG_BIOS; // 16 bit code segment base
64 regs->si = 0xfff0; // 16 bit code segment size
65 regs->cx = SEG_BIOS; // data segment address
66 regs->di = 0xfff0; // data segment length
Kevin O'Connor6c781222008-03-09 12:19:23 -040067 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050068}
69
70// APM 32 bit protected mode interface connect
71static void
72handle_155303(struct bregs *regs)
73{
Kevin O'Connor44d65302008-03-08 11:34:46 -050074 regs->ax = SEG_BIOS; // 32 bit code segment base
Kevin O'Connor47c8e312011-07-10 22:57:32 -040075 regs->ebx = (u32)entry_apm32;
Kevin O'Connor44d65302008-03-08 11:34:46 -050076 regs->cx = SEG_BIOS; // 16 bit code segment base
Kevin O'Connor95b2f782008-03-05 19:52:06 -050077 // 32 bit code segment size (low 16 bits)
78 // 16 bit code segment size (high 16 bits)
79 regs->esi = 0xfff0fff0;
Kevin O'Connor44d65302008-03-08 11:34:46 -050080 regs->dx = SEG_BIOS; // data segment address
Kevin O'Connor95b2f782008-03-05 19:52:06 -050081 regs->di = 0xfff0; // data segment length
Kevin O'Connor6c781222008-03-09 12:19:23 -040082 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050083}
84
85// APM interface disconnect
86static void
87handle_155304(struct bregs *regs)
88{
Kevin O'Connor6c781222008-03-09 12:19:23 -040089 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050090}
91
92// APM cpu idle
93static void
94handle_155305(struct bregs *regs)
95{
Kevin O'Connor94c749c2012-05-28 11:44:02 -040096 yield_toirq();
Kevin O'Connor6c781222008-03-09 12:19:23 -040097 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050098}
99
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400100// APM cpu busy
101static void
102handle_155306(struct bregs *regs)
103{
104 set_success(regs);
105}
106
Kevin O'Connor244caf82010-09-15 21:48:16 -0400107void
108apm_shutdown(void)
109{
110 irq_disable();
111 out_str("Shutdown");
112 for (;;)
113 hlt();
114}
115
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500116// APM Set Power State
117static void
118handle_155307(struct bregs *regs)
119{
120 if (regs->bx != 1) {
Kevin O'Connor6c781222008-03-09 12:19:23 -0400121 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500122 return;
123 }
124 switch (regs->cx) {
125 case 1:
126 out_str("Standby");
127 break;
128 case 2:
129 out_str("Suspend");
130 break;
131 case 3:
Kevin O'Connor244caf82010-09-15 21:48:16 -0400132 apm_shutdown();
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500133 break;
134 }
Kevin O'Connor6c781222008-03-09 12:19:23 -0400135 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500136}
137
138static void
139handle_155308(struct bregs *regs)
140{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400141 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500142}
143
144// Get Power Status
145static void
146handle_15530a(struct bregs *regs)
147{
148 regs->bh = 0x01; // on line
149 regs->bl = 0xff; // unknown battery status
150 regs->ch = 0x80; // no system battery
151 regs->cl = 0xff; // unknown remaining time
152 regs->dx = 0xffff; // unknown remaining time
153 regs->si = 0x00; // zero battery
Kevin O'Connor6c781222008-03-09 12:19:23 -0400154 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500155}
156
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400157#define RET_ENOEVENT 0x80
158
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500159// Get PM Event
160static void
161handle_15530b(struct bregs *regs)
162{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500163 set_code_invalid_silent(regs, RET_ENOEVENT);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500164}
165
166// APM Driver Version
167static void
168handle_15530e(struct bregs *regs)
169{
170 regs->ah = 1;
171 regs->al = 2;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400172 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500173}
174
175// APM Engage / Disengage
176static void
177handle_15530f(struct bregs *regs)
178{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400179 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500180}
181
182// APM Get Capabilities
183static void
184handle_155310(struct bregs *regs)
185{
186 regs->bl = 0;
187 regs->cx = 0;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400188 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500189}
190
191static void
192handle_1553XX(struct bregs *regs)
193{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500194 set_unimplemented(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500195}
196
Kevin O'Connorc0031482010-01-01 13:03:17 -0500197void
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500198handle_1553(struct bregs *regs)
199{
Kevin O'Connor7ba6b302008-05-26 15:19:33 -0400200 if (! CONFIG_APMBIOS) {
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500201 set_code_invalid(regs, RET_EUNSUPPORTED);
Kevin O'Connor7ba6b302008-05-26 15:19:33 -0400202 return;
203 }
204
Kevin O'Connorc38e4802008-03-15 11:07:50 -0400205 //debug_stub(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500206 switch (regs->al) {
207 case 0x00: handle_155300(regs); break;
208 case 0x01: handle_155301(regs); break;
209 case 0x02: handle_155302(regs); break;
210 case 0x03: handle_155303(regs); break;
211 case 0x04: handle_155304(regs); break;
212 case 0x05: handle_155305(regs); break;
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400213 case 0x06: handle_155306(regs); break;
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500214 case 0x07: handle_155307(regs); break;
215 case 0x08: handle_155308(regs); break;
216 case 0x0a: handle_15530a(regs); break;
217 case 0x0b: handle_15530b(regs); break;
218 case 0x0e: handle_15530e(regs); break;
219 case 0x0f: handle_15530f(regs); break;
220 case 0x10: handle_155310(regs); break;
221 default: handle_1553XX(regs); break;
222 }
223}
Kevin O'Connorc0031482010-01-01 13:03:17 -0500224
Kevin O'Connord3e43672012-05-28 11:37:53 -0400225void VISIBLE16 VISIBLE32SEG
226handle_apm(struct bregs *regs)
Kevin O'Connorc0031482010-01-01 13:03:17 -0500227{
228 debug_enter(regs, DEBUG_HDL_apm);
229 handle_1553(regs);
230}