blob: c497dbecd8306b514d1d07e9baf2dac889b1f50b [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
Kevin O'Connor6d768b52009-12-10 21:15:04 -050012#include "util.h" // wait_irq
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
Kevin O'Connor47c8e312011-07-10 22:57:32 -040056extern void entry_apm16(void);
57extern void entry_apm32(void);
Kevin O'Connor44d65302008-03-08 11:34:46 -050058
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'Connor47c8e312011-07-10 22:57:32 -040063 regs->bx = (u32)entry_apm16;
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
Kevin O'Connor47c8e312011-07-10 22:57:32 -040076 regs->ebx = (u32)entry_apm32;
Kevin O'Connor44d65302008-03-08 11:34:46 -050077 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{
Kevin O'Connor6d768b52009-12-10 21:15:04 -050097 wait_irq();
Kevin O'Connor6c781222008-03-09 12:19:23 -040098 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050099}
100
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400101// APM cpu busy
102static void
103handle_155306(struct bregs *regs)
104{
105 set_success(regs);
106}
107
Kevin O'Connor244caf82010-09-15 21:48:16 -0400108void
109apm_shutdown(void)
110{
111 irq_disable();
112 out_str("Shutdown");
113 for (;;)
114 hlt();
115}
116
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500117// APM Set Power State
118static void
119handle_155307(struct bregs *regs)
120{
121 if (regs->bx != 1) {
Kevin O'Connor6c781222008-03-09 12:19:23 -0400122 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500123 return;
124 }
125 switch (regs->cx) {
126 case 1:
127 out_str("Standby");
128 break;
129 case 2:
130 out_str("Suspend");
131 break;
132 case 3:
Kevin O'Connor244caf82010-09-15 21:48:16 -0400133 apm_shutdown();
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500134 break;
135 }
Kevin O'Connor6c781222008-03-09 12:19:23 -0400136 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500137}
138
139static void
140handle_155308(struct bregs *regs)
141{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400142 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500143}
144
145// Get Power Status
146static void
147handle_15530a(struct bregs *regs)
148{
149 regs->bh = 0x01; // on line
150 regs->bl = 0xff; // unknown battery status
151 regs->ch = 0x80; // no system battery
152 regs->cl = 0xff; // unknown remaining time
153 regs->dx = 0xffff; // unknown remaining time
154 regs->si = 0x00; // zero battery
Kevin O'Connor6c781222008-03-09 12:19:23 -0400155 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500156}
157
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400158#define RET_ENOEVENT 0x80
159
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500160// Get PM Event
161static void
162handle_15530b(struct bregs *regs)
163{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500164 set_code_invalid_silent(regs, RET_ENOEVENT);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500165}
166
167// APM Driver Version
168static void
169handle_15530e(struct bregs *regs)
170{
171 regs->ah = 1;
172 regs->al = 2;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400173 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500174}
175
176// APM Engage / Disengage
177static void
178handle_15530f(struct bregs *regs)
179{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400180 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500181}
182
183// APM Get Capabilities
184static void
185handle_155310(struct bregs *regs)
186{
187 regs->bl = 0;
188 regs->cx = 0;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400189 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500190}
191
192static void
193handle_1553XX(struct bregs *regs)
194{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500195 set_unimplemented(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500196}
197
Kevin O'Connorc0031482010-01-01 13:03:17 -0500198void
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500199handle_1553(struct bregs *regs)
200{
Kevin O'Connor7ba6b302008-05-26 15:19:33 -0400201 if (! CONFIG_APMBIOS) {
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500202 set_code_invalid(regs, RET_EUNSUPPORTED);
Kevin O'Connor7ba6b302008-05-26 15:19:33 -0400203 return;
204 }
205
Kevin O'Connorc38e4802008-03-15 11:07:50 -0400206 //debug_stub(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500207 switch (regs->al) {
208 case 0x00: handle_155300(regs); break;
209 case 0x01: handle_155301(regs); break;
210 case 0x02: handle_155302(regs); break;
211 case 0x03: handle_155303(regs); break;
212 case 0x04: handle_155304(regs); break;
213 case 0x05: handle_155305(regs); break;
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400214 case 0x06: handle_155306(regs); break;
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500215 case 0x07: handle_155307(regs); break;
216 case 0x08: handle_155308(regs); break;
217 case 0x0a: handle_15530a(regs); break;
218 case 0x0b: handle_15530b(regs); break;
219 case 0x0e: handle_15530e(regs); break;
220 case 0x0f: handle_15530f(regs); break;
221 case 0x10: handle_155310(regs); break;
222 default: handle_1553XX(regs); break;
223 }
224}
Kevin O'Connorc0031482010-01-01 13:03:17 -0500225
226void VISIBLE16
227handle_apm16(struct bregs *regs)
228{
229 debug_enter(regs, DEBUG_HDL_apm);
230 handle_1553(regs);
231}
232
Kevin O'Connorc0031482010-01-01 13:03:17 -0500233void VISIBLE32SEG
234handle_apm32(struct bregs *regs)
235{
236 debug_enter(regs, DEBUG_HDL_apm);
237 handle_1553(regs);
238}