From bfd4c59b639308dc5bc06f8273c4bb0c5e4e4598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 5 Jun 2009 13:03:05 +0000 Subject: [PATCH] * Added DPMS support to the VESA driver, in case the hardware/BIOS supports it. * Minor cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30974 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/graphics/vesa/vesa.h | 11 +- headers/private/graphics/vesa/vesa_info.h | 5 +- src/add-ons/accelerants/vesa/dpms.cpp | 19 +- src/add-ons/accelerants/vesa/mode.cpp | 50 ++-- .../kernel/drivers/graphics/vesa/device.cpp | 124 +++++---- .../kernel/drivers/graphics/vesa/vesa.cpp | 250 ++++++++++++++---- .../drivers/graphics/vesa/vesa_private.h | 17 +- 7 files changed, 332 insertions(+), 144 deletions(-) diff --git a/headers/private/graphics/vesa/vesa.h b/headers/private/graphics/vesa/vesa.h index 55a17052af..11c3f5e203 100644 --- a/headers/private/graphics/vesa/vesa.h +++ b/headers/private/graphics/vesa/vesa.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef VESA_H @@ -141,6 +141,15 @@ struct crtc_info_block { #define CRTC_NEGATIVE_VSYNC 0x08 +/* Power Management */ + +#define DPMS_ON 0x00 +#define DPMS_STANDBY 0x01 +#define DPMS_SUSPEND 0x02 +#define DPMS_OFF 0x04 +#define DPMS_REDUCED_ON 0x08 + + /* VBE 3.0 protected mode interface * The BIOS area can be scanned for the protected mode * signature that identifies the structure below. diff --git a/headers/private/graphics/vesa/vesa_info.h b/headers/private/graphics/vesa/vesa_info.h index de6c94a224..3db0fd27fa 100644 --- a/headers/private/graphics/vesa/vesa_info.h +++ b/headers/private/graphics/vesa/vesa_info.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef VESA_INFO_H @@ -40,6 +40,7 @@ struct vesa_shared_info { edid1_info edid_info; bool has_edid; + uint32 dpms_capabilities; }; //----------------- ioctl() interface ---------------- @@ -49,6 +50,8 @@ enum { VESA_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, VESA_GET_DEVICE_NAME, VESA_SET_DISPLAY_MODE, + VESA_GET_DPMS_MODE, + VESA_SET_DPMS_MODE, VGA_SET_INDEXED_COLORS, VGA_PLANAR_BLIT, diff --git a/src/add-ons/accelerants/vesa/dpms.cpp b/src/add-ons/accelerants/vesa/dpms.cpp index caff4d6a4f..ddb778b7a5 100644 --- a/src/add-ons/accelerants/vesa/dpms.cpp +++ b/src/add-ons/accelerants/vesa/dpms.cpp @@ -1,9 +1,11 @@ /* - * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ +#include + #include "accelerant_protos.h" #include "accelerant.h" @@ -11,20 +13,27 @@ uint32 vesa_dpms_capabilities(void) { - return B_DPMS_ON; + return gInfo->shared_info->dpms_capabilities; } uint32 vesa_dpms_mode(void) { - return B_DPMS_ON; + uint32 mode; + if (ioctl(gInfo->device, VESA_GET_DPMS_MODE, &mode, sizeof(mode)) != 0) + return B_DPMS_ON; + + return mode; } status_t -vesa_set_dpms_mode(uint32 dpms_flags) +vesa_set_dpms_mode(uint32 mode) { - return B_ERROR; + if (ioctl(gInfo->device, VESA_SET_DPMS_MODE, &mode, sizeof(mode)) != 0) + return errno; + + return B_OK; } diff --git a/src/add-ons/accelerants/vesa/mode.cpp b/src/add-ons/accelerants/vesa/mode.cpp index 9a1bb81342..7fd534f3c9 100644 --- a/src/add-ons/accelerants/vesa/mode.cpp +++ b/src/add-ons/accelerants/vesa/mode.cpp @@ -1,8 +1,9 @@ /* - * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ + #include #include @@ -14,7 +15,7 @@ //#define TRACE_MODE #ifdef TRACE_MODE -extern "C" void _sPrintf(const char *format, ...); +extern "C" void _sPrintf(const char* format, ...); # define TRACE(x) _sPrintf x #else # define TRACE(x) ; @@ -46,9 +47,9 @@ get_color_space_for_depth(uint32 depth) /*! Checks if the specified \a mode can be set using VESA. */ static bool -is_mode_supported(display_mode *mode) +is_mode_supported(display_mode* mode) { - vesa_mode *modes = gInfo->vesa_modes; + vesa_mode* modes = gInfo->vesa_modes; for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { // search mode in VESA mode list @@ -96,7 +97,7 @@ vesa_accelerant_mode_count(void) status_t -vesa_get_mode_list(display_mode *modeList) +vesa_get_mode_list(display_mode* modeList) { TRACE(("vesa_get_mode_info()\n")); memcpy(modeList, gInfo->mode_list, @@ -106,15 +107,15 @@ vesa_get_mode_list(display_mode *modeList) status_t -vesa_propose_display_mode(display_mode *target, const display_mode *low, - const display_mode *high) +vesa_propose_display_mode(display_mode* target, const display_mode* low, + const display_mode* high) { TRACE(("vesa_propose_display_mode()\n")); // just search for the specified mode in the list for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { - display_mode *current = &gInfo->mode_list[i]; + display_mode* current = &gInfo->mode_list[i]; if (target->virtual_width != current->virtual_width || target->virtual_height != current->virtual_height @@ -129,7 +130,7 @@ vesa_propose_display_mode(display_mode *target, const display_mode *low, status_t -vesa_set_display_mode(display_mode *_mode) +vesa_set_display_mode(display_mode* _mode) { TRACE(("vesa_set_display_mode()\n")); @@ -137,8 +138,8 @@ vesa_set_display_mode(display_mode *_mode) if (vesa_propose_display_mode(&mode, &mode, &mode) != B_OK) return B_BAD_VALUE; - vesa_mode *modes = gInfo->vesa_modes; - for (unsigned int i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { + vesa_mode* modes = gInfo->vesa_modes; + for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) { // search mode in VESA mode list // TODO: list is ordered, we could use binary search if (modes[i].width == mode.virtual_width @@ -153,7 +154,7 @@ vesa_set_display_mode(display_mode *_mode) status_t -vesa_get_display_mode(display_mode *_currentMode) +vesa_get_display_mode(display_mode* _currentMode) { TRACE(("vesa_get_display_mode()\n")); *_currentMode = gInfo->shared_info->current_mode; @@ -162,7 +163,7 @@ vesa_get_display_mode(display_mode *_currentMode) status_t -vesa_get_edid_info(void *info, size_t size, uint32 *_version) +vesa_get_edid_info(void* info, size_t size, uint32* _version) { TRACE(("intel_get_edid_info()\n")); @@ -178,7 +179,7 @@ vesa_get_edid_info(void *info, size_t size, uint32 *_version) status_t -vesa_get_frame_buffer_config(frame_buffer_config *config) +vesa_get_frame_buffer_config(frame_buffer_config* config) { TRACE(("vesa_get_frame_buffer_config()\n")); @@ -191,20 +192,21 @@ vesa_get_frame_buffer_config(frame_buffer_config *config) status_t -vesa_get_pixel_clock_limits(display_mode *mode, uint32 *low, uint32 *high) +vesa_get_pixel_clock_limits(display_mode* mode, uint32* low, uint32* high) { TRACE(("vesa_get_pixel_clock_limits()\n")); - // ToDo: do some real stuff here (taken from radeon driver) - uint32 total_pix = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total; - uint32 clock_limit = 2000000; + // TODO: do some real stuff here (taken from radeon driver) + uint32 totalPixel = (uint32)mode->timing.h_total + * (uint32)mode->timing.v_total; + uint32 clockLimit = 2000000; - /* lower limit of about 48Hz vertical refresh */ - *low = (total_pix * 48L) / 1000L; - if (*low > clock_limit) + // lower limit of about 48Hz vertical refresh + *low = totalPixel * 48L / 1000L; + if (*low > clockLimit) return B_ERROR; - *high = clock_limit; + *high = clockLimit; return B_OK; } @@ -218,7 +220,7 @@ vesa_move_display(uint16 h_display_start, uint16 v_display_start) status_t -vesa_get_timing_constraints(display_timing_constraints *dtc) +vesa_get_timing_constraints(display_timing_constraints* constraints) { TRACE(("vesa_get_timing_constraints()\n")); return B_ERROR; @@ -226,7 +228,7 @@ vesa_get_timing_constraints(display_timing_constraints *dtc) void -vesa_set_indexed_colors(uint count, uint8 first, uint8 *colors, uint32 flags) +vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) { TRACE(("vesa_set_indexed_colors()\n")); vga_set_indexed_colors_args args; diff --git a/src/add-ons/kernel/drivers/graphics/vesa/device.cpp b/src/add-ons/kernel/drivers/graphics/vesa/device.cpp index d6fd5b4daa..c8ddde7bd4 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/device.cpp +++ b/src/add-ons/kernel/drivers/graphics/vesa/device.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -32,53 +32,23 @@ #endif -/* device hooks prototypes */ - -static status_t device_open(const char *, uint32, void **); -static status_t device_close(void *); -static status_t device_free(void *); -static status_t device_ioctl(void *, uint32, void *, size_t); -static status_t device_read(void *, off_t, void *, size_t *); -static status_t device_write(void *, off_t, const void *, size_t *); - - -device_hooks gDeviceHooks = { - device_open, - device_close, - device_free, - device_ioctl, - device_read, - device_write, - NULL, - NULL, - NULL, - NULL -}; - - -// #pragma mark - -// the device will be accessed through the following functions (a.k.a. device hooks) - - static status_t -device_open(const char *name, uint32 flags, void **_cookie) +device_open(const char* name, uint32 flags, void** _cookie) { int id; // find accessed device - { - char *thisName; + char* thisName; - // search for device name - for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) { - if (!strcmp(name, thisName)) - break; - } - if (!thisName) - return EINVAL; + // search for device name + for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) { + if (!strcmp(name, thisName)) + break; } + if (thisName == NULL) + return B_BAD_VALUE; - vesa_info *info = gDeviceInfo[id]; + vesa_info* info = gDeviceInfo[id]; *_cookie = info; acquire_lock(&gLock); @@ -100,16 +70,16 @@ device_open(const char *name, uint32 flags, void **_cookie) static status_t -device_close(void *cookie) +device_close(void* cookie) { return B_OK; } static status_t -device_free(void *cookie) +device_free(void* cookie) { - struct vesa_info *info = (vesa_info *)cookie; + struct vesa_info* info = (vesa_info*)cookie; acquire_lock(&gLock); @@ -124,26 +94,26 @@ device_free(void *cookie) static status_t -device_ioctl(void *cookie, uint32 msg, void *buffer, size_t bufferLength) +device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength) { - struct vesa_info *info = (vesa_info *)cookie; + struct vesa_info* info = (vesa_info*)cookie; switch (msg) { case B_GET_ACCELERANT_SIGNATURE: dprintf(DEVICE_NAME ": acc: %s\n", VESA_ACCELERANT_NAME); - if (user_strlcpy((char *)buffer, VESA_ACCELERANT_NAME, + if (user_strlcpy((char*)buffer, VESA_ACCELERANT_NAME, B_FILE_NAME_LENGTH) < B_OK) return B_BAD_ADDRESS; return B_OK; - // needed to share data between kernel and accelerant + // needed to share data between kernel and accelerant case VESA_GET_PRIVATE_DATA: return user_memcpy(buffer, &info->shared_area, sizeof(area_id)); // needed for cloning case VESA_GET_DEVICE_NAME: - if (user_strlcpy((char *)buffer, gDeviceNames[info->id], + if (user_strlcpy((char*)buffer, gDeviceNames[info->id], B_PATH_NAME_LENGTH) < B_OK) return B_BAD_ADDRESS; @@ -151,15 +121,41 @@ device_ioctl(void *cookie, uint32 msg, void *buffer, size_t bufferLength) case VESA_SET_DISPLAY_MODE: { - unsigned int mode; + if (bufferLength != sizeof(uint32)) + return B_BAD_VALUE; - if (bufferLength != sizeof(mode) - || user_memcpy(&mode, buffer, sizeof(mode)) < B_OK) + uint32 mode; + if (user_memcpy(&mode, buffer, sizeof(uint32)) < B_OK) return B_BAD_ADDRESS; return vesa_set_display_mode(*info, mode); } + case VESA_GET_DPMS_MODE: + { + if (bufferLength != sizeof(uint32)) + return B_BAD_VALUE; + + uint32 mode; + status_t status = vesa_get_dpms_mode(*info, mode); + if (status != B_OK) + return status; + + return user_memcpy(buffer, &mode, sizeof(mode)); + } + + case VESA_SET_DPMS_MODE: + { + if (bufferLength != sizeof(uint32)) + return B_BAD_VALUE; + + uint32 mode; + if (user_memcpy(&mode, buffer, sizeof(uint32)) < B_OK) + return B_BAD_ADDRESS; + + return vesa_set_dpms_mode(*info, mode); + } + case VGA_SET_INDEXED_COLORS: { vga_set_indexed_colors_args args; @@ -181,7 +177,9 @@ device_ioctl(void *cookie, uint32 msg, void *buffer, size_t bufferLength) } default: - TRACE((DEVICE_NAME ": ioctl() unknown message %ld (length = %lu)\n", msg, bufferLength)); + TRACE((DEVICE_NAME ": ioctl() unknown message %ld (length = %lu)\n", + msg, bufferLength)); + break; } return B_DEV_INVALID_IOCTL; @@ -189,17 +187,31 @@ device_ioctl(void *cookie, uint32 msg, void *buffer, size_t bufferLength) static status_t -device_read(void */*cookie*/, off_t /*pos*/, void */*buffer*/, size_t *_length) +device_read(void* /*cookie*/, off_t /*pos*/, void* /*buffer*/, size_t* _length) { - *_length = 0; + *_length = 0; return B_NOT_ALLOWED; } static status_t -device_write(void */*cookie*/, off_t /*pos*/, const void */*buffer*/, size_t *_length) +device_write(void* /*cookie*/, off_t /*pos*/, const void* /*buffer*/, + size_t* _length) { - *_length = 0; + *_length = 0; return B_NOT_ALLOWED; } + +device_hooks gDeviceHooks = { + device_open, + device_close, + device_free, + device_ioctl, + device_read, + device_write, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp b/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp index f5fcf87b0e..f38ad72b40 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp +++ b/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -44,26 +44,26 @@ get_color_space_for_depth(uint32 depth) static status_t -vbe_get_mode_info(struct vm86_state *vmState, uint16 mode, - struct vbe_mode_info *modeInfo) +vbe_get_mode_info(struct vm86_state& vmState, uint16 mode, + struct vbe_mode_info* modeInfo) { - struct vbe_mode_info *vbeModeInfo = (struct vbe_mode_info *)0x1000; + struct vbe_mode_info* vbeModeInfo = (struct vbe_mode_info*)0x1000; memset(vbeModeInfo, 0, sizeof(vbe_mode_info)); - vmState->regs.eax = 0x4f01; - vmState->regs.ecx = mode; - vmState->regs.es = 0x1000 >> 4; - vmState->regs.edi = 0x0000; + vmState.regs.eax = 0x4f01; + vmState.regs.ecx = mode; + vmState.regs.es = 0x1000 >> 4; + vmState.regs.edi = 0x0000; - status_t status = vm86_do_int(vmState, 0x10); + status_t status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): vm86 failed\n", mode); return status; } - if ((vmState->regs.eax & 0xffff) != 0x4f) { + if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vbe_get_mode_info(): BIOS returned 0x%04lx\n", - vmState->regs.eax & 0xffff); + vmState.regs.eax & 0xffff); return B_ENTRY_NOT_FOUND; } @@ -73,20 +73,20 @@ vbe_get_mode_info(struct vm86_state *vmState, uint16 mode, static status_t -vbe_set_mode(struct vm86_state *vmState, uint16 mode) +vbe_set_mode(struct vm86_state& vmState, uint16 mode) { - vmState->regs.eax = 0x4f02; - vmState->regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; + vmState.regs.eax = 0x4f02; + vmState.regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; - status_t status = vm86_do_int(vmState, 0x10); + status_t status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vbe_set_mode(%u): vm86 failed\n", mode); return status; } - if ((vmState->regs.eax & 0xffff) != 0x4f) { + if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vbe_set_mode(): BIOS returned 0x%04lx\n", - vmState->regs.eax & 0xffff); + vmState.regs.eax & 0xffff); return B_ERROR; } @@ -94,26 +94,84 @@ vbe_set_mode(struct vm86_state *vmState, uint16 mode) } +static uint32 +vbe_to_system_dpms(uint8 vbeMode) +{ + uint32 mode = 0; + if ((vbeMode & (DPMS_OFF | DPMS_REDUCED_ON)) != 0) + mode |= B_DPMS_OFF; + if ((vbeMode & DPMS_STANDBY) != 0) + mode |= B_DPMS_STAND_BY; + if ((vbeMode & DPMS_SUSPEND) != 0) + mode |= B_DPMS_SUSPEND; + + return mode; +} + + +static status_t +vbe_get_dpms_capabilities(uint32& vbeMode, uint32& mode) +{ + // we always return a valid mode + vbeMode = 0; + mode = B_DPMS_ON; + + // Prepare vm86 mode environment + struct vm86_state vmState; + status_t status = vm86_prepare(&vmState, 0x20000); + if (status != B_OK) { + dprintf(DEVICE_NAME": vbe_get_dpms_capabilities(): vm86_prepare " + "failed: %s\n", strerror(status)); + return status; + } + + vmState.regs.eax = 0x4f10; + vmState.regs.ebx = 0; + vmState.regs.esi = 0; + vmState.regs.edi = 0; + + status = vm86_do_int(&vmState, 0x10); + if (status != B_OK) { + dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): vm86 failed\n"); + goto out; + } + + if ((vmState.regs.eax & 0xffff) != 0x4f) { + dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): BIOS returned " + "0x%04lx\n", vmState.regs.eax & 0xffff); + status = B_ERROR; + goto out; + } + + vbeMode = vmState.regs.ebx >> 8; + mode = vbe_to_system_dpms(vbeMode); + +out: + vm86_cleanup(&vmState); + return status; +} + + // #pragma mark - status_t -vesa_init(vesa_info &info) +vesa_init(vesa_info& info) { - frame_buffer_boot_info *bufferInfo - = (frame_buffer_boot_info *)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); + frame_buffer_boot_info* bufferInfo + = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); if (bufferInfo == NULL) return B_ERROR; size_t modesSize = 0; - vesa_mode *modes = (vesa_mode *)get_boot_item(VESA_MODES_BOOT_INFO, + vesa_mode* modes = (vesa_mode*)get_boot_item(VESA_MODES_BOOT_INFO, &modesSize); info.modes = modes; size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7; info.shared_area = create_area("vesa shared info", - (void **)&info.shared_info, B_ANY_KERNEL_ADDRESS, + (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(sharedSize + modesSize), B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA); if (info.shared_area < B_OK) @@ -131,7 +189,7 @@ vesa_init(vesa_info &info) } sharedInfo.frame_buffer_area = bufferInfo->area; - sharedInfo.frame_buffer = (uint8 *)bufferInfo->frame_buffer; + sharedInfo.frame_buffer = (uint8*)bufferInfo->frame_buffer; sharedInfo.current_mode.virtual_width = bufferInfo->width; sharedInfo.current_mode.virtual_height = bufferInfo->height; @@ -140,17 +198,19 @@ vesa_init(vesa_info &info) sharedInfo.bytes_per_row = bufferInfo->bytes_per_row; // TODO: we might want to do this via vm86 instead - edid1_info *edidInfo = (edid1_info *)get_boot_item(VESA_EDID_BOOT_INFO, + edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO, NULL); if (edidInfo != NULL) { sharedInfo.has_edid = true; memcpy(&sharedInfo.edid_info, edidInfo, sizeof(edid1_info)); } + vbe_get_dpms_capabilities(info.vbe_dpms_capabilities, + sharedInfo.dpms_capabilities); + physical_entry mapping; - get_memory_map((void *)sharedInfo.frame_buffer, B_PAGE_SIZE, - &mapping, 1); - sharedInfo.physical_frame_buffer = (uint8 *)mapping.address; + get_memory_map((void*)sharedInfo.frame_buffer, B_PAGE_SIZE, &mapping, 1); + sharedInfo.physical_frame_buffer = (uint8*)mapping.address; dprintf(DEVICE_NAME ": vesa_init() completed successfully!\n"); return B_OK; @@ -158,7 +218,7 @@ vesa_init(vesa_info &info) void -vesa_uninit(vesa_info &info) +vesa_uninit(vesa_info& info) { dprintf(DEVICE_NAME": vesa_uninit()\n"); @@ -168,7 +228,7 @@ vesa_uninit(vesa_info &info) status_t -vesa_set_display_mode(vesa_info &info, unsigned int mode) +vesa_set_display_mode(vesa_info& info, uint32 mode) { if (mode >= info.shared_info->vesa_mode_count) return B_ENTRY_NOT_FOUND; @@ -181,43 +241,42 @@ vesa_set_display_mode(vesa_info &info, unsigned int mode) return status; } - area_id newFBArea; - frame_buffer_boot_info *bufferInfo; + area_id frameBufferArea; + frame_buffer_boot_info* bufferInfo; struct vbe_mode_info modeInfo; // Get mode information - status = vbe_get_mode_info(&vmState, info.modes[mode].mode, &modeInfo); + status = vbe_get_mode_info(vmState, info.modes[mode].mode, &modeInfo); if (status != B_OK) { dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot get mode info\n"); - goto error; + goto out; } // Set mode - status = vbe_set_mode(&vmState, info.modes[mode].mode); + status = vbe_set_mode(vmState, info.modes[mode].mode); if (status != B_OK) { dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot set mode\n"); - goto error; + goto out; } // Map new frame buffer - void *frameBuffer; - newFBArea = map_physical_memory("vesa_fb", - (void *)modeInfo.physical_base, - modeInfo.bytes_per_row * modeInfo.height, B_ANY_KERNEL_ADDRESS, - B_READ_AREA | B_WRITE_AREA, &frameBuffer); - if (newFBArea < B_OK) { - status = (status_t)newFBArea; - goto error; + void* frameBuffer; + frameBufferArea = map_physical_memory("vesa_fb", + (void*)modeInfo.physical_base, modeInfo.bytes_per_row * modeInfo.height, + B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, &frameBuffer); + if (frameBufferArea < B_OK) { + status = (status_t)frameBufferArea; + goto out; } delete_area(info.shared_info->frame_buffer_area); // Turn on write combining for the area - vm_set_area_memory_type(newFBArea, modeInfo.physical_base, B_MTR_WC); + vm_set_area_memory_type(frameBufferArea, modeInfo.physical_base, B_MTR_WC); // Update shared frame buffer information - info.shared_info->frame_buffer_area = newFBArea; - info.shared_info->frame_buffer = (uint8 *)frameBuffer; - info.shared_info->physical_frame_buffer = (uint8 *)modeInfo.physical_base; + info.shared_info->frame_buffer_area = frameBufferArea; + info.shared_info->frame_buffer = (uint8*)frameBuffer; + info.shared_info->physical_frame_buffer = (uint8*)modeInfo.physical_base; info.shared_info->bytes_per_row = modeInfo.bytes_per_row; info.shared_info->current_mode.virtual_width = modeInfo.width; info.shared_info->current_mode.virtual_height = modeInfo.height; @@ -226,16 +285,107 @@ vesa_set_display_mode(vesa_info &info, unsigned int mode) // Update boot item as it's used in vesa_init() bufferInfo - = (frame_buffer_boot_info *)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); - bufferInfo->area = newFBArea; + = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); + bufferInfo->area = frameBufferArea; bufferInfo->frame_buffer = (addr_t)frameBuffer; bufferInfo->width = modeInfo.width; bufferInfo->height = modeInfo.height; bufferInfo->depth = modeInfo.bits_per_pixel; bufferInfo->bytes_per_row = modeInfo.bytes_per_row; -error: +out: vm86_cleanup(&vmState); return status; } + +status_t +vesa_get_dpms_mode(vesa_info& info, uint32& mode) +{ + mode = B_DPMS_ON; + // we always return a valid mode + + // Prepare vm86 mode environment + struct vm86_state vmState; + status_t status = vm86_prepare(&vmState, 0x20000); + if (status != B_OK) { + dprintf(DEVICE_NAME": vesa_get_dpms_mode(): vm86_prepare failed: %s\n", + strerror(status)); + return status; + } + + vmState.regs.eax = 0x4f10; + vmState.regs.ebx = 2; + vmState.regs.esi = 0; + vmState.regs.edi = 0; + + status = vm86_do_int(&vmState, 0x10); + if (status != B_OK) { + dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): vm86 failed: %s\n", + strerror(status)); + goto out; + } + + if ((vmState.regs.eax & 0xffff) != 0x4f) { + dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): BIOS returned 0x%04lx\n", + vmState.regs.eax & 0xffff); + status = B_ERROR; + goto out; + } + + mode = vbe_to_system_dpms(vmState.regs.ebx >> 8); + +out: + vm86_cleanup(&vmState); + return status; +} + + +status_t +vesa_set_dpms_mode(vesa_info& info, uint32 mode) +{ + // Only let supported modes through + mode &= info.shared_info->dpms_capabilities; + + uint8 vbeMode = 0; + if ((mode & B_DPMS_OFF) != 0) + vbeMode |= DPMS_OFF | DPMS_REDUCED_ON; + if ((mode & B_DPMS_STAND_BY) != 0) + vbeMode |= DPMS_STANDBY; + if ((mode & B_DPMS_SUSPEND) != 0) + vbeMode |= DPMS_SUSPEND; + + vbeMode &= info.vbe_dpms_capabilities; + + // Prepare vm86 mode environment + struct vm86_state vmState; + status_t status = vm86_prepare(&vmState, 0x20000); + if (status != B_OK) { + dprintf(DEVICE_NAME": vesa_set_dpms_mode(): vm86_prepare failed: %s\n", + strerror(status)); + return status; + } + + vmState.regs.eax = 0x4f10; + vmState.regs.ebx = (vbeMode << 8) | 1; + vmState.regs.esi = 0; + vmState.regs.edi = 0; + + status = vm86_do_int(&vmState, 0x10); + if (status != B_OK) { + dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): vm86 failed: %s\n", + strerror(status)); + goto out; + } + + if ((vmState.regs.eax & 0xffff) != 0x4f) { + dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): BIOS returned 0x%04lx\n", + vmState.regs.eax & 0xffff); + status = B_ERROR; + goto out; + } + +out: + vm86_cleanup(&vmState); + return status; +} diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h b/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h index 973a3b6b8c..27c5da9780 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h +++ b/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef VESA_PRIVATE_H @@ -22,14 +22,17 @@ struct vesa_info { uint32 cookie_magic; int32 open_count; int32 id; - pci_info *pci; - struct vesa_shared_info *shared_info; + pci_info* pci; + struct vesa_shared_info* shared_info; area_id shared_area; - vesa_mode *modes; + vesa_mode* modes; + uint32 vbe_dpms_capabilities; }; -extern status_t vesa_init(vesa_info &info); -extern void vesa_uninit(vesa_info &info); -extern status_t vesa_set_display_mode(vesa_info &info, unsigned int mode); +extern status_t vesa_init(vesa_info& info); +extern void vesa_uninit(vesa_info& info); +extern status_t vesa_set_display_mode(vesa_info& info, uint32 mode); +extern status_t vesa_get_dpms_mode(vesa_info& info, uint32& mode); +extern status_t vesa_set_dpms_mode(vesa_info& info, uint32 mode); #endif /* VESA_PRIVATE_H */