1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
|
// Basic support for apmbios callbacks.
//
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2005 Struan Bartlett
// Copyright (C) 2004 Fabrice Bellard
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "biosvar.h" // GET_GLOBAL
#include "bregs.h" // struct bregs
#include "config.h" // CONFIG_*
#include "output.h" // dprintf
#include "stacks.h" // yield_toirq
#include "util.h" // apm_shutdown
#include "x86.h" // outb
// APM installation check
static void
handle_155300(struct bregs *regs)
{
regs->ah = 1; // APM major version
regs->al = 2; // APM minor version
regs->bh = 'P';
regs->bl = 'M';
// bit 0 : 16 bit interface supported
// bit 1 : 32 bit interface supported
regs->cx = 0x03;
set_success(regs);
}
// APM real mode interface connect
static void
handle_155301(struct bregs *regs)
{
set_success(regs);
}
// APM 16 bit protected mode interface connect
static void
handle_155302(struct bregs *regs)
{
extern void entry_apm16(void);
regs->bx = (u32)entry_apm16;
regs->ax = SEG_BIOS; // 16 bit code segment base
regs->si = 0xfff0; // 16 bit code segment size
regs->cx = SEG_BIOS; // data segment address
regs->di = 0xfff0; // data segment length
set_success(regs);
}
// APM 32 bit protected mode interface connect
static void
handle_155303(struct bregs *regs)
{
extern void entry_apm32(void);
regs->ax = SEG_BIOS; // 32 bit code segment base
regs->ebx = (u32)entry_apm32;
regs->cx = SEG_BIOS; // 16 bit code segment base
// 32 bit code segment size (low 16 bits)
// 16 bit code segment size (high 16 bits)
regs->esi = 0xfff0fff0;
regs->dx = SEG_BIOS; // data segment address
regs->di = 0xfff0; // data segment length
set_success(regs);
}
// APM interface disconnect
static void
handle_155304(struct bregs *regs)
{
set_success(regs);
}
// APM cpu idle
static void
handle_155305(struct bregs *regs)
{
yield_toirq();
set_success(regs);
}
// APM cpu busy
static void
handle_155306(struct bregs *regs)
{
set_success(regs);
}
void
apm_shutdown(void)
{
u16 pm1a_cnt = GET_GLOBAL(acpi_pm1a_cnt);
if (pm1a_cnt)
outw(0x2000, pm1a_cnt);
irq_disable();
for (;;)
hlt();
}
// APM Set Power State
static void
handle_155307(struct bregs *regs)
{
if (regs->bx != 1) {
set_success(regs);
return;
}
switch (regs->cx) {
case 1:
dprintf(1, "APM standby request\n");
break;
case 2:
dprintf(1, "APM suspend request\n");
break;
case 3:
apm_shutdown();
break;
}
set_success(regs);
}
static void
handle_155308(struct bregs *regs)
{
set_success(regs);
}
// Get Power Status
static void
handle_15530a(struct bregs *regs)
{
regs->bh = 0x01; // on line
regs->bl = 0xff; // unknown battery status
regs->ch = 0x80; // no system battery
regs->cl = 0xff; // unknown remaining time
regs->dx = 0xffff; // unknown remaining time
regs->si = 0x00; // zero battery
set_success(regs);
}
#define RET_ENOEVENT 0x80
// Get PM Event
static void
handle_15530b(struct bregs *regs)
{
set_code_invalid_silent(regs, RET_ENOEVENT);
}
// APM Driver Version
static void
handle_15530e(struct bregs *regs)
{
regs->ah = 1;
regs->al = 2;
set_success(regs);
}
// APM Engage / Disengage
static void
handle_15530f(struct bregs *regs)
{
set_success(regs);
}
// APM Get Capabilities
static void
handle_155310(struct bregs *regs)
{
regs->bl = 0;
regs->cx = 0;
set_success(regs);
}
static void
handle_1553XX(struct bregs *regs)
{
set_unimplemented(regs);
}
void
handle_1553(struct bregs *regs)
{
if (! CONFIG_APMBIOS) {
set_code_invalid(regs, RET_EUNSUPPORTED);
return;
}
//debug_stub(regs);
switch (regs->al) {
case 0x00: handle_155300(regs); break;
case 0x01: handle_155301(regs); break;
case 0x02: handle_155302(regs); break;
case 0x03: handle_155303(regs); break;
case 0x04: handle_155304(regs); break;
case 0x05: handle_155305(regs); break;
case 0x06: handle_155306(regs); break;
case 0x07: handle_155307(regs); break;
case 0x08: handle_155308(regs); break;
case 0x0a: handle_15530a(regs); break;
case 0x0b: handle_15530b(regs); break;
case 0x0e: handle_15530e(regs); break;
case 0x0f: handle_15530f(regs); break;
case 0x10: handle_155310(regs); break;
default: handle_1553XX(regs); break;
}
}
void VISIBLE16 VISIBLE32SEG
handle_apm(struct bregs *regs)
{
debug_enter(regs, DEBUG_HDL_apm);
handle_1553(regs);
}
|