[PATCH 8/8] i386/pc386: VESA based frame buffer utilizing real mode interrupt 10h

Joel Sherrill joel.sherrill at oarcorp.com
Thu Nov 20 15:02:47 UTC 2014


Same comments as on others.

Gedare just pushed this. Do the fixes I noted across the file
set in another round of patches. It is easier for all involved. :)

--joel


On 11/20/2014 8:00 AM, Jan Dolezal wrote:
> ---
>  c/src/lib/libbsp/i386/pc386/Makefile.am          |   5 +
>  c/src/lib/libbsp/i386/pc386/configure.ac         |  13 +
>  c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c | 858 +++++++++++++++++++++++
>  c/src/lib/libbsp/i386/pc386/include/fb_vesa.h    | 131 ++++
>  c/src/lib/libbsp/i386/pc386/preinstall.am        |   6 +
>  c/src/lib/libbsp/i386/pc386/start/start.S        |   8 +
>  6 files changed, 1021 insertions(+)
>  create mode 100644 c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c
>  create mode 100644 c/src/lib/libbsp/i386/pc386/include/fb_vesa.h
>
> diff --git a/c/src/lib/libbsp/i386/pc386/Makefile.am b/c/src/lib/libbsp/i386/pc386/Makefile.am
> index de970a3..391bfa9 100644
> --- a/c/src/lib/libbsp/i386/pc386/Makefile.am
> +++ b/c/src/lib/libbsp/i386/pc386/Makefile.am
> @@ -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
> diff --git a/c/src/lib/libbsp/i386/pc386/configure.ac b/c/src/lib/libbsp/i386/pc386/configure.ac
> index ecec056..a74d6cb 100644
> --- a/c/src/lib/libbsp/i386/pc386/configure.ac
> +++ b/c/src/lib/libbsp/i386/pc386/configure.ac
> @@ -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
> diff --git a/c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c b/c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c
> new file mode 100644
> index 0000000..6b26d35
> --- /dev/null
> +++ b/c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c
> @@ -0,0 +1,858 @@
> +/*
> + *  FB driver for graphic hardware compatible with VESA Bios Extension
> + *  Real mode interface utilized
> + *  Tested on real HW.
> + *
Needs file head and this should be in it.
> + *  Copyright (c) 2014 - CTU in Prague
> + *                       Jan Doležal ( dolezj21 at 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 at gmail.com)
> + *
The following should be in the file header block.
> + *  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
> + */
> +
Maybe even this block?
> +/*
> + *  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;
> +}
> diff --git a/c/src/lib/libbsp/i386/pc386/include/fb_vesa.h b/c/src/lib/libbsp/i386/pc386/include/fb_vesa.h
> new file mode 100644
> index 0000000..5638b50
> --- /dev/null
> +++ b/c/src/lib/libbsp/i386/pc386/include/fb_vesa.h
> @@ -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 at 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 */
> diff --git a/c/src/lib/libbsp/i386/pc386/preinstall.am b/c/src/lib/libbsp/i386/pc386/preinstall.am
> index b4ac86b..33a230c 100644
> --- a/c/src/lib/libbsp/i386/pc386/preinstall.am
> +++ b/c/src/lib/libbsp/i386/pc386/preinstall.am
> @@ -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
> diff --git a/c/src/lib/libbsp/i386/pc386/start/start.S b/c/src/lib/libbsp/i386/pc386/start/start.S
> index 1cba124..ab92a4f 100644
> --- a/c/src/lib/libbsp/i386/pc386/start/start.S
> +++ b/c/src/lib/libbsp/i386/pc386/start/start.S
> @@ -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.
>  +---------------------------------------------------------------------*/
> --
> 1.9.1
>
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel

-- 
Joel Sherrill, Ph.D.             Director of Research & Development
joel.sherrill at OARcorp.com        On-Line Applications Research
Ask me about RTEMS: a free RTOS  Huntsville AL 35805
Support Available                (256) 722-9985




More information about the devel mailing list