==== //depot/projects/power/sys/dev/acpica/acpi_video.c#2 - /home/john/work/p4/power/sys/dev/acpica/acpi_video.c ==== @@ -1,5 +1,6 @@ /*- * Copyright (c) 2002-2003 Taku YAMAMOTO + * Copyright (c) 2004 Benjamin Close * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,10 +35,33 @@ #include #include #include +#ifdef __i386__ +#include +#endif #include "acpi.h" #include +#ifdef __i386__ +#define USE_DPMS + +/* + * VESA DPMS States + */ +#define DPMS_ON 0x00 +#define DPMS_STANDBY 0x01 +#define DPMS_SUSPEND 0x02 +#define DPMS_OFF 0x04 +#define DPMS_REDUCEDON 0x08 + +#define VBE_DPMS_FUNCTION 0x4F10 +#define VBE_DPMS_GET_SUPPORTED_STATES 0x00 +#define VBE_DPMS_GET_STATE 0x02 +#define VBE_DPMS_SET_STATE 0x01 +#define VBE_MAJORVERSION_MASK 0x0F +#define VBE_MINORVERSION_MASK 0xF0 +#endif + /* ACPI video extension driver. */ struct acpi_video_output { ACPI_HANDLE handle; @@ -63,6 +87,10 @@ ACPI_HANDLE handle; STAILQ_HEAD(, acpi_video_output) vid_outputs; eventhandler_tag vid_pwr_evh; +#ifdef USE_DPMS + int vid_dpms_supported_states; + int vid_dpms_initial_state; +#endif }; /* interfaces */ @@ -71,6 +99,8 @@ static int acpi_video_attach(device_t); static int acpi_video_detach(device_t); static int acpi_video_shutdown(device_t); +static int acpi_video_suspend(device_t); +static int acpi_video_resume(device_t); static void acpi_video_notify_handler(ACPI_HANDLE, UINT32, void *); static void acpi_video_power_profile(void *); static void acpi_video_bind_outputs(struct acpi_video_softc *); @@ -94,6 +124,11 @@ static UINT32 vo_get_device_status(ACPI_HANDLE); static UINT32 vo_query_graphics_state(ACPI_HANDLE); static void vo_set_device_state(ACPI_HANDLE, UINT32); +#ifdef USE_DPMS +static int dpms_get_supported_states(int *); +static int dpms_get_current_state(int *); +static int dpms_set_state(int); +#endif /* events */ #define VID_NOTIFY_SWITCHED 0x80 @@ -141,6 +176,8 @@ DEVMETHOD(device_attach, acpi_video_attach), DEVMETHOD(device_detach, acpi_video_detach), DEVMETHOD(device_shutdown, acpi_video_shutdown), + DEVMETHOD(device_resume, acpi_video_resume), + DEVMETHOD(device_suspend, acpi_video_suspend), { 0, 0 } }; @@ -242,6 +279,13 @@ ACPI_UNLOCK; acpi_video_power_profile(sc); +#ifdef USE_DPMS + if (dpms_get_supported_states(&sc->vid_dpms_supported_states) == 0) + dpms_get_current_state(&sc->vid_dpms_initial_state); + else + sc->vid_dpms_supported_states = -1; +#endif + return (0); } @@ -283,6 +327,32 @@ return (0); } +static int +acpi_video_suspend(device_t dev) +{ + struct acpi_video_softc *sc; + + sc = device_get_softc(dev); +#ifdef USE_DPMS + if (sc->vid_dpms_supported_states != -1) + dpms_set_state(DPMS_OFF); +#endif + return (0); +} + +static int +acpi_video_resume(device_t dev) +{ + struct acpi_video_softc *sc; + + sc = device_get_softc(dev); +#ifdef USE_DPMS + if (sc->vid_dpms_supported_states != -1) + dpms_set_state(sc->vid_dpms_initial_state); +#endif + return (0); +} + static void acpi_video_notify_handler(ACPI_HANDLE handle __unused, UINT32 notify, void *context) { @@ -929,3 +999,49 @@ printf("can't evaluate %s._DSS - %s\n", acpi_name(handle), AcpiFormatException(status)); } + +#ifdef USE_DPMS +/* XXX: Requires VM86 support in the kernel. */ +static int +dpms_call_bios(int subfunction, int *bh) +{ + struct vm86frame vmf; + int error; + + bzero(&vmf, sizeof(vmf)); + vmf.vmf_ax = VBE_DPMS_FUNCTION; + vmf.vmf_bl = subfunction; + vmf.vmf_bh = *bh; + vmf.vmf_es = 0; + vmf.vmf_di = 0; + error = vm86_intcall(0x10, &vmf); + if (error == 0 && (vmf.vmf_eax & 0xffff) != 0x004f) + error = ENXIO; + if (error == 0) + *bh = vmf.vmf_bh; + return (error); +} + +static int +dpms_get_supported_states(int *states) +{ + + *states = 0; + return (dpms_call_bios(VBE_DPMS_GET_SUPPORTED_STATES, states)); +} + +static int +dpms_get_current_state(int *state) +{ + + *state = 0; + return (dpms_call_bios(VBE_DPMS_GET_STATE, state)); +} + +static int +dpms_set_state(int state) +{ + + return (dpms_call_bios(VBE_DPMS_SET_STATE, &state)); +} +#endif