blob: 6efead02f683e8b97bf80636d1efc886549dcbb5 [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
9#include "farptr.h" // GET_VAR
Kevin O'Connor9521e262008-07-04 13:04:29 -040010#include "bregs.h" // struct bregs
Kevin O'Connor95b2f782008-03-05 19:52:06 -050011#include "ioport.h" // outb
12#include "util.h" // irq_enable
Kevin O'Connor9521e262008-07-04 13:04:29 -040013#include "config.h" // CONFIG_*
Kevin O'Connor15157a32008-12-13 11:10:37 -050014#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor95b2f782008-03-05 19:52:06 -050015
16static void
17out_str(const char *str_cs)
18{
Kevin O'Connorf64f0db2008-05-18 02:42:58 -040019 if (CONFIG_COREBOOT) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -040020 dprintf(1, "APM request '%s'\n", str_cs);
Kevin O'Connorf64f0db2008-05-18 02:42:58 -040021 return;
22 }
23
Kevin O'Connor95b2f782008-03-05 19:52:06 -050024 u8 *s = (u8*)str_cs;
25 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -050026 u8 c = GET_GLOBAL(*s);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050027 if (!c)
28 break;
Kevin O'Connor2ad37442008-05-06 19:49:01 -040029 outb(c, PORT_BIOS_APM);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050030 s++;
31 }
32}
33
34// APM installation check
35static void
36handle_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;
Kevin O'Connor6c781222008-03-09 12:19:23 -040045 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050046}
47
48// APM real mode interface connect
49static void
50handle_155301(struct bregs *regs)
51{
Kevin O'Connor6c781222008-03-09 12:19:23 -040052 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050053}
54
Kevin O'Connor44d65302008-03-08 11:34:46 -050055// Assembler entry points defined in romlayout.S
56extern void apm16protected_entry();
57extern void apm32protected_entry();
58
Kevin O'Connor95b2f782008-03-05 19:52:06 -050059// APM 16 bit protected mode interface connect
60static void
61handle_155302(struct bregs *regs)
62{
Kevin O'Connor44d65302008-03-08 11:34:46 -050063 regs->bx = (u32)apm16protected_entry;
Kevin O'Connor95b2f782008-03-05 19:52:06 -050064 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
Kevin O'Connor6c781222008-03-09 12:19:23 -040068 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050069}
70
71// APM 32 bit protected mode interface connect
72static void
73handle_155303(struct bregs *regs)
74{
Kevin O'Connor44d65302008-03-08 11:34:46 -050075 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
Kevin O'Connor95b2f782008-03-05 19:52:06 -050078 // 32 bit code segment size (low 16 bits)
79 // 16 bit code segment size (high 16 bits)
80 regs->esi = 0xfff0fff0;
Kevin O'Connor44d65302008-03-08 11:34:46 -050081 regs->dx = SEG_BIOS; // data segment address
Kevin O'Connor95b2f782008-03-05 19:52:06 -050082 regs->di = 0xfff0; // data segment length
Kevin O'Connor6c781222008-03-09 12:19:23 -040083 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050084}
85
86// APM interface disconnect
87static void
88handle_155304(struct bregs *regs)
89{
Kevin O'Connor6c781222008-03-09 12:19:23 -040090 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050091}
92
93// APM cpu idle
94static void
95handle_155305(struct bregs *regs)
96{
97 irq_enable();
98 hlt();
Kevin O'Connor6c781222008-03-09 12:19:23 -040099 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500100}
101
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400102// APM cpu busy
103static void
104handle_155306(struct bregs *regs)
105{
106 set_success(regs);
107}
108
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500109// APM Set Power State
110static void
111handle_155307(struct bregs *regs)
112{
113 if (regs->bx != 1) {
Kevin O'Connor6c781222008-03-09 12:19:23 -0400114 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500115 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 }
Kevin O'Connor6c781222008-03-09 12:19:23 -0400131 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500132}
133
134static void
135handle_155308(struct bregs *regs)
136{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400137 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500138}
139
140// Get Power Status
141static void
142handle_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
Kevin O'Connor6c781222008-03-09 12:19:23 -0400150 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500151}
152
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400153#define RET_ENOEVENT 0x80
154
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500155// Get PM Event
156static void
157handle_15530b(struct bregs *regs)
158{
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400159 set_code_fail_silent(regs, RET_ENOEVENT);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500160}
161
162// APM Driver Version
163static void
164handle_15530e(struct bregs *regs)
165{
166 regs->ah = 1;
167 regs->al = 2;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400168 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500169}
170
171// APM Engage / Disengage
172static void
173handle_15530f(struct bregs *regs)
174{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400175 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500176}
177
178// APM Get Capabilities
179static void
180handle_155310(struct bregs *regs)
181{
182 regs->bl = 0;
183 regs->cx = 0;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400184 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500185}
186
187static void
188handle_1553XX(struct bregs *regs)
189{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400190 set_fail(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500191}
192
Kevin O'Connor44d65302008-03-08 11:34:46 -0500193void VISIBLE16
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500194handle_1553(struct bregs *regs)
195{
Kevin O'Connor7ba6b302008-05-26 15:19:33 -0400196 if (! CONFIG_APMBIOS) {
197 set_code_fail(regs, RET_EUNSUPPORTED);
198 return;
199 }
200
Kevin O'Connorc38e4802008-03-15 11:07:50 -0400201 //debug_stub(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500202 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;
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400209 case 0x06: handle_155306(regs); break;
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500210 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}