blob: 4a0f8036cec7c2b915317cbb5e5b064603d165a3 [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//
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
14static void
15out_str(const char *str_cs)
16{
Kevin O'Connorf64f0db2008-05-18 02:42:58 -040017 if (CONFIG_COREBOOT) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -040018 dprintf(1, "APM request '%s'\n", str_cs);
Kevin O'Connorf64f0db2008-05-18 02:42:58 -040019 return;
20 }
21
Kevin O'Connor95b2f782008-03-05 19:52:06 -050022 u8 *s = (u8*)str_cs;
23 for (;;) {
24 u8 c = GET_VAR(CS, *s);
25 if (!c)
26 break;
Kevin O'Connor2ad37442008-05-06 19:49:01 -040027 outb(c, PORT_BIOS_APM);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050028 s++;
29 }
30}
31
32// APM installation check
33static void
34handle_155300(struct bregs *regs)
35{
36 regs->ah = 1; // APM major version
37 regs->al = 2; // APM minor version
38 regs->bh = 'P';
39 regs->bl = 'M';
40 // bit 0 : 16 bit interface supported
41 // bit 1 : 32 bit interface supported
42 regs->cx = 0x03;
Kevin O'Connor6c781222008-03-09 12:19:23 -040043 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050044}
45
46// APM real mode interface connect
47static void
48handle_155301(struct bregs *regs)
49{
Kevin O'Connor6c781222008-03-09 12:19:23 -040050 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050051}
52
Kevin O'Connor44d65302008-03-08 11:34:46 -050053// Assembler entry points defined in romlayout.S
54extern void apm16protected_entry();
55extern void apm32protected_entry();
56
Kevin O'Connor95b2f782008-03-05 19:52:06 -050057// APM 16 bit protected mode interface connect
58static void
59handle_155302(struct bregs *regs)
60{
Kevin O'Connor44d65302008-03-08 11:34:46 -050061 regs->bx = (u32)apm16protected_entry;
Kevin O'Connor95b2f782008-03-05 19:52:06 -050062 regs->ax = SEG_BIOS; // 16 bit code segment base
63 regs->si = 0xfff0; // 16 bit code segment size
64 regs->cx = SEG_BIOS; // data segment address
65 regs->di = 0xfff0; // data segment length
Kevin O'Connor6c781222008-03-09 12:19:23 -040066 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050067}
68
69// APM 32 bit protected mode interface connect
70static void
71handle_155303(struct bregs *regs)
72{
Kevin O'Connor44d65302008-03-08 11:34:46 -050073 regs->ax = SEG_BIOS; // 32 bit code segment base
74 regs->ebx = (u32)apm32protected_entry;
75 regs->cx = SEG_BIOS; // 16 bit code segment base
Kevin O'Connor95b2f782008-03-05 19:52:06 -050076 // 32 bit code segment size (low 16 bits)
77 // 16 bit code segment size (high 16 bits)
78 regs->esi = 0xfff0fff0;
Kevin O'Connor44d65302008-03-08 11:34:46 -050079 regs->dx = SEG_BIOS; // data segment address
Kevin O'Connor95b2f782008-03-05 19:52:06 -050080 regs->di = 0xfff0; // data segment length
Kevin O'Connor6c781222008-03-09 12:19:23 -040081 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050082}
83
84// APM interface disconnect
85static void
86handle_155304(struct bregs *regs)
87{
Kevin O'Connor6c781222008-03-09 12:19:23 -040088 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050089}
90
91// APM cpu idle
92static void
93handle_155305(struct bregs *regs)
94{
95 irq_enable();
96 hlt();
Kevin O'Connor6c781222008-03-09 12:19:23 -040097 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -050098}
99
100// APM Set Power State
101static void
102handle_155307(struct bregs *regs)
103{
104 if (regs->bx != 1) {
Kevin O'Connor6c781222008-03-09 12:19:23 -0400105 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500106 return;
107 }
108 switch (regs->cx) {
109 case 1:
110 out_str("Standby");
111 break;
112 case 2:
113 out_str("Suspend");
114 break;
115 case 3:
116 irq_disable();
117 out_str("Shutdown");
118 for (;;)
119 hlt();
120 break;
121 }
Kevin O'Connor6c781222008-03-09 12:19:23 -0400122 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500123}
124
125static void
126handle_155308(struct bregs *regs)
127{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400128 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500129}
130
131// Get Power Status
132static void
133handle_15530a(struct bregs *regs)
134{
135 regs->bh = 0x01; // on line
136 regs->bl = 0xff; // unknown battery status
137 regs->ch = 0x80; // no system battery
138 regs->cl = 0xff; // unknown remaining time
139 regs->dx = 0xffff; // unknown remaining time
140 regs->si = 0x00; // zero battery
Kevin O'Connor6c781222008-03-09 12:19:23 -0400141 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500142}
143
144// Get PM Event
145static void
146handle_15530b(struct bregs *regs)
147{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400148 set_fail(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500149 regs->ah = 0x80; // no event pending
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500150}
151
152// APM Driver Version
153static void
154handle_15530e(struct bregs *regs)
155{
156 regs->ah = 1;
157 regs->al = 2;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400158 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500159}
160
161// APM Engage / Disengage
162static void
163handle_15530f(struct bregs *regs)
164{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400165 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500166}
167
168// APM Get Capabilities
169static void
170handle_155310(struct bregs *regs)
171{
172 regs->bl = 0;
173 regs->cx = 0;
Kevin O'Connor6c781222008-03-09 12:19:23 -0400174 set_success(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500175}
176
177static void
178handle_1553XX(struct bregs *regs)
179{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400180 set_fail(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500181}
182
Kevin O'Connor44d65302008-03-08 11:34:46 -0500183void VISIBLE16
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500184handle_1553(struct bregs *regs)
185{
Kevin O'Connorc38e4802008-03-15 11:07:50 -0400186 //debug_stub(regs);
Kevin O'Connor95b2f782008-03-05 19:52:06 -0500187 switch (regs->al) {
188 case 0x00: handle_155300(regs); break;
189 case 0x01: handle_155301(regs); break;
190 case 0x02: handle_155302(regs); break;
191 case 0x03: handle_155303(regs); break;
192 case 0x04: handle_155304(regs); break;
193 case 0x05: handle_155305(regs); break;
194 case 0x07: handle_155307(regs); break;
195 case 0x08: handle_155308(regs); break;
196 case 0x0a: handle_15530a(regs); break;
197 case 0x0b: handle_15530b(regs); break;
198 case 0x0e: handle_15530e(regs); break;
199 case 0x0f: handle_15530f(regs); break;
200 case 0x10: handle_155310(regs); break;
201 default: handle_1553XX(regs); break;
202 }
203}