diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/apm.c | 193 | ||||
-rw-r--r-- | src/system.c | 7 | ||||
-rw-r--r-- | src/util.h | 8 |
4 files changed, 202 insertions, 8 deletions
@@ -9,7 +9,7 @@ OUT=out/ # Source files SRC16=floppy.c disk.c system.c clock.c serial.c kbd.c mouse.c output.c \ - boot.c ata.c cdrom.c + boot.c ata.c cdrom.c apm.c SRC32=post.c output.c TABLESRC=font.c cbt.c floppy_dbt.c 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; + } +} diff --git a/src/system.c b/src/system.c index e09797b6..29f00527 100644 --- a/src/system.c +++ b/src/system.c @@ -78,13 +78,6 @@ handle_1552(struct bregs *regs) handle_ret(regs, 0); } -static void -handle_1553(struct bregs *regs) -{ - // XXX - APM call - handle_ret(regs, RET_EUNSUPPORTED); -} - // Sleep for n microseconds. currently using the // refresh request port 0x61 bit4, toggling every 15usec static void @@ -37,6 +37,11 @@ static inline void nop(void) asm volatile("nop"); } +static inline void hlt(void) +{ + asm volatile("hlt"); +} + #define BX_PANIC(fmt, args...) bprintf(0, fmt , ##args) #define BX_INFO(fmt, args...) bprintf(0, fmt , ##args) @@ -121,6 +126,9 @@ void handle_15c2(struct bregs *regs); // clock.c void handle_1583(struct bregs *regs); +// apm.c +void handle_1553(struct bregs *regs); + // Frequent bios return helper #define RET_EUNSUPPORTED 0x86 static inline void |