i386/pc386: VESA based frame buffer utilizing real mode interrupt 10h

This commit is contained in:
Jan Dolezal
2014-11-20 15:00:33 +01:00
committed by Gedare Bloom
parent c5a74946ac
commit 067da5c45d
6 changed files with 1021 additions and 0 deletions

View File

@@ -106,13 +106,18 @@ libbsp_a_SOURCES += console/printk_support.c
libbsp_a_SOURCES += console/vgacons.c
libbsp_a_SOURCES += console/exar17d15x.c
libbsp_a_SOURCES += console/rtd316.c
if USE_VBE_RM
include_bsp_HEADERS += include/vbe3.h
include_HEADERS += include/edid.h
include_bsp_HEADERS += include/fb_vesa.h
libbsp_a_SOURCES += console/fb_vesa_rm.c
else
if USE_CIRRUS_GD5446
libbsp_a_SOURCES += console/fb_cirrus.c
else
libbsp_a_SOURCES += console/fb_vga.c
endif
endif
# gdb
libbsp_a_SOURCES += ../../i386/shared/comm/i386-stub.c

View File

@@ -82,6 +82,19 @@ RTEMS_BSPOPTS_HELP([USE_CIRRUS_GD5446],
NOTE: This has only been tested on Qemu.])
AM_CONDITIONAL(USE_CIRRUS_GD5446,test "$USE_CIRRUS_GD5446" = "1")
RTEMS_BSPOPTS_SET([USE_VBE_RM],[*],[0])
RTEMS_BSPOPTS_HELP([USE_VBE_RM],
[If defined, enables use of the Vesa Bios Extensions - real mode interface,
which enables graphical mode and introduce it upon bootup.])
AM_CONDITIONAL(USE_VBE_RM,test "$USE_VBE_RM" = "1")
if test "${USE_VBE_RM}" = "1" ; then
if test -z "${NUM_APP_DRV_GDT_DESCRIPTORS}"; then
NUM_APP_DRV_GDT_DESCRIPTORS=2 ;
else
NUM_APP_DRV_GDT_DESCRIPTORS+=2 ;
fi
fi
RTEMS_BSPOPTS_SET([NUM_APP_DRV_GDT_DESCRIPTORS],[*],[0])
RTEMS_BSPOPTS_HELP([NUM_APP_DRV_GDT_DESCRIPTORS],
[Defines how many descriptors in GDT may be allocated for application or

View File

@@ -0,0 +1,858 @@
/*
* FB driver for graphic hardware compatible with VESA Bios Extension
* Real mode interface utilized
* Tested on real HW.
*
* Copyright (c) 2014 - CTU in Prague
* Jan Doležal ( dolezj21@fel.cvut.cz )
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* The code for rtems_buffer_* functions were greatly
* inspired or coppied from:
* - RTEMS fb_cirrus.c - Alexandru-Sever Horin (alex.sever.h@gmail.com)
*
* Public sources related:
* - VESA BIOS EXTENSION (VBE) Core Function Standard, Ver: 3.0, Sep 16, 1998
* - VESA Enhanced Extended Display Identification Data (E-EDID) Standard
* Release A, Revision 2, September 25, 2006
*/
/*
* Hardware is completely initialized upon boot of the system.
* Therefore there is no way to change graphics mode later.
*
* Interrupt 0x10 is used for entering graphics BIOS.
*
* Driver reads parameter from multiboot command line to setup video:
* "--video=<resX>x<resY>[-<bpp>]"
* If cmdline parameter is not specified an attempt for obtaining
* resolution from display attached is made.
*/
#include <bsp.h>
#include <bsp/fb_vesa.h>
#include <bsp/realmode_int.h>
#include <pthread.h>
#include <rtems/libio.h>
#include <rtems/fb.h>
#include <rtems/framebuffer.h>
#include <stdlib.h>
#define FB_VESA_NAME "FB_VESA_RM"
void vesa_realmode_bootup_init(void);
/* mutex for protection against multiple opens, when called frame_buffer_open */
static pthread_mutex_t vesa_mutex = PTHREAD_MUTEX_INITIALIZER;
/* screen information for the VGA driver
* standard structures - from RTEMS fb interface
*/
static struct fb_var_screeninfo fb_var;
static struct fb_fix_screeninfo fb_fix;
static uint16_t vbe_usedMode;
inline uint32_t VBEControllerInformation( struct VBE_VbeInfoBlock *infoBlock,
uint16_t queriedVBEVersion)
{
uint16_t size;
struct VBE_VbeInfoBlock *VBE_buffer =
(struct VBE_VbeInfoBlock *)i386_get_default_rm_buffer(&size);
i386_realmode_interrupt_registers parret;
parret.reg_eax = VBE_RetVBEConInf;
uint16_t seg, off;
i386_Physical_to_real(VBE_buffer, &seg, &off);
parret.reg_edi = (uint32_t)off;
parret.reg_es = seg;
/* indicate to graphic's bios that VBE2.0 extended information is desired */
if (queriedVBEVersion >= 0x200)
{
strncpy(
(char *)&VBE_buffer->VbeSignature,
VBE20plus_SIGNATURE,
4*sizeof(size_t)
);
}
if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
return -1;
if ((parret.reg_eax & 0xFFFF) ==
(VBE_callSuccessful<<8 | VBE_functionSupported))
{
*infoBlock = *VBE_buffer;
}
return (parret.reg_eax & 0xFFFF);
}
inline uint32_t VBEModeInformation( struct VBE_ModeInfoBlock *infoBlock,
uint16_t modeNumber)
{
uint16_t size;
struct VBE_ModeInfoBlock *VBE_buffer =
(struct VBE_ModeInfoBlock *)i386_get_default_rm_buffer(&size);
i386_realmode_interrupt_registers parret;
parret.reg_eax = VBE_RetVBEModInf;
parret.reg_ecx = modeNumber;
uint16_t seg, off;
i386_Physical_to_real(VBE_buffer, &seg, &off);
parret.reg_edi = (uint32_t)off;
parret.reg_es = seg;
if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
return -1;
if ((parret.reg_eax & 0xFFFF) ==
(VBE_callSuccessful<<8 | VBE_functionSupported))
{
*infoBlock = *VBE_buffer;
}
return (parret.reg_eax & 0xFFFF);
}
inline uint32_t VBESetMode( uint16_t modeNumber,
struct VBE_CRTCInfoBlock *infoBlock)
{
uint16_t size;
struct VBE_CRTCInfoBlock *VBE_buffer =
(struct VBE_CRTCInfoBlock *)i386_get_default_rm_buffer(&size);
i386_realmode_interrupt_registers parret;
/* copy CRTC */
*VBE_buffer = *infoBlock;
parret.reg_eax = VBE_SetVBEMod;
parret.reg_ebx = modeNumber;
uint16_t seg, off;
i386_Physical_to_real(VBE_buffer, &seg, &off);
parret.reg_edi = (uint32_t)off;
parret.reg_es = seg;
if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
return -1;
return (parret.reg_eax & 0xFFFF);
}
inline uint32_t VBECurrentMode(uint16_t *modeNumber)
{
i386_realmode_interrupt_registers parret;
parret.reg_eax = VBE_RetCurVBEMod;
if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
return -1;
*modeNumber = (uint16_t)parret.reg_ebx;
return (parret.reg_eax & 0xFFFF);
}
inline uint32_t VBEReportDDCCapabilities( uint16_t controllerUnitNumber,
uint8_t *secondsToTransferEDIDBlock,
uint8_t *DDCLevelSupported)
{
i386_realmode_interrupt_registers parret;
parret.reg_eax = VBE_DisDatCha;
parret.reg_ebx = VBEDDC_Capabilities;
parret.reg_ecx = controllerUnitNumber;
parret.reg_edi = 0;
parret.reg_es = 0;
if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
return -1;
*secondsToTransferEDIDBlock = (uint8_t)parret.reg_ebx >> 8;
*DDCLevelSupported = (uint8_t)parret.reg_ebx;
return (parret.reg_eax & 0xFFFF);
}
inline uint32_t VBEReadEDID(uint16_t controllerUnitNumber,
uint16_t EDIDBlockNumber,
struct edid1 *buffer)
{
uint16_t size;
struct edid1 *VBE_buffer = (struct edid1 *)i386_get_default_rm_buffer(&size);
i386_realmode_interrupt_registers parret;
parret.reg_eax = VBE_DisDatCha;
parret.reg_ebx = VBEDDC_ReadEDID;
parret.reg_ecx = controllerUnitNumber;
parret.reg_edx = EDIDBlockNumber;
uint16_t seg, off;
i386_Physical_to_real(VBE_buffer, &seg, &off);
parret.reg_edi = (uint32_t)off;
parret.reg_es = seg;
if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
return -1;
if ((parret.reg_eax & 0xFFFF) ==
(VBE_callSuccessful<<8 | VBE_functionSupported))
{
*buffer = *VBE_buffer;
}
return (parret.reg_eax & 0xFFFF);
}
typedef struct {
uint16_t modeNumber;
uint16_t resX;
uint16_t resY;
uint8_t bpp;
} modeParams;
/* finds mode in 'modeList' of 'listLength' length according to resolution
given in 'searchedResolution'. If bpp is given in that struct as well
mode with such color depth and resolution is searched for. Otherwise bpp
has to be zero. Mode number found is returned and also filled into
'searchedResolution'. bpp is also filled into 'searchedResolution' if it
was 0 before call. */
static uint16_t findModeByResolution( modeParams *modeList,
uint8_t listLength,
modeParams *searchedResolution)
{
uint8_t i = 0;
while (i < listLength)
{
if (searchedResolution->resX == modeList[i].resX &&
searchedResolution->resY == modeList[i].resY)
{
if (searchedResolution->bpp==0 ||
searchedResolution->bpp==modeList[i].bpp)
{
searchedResolution->bpp = modeList[i].bpp;
searchedResolution->modeNumber = modeList[i].modeNumber;
return modeList[i].modeNumber;
}
}
i++;
}
return -1;
}
/*
* Parse comandline option "--video=" if available.
* expected format
* --video=<resX>x<resY>[-<bpp>]
* numbers <resX>, <resY> and <bpp> are decadic
*
* @retval video mode number to be set
* -1 on parsing error or when no suitable mode found
*/
static uint16_t findModeUsingCmdline( modeParams *modeList,
uint8_t listLength)
{
const char* opt;
modeParams cmdlineMode;
char* endptr;
cmdlineMode.bpp = 0;
opt = bsp_cmdline_arg("--video=");
if (opt)
{
opt += sizeof("--video=")-1;
cmdlineMode.resX = strtol(opt, &endptr, 10);
if (*endptr != 'x')
{
return -1;
}
opt = endptr+1;
cmdlineMode.resY = strtol(opt, &endptr, 10);
switch (*endptr)
{
case '-':
opt = endptr+1;
if (strlen(opt) <= 2)
cmdlineMode.bpp = strtol(opt, &endptr, 10);
else
{
cmdlineMode.bpp = strtol(opt, &endptr, 10);
if (*endptr != ' ')
{
return -1;
}
}
case ' ':
case 0:
break;
default:
return -1;
}
if (findModeByResolution(modeList, listLength, &cmdlineMode) !=
(uint16_t)-1)
return cmdlineMode.modeNumber;
}
return -1;
}
/*
* returns mode number best fitting to monitor attached
*
* @retval video mode number to be set
* -1 on parsing error or when no suitable mode found
*/
static uint16_t findModeUsingEDID( modeParams *modeList,
uint8_t listLength)
{
struct edid1 edid;
uint8_t checksum, iterator;
uint8_t index, j;
modeParams EDIDmode;
checksum = 0;
iterator = 0;
EDIDmode.bpp = 0;
if (VBEReadEDID(0, 0, &edid) !=
(VBE_callSuccessful<<8 | VBE_functionSupported))
{
printk(FB_VESA_NAME " Function 15h (read EDID) not supported.\n");
return -1;
}
/* version of EDID structure */
if (edid.Version == 1)
{ /* EDID version 1 */
while (iterator < sizeof(struct edid1))
{
checksum += *((uint8_t *)&edid+iterator);
iterator++;
}
if (checksum)
/* not implemented: try to read EDID again */
printk(FB_VESA_NAME " EDID v1 checksum failed\n");
/* try to find Detailed Timing Descriptor (defined in BASE EDID)
in controller mode list; first should be preffered mode */
index = 0;
while (index < 4)
{
/* skip if it is monitor descriptor */
if (edid.dtd_md[index].md.Flag0[0] == 0 &&
edid.dtd_md[index].md.Flag0[1] == 0 &&
edid.dtd_md[index].md.Flag1 == 0)
{
index++;
continue;
}
EDIDmode.resX = DTD_HorizontalActive(&edid.dtd_md[0].dtd);
EDIDmode.resY = DTD_VerticalActive(&edid.dtd_md[0].dtd);
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
index++;
}
/* try to find Detailed Timing Descriptor (defined in optional EXTENSION
Blocks) in controller mode list */
if (edid.ExtensionFlag > 0)
{
/* not implemented */
}
/* try to find CVT (defined in BASE EDID) in controller mode list */
index = 1;
while (index < 4)
{
if (edid.dtd_md[index].md.DataTypeTag ==
EDID_DTT_CVT3ByteTimingCodes &&
edid.dtd_md[index].md.Flag0[0] == 0 &&
edid.dtd_md[index].md.Flag0[1] == 0 &&
edid.dtd_md[index].md.Flag1 == 0 &&
edid.dtd_md[index].md.Flag2 == 0)
{
struct CVTTimingCodes3B *cvt = (struct CVTTimingCodes3B *)
&edid.dtd_md[index].md.DescriptorData[0];
j = 0;
while (j < 4)
{
EDIDmode.resY = edid1_CVT_AddressableLinesHigh(&cvt->cvt[j]);
switch (edid1_CVT_AspectRatio(&cvt->cvt[j]))
{
case EDID_CVT_AspectRatio_4_3:
EDIDmode.resX = (EDIDmode.resY*4)/3;
break;
case EDID_CVT_AspectRatio_16_9:
EDIDmode.resX = (EDIDmode.resY*16)/9;
break;
case EDID_CVT_AspectRatio_16_10:
EDIDmode.resX = (EDIDmode.resY*16)/10;
break;
case EDID_CVT_AspectRatio_15_9:
EDIDmode.resX = (EDIDmode.resY*15)/9;
break;
}
EDIDmode.resX = (EDIDmode.resX/8)*8;
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
j++;
}
}
index++;
}
/* try to find CVT (defined in optional EXTENSION Blocks)
in controller mode list */
/* not implemented */
/* try to find Standard Timings (listed in BASE EDID)
in controller mode list */
index = 0;
while (index < 8)
{
/* check if descriptor is unused */
if (*(uint16_t*)&edid.STI[index] == EDID_STI_DescriptorUnused)
{
index++;
continue;
}
EDIDmode.resX = (edid.STI[index].HorizontalActivePixels+31)*8;
switch (edid.STI[index].ImageAspectRatio_RefreshRate & EDID1_STI_ImageAspectRatioMask)
{
case EDID_STI_AspectRatio_16_10:
EDIDmode.resY = (EDIDmode.resX*10)/16;
break;
case EDID_STI_AspectRatio_4_3:
EDIDmode.resY = (EDIDmode.resX*3)/4;
break;
case EDID_STI_AspectRatio_5_4:
EDIDmode.resY = (EDIDmode.resX*4)/5;
break;
case EDID_STI_AspectRatio_16_9:
EDIDmode.resY = (EDIDmode.resX*9)/16;
break;
}
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
index++;
}
/* try to find Standard Timings (listed in optional EXTENSION Blocks)
in controller mode list */
/* not implemented */
/* use Established Timings */
if (edid1_EstablishedTim(&edid, EST_1280x1024_75Hz))
{
EDIDmode.resX = 1280;
EDIDmode.resY = 1024;
EDIDmode.bpp = 0;
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
}
if (edid1_EstablishedTim(&edid, EST_1152x870_75Hz))
{
EDIDmode.resX = 1152;
EDIDmode.resY = 870;
EDIDmode.bpp = 0;
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
}
if (edid1_EstablishedTim(&edid, EST_1024x768_75Hz) ||
edid1_EstablishedTim(&edid, EST_1024x768_70Hz) ||
edid1_EstablishedTim(&edid, EST_1024x768_60Hz) ||
edid1_EstablishedTim(&edid, EST_1024x768_87Hz))
{
EDIDmode.resX = 1024;
EDIDmode.resY = 768;
EDIDmode.bpp = 0;
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
}
if (edid1_EstablishedTim(&edid, EST_832x624_75Hz))
{
EDIDmode.resX = 832;
EDIDmode.resY = 624;
EDIDmode.bpp = 0;
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
}
if (edid1_EstablishedTim(&edid, EST_800x600_60Hz) ||
edid1_EstablishedTim(&edid, EST_800x600_56Hz) ||
edid1_EstablishedTim(&edid, EST_800x600_75Hz) ||
edid1_EstablishedTim(&edid, EST_800x600_72Hz))
{
EDIDmode.resX = 800;
EDIDmode.resY = 600;
EDIDmode.bpp = 0;
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
}
if (edid1_EstablishedTim(&edid, EST_720x400_88Hz) ||
edid1_EstablishedTim(&edid, EST_720x400_70Hz))
{
EDIDmode.resX = 720;
EDIDmode.resY = 400;
EDIDmode.bpp = 0;
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
}
if (edid1_EstablishedTim(&edid, EST_640x480_75Hz) ||
edid1_EstablishedTim(&edid, EST_640x480_72Hz) ||
edid1_EstablishedTim(&edid, EST_640x480_67Hz) ||
edid1_EstablishedTim(&edid, EST_640x480_60Hz))
{
EDIDmode.resX = 640;
EDIDmode.resY = 480;
EDIDmode.bpp = 0;
if (findModeByResolution(modeList, listLength, &EDIDmode) !=
(uint16_t)-1)
return EDIDmode.modeNumber;
}
}
else
printk(FB_VESA_NAME " error reading EDID: unsupported version\n");
return (uint16_t)-1;
}
void vesa_realmode_bootup_init(void)
{
uint32_t vbe_ret_val;
uint16_t size;
struct VBE_VbeInfoBlock *vib = (struct VBE_VbeInfoBlock *)
i386_get_default_rm_buffer(&size);
vbe_ret_val = VBEControllerInformation(vib, 0x300);
if (vbe_ret_val == -1)
{
printk(FB_VESA_NAME " error calling real mode interrupt.\n");
return;
}
if (vbe_ret_val != (VBE_callSuccessful<<8 | VBE_functionSupported))
{
printk(FB_VESA_NAME " Function 00h (read VBE info block)"
"not supported.\n");
}
/* Helper array is later filled with mode numbers and their parameters
sorted from the biggest values to the smalest where priorities of
parameters are from the highest to the lowest: resolution X,
resolution Y, bits per pixel.
The array is used for search the monitor provided parameters in EDID
structure and if found we set such mode using corresponding
VESA function. */
#define MAX_NO_OF_SORTED_MODES 100
modeParams sortModeParams[MAX_NO_OF_SORTED_MODES];
uint16_t *vmpSegOff = (uint16_t *)&vib->VideoModePtr;
uint16_t *modeNOPtr = (uint16_t*)
i386_Real_to_physical(*(vmpSegOff+1), *vmpSegOff);
uint16_t iterator = 0;
if (*(uint16_t*)vib->VideoModePtr == VBE_STUB_VideoModeList)
{
printk(FB_VESA_NAME " VBE Core not implemented!\n");
}
else
{
/* prepare list of modes */
while (*(modeNOPtr+iterator) != VBE_END_OF_VideoModeList &&
*(modeNOPtr+iterator) != 0)
{ /* some bios implementations ends the list incorrectly with 0 */
if (iterator < MAX_NO_OF_SORTED_MODES)
{
sortModeParams[iterator].modeNumber = *(modeNOPtr+iterator);
iterator ++;
}
else
break;
}
if (iterator < MAX_NO_OF_SORTED_MODES)
sortModeParams[iterator].modeNumber = 0;
}
struct VBE_ModeInfoBlock *mib = (struct VBE_ModeInfoBlock *)
i386_get_default_rm_buffer(&size);
iterator = 0;
uint8_t nextFilteredMode = 0;
uint16_t required_mode_attributes = VBE_modSupInHWMask |
VBE_ColorModeMask | VBE_GraphicsModeMask | VBE_LinFraBufModeAvaiMask;
/* get parameters of modes and filter modes according to set
required parameters */
while (iterator < MAX_NO_OF_SORTED_MODES &&
sortModeParams[iterator].modeNumber!=0)
{
VBEModeInformation(mib, sortModeParams[iterator].modeNumber);
if ((mib->ModeAttributes&required_mode_attributes) ==
required_mode_attributes)
{
sortModeParams[nextFilteredMode].modeNumber =
sortModeParams[iterator].modeNumber;
sortModeParams[nextFilteredMode].resX = mib->XResolution;
sortModeParams[nextFilteredMode].resY = mib->YResolution;
sortModeParams[nextFilteredMode].bpp = mib->BitsPerPixel;
nextFilteredMode ++;
}
iterator ++;
}
sortModeParams[nextFilteredMode].modeNumber = 0;
uint8_t numberOfModes = nextFilteredMode;
/* sort filtered modes */
modeParams modeXchgPlace;
iterator = 0;
uint8_t j;
uint8_t idxBestMode;
while (iterator < numberOfModes)
{
idxBestMode = iterator;
j = iterator+1;
while (j < numberOfModes)
{
if (sortModeParams[j].resX > sortModeParams[idxBestMode].resX)
idxBestMode = j;
else if (sortModeParams[j].resX == sortModeParams[idxBestMode].resX)
{
if (sortModeParams[j].resY > sortModeParams[idxBestMode].resY)
idxBestMode = j;
else if (sortModeParams[j].resY ==
sortModeParams[idxBestMode].resY)
{
if (sortModeParams[j].bpp > sortModeParams[idxBestMode].bpp)
idxBestMode = j;
}
}
j++;
}
if (idxBestMode != iterator)
{
modeXchgPlace = sortModeParams[iterator];
sortModeParams[iterator] = sortModeParams[idxBestMode];
sortModeParams[idxBestMode] = modeXchgPlace;
}
iterator++;
}
/* first search for video argument in multiboot options */
vbe_usedMode = findModeUsingCmdline(sortModeParams, numberOfModes);
if (vbe_usedMode == (uint16_t)-1)
{
printk(FB_VESA_NAME " video on command line not provided"
"\n\ttrying EDID ...\n");
/* second search monitor for good resolution */
vbe_usedMode = findModeUsingEDID(sortModeParams, numberOfModes);
if (vbe_usedMode == (uint16_t)-1)
{
printk(FB_VESA_NAME" monitor's EDID video parameters not supported"
"\n\tusing mode with highest resolution, bpp\n");
/* third set highest values */
vbe_usedMode = sortModeParams[0].modeNumber;
}
}
/* fill framebuffer structs with info about selected mode */
vbe_ret_val = VBEModeInformation(mib, vbe_usedMode);
if ((vbe_ret_val&0xff)!=VBE_functionSupported ||
(vbe_ret_val>>8)!=VBE_callSuccessful)
{
printk(FB_VESA_NAME " Cannot get mode info anymore. ax=0x%x\n",
vbe_ret_val);
}
fb_var.xres = mib->XResolution;
fb_var.yres = mib->YResolution;
fb_var.bits_per_pixel = mib->BitsPerPixel;
fb_var.red.offset = mib->LinRedFieldPosition;
fb_var.red.length = mib->LinRedMaskSize;
fb_var.red.msb_right = 0;
fb_var.green.offset = mib->LinGreenFieldPosition;
fb_var.green.length = mib->LinGreenMaskSize;
fb_var.green.msb_right = 0;
fb_var.blue.offset = mib->LinBlueFieldPosition;
fb_var.blue.length = mib->LinBlueMaskSize;
fb_var.blue.msb_right = 0;
fb_var.transp.offset = mib->LinRsvdFieldPosition;
fb_var.transp.length = mib->LinRsvdMaskSize;
fb_var.transp.msb_right =0;
fb_fix.smem_start = (char *)mib->PhysBasePtr;
fb_fix.line_length = mib->LinBytesPerScanLine;
fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
fb_fix.type = FB_TYPE_PACKED_PIXELS;
if (fb_var.bits_per_pixel < 24)
fb_fix.visual = FB_VISUAL_DIRECTCOLOR;
else
fb_fix.visual = FB_VISUAL_TRUECOLOR;
/* set selected mode */
vbe_ret_val = VBESetMode(vbe_usedMode | VBE_linearFlatFrameBufMask,
(struct VBE_CRTCInfoBlock *)(i386_get_default_rm_buffer(&size)));
if (vbe_ret_val>>8 == VBE_callFailed)
printk(FB_VESA_NAME " VBE: Requested mode is not available.");
if ((vbe_ret_val&0xff)!= (VBE_functionSupported | VBE_callSuccessful<<8))
printk(FB_VESA_NAME " Call to function 2h (set VBE mode) failed. "
"ax=0x%x\n", vbe_ret_val);
vib = (void *) 0;
mib = (void *) 0;
}
/*
* fb_vesa device driver INITIALIZE entry point.
*/
rtems_device_driver
frame_buffer_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
rtems_status_code status;
printk(FB_VESA_NAME " frame buffer -- driver initializing..\n" );
/*
* Register the device.
*/
status = rtems_io_register_name(FRAMEBUFFER_DEVICE_0_NAME, major, 0);
if (status != RTEMS_SUCCESSFUL)
{
printk("Error registering " FRAMEBUFFER_DEVICE_0_NAME
" - " FB_VESA_NAME " frame buffer device!\n");
rtems_fatal_error_occurred( status );
}
return RTEMS_SUCCESSFUL;
}
/*
* fb_vesa device driver OPEN entry point
*/
rtems_device_driver
frame_buffer_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
printk( FB_VESA_NAME " open device\n" );
if (pthread_mutex_trylock(&vesa_mutex) != 0)
{
printk( FB_VESA_NAME " could not lock vesa_mutex\n" );
return RTEMS_UNSATISFIED;
}
return RTEMS_SUCCESSFUL;
}
/*
* fb_vesa device driver CLOSE entry point
*/
rtems_device_driver
frame_buffer_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
printk( FB_VESA_NAME " close device\n" );
if (pthread_mutex_unlock(&vesa_mutex) == 0)
{
/* restore previous state. for VGA this means return to text mode.
* leave out if graphics hardware has been initialized in
* frame_buffer_initialize() */
printk(FB_VESA_NAME ": close called.\n" );
return RTEMS_SUCCESSFUL;
}
return RTEMS_UNSATISFIED;
}
/*
* fb_vesa device driver READ entry point.
*/
rtems_device_driver
frame_buffer_read(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
printk( FB_VESA_NAME " read device\n" );
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
rw_args->bytes_moved =
((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ?
(fb_fix.smem_len - rw_args->offset) :
rw_args->count;
memcpy(rw_args->buffer, (const void *)
(fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved);
return RTEMS_SUCCESSFUL;
}
/*
* frame_vesa device driver WRITE entry point.
*/
rtems_device_driver
frame_buffer_write(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
printk( FB_VESA_NAME " write device\n" );
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
rw_args->bytes_moved =
((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ?
(fb_fix.smem_len - rw_args->offset) :
rw_args->count;
memcpy( (void *) (fb_fix.smem_start + rw_args->offset),
rw_args->buffer, rw_args->bytes_moved);
return RTEMS_SUCCESSFUL;
}
static int get_fix_screen_info( struct fb_fix_screeninfo *info )
{
printk("get_fix_screen_info\n");
*info = fb_fix;
return 0;
}
static int get_var_screen_info( struct fb_var_screeninfo *info )
{
printk("get_var_screen_info\n");
*info = fb_var;
return 0;
}
/*
* IOCTL entry point -- This method is called to carry
* all services of this interface.
*/
rtems_device_driver
frame_buffer_control(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
rtems_libio_ioctl_args_t *args = arg;
printk( FB_VESA_NAME " ioctl called, cmd=%x\n", args->command );
printk("fbxres %d, fbyres %d\n", fb_var.xres, fb_var.yres);
printk("fbbpp %d\n", fb_var.bits_per_pixel);
switch (args->command)
{
case FBIOGET_FSCREENINFO:
args->ioctl_return =
get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer );
break;
case FBIOGET_VSCREENINFO:
args->ioctl_return =
get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer );
break;
case FBIOPUT_VSCREENINFO:
/* not implemented yet */
args->ioctl_return = -1;
return RTEMS_UNSATISFIED;
case FBIOGETCMAP:
/* no palette - truecolor mode */
args->ioctl_return = -1;
return RTEMS_UNSATISFIED;
case FBIOPUTCMAP:
/* no palette - truecolor mode */
args->ioctl_return = -1;
return RTEMS_UNSATISFIED;
default:
args->ioctl_return = 0;
break;
}
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,131 @@
/**
* @file fb_vesa.h
*
* @ingroup i386_pc386
*
* @brief Definitioins for vesa based framebuffer drivers.
*/
/*
* Headers specific for framebuffer drivers utilizing VESA VBE.
*
* Copyright (C) 2014 Jan Doležal (dolezj21@fel.cvut.cz)
* CTU in Prague.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp/vbe3.h>
#include <edid.h>
#ifndef _FB_VESA_H
#define _FB_VESA_H
#ifndef ASM /* ASM */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* ----- Prototypes ----- */
/**
* Returns information about graphic's controller in the infoBlock structure.
*
* @param infoBlock pointer to the struct to be filled with
controller information
* @param queriedVBEVersion if >0x200 then video bios is asked to fill in
* parameters which appeared with second version
* of VBE.
* @retval register ax content as defined in VBE RETURN STATUS paragraph
* -1 error calling graphical bios
*/
uint32_t VBEControllerInformation (
struct VBE_VbeInfoBlock *infoBlock,
uint16_t queriedVBEVersion
);
/**
* Fills structure infoBlock with informations about selected mode in
* modeNumber variable.
*
* @param infoBlock pointer to the struct to be filled with mode information
* @param modeNumber detailes of this mode to be filled
* @retval register ax content as defined in VBE RETURN STATUS paragraph
* -1 error calling graphical bios
*/
uint32_t VBEModeInformation (
struct VBE_ModeInfoBlock *infoBlock,
uint16_t modeNumber
);
/**
* Sets graphics mode selected. If mode has refreshRateCtrl bit set, than the
* infoBlock must be filled accordingly.
*
* @param modeNumber number of mode to be set
* @param infoBlock pointer to struct containing refresh rate control info
* @retval register ax content as defined in VBE RETURN STATUS paragraph
* -1 error calling graphical bios
*/
uint32_t VBESetMode (
uint16_t modeNumber,
struct VBE_CRTCInfoBlock *infoBlock
);
/**
* Get currently set mode number.
*
* @param modeNumber variable to be filled with current mode number
* @retval register ax content as defined in VBE RETURN STATUS paragraph
* -1 error calling graphical bios
*/
uint32_t VBECurrentMode (
uint16_t *modeNumber
);
/**
* Gets information about display data channel implemented in the
* graphic's controller.
*
* @param controllerUnitNumber
* @param secondsToTransferEDIDBlock approximate time to transfer one EDID block
* rounded up to seconds
* @param DDCLevelSupported after call contains DDC version supported and
* screen blanking state during transfer
* @retval register ax content as defined in VBE RETURN STATUS paragraph
* -1 error calling graphical bios
*/
uint32_t VBEReportDDCCapabilities (
uint16_t controllerUnitNumber,
uint8_t *secondsToTransferEDIDBlock,
uint8_t *DDCLevelSupported
);
/**
* Reads selected EDID block from display attached to controller's interface.
*
* @param controllerUnitNumber
* @param EDIDBlockNumber block no. to be read from the display
* @param buffer place to store block fetched from the display
* @retval register ax content as defined in VBE RETURN STATUS paragraph
* -1 error calling graphical bios
*/
uint32_t VBEReadEDID (
uint16_t controllerUnitNumber,
uint16_t EDIDBlockNumber,
struct edid1 *buffer
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* ASM */
#endif /* _FB_VESA_H */

View File

@@ -147,6 +147,7 @@ $(PROJECT_INCLUDE)/i386_io.h: ../../i386/shared/comm/i386_io.h $(PROJECT_INCLUDE
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i386_io.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/i386_io.h
if USE_VBE_RM
$(PROJECT_INCLUDE)/bsp/vbe3.h: include/vbe3.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vbe3.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vbe3.h
@@ -155,6 +156,11 @@ $(PROJECT_INCLUDE)/edid.h: include/edid.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/edid.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/edid.h
$(PROJECT_INCLUDE)/bsp/fb_vesa.h: include/fb_vesa.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/fb_vesa.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/fb_vesa.h
endif
$(PROJECT_INCLUDE)/pcibios.h: ../../i386/shared/pci/pcibios.h $(PROJECT_INCLUDE)/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/pcibios.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/pcibios.h

View File

@@ -41,6 +41,7 @@
#include <rtems/asm.h>
#include <rtems/score/cpu.h>
#include <bspopts.h>
/*----------------------------------------------------------------------------+
| Size of heap and stack:
@@ -61,6 +62,9 @@ BEGIN_CODE
PUBLIC (start) # GNU default entry point
EXTERN (boot_card)
#ifdef USE_VBE_RM
EXTERN (vesa_realmode_bootup_init)
#endif
EXTERN (_load_segments)
EXTERN (_return_to_monitor)
EXTERN (_IBMPC_initVideo)
@@ -201,6 +205,10 @@ SYM (zero_bss):
+-------------------------------------------------------------------*/
call _IBMPC_initVideo
#ifdef USE_VBE_RM
call vesa_realmode_bootup_init
#endif
/*---------------------------------------------------------------------+
| Check CPU type. Enable Cache and init coprocessor if needed.
+---------------------------------------------------------------------*/