aboutsummaryrefslogtreecommitdiffstats
path: root/src/apm.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2008-03-05 19:52:06 -0500
committerKevin O'Connor <kevin@koconnor.net>2008-03-05 19:52:06 -0500
commit95b2f78f97a83787c5f669f349b0ea4f682d2674 (patch)
treefcaeb88eeec2c6772696f81298be8c25d2096c4a /src/apm.c
parent180a959053bd1b955bef8db4dab443f341ee1ce7 (diff)
downloadseabios-95b2f78f97a83787c5f669f349b0ea4f682d2674.tar.gz
Add initial support for apmbios code.
Diffstat (limited to 'src/apm.c')
-rw-r--r--src/apm.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/apm.c b/src/apm.c
new file mode 100644
index 00000000..9b6d1e38
--- /dev/null
+++ b/src/apm.c
@@ -0,0 +1,193 @@
+// 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 GPLv3 license.
+
+#include "farptr.h" // GET_VAR
+#include "biosvar.h" // struct bregs
+#include "ioport.h" // outb
+#include "util.h" // irq_enable
+
+static void
+out_str(const char *str_cs)
+{
+ u8 *s = (u8*)str_cs;
+ for (;;) {
+ u8 c = GET_VAR(CS, *s);
+ if (!c)
+ break;
+ outb(c, 0x8900);
+ s++;
+ }
+}
+
+// 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_cf(regs, 0);
+}
+
+// APM real mode interface connect
+static void
+handle_155301(struct bregs *regs)
+{
+ set_cf(regs, 0);
+}
+
+// APM 16 bit protected mode interface connect
+static void
+handle_155302(struct bregs *regs)
+{
+ regs->bx = 0; // XXX - apm16_entry
+ 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_cf(regs, 0);
+}
+
+// APM 32 bit protected mode interface connect
+static void
+handle_155303(struct bregs *regs)
+{
+ regs->ax = 0xf000; // 32 bit code segment base
+ regs->ebx = 0; // XXX - apm32_entry
+ regs->cx = 0xf000; // 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 = 0xf000; // data segment address
+ regs->di = 0xfff0; // data segment length
+ set_cf(regs, 0);
+}
+
+// APM interface disconnect
+static void
+handle_155304(struct bregs *regs)
+{
+ set_cf(regs, 0);
+}
+
+// APM cpu idle
+static void
+handle_155305(struct bregs *regs)
+{
+ irq_enable();
+ hlt();
+ set_cf(regs, 0);
+}
+
+// APM Set Power State
+static void
+handle_155307(struct bregs *regs)
+{
+ if (regs->bx != 1) {
+ set_cf(regs, 0);
+ return;
+ }
+ switch (regs->cx) {
+ case 1:
+ out_str("Standby");
+ break;
+ case 2:
+ out_str("Suspend");
+ break;
+ case 3:
+ irq_disable();
+ out_str("Shutdown");
+ for (;;)
+ hlt();
+ break;
+ }
+ set_cf(regs, 0);
+}
+
+static void
+handle_155308(struct bregs *regs)
+{
+ set_cf(regs, 0);
+}
+
+// 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_cf(regs, 0);
+}
+
+// Get PM Event
+static void
+handle_15530b(struct bregs *regs)
+{
+ regs->ah = 0x80; // no event pending
+ set_cf(regs, 1);
+}
+
+// APM Driver Version
+static void
+handle_15530e(struct bregs *regs)
+{
+ regs->ah = 1;
+ regs->al = 2;
+ set_cf(regs, 0);
+}
+
+// APM Engage / Disengage
+static void
+handle_15530f(struct bregs *regs)
+{
+ set_cf(regs, 0);
+}
+
+// APM Get Capabilities
+static void
+handle_155310(struct bregs *regs)
+{
+ regs->bl = 0;
+ regs->cx = 0;
+ set_cf(regs, 0);
+}
+
+static void
+handle_1553XX(struct bregs *regs)
+{
+ set_cf(regs, 1);
+}
+
+void
+handle_1553(struct bregs *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 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;
+ }
+}