vgabios: Add scrolling for linear (packed pixel) graphics mode.
[seabios.git] / src / apm.c
index 9b6d1e3830a1644d4197a1172dd12fcacfcb8702..c497dbecd8306b514d1d07e9baf2dac889b1f50b 100644 (file)
--- a/src/apm.c
+++ b/src/apm.c
@@ -4,22 +4,29 @@
 // Copyright (C) 2005 Struan Bartlett
 // Copyright (C) 2004 Fabrice Bellard
 //
-// This file may be distributed under the terms of the GNU GPLv3 license.
+// This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "farptr.h" // GET_VAR
-#include "biosvar.h" // struct bregs
+#include "bregs.h" // struct bregs
 #include "ioport.h" // outb
-#include "util.h" // irq_enable
+#include "util.h" // wait_irq
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
 
 static void
 out_str(const char *str_cs)
 {
+    if (CONFIG_COREBOOT) {
+        dprintf(1, "APM request '%s'\n", str_cs);
+        return;
+    }
+
     u8 *s = (u8*)str_cs;
     for (;;) {
-        u8 c = GET_VAR(CS, *s);
+        u8 c = GET_GLOBAL(*s);
         if (!c)
             break;
-        outb(c, 0x8900);
+        outb(c, PORT_BIOS_APM);
         s++;
     }
 }
@@ -35,57 +42,76 @@ handle_155300(struct bregs *regs)
     // bit 0 : 16 bit interface supported
     // bit 1 : 32 bit interface supported
     regs->cx = 0x03;
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
 // APM real mode interface connect
 static void
 handle_155301(struct bregs *regs)
 {
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
+// Assembler entry points defined in romlayout.S
+extern void entry_apm16(void);
+extern void entry_apm32(void);
+
 // APM 16 bit protected mode interface connect
 static void
 handle_155302(struct bregs *regs)
 {
-    regs->bx = 0; // XXX - apm16_entry
+    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_cf(regs, 0);
+    set_success(regs);
 }
 
 // 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
+    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 = 0xf000; // data segment address
+    regs->dx = SEG_BIOS; // data segment address
     regs->di = 0xfff0; // data segment length
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
 // APM interface disconnect
 static void
 handle_155304(struct bregs *regs)
 {
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
 // APM cpu idle
 static void
 handle_155305(struct bregs *regs)
 {
-    irq_enable();
-    hlt();
-    set_cf(regs, 0);
+    wait_irq();
+    set_success(regs);
+}
+
+// APM cpu busy
+static void
+handle_155306(struct bregs *regs)
+{
+    set_success(regs);
+}
+
+void
+apm_shutdown(void)
+{
+    irq_disable();
+    out_str("Shutdown");
+    for (;;)
+        hlt();
 }
 
 // APM Set Power State
@@ -93,7 +119,7 @@ static void
 handle_155307(struct bregs *regs)
 {
     if (regs->bx != 1) {
-        set_cf(regs, 0);
+        set_success(regs);
         return;
     }
     switch (regs->cx) {
@@ -104,19 +130,16 @@ handle_155307(struct bregs *regs)
         out_str("Suspend");
         break;
     case 3:
-        irq_disable();
-        out_str("Shutdown");
-        for (;;)
-            hlt();
+        apm_shutdown();
         break;
     }
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
 static void
 handle_155308(struct bregs *regs)
 {
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
 // Get Power Status
@@ -129,15 +152,16 @@ handle_15530a(struct bregs *regs)
     regs->cl = 0xff; // unknown remaining time
     regs->dx = 0xffff; // unknown remaining time
     regs->si = 0x00; // zero battery
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
+#define RET_ENOEVENT 0x80
+
 // Get PM Event
 static void
 handle_15530b(struct bregs *regs)
 {
-    regs->ah = 0x80; // no event pending
-    set_cf(regs, 1);
+    set_code_invalid_silent(regs, RET_ENOEVENT);
 }
 
 // APM Driver Version
@@ -146,14 +170,14 @@ handle_15530e(struct bregs *regs)
 {
     regs->ah = 1;
     regs->al = 2;
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
 // APM Engage / Disengage
 static void
 handle_15530f(struct bregs *regs)
 {
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
 // APM Get Capabilities
@@ -162,18 +186,24 @@ handle_155310(struct bregs *regs)
 {
     regs->bl = 0;
     regs->cx = 0;
-    set_cf(regs, 0);
+    set_success(regs);
 }
 
 static void
 handle_1553XX(struct bregs *regs)
 {
-    set_cf(regs, 1);
+    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;
@@ -181,6 +211,7 @@ handle_1553(struct bregs *regs)
     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;
@@ -191,3 +222,17 @@ handle_1553(struct bregs *regs)
     default:   handle_1553XX(regs); break;
     }
 }
+
+void VISIBLE16
+handle_apm16(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_apm);
+    handle_1553(regs);
+}
+
+void VISIBLE32SEG
+handle_apm32(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_apm);
+    handle_1553(regs);
+}