* 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
This commit is contained in:
Axel Dörfler 2009-06-05 13:03:05 +00:00
parent 08acbdd994
commit bfd4c59b63
7 changed files with 332 additions and 144 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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 <errno.h>
#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;
}

View File

@ -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 <string.h>
#include <create_display_modes.h>
@ -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;

View File

@ -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
};

View File

@ -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;
}

View File

@ -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 */