diff --git a/headers/private/graphics/vesa/vesa.h b/headers/private/graphics/vesa/vesa.h index 9bf55b261e..044e295ce6 100644 --- a/headers/private/graphics/vesa/vesa.h +++ b/headers/private/graphics/vesa/vesa.h @@ -37,6 +37,10 @@ struct vbe_info_block { uint8 oem_data[256]; } _PACKED; +// capabilities +#define CAPABILITY_DAC_WIDTH 0x01 +#define CAPABILITY_VGA_COMPATIBLE 0x02 + /* VBE mode info structure */ diff --git a/headers/private/graphics/vesa/vesa_info.h b/headers/private/graphics/vesa/vesa_info.h index 3db0fd27fa..654efbfd00 100644 --- a/headers/private/graphics/vesa/vesa_info.h +++ b/headers/private/graphics/vesa/vesa_info.h @@ -31,9 +31,9 @@ struct vesa_shared_info { uint32 bytes_per_row; area_id frame_buffer_area; // area of frame buffer - uint8 *frame_buffer; + uint8* frame_buffer; // pointer to frame buffer (visible by all apps!) - uint8 *physical_frame_buffer; + uint8* physical_frame_buffer; uint32 vesa_mode_offset; uint32 vesa_mode_count; @@ -52,24 +52,24 @@ enum { VESA_SET_DISPLAY_MODE, VESA_GET_DPMS_MODE, VESA_SET_DPMS_MODE, + VESA_SET_INDEXED_COLORS, - VGA_SET_INDEXED_COLORS, VGA_PLANAR_BLIT, }; -struct vga_set_indexed_colors_args { - uint8 first; - uint16 count; - uint8 *colors; +struct vesa_set_indexed_colors_args { + uint8 first; + uint16 count; + uint8* colors; }; struct vga_planar_blit_args { - uint8 *source; - int32 source_bytes_per_row; - int32 left; - int32 top; - int32 right; - int32 bottom; + uint8* source; + int32 source_bytes_per_row; + int32 left; + int32 top; + int32 right; + int32 bottom; }; #endif /* VESA_INFO_H */ diff --git a/headers/private/kernel/boot/kernel_args.h b/headers/private/kernel/boot/kernel_args.h index ed7b22809b..4e80a99dbb 100644 --- a/headers/private/kernel/boot/kernel_args.h +++ b/headers/private/kernel/boot/kernel_args.h @@ -72,7 +72,8 @@ typedef struct kernel_args { } frame_buffer; void *vesa_modes; - uint32 vesa_modes_size; + uint16 vesa_modes_size; + uint8 vesa_capabilities; void *edid_info; void *debug_output; diff --git a/headers/private/kernel/frame_buffer_console.h b/headers/private/kernel/frame_buffer_console.h index 4c80a4c7d6..a865a547ce 100644 --- a/headers/private/kernel/frame_buffer_console.h +++ b/headers/private/kernel/frame_buffer_console.h @@ -1,12 +1,14 @@ /* - * 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. */ #ifndef KERNEL_FRAME_BUFFER_CONSOLE_H #define KERNEL_FRAME_BUFFER_CONSOLE_H + #include + struct kernel_args; @@ -20,18 +22,19 @@ struct frame_buffer_boot_info { int32 height; int32 depth; int32 bytes_per_row; + uint8 vesa_capabilities; }; #ifdef __cplusplus extern "C" { #endif -bool frame_buffer_console_available(void); -status_t frame_buffer_console_init(struct kernel_args *args); -status_t frame_buffer_console_init_post_modules(struct kernel_args *args); +bool frame_buffer_console_available(void); +status_t frame_buffer_console_init(struct kernel_args* args); +status_t frame_buffer_console_init_post_modules(struct kernel_args* args); -status_t _user_frame_buffer_update(addr_t baseAddress, int32 width, int32 height, - int32 depth, int32 bytesPerRow); +status_t _user_frame_buffer_update(addr_t baseAddress, int32 width, + int32 height, int32 depth, int32 bytesPerRow); #ifdef __cplusplus } diff --git a/src/add-ons/accelerants/vesa/mode.cpp b/src/add-ons/accelerants/vesa/mode.cpp index 4b71122dcc..795c514f78 100644 --- a/src/add-ons/accelerants/vesa/mode.cpp +++ b/src/add-ons/accelerants/vesa/mode.cpp @@ -193,7 +193,7 @@ 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")); @@ -203,11 +203,11 @@ vesa_get_pixel_clock_limits(display_mode* mode, uint32* low, uint32* high) uint32 clockLimit = 2000000; // lower limit of about 48Hz vertical refresh - *low = totalPixel * 48L / 1000L; - if (*low > clockLimit) + *_low = totalPixel * 48L / 1000L; + if (*_low > clockLimit) return B_ERROR; - *high = clockLimit; + *_high = clockLimit; return B_OK; } @@ -232,10 +232,11 @@ void vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) { TRACE(("vesa_set_indexed_colors()\n")); - vga_set_indexed_colors_args args; + + vesa_set_indexed_colors_args args; args.first = first; args.count = count; args.colors = colors; - ioctl(gInfo->device, VGA_SET_INDEXED_COLORS, &args, sizeof(args)); + ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args)); } diff --git a/src/add-ons/kernel/drivers/graphics/vesa/device.cpp b/src/add-ons/kernel/drivers/graphics/vesa/device.cpp index c8ddde7bd4..39494bfe96 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/device.cpp +++ b/src/add-ons/kernel/drivers/graphics/vesa/device.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include "driver.h" #include "utility.h" #include "vesa_info.h" @@ -125,7 +127,7 @@ device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength) return B_BAD_VALUE; uint32 mode; - if (user_memcpy(&mode, buffer, sizeof(uint32)) < B_OK) + if (user_memcpy(&mode, buffer, sizeof(uint32)) != B_OK) return B_BAD_ADDRESS; return vesa_set_display_mode(*info, mode); @@ -150,25 +152,38 @@ device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength) return B_BAD_VALUE; uint32 mode; - if (user_memcpy(&mode, buffer, sizeof(uint32)) < B_OK) + 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: + case VESA_SET_INDEXED_COLORS: { - vga_set_indexed_colors_args args; - if (user_memcpy(&args, buffer, sizeof(args)) < B_OK) + vesa_set_indexed_colors_args args; + if (user_memcpy(&args, buffer, sizeof(args)) != B_OK) return B_BAD_ADDRESS; - return vga_set_indexed_colors(args.first, args.colors, args.count); + if (info->shared_info->current_mode.space == B_GRAY8) { + if ((info->vbe_capabilities & CAPABILITY_VGA_COMPATIBLE) == 0) + return B_NOT_SUPPORTED; + + return vga_set_indexed_colors(args.first, args.colors, + args.count); + } + + return vesa_set_indexed_colors(*info, args.first, args.colors, + args.count); } case VGA_PLANAR_BLIT: { + if (info->shared_info->current_mode.space != B_GRAY8 + && (info->vbe_capabilities & CAPABILITY_VGA_COMPATIBLE) == 0) + return B_NOT_SUPPORTED; + vga_planar_blit_args args; - if (user_memcpy(&args, buffer, sizeof(args)) < B_OK) + if (user_memcpy(&args, buffer, sizeof(args)) != B_OK) return B_BAD_ADDRESS; return vga_planar_blit(info->shared_info, args.source, diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp b/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp index 5a6d6f8af2..1fbd334515 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp +++ b/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp @@ -154,6 +154,52 @@ out: } +static status_t +vbe_set_bits_per_gun(vm86_state& vmState, vesa_info& info, uint8 bits) +{ + info.bits_per_gun = 6; + + vmState.regs.eax = 0x4f08; + vmState.regs.ebx = (bits << 8) | 1; + + status_t status = vm86_do_int(&vmState, 0x10); + if (status != B_OK) { + dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): vm86 failed: %s\n", + strerror(status)); + return status; + } + + if ((vmState.regs.eax & 0xffff) != 0x4f) { + dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): BIOS returned 0x%04lx\n", + vmState.regs.eax & 0xffff); + return B_ERROR; + } + + info.bits_per_gun = vmState.regs.ebx >> 8; + return B_OK; +} + + +static status_t +vbe_set_bits_per_gun(vesa_info& info, uint8 bits) +{ + info.bits_per_gun = 6; + + struct vm86_state vmState; + status_t status = vm86_prepare(&vmState, 0x20000); + if (status != B_OK) { + dprintf(DEVICE_NAME": vbe_set_bits_per_gun(): vm86_prepare failed: " + "%s\n", strerror(status)); + return status; + } + + status = vbe_set_bits_per_gun(vmState, info, bits); + + vm86_cleanup(&vmState); + return status; +} + + // #pragma mark - @@ -165,6 +211,8 @@ vesa_init(vesa_info& info) if (bufferInfo == NULL) return B_ERROR; + info.vbe_capabilities = bufferInfo->vesa_capabilities; + size_t modesSize = 0; vesa_mode* modes = (vesa_mode*)get_boot_item(VESA_MODES_BOOT_INFO, &modesSize); @@ -176,7 +224,7 @@ vesa_init(vesa_info& info) (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) + if (info.shared_area < 0) return info.shared_area; vesa_shared_info &sharedInfo = *info.shared_info; @@ -199,7 +247,6 @@ vesa_init(vesa_info& info) bufferInfo->depth); 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, NULL); if (edidInfo != NULL) { @@ -209,6 +256,8 @@ vesa_init(vesa_info& info) vbe_get_dpms_capabilities(info.vbe_dpms_capabilities, sharedInfo.dpms_capabilities); + 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); @@ -261,6 +310,9 @@ vesa_set_display_mode(vesa_info& info, uint32 mode) goto out; } + 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", @@ -391,3 +443,62 @@ out: vm86_cleanup(&vmState); return status; } + + +status_t +vesa_set_indexed_colors(vesa_info& info, uint8 first, uint8* colors, + uint16 count) +{ + if (first + count > 256) + count = 256 - first; + + // Prepare vm86 mode environment + struct vm86_state vmState; + status_t status = vm86_prepare(&vmState, 0x20000); + if (status != B_OK) { + dprintf(DEVICE_NAME": vesa_set_indexed_colors(): vm86_prepare failed: " + "%s\n", strerror(status)); + return status; + } + + uint8* palette = (uint8*)0x1000; + uint32 shift = 8 - info.bits_per_gun; + + // convert colors to VESA palette + for (int32 i = first; i < count; i++) { + uint8 color[3]; + if (user_memcpy(color, &colors[i * 3], 3) < B_OK) + return B_BAD_ADDRESS; + + // order is BGR- + palette[i * 4 + 0] = color[2] >> shift; + palette[i * 4 + 1] = color[1] >> shift; + palette[i * 4 + 2] = color[0] >> shift; + palette[i * 4 + 3] = 0; + } + + // set palette + vmState.regs.eax = 0x4f09; + vmState.regs.ebx = 0; + vmState.regs.ecx = count; + vmState.regs.edx = first; + vmState.regs.es = 0x1000 >> 4; + vmState.regs.edi = 0x0000; + + status = vm86_do_int(&vmState, 0x10); + if (status != B_OK) { + dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): vm86 failed: %s\n", + strerror(status)); + goto out; + } + + if ((vmState.regs.eax & 0xffff) != 0x4f) { + dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): BIOS returned " + "0x%04lx\n", vmState.regs.eax & 0xffff); + status = B_ERROR; + } + +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 27c5da9780..15e955485d 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h +++ b/src/add-ons/kernel/drivers/graphics/vesa/vesa_private.h @@ -27,6 +27,8 @@ struct vesa_info { area_id shared_area; vesa_mode* modes; uint32 vbe_dpms_capabilities; + uint8 vbe_capabilities; + uint8 bits_per_gun; }; extern status_t vesa_init(vesa_info& info); @@ -34,5 +36,7 @@ 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); +extern status_t vesa_set_indexed_colors(vesa_info& info, uint8 first, + uint8* colors, uint16 count); #endif /* VESA_PRIVATE_H */ diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vga.cpp b/src/add-ons/kernel/drivers/graphics/vesa/vga.cpp index ec1c4e76ce..ffc062941a 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/vga.cpp +++ b/src/add-ons/kernel/drivers/graphics/vesa/vga.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2006-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -15,6 +15,9 @@ status_t vga_set_indexed_colors(uint8 first, uint8 *colors, uint16 count) { + if (first + count > 256) + count = 256 - first; + gISA->write_io_8(VGA_COLOR_WRITE_MODE, first); // write VGA palette diff --git a/src/system/boot/platform/bios_ia32/video.cpp b/src/system/boot/platform/bios_ia32/video.cpp index 590c727a33..6a1141362a 100644 --- a/src/system/boot/platform/bios_ia32/video.cpp +++ b/src/system/boot/platform/bios_ia32/video.cpp @@ -1159,9 +1159,12 @@ platform_init_video(void) sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK; if (!sVesaCompatible) { TRACE(("No VESA compatible graphics!\n")); + gKernelArgs.vesa_capabilities = CAPABILITY_VGA_COMPATIBLE; return B_ERROR; } + gKernelArgs.vesa_capabilities = sInfo.capabilities; + TRACE(("VESA compatible graphics!\n")); // store VESA modes into kernel args diff --git a/src/system/kernel/debug/frame_buffer_console.cpp b/src/system/kernel/debug/frame_buffer_console.cpp index 160a08f6ef..4f868820ef 100644 --- a/src/system/kernel/debug/frame_buffer_console.cpp +++ b/src/system/kernel/debug/frame_buffer_console.cpp @@ -417,7 +417,7 @@ frame_buffer_console_init(kernel_args* args) (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); - if (sConsole.area < B_OK) + if (sConsole.area < 0) return sConsole.area; frame_buffer_update((addr_t)frameBuffer, args->frame_buffer.width, @@ -430,6 +430,8 @@ frame_buffer_console_init(kernel_args* args) sBootInfo.height = args->frame_buffer.height; sBootInfo.depth = args->frame_buffer.depth; sBootInfo.bytes_per_row = args->frame_buffer.bytes_per_row; + sBootInfo.vesa_capabilities = args->vesa_capabilities; + add_boot_item(FRAME_BUFFER_BOOT_INFO, &sBootInfo, sizeof(frame_buffer_boot_info));