* The VESA driver now tries to find the PCI card that it is controlling by

checking the physical frame buffer location.
* This allows us to map the whole frame buffer at once, which means there is no
  need anymore to remap the memory on mode change.
* Also, this will ease the burden of the MTRRs, as the memory size will be
  properly aligned.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34206 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-11-24 15:26:52 +00:00
parent 4ea01167bd
commit 5472c0c23e
4 changed files with 120 additions and 44 deletions

View File

@ -17,6 +17,7 @@ struct kernel_args;
struct frame_buffer_boot_info {
area_id area;
addr_t physical_frame_buffer;
addr_t frame_buffer;
int32 width;
int32 height;

View File

@ -20,6 +20,40 @@
#include "vesa_info.h"
static status_t
find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size)
{
// TODO: when we port this over to the new driver API, this mechanism can be
// used to find the right device_node
pci_module_info* pci;
if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK)
return B_ERROR;
pci_info info;
for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) {
if (info.class_base != PCI_display)
continue;
// check PCI BARs
for (uint32 i = 0; i < 6; i++) {
if (info.u.h0.base_registers[i] <= frameBuffer
&& info.u.h0.base_registers[i] + info.u.h0.base_register_sizes[i]
> frameBuffer) {
// found it!
base = info.u.h0.base_registers[i];
size = info.u.h0.base_register_sizes[i];
put_module(B_PCI_MODULE_NAME);
return B_OK;
}
}
}
put_module(B_PCI_MODULE_NAME);
return B_ENTRY_NOT_FOUND;
}
static uint32
get_color_space_for_depth(uint32 depth)
{
@ -200,6 +234,61 @@ vbe_set_bits_per_gun(vesa_info& info, uint8 bits)
}
/*! Remaps the frame buffer if necessary; if we've already mapped the complete
frame buffer, there is no need to map it again.
*/
static status_t
remap_frame_buffer(vesa_info& info, addr_t physicalBase,
uint32 bytesPerRow, uint32 height, bool initializing)
{
vesa_shared_info& sharedInfo = *info.shared_info;
addr_t frameBuffer;
if (!info.complete_frame_buffer_mapped) {
addr_t base = physicalBase;
size_t size = bytesPerRow * height;
bool remap = !initializing;
if (info.physical_frame_buffer_size != 0) {
// we can map the complete frame buffer
base = info.physical_frame_buffer;
size = info.physical_frame_buffer_size;
remap = true;
}
if (remap) {
area_id area = map_physical_memory("vesa frame buffer", (void*)base,
size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA,
(void**)&frameBuffer);
if (area < 0)
return area;
delete_area(info.shared_info->frame_buffer_area);
info.frame_buffer = frameBuffer;
sharedInfo.frame_buffer_area = area;
// Turn on write combining for the area
vm_set_area_memory_type(area, base, B_MTR_WC);
if (info.physical_frame_buffer_size != 0)
info.complete_frame_buffer_mapped = true;
}
} else
frameBuffer = info.frame_buffer;
if (info.complete_frame_buffer_mapped)
frameBuffer += physicalBase - info.physical_frame_buffer;
// Update shared frame buffer information
sharedInfo.frame_buffer = (uint8*)frameBuffer;
sharedInfo.physical_frame_buffer = (uint8*)physicalBase;
sharedInfo.bytes_per_row = bytesPerRow;
return B_OK;
}
// #pragma mark -
@ -212,6 +301,12 @@ vesa_init(vesa_info& info)
return B_ERROR;
info.vbe_capabilities = bufferInfo->vesa_capabilities;
info.complete_frame_buffer_mapped = false;
// Find out which PCI device we belong to, so that we know its frame buffer
// size
find_graphics_card(bufferInfo->physical_frame_buffer,
info.physical_frame_buffer, info.physical_frame_buffer_size);
size_t modesSize = 0;
vesa_mode* modes = (vesa_mode*)get_boot_item(VESA_MODES_BOOT_INFO,
@ -227,7 +322,7 @@ vesa_init(vesa_info& info)
if (info.shared_area < 0)
return info.shared_area;
vesa_shared_info &sharedInfo = *info.shared_info;
vesa_shared_info& sharedInfo = *info.shared_info;
memset(&sharedInfo, 0, sizeof(vesa_shared_info));
@ -239,13 +334,16 @@ vesa_init(vesa_info& info)
}
sharedInfo.frame_buffer_area = bufferInfo->area;
sharedInfo.frame_buffer = (uint8*)bufferInfo->frame_buffer;
remap_frame_buffer(info, bufferInfo->physical_frame_buffer,
bufferInfo->bytes_per_row, bufferInfo->height, true);
// Does not matter if this fails - the frame buffer was already mapped
// before.
sharedInfo.current_mode.virtual_width = bufferInfo->width;
sharedInfo.current_mode.virtual_height = bufferInfo->height;
sharedInfo.current_mode.space = get_color_space_for_depth(
bufferInfo->depth);
sharedInfo.bytes_per_row = bufferInfo->bytes_per_row;
edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO,
NULL);
@ -259,10 +357,6 @@ vesa_init(vesa_info& info)
if (bufferInfo->depth <= 8)
vbe_set_bits_per_gun(info, 8);
physical_entry mapping;
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;
}
@ -292,11 +386,8 @@ vesa_set_display_mode(vesa_info& info, uint32 mode)
return status;
}
area_id frameBufferArea;
frame_buffer_boot_info* bufferInfo;
struct vbe_mode_info modeInfo;
// Get mode information
struct vbe_mode_info 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");
@ -313,39 +404,17 @@ vesa_set_display_mode(vesa_info& info, uint32 mode)
if (info.modes[mode].bits_per_pixel <= 8)
vbe_set_bits_per_gun(vmState, info, 8);
// Map new frame buffer
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;
// Map new frame buffer if necessary
status = remap_frame_buffer(info, modeInfo.physical_base,
modeInfo.bytes_per_row, modeInfo.height, false);
if (status == B_OK) {
// Update shared frame buffer information
info.shared_info->current_mode.virtual_width = modeInfo.width;
info.shared_info->current_mode.virtual_height = modeInfo.height;
info.shared_info->current_mode.space = get_color_space_for_depth(
modeInfo.bits_per_pixel);
}
delete_area(info.shared_info->frame_buffer_area);
// Turn on write combining for the area
vm_set_area_memory_type(frameBufferArea, modeInfo.physical_base, B_MTR_WC);
// Update shared frame buffer information
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;
info.shared_info->current_mode.space = get_color_space_for_depth(
modeInfo.bits_per_pixel);
// 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 = 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;
out:
vm86_cleanup(&vmState);

View File

@ -29,6 +29,11 @@ struct vesa_info {
uint32 vbe_dpms_capabilities;
uint8 vbe_capabilities;
uint8 bits_per_gun;
addr_t frame_buffer;
addr_t physical_frame_buffer;
size_t physical_frame_buffer_size;
bool complete_frame_buffer_mapped;
};
extern status_t vesa_init(vesa_info& info);

View File

@ -413,7 +413,7 @@ frame_buffer_console_init(kernel_args* args)
mutex_init(&sConsole.lock, "console_lock");
void* frameBuffer;
sConsole.area = map_physical_memory("vesa_fb",
sConsole.area = map_physical_memory("vesa frame buffer",
(void*)args->frame_buffer.physical_buffer.start,
args->frame_buffer.physical_buffer.size, B_ANY_KERNEL_ADDRESS,
B_READ_AREA | B_WRITE_AREA | B_USER_CLONEABLE_AREA, &frameBuffer);
@ -425,6 +425,7 @@ frame_buffer_console_init(kernel_args* args)
args->frame_buffer.bytes_per_row);
sBootInfo.area = sConsole.area;
sBootInfo.physical_frame_buffer = args->frame_buffer.physical_buffer.start;
sBootInfo.frame_buffer = (addr_t)frameBuffer;
sBootInfo.width = args->frame_buffer.width;
sBootInfo.height = args->frame_buffer.height;