apm.c revision ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/* $Id$ */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/** @file
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * APM BIOS support. Implements APM version 1.2.
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/*
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * Copyright (C) 2004-2012 Oracle Corporation
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync *
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * available from http://www.virtualbox.org. This file is free software;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * General Public License (GPL) as published by the Free Software
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#include <stdint.h>
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#include <string.h>
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#include "biosint.h"
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#include "inlines.h"
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define DEBUG_APM 1 //@todo!
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#if DEBUG_APM
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync# define BX_DEBUG_APM(...) BX_DEBUG(__VA_ARGS__)
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#else
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync# define BX_DEBUG_APM(...)
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#endif
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/* Implemented in assembly. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncextern void apm_pm16_entry(void);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#pragma aux apm_pm16_entry "*"
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncextern void apm_pm32_entry(void);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#pragma aux apm_pm32_entry "*"
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/* APM function codes. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncenum apm_func {
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_CHECK = 0x00, /* APM Installation Check */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_RM_CONN = 0x01, /* APM Real Mode Interface Connect */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_PM_CONN = 0x02, /* APM Protected Mode 16-bit Interface Connect */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_32_CONN = 0x03, /* APM Protected Mode 32-bit Interface Connect */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_DISCONN = 0x04, /* APM Interface Disconnect */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_IDLE = 0x05, /* CPU Idle */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_BUSY = 0x06, /* CPU Busy */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_SET_PWR = 0x07, /* Set Power State */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ENBL_PM = 0x08, /* Enable/Disable Power Management */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_SET_DFL = 0x09, /* Restore APM BIOS Power-On Defaults */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_STATUS = 0x0A, /* Get Power Status */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_GET_EVT = 0x0B, /* Get PM Event */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_GET_PWR = 0x0C, /* Get Power State */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_DEVPM = 0x0D, /* Enable/Disable Device Power Management */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_DRV_VER = 0x0E, /* APM Driver Version */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ENGAGE = 0x0F, /* Engage/Disengage Power Management */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_GET_CAP = 0x10 /* Get Capabilities */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync};
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncenum apm_error {
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_PM_DISABLED = 0x01, /* Power Management functionality disabled */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_RM_INUSE = 0x02, /* Real mode interface connection already established */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_NOT_CONN = 0x03, /* Interface not connected */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_PM_16_INUSE = 0x05, /* 16-bit protected mode interface connection already established */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_NO_PM_16 = 0x06, /* 16-bit protected mode interface not supported */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_PM_32_INUSE = 0x07, /* 32-bit protected mode interface connection already established */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_NO_PM_32 = 0x08, /* 32-bit protected mode interface not supported */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_BAD_DEV_ID = 0x09, /* Unrecognized device ID */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_INVAL_PARAM = 0x0A, /* Parameter out of range */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_NOT_ENGAGED = 0x0B, /* Interface not engaged */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_UNSUPPORTED = 0x0C, /* Function not supported */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_NO_RSM_TMR = 0x0D, /* Resume timer disabled */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_ERR_NO_EVENTS = 0x80 /* No power management events pending */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync};
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncenum apm_power_state {
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_PS_ENABLED = 0x00, /* APM enabled */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_PS_STANDBY = 0x01, /* Standby */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_PS_SUSPEND = 0x02, /* Suspend */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync APM_PS_OFF = 0x03, /* Suspend */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync};
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define APM_PORT 0x8900 /* Bochs power control port. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync// @todo: merge with system.c
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define AX r.gr.u.r16.ax
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define BX r.gr.u.r16.bx
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define CX r.gr.u.r16.cx
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define DX r.gr.u.r16.dx
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define SI r.gr.u.r16.si
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define DI r.gr.u.r16.di
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define BP r.gr.u.r16.bp
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define SP r.gr.u.r16.sp
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define FLAGS r.fl.u.r16.flags
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define EAX r.gr.u.r32.eax
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define EBX r.gr.u.r32.ebx
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define ECX r.gr.u.r32.ecx
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define EDX r.gr.u.r32.edx
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define ES r.es
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define APM_BIOS_SEG 0xF000 /* Real-mode APM segment. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#define APM_BIOS_SEG_LEN 0xFFF0 /* Length of APM segment. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/* The APM BIOS interface uses 32-bit registers *only* in the 32-bit
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * protected mode connect call. Rather than saving/restoring 32-bit
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * registers all the time, simply set the high words of those registers
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * when necessary.
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncvoid set_ebx_hi(uint16_t val);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#pragma aux set_ebx_hi = \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync ".386" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "shl ebx, 16" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync parm [bx] modify exact [bx] nomemory;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncvoid set_esi_hi(uint16_t val);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#pragma aux set_esi_hi = \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync ".386" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "shl esi, 16" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync parm [si] modify exact [si] nomemory;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/* The APM handler has unique requirements. It must be callable from real and
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * protected mode, both 16-bit and 32-bit. In protected mode, the caller must
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * ensures that appropriate selectors are available; these only cover the BIOS
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * code and data, hence the BIOS Data Area or EBDA cannot be accessed. CMOS is
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * a good place to store information which needs to be accessible from several
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * different contexts.
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync *
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * Note that the 32-bit protected-mode handler only needs to thunk down to the
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * 16-bit code. There's no need for separate 16-bit and 32-bit implementation.
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/* Output a null-terminated string to a specified port, without the
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync * terminating null character.
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncstatic void apm_out_str_asm(uint16_t port, const char *s);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync#pragma aux apm_out_str_asm = \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "mov al, [bx]" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "next:" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "out dx, al" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "inc bx" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "mov al, [bx]" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "or al, al" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync "jnz next" \
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync parm [dx] [bx] modify exact [ax bx] nomemory;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync/* Wrapper to avoid unnecessary inlining. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncvoid apm_out_str(const char *s, uint16_t port)
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync{
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync if (*s)
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync apm_out_str_asm(port, s);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync}
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsyncvoid BIOSCALL apm_function(sys_regs_t r)
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync{
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync BX_DEBUG_APM("APM: AX=%04X BX=%04X CX=%04X\n", AX, BX, CX);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync CLEAR_CF(); /* Boldly expect success. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync switch (GET_AL()) {
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_CHECK:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync AX = 0x0102; /* Version 1.2 */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync BX = 0x504D; /* 'PM' */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync CX = 3; /* Bits 0/1: 16-bit/32-bit PM interface */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_RM_CONN:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: validate device ID
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: validate current connection state
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: change connection state
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync case APM_PM_CONN:
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync // @todo: validate device ID
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync // @todo: validate current connection state
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync // @todo: change connection state
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync AX = APM_BIOS_SEG; /* 16-bit PM code segment (RM segment base). */
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync BX = (uint16_t)apm_pm16_entry; /* 16-bit PM entry point offset. */
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync CX = APM_BIOS_SEG; /* 16-bit data segment. */
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync SI = APM_BIOS_SEG_LEN; /* 16-bit PM code segment length. */
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync DI = APM_BIOS_SEG_LEN; /* Data segment length. */
ea18eebe4b48f0b8dac8abfa45b1f8d677b4a731vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_32_CONN:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: validate device ID
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: validate current connection state
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: change connection state
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync AX = APM_BIOS_SEG; /* 32-bit PM code segment (RM segment base). */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync BX = (uint16_t)apm_pm32_entry; /* 32-bit entry point offset. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync CX = APM_BIOS_SEG; /* 16-bit code segment. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync DX = APM_BIOS_SEG; /* 16-bit data segment. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync SI = APM_BIOS_SEG_LEN; /* 32-bit code segment length. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync DI = APM_BIOS_SEG_LEN; /* Data segment length. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync set_ebx_hi(0);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync set_esi_hi(APM_BIOS_SEG_LEN); /* 16-bit code segment length. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_IDLE:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync int_enable(); /* Simply halt the CPU with interrupts enabled. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync halt();
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_SET_PWR:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: validate device ID
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: validate current connection state
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync switch (CX) {
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_PS_STANDBY:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync apm_out_str("Standby", APM_PORT);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_PS_SUSPEND:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync apm_out_str("Suspend", APM_PORT);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_PS_OFF:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync apm_out_str("Shutdown", APM_PORT); /* Should not return. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync default:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync SET_AH(APM_ERR_INVAL_PARAM);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync SET_CF();
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync }
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_DRV_VER:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync AX = 0x0102; // @todo: Not right - must take driver version into account!
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_DISCONN:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: actually perform a disconnect...
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_BUSY: /* Nothing to do as APM Idle doesn't slow CPU clock. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync case APM_GET_EVT:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync // @todo: error should be different if interface not connected + engaged
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync SET_AH(APM_ERR_NO_EVENTS); /* PM events don't happen. */
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync SET_CF();
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync break;
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync default:
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync BX_INFO("APM: Unsupported function AX=%04X BX=%04X called\n", AX, BX);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync SET_AH(APM_ERR_UNSUPPORTED);
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync SET_CF();
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync }
0886d8f3dd24cf84b1875e6b3147c600c2eec6c2vboxsync}