blob: f7c2306c3d505f3a719499df054c1c68e47f191b [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'Connor15157a32008-12-13 11:10:37 -05009#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040010#include "bregs.h" // struct bregs
11#include "config.h" // CONFIG_*
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040012#include "output.h" // dprintf
Kevin O'Connor3df600b2013-09-14 19:28:55 -040013#include "stacks.h" // yield_toirq
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040014#include "util.h" // apm_shutdown
Kevin O'Connor4ade5232013-09-18 21:41:48 -040015#include "x86.h" // outb
Kevin O'Connor95b2f782008-03-05 19:52:06 -050016
Kevin O'Connor95b2f782008-03-05 19:52:06 -050017// APM installation check
18static void
19handle_155300(struct bregs *regs)
20{
21 regs->ah = 1; // APM major version
22 regs->al = 2; // APM minor version
23 regs->bh = 'P';
24 regs->bl = 'M';
25 // bit 0 : 16 bit interface supported
26 // bit 1 : 32 bit interface supported
27 regs->cx = 0x03;
Kevin O'Connor6c781222008-03-09 12:19:23 -040028 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050029}
30
31// APM real mode interface connect
32static void
33handle_155301(struct bregs *regs)
34{
Kevin O'Connor6c781222008-03-09 12:19:23 -040035 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050036}
37
38// APM 16 bit protected mode interface connect
39static void
40handle_155302(struct bregs *regs)
41{
Kevin O'Connorf5037fd2014-04-07 17:31:43 -040042 extern void entry_apm16(void);
Kevin O'Connor47c8e312011-07-10 22:57:32 -040043 regs->bx = (u32)entry_apm16;
Kevin O'Connor95b2f782008-03-05 19:52:06 -050044 regs->ax = SEG_BIOS; // 16 bit code segment base
45 regs->si = 0xfff0; // 16 bit code segment size
46 regs->cx = SEG_BIOS; // data segment address
47 regs->di = 0xfff0; // data segment length
Kevin O'Connor6c781222008-03-09 12:19:23 -040048 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050049}
50
51// APM 32 bit protected mode interface connect
52static void
53handle_155303(struct bregs *regs)
54{
Kevin O'Connorf5037fd2014-04-07 17:31:43 -040055 extern void entry_apm32(void);
Kevin O'Connor44d65302008-03-08 11:34:46 -050056 regs->ax = SEG_BIOS; // 32 bit code segment base
Kevin O'Connor47c8e312011-07-10 22:57:32 -040057 regs->ebx = (u32)entry_apm32;
Kevin O'Connor44d65302008-03-08 11:34:46 -050058 regs->cx = SEG_BIOS; // 16 bit code segment base
Kevin O'Connor95b2f782008-03-05 19:52:06 -050059 // 32 bit code segment size (low 16 bits)
60 // 16 bit code segment size (high 16 bits)
61 regs->esi = 0xfff0fff0;
Kevin O'Connor44d65302008-03-08 11:34:46 -050062 regs->dx = SEG_BIOS; // data segment address
Kevin O'Connor95b2f782008-03-05 19:52:06 -050063 regs->di = 0xfff0; // data segment length
Kevin O'Connor6c781222008-03-09 12:19:23 -040064 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050065}
66
67// APM interface disconnect
68static void
69handle_155304(struct bregs *regs)
70{
Kevin O'Connor6c781222008-03-09 12:19:23 -040071 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050072}
73
74// APM cpu idle
75static void
76handle_155305(struct bregs *regs)
77{
Kevin O'Connor94c749c2012-05-28 11:44:02 -040078 yield_toirq();
Kevin O'Connor6c781222008-03-09 12:19:23 -040079 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050080}
81
Kevin O'Connor0fae9e12008-06-07 14:51:14 -040082// APM cpu busy
83static void
84handle_155306(struct bregs *regs)
85{
86 set_success(regs);
87}
88
Kevin O'Connor244caf82010-09-15 21:48:16 -040089void
90apm_shutdown(void)
91{
Gerd Hoffmann5b631092013-07-25 09:47:18 +020092 u16 pm1a_cnt = GET_GLOBAL(acpi_pm1a_cnt);
Gerd Hoffmann5b631092013-07-25 09:47:18 +020093 if (pm1a_cnt)
94 outw(0x2000, pm1a_cnt);
Kevin O'Connorf5037fd2014-04-07 17:31:43 -040095
96 irq_disable();
Kevin O'Connor244caf82010-09-15 21:48:16 -040097 for (;;)
98 hlt();
99}
100
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500101// APM Set Power State
102static void
103handle_155307(struct bregs *regs)
104{
105 if (regs->bx != 1) {
Kevin O'Connor6c781222008-03-09 12:19:23 -0400106 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500107 return;
108 }
109 switch (regs->cx) {
110 case 1:
Kevin O'Connorf5037fd2014-04-07 17:31:43 -0400111 dprintf(1, "APM standby request\n");
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500112 break;
113 case 2:
Kevin O'Connorf5037fd2014-04-07 17:31:43 -0400114 dprintf(1, "APM suspend request\n");
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500115 break;
116 case 3:
Kevin O'Connor244caf82010-09-15 21:48:16 -0400117 apm_shutdown();
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500118 break;
119 }
Kevin O'Connor6c781222008-03-09 12:19:23 -0400120 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500121}
122
123static void
124handle_155308(struct bregs *regs)
125{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400126 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500127}
128
129// Get Power Status
130static void
131handle_15530a(struct bregs *regs)
132{
133 regs->bh = 0x01; // on line
134 regs->bl = 0xff; // unknown battery status
135 regs->ch = 0x80; // no system battery
136 regs->cl = 0xff; // unknown remaining time
137 regs->dx = 0xffff; // unknown remaining time
138 regs->si = 0x00; // zero battery
Kevin O'Connor6c781222008-03-09 12:19:23 -0400139 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500140}
141
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400142#define RET_ENOEVENT 0x80
143
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500144// Get PM Event
145static void
146handle_15530b(struct bregs *regs)
147{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500148 set_code_invalid_silent(regs, RET_ENOEVENT);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500149}
150
151// APM Driver Version
152static void
153handle_15530e(struct bregs *regs)
154{
155 regs->ah = 1;
156 regs->al = 2;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400157 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500158}
159
160// APM Engage / Disengage
161static void
162handle_15530f(struct bregs *regs)
163{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400164 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500165}
166
167// APM Get Capabilities
168static void
169handle_155310(struct bregs *regs)
170{
171 regs->bl = 0;
172 regs->cx = 0;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400173 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500174}
175
176static void
177handle_1553XX(struct bregs *regs)
178{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500179 set_unimplemented(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500180}
181
Kevin O'Connorc0031482010-01-01 13:03:17 -0500182void
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500183handle_1553(struct bregs *regs)
184{
Kevin O'Connor7ba6b302008-05-26 15:19:33 -0400185 if (! CONFIG_APMBIOS) {
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500186 set_code_invalid(regs, RET_EUNSUPPORTED);
Kevin O'Connor7ba6b302008-05-26 15:19:33 -0400187 return;
188 }
189
Kevin O'Connorc38e4802008-03-15 11:07:50 -0400190 //debug_stub(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500191 switch (regs->al) {
192 case 0x00: handle_155300(regs); break;
193 case 0x01: handle_155301(regs); break;
194 case 0x02: handle_155302(regs); break;
195 case 0x03: handle_155303(regs); break;
196 case 0x04: handle_155304(regs); break;
197 case 0x05: handle_155305(regs); break;
Kevin O'Connor0fae9e12008-06-07 14:51:14 -0400198 case 0x06: handle_155306(regs); break;
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500199 case 0x07: handle_155307(regs); break;
200 case 0x08: handle_155308(regs); break;
201 case 0x0a: handle_15530a(regs); break;
202 case 0x0b: handle_15530b(regs); break;
203 case 0x0e: handle_15530e(regs); break;
204 case 0x0f: handle_15530f(regs); break;
205 case 0x10: handle_155310(regs); break;
206 default: handle_1553XX(regs); break;
207 }
208}
Kevin O'Connorc0031482010-01-01 13:03:17 -0500209
Kevin O'Connord3e43672012-05-28 11:37:53 -0400210void VISIBLE16 VISIBLE32SEG
211handle_apm(struct bregs *regs)
Kevin O'Connorc0031482010-01-01 13:03:17 -0500212{
213 debug_enter(regs, DEBUG_HDL_apm);
214 handle_1553(regs);
215}