vesavbe.c

来自「适合KS8695X」· C语言 代码 · 共 1,215 行 · 第 1/3 页

C
1,215
字号
*               pixelClock  - Desired pixel clock
* Returns:      Closest pixel clock to desired clock (-1 if not supported)
*
* Description:  Calls the VBE/Core 3.0 interface to determine the closest
*               pixel clock to the requested value. The BIOS will always
*               search for a pixel clock that is no more than 1% below the
*               requested clock or somewhere higher than the clock. If the
*               clock is higher note that it may well be many Mhz higher
*               that requested and the application will have to check that
*               the returned value is suitable for it's needs. This function
*               returns the actual pixel clock that will be programmed by
*               the hardware.
*
*               Note that if the pixel clock will be used with a linear
*               framebuffer mode, make sure you pass in the linear
*               framebuffer flag to this function.
*
*               NOTE: Requires VBE/Core 3.0
*
****************************************************************************/
{
    RMREGS  regs;

    if (state->VBEVersion >= 0x300) {
	regs.x.ax = 0x4F0B;
	regs.h.bl = 0x00;
	regs.e.ecx = pixelClock;
	regs.x.dx = mode;
	PM_int86(0x10,&regs,&regs);
	if (regs.x.ax == VBE_SUCCESS)
	    return regs.e.ecx;
	}
    return -1;
}

ibool VBEAPI VBE_setDACWidth(int width)
/****************************************************************************
*
* Function:     VBE_setDACWidth
* Parameters:   width   - Width to set the DAC to
* Returns:      True on success, false on failure
*
****************************************************************************/
{
    RMREGS  regs;

    regs.x.ax = 0x4F08;
    regs.h.bl = 0x00;
    regs.h.bh = width;
    PM_int86(0x10,&regs,&regs);
    return regs.x.ax == VBE_SUCCESS;
}

int VBEAPI VBE_getDACWidth(void)
/****************************************************************************
*
* Function:     VBE_getDACWidth
* Returns:      Current width of the palette DAC
*
****************************************************************************/
{
    RMREGS  regs;

    regs.x.ax = 0x4F08;
    regs.h.bl = 0x01;
    PM_int86(0x10,&regs,&regs);
    if (regs.x.ax != VBE_SUCCESS)
	return -1;
    return regs.h.bh;
}

ibool VBEAPI VBE_setPalette(int start,int num,VBE_palette *pal,ibool waitVRT)
/****************************************************************************
*
* Function:     VBE_setPalette
* Parameters:   start   - Starting palette index to program
*               num     - Number of palette indexes to program
*               pal     - Palette buffer containing values
*               waitVRT - Wait for vertical retrace flag
* Returns:      True on success, false on failure
*
* Description:  Sets a block of palette registers by calling the VBE 2.0
*               BIOS. This function will fail on VBE 1.2 implementations.
*
****************************************************************************/
{
    RMREGS  regs;

    regs.x.ax = 0x4F09;
    regs.h.bl = waitVRT ? 0x80 : 0x00;
    regs.x.cx = num;
    regs.x.dx = start;
    VBE_callESDI(&regs, pal, sizeof(VBE_palette) * num);
    return regs.x.ax == VBE_SUCCESS;
}

void * VBEAPI VBE_getBankedPointer(VBE_modeInfo *modeInfo)
/****************************************************************************
*
* Function:     VBE_getBankedPointer
* Parameters:   modeInfo    - Mode info block for video mode
* Returns:      Selector to the linear framebuffer (0 on failure)
*
* Description:  Returns a near pointer to the VGA framebuffer area.
*
****************************************************************************/
{
    /* We just map the pointer every time, since the pointer will always
     * be in real mode memory, so we wont actually be mapping any real
     * memory.
     *
     * NOTE: We cannot currently map a near pointer to the banked frame
     *       buffer for Watcom Win386, so we create a 16:16 far pointer to
     *       the video memory. All the assembler code will render to the
     *       video memory by loading the selector rather than using a
     *       near pointer.
     */
    ulong seg = (ushort)modeInfo->WinASegment;
    if (seg != 0) {
	if (seg == 0xA000)
	    return (void*)PM_getA0000Pointer();
	else
	    return (void*)PM_mapPhysicalAddr(seg << 4,0xFFFF,true);
	}
    return NULL;
}

#ifndef REALMODE

void * VBEAPI VBE_getLinearPointer(VBE_modeInfo *modeInfo)
/****************************************************************************
*
* Function:     VBE_getLinearPointer
* Parameters:   modeInfo    - Mode info block for video mode
* Returns:      Selector to the linear framebuffer (0 on failure)
*
* Description:  Returns a near pointer to the linear framebuffer for the video
*               mode.
*
****************************************************************************/
{
    static ulong physPtr[MAX_LIN_PTRS] = {0};
    static void *linPtr[MAX_LIN_PTRS] = {0};
    static int numPtrs = 0;
    int i;

    /* Search for an already mapped pointer */
    for (i = 0; i < numPtrs; i++) {
	if (physPtr[i] == modeInfo->PhysBasePtr)
	    return linPtr[i];
	}
    if (numPtrs < MAX_LIN_PTRS) {
	physPtr[numPtrs] = modeInfo->PhysBasePtr;
	linPtr[numPtrs] = PM_mapPhysicalAddr(modeInfo->PhysBasePtr,(state->VBEMemory * 1024L)-1,true);
	return linPtr[numPtrs++];
	}
    return NULL;
}

static void InitPMCode(void)
/****************************************************************************
*
* Function:     InitPMCode  - 32 bit protected mode version
*
* Description:  Finds the address of and relocates the protected mode
*               code block from the VBE 2.0 into a local memory block. The
*               memory block is allocated with malloc() and must be freed
*               with VBE_freePMCode() after graphics processing is complete.
*
*               Note that this buffer _must_ be recopied after each mode set,
*               as the routines will change depending on the underlying
*               video mode.
*
****************************************************************************/
{
    RMREGS      regs;
    RMSREGS     sregs;
    uchar       *code;
    int         pmLen;

    if (!state->pmInfo && state->VBEVersion >= 0x200) {
	regs.x.ax = 0x4F0A;
	regs.x.bx = 0;
	PM_int86x(0x10,&regs,&regs,&sregs);
	if (regs.x.ax != VBE_SUCCESS)
	    return;
	if (VBE_shared)
	    state->pmInfo = PM_mallocShared(regs.x.cx);
	else
	    state->pmInfo = PM_malloc(regs.x.cx);
	if (state->pmInfo == NULL)
	    return;
	state->pmInfo32 = state->pmInfo;
	pmLen = regs.x.cx;

	/* Relocate the block into our local data segment */
	code = PM_mapRealPointer(sregs.es,regs.x.di);
	memcpy(state->pmInfo,code,pmLen);

	/* Now do a sanity check on the information we recieve to ensure
	 * that is is correct. Some BIOS return totally bogus information
	 * in here (Matrox is one)! Under DOS this works OK, but under OS/2
	 * we are screwed.
	 */
	if (state->pmInfo->setWindow >= pmLen ||
	    state->pmInfo->setDisplayStart >= pmLen ||
	    state->pmInfo->setPalette >= pmLen ||
	    state->pmInfo->IOPrivInfo >= pmLen) {
	    if (VBE_shared)
		PM_freeShared(state->pmInfo);
	    else
		PM_free(state->pmInfo);
	    state->pmInfo32 = state->pmInfo = NULL;
	    return;
	    }

	/* Read the IO priveledge info and determine if we need to
	 * pass a selector to MMIO registers to the bank switch code.
	 * Since we no longer support selector allocation, we no longer
	 * support this mechanism so we disable the protected mode
	 * interface in this case.
	 */
	if (state->pmInfo->IOPrivInfo && !state->MMIOSel) {
	    ushort *p = (ushort*)((uchar*)state->pmInfo + state->pmInfo->IOPrivInfo);
	    while (*p != 0xFFFF)
		p++;
	    p++;
	    if (*p != 0xFFFF)
		VBE_freePMCode();
	    }
	}
}

void * VBEAPI VBE_getSetBank(void)
/****************************************************************************
*
* Function:     VBE_getSetBank
* Returns:      Pointer to the 32 VBE 2.0 bit bank switching routine.
*
****************************************************************************/
{
    if (state->VBEVersion >= 0x200) {
	InitPMCode();
	if (state->pmInfo)
	    return (uchar*)state->pmInfo + state->pmInfo->setWindow;
	}
    return NULL;
}

void * VBEAPI VBE_getSetDisplayStart(void)
/****************************************************************************
*
* Function:     VBE_getSetDisplayStart
* Returns:      Pointer to the 32 VBE 2.0 bit CRT start address routine.
*
****************************************************************************/
{
    if (state->VBEVersion >= 0x200) {
	InitPMCode();
	if (state->pmInfo)
	    return (uchar*)state->pmInfo + state->pmInfo->setDisplayStart;
	}
    return NULL;
}

void * VBEAPI VBE_getSetPalette(void)
/****************************************************************************
*
* Function:     VBE_getSetPalette
* Returns:      Pointer to the 32 VBE 2.0 bit palette programming routine.
*
****************************************************************************/
{
    if (state->VBEVersion >= 0x200) {
	InitPMCode();
	if (state->pmInfo)
	    return (uchar*)state->pmInfo + state->pmInfo->setPalette;
	}
    return NULL;
}

void VBEAPI VBE_freePMCode(void)
/****************************************************************************
*
* Function:     VBE_freePMCode
*
* Description:  This routine frees the protected mode code blocks that
*               we copied from the VBE 2.0 interface. This routine must
*               be after you have finished graphics processing to free up
*               the memory occupied by the routines. This is necessary
*               because the PM info memory block must be re-copied after
*               every video mode set from the VBE 2.0 implementation.
*
****************************************************************************/
{
    if (state->pmInfo) {
	if (VBE_shared)
	    PM_freeShared(state->pmInfo);
	else
	    PM_free(state->pmInfo);
	state->pmInfo = NULL;
	state->pmInfo32 = NULL;
	}
}

void VBEAPI VBE_sharePMCode(void)
/****************************************************************************
*
* Function:     VBE_sharePMCode
*
* Description:  Enables internal sharing of the PM code buffer for OS/2.
*
****************************************************************************/
{
    VBE_shared = true;
}

/* Set of code stubs used to build the final bank switch code */

#define VBE20_adjustOffset  7

static uchar VBE20A_bankFunc32_Start[] = {
    0x53,0x51,                  /*  push    ebx,ecx     */
    0x8B,0xD0,                  /*  mov     edx,eax     */
    0x33,0xDB,                  /*  xor     ebx,ebx     */
    0xB1,0x00,                  /*  mov     cl,0        */
    0xD2,0xE2,                  /*  shl     dl,cl       */
    };

static uchar VBE20_bankFunc32_End[] = {
    0x59,0x5B,                  /*  pop     ecx,ebx     */
    };

static uchar bankFunc32[100];

#define copy(p,b,a) memcpy(b,a,sizeof(a)); (p) = (b) + sizeof(a)

ibool VBEAPI VBE_getBankFunc32(int *codeLen,void **bankFunc,int dualBanks,
    int bankAdjust)
/****************************************************************************
*
* Function:     VBE_getBankFunc32
* Parameters:   codeLen     - Place to store length of code
*               bankFunc    - Place to store pointer to bank switch code
*               dualBanks   - True if dual banks are in effect
*               bankAdjust  - Bank shift adjustment factor
* Returns:      True on success, false if not compatible.
*
* Description:  Creates a local 32 bit bank switch function from the
*               VBE 2.0 bank switch code that is compatible with the
*               virtual flat framebuffer devices (does not have a return
*               instruction at the end and takes the bank number in EAX
*               not EDX). Note that this 32 bit code cannot include int 10h
*               instructions, so we can only do this if we have VBE 2.0
*               or later.
*
*               Note that we need to know the length of the 32 bit
*               bank switch function, which the standard VBE 2.0 spec
*               does not provide. In order to support this we have
*               extended the VBE 2.0 state->pmInfo structure in UniVBE 5.2 in a
*               way to support this, and we hope that this will become
*               a VBE 2.0 ammendment.
*
*               Note also that we cannot run the linear framebuffer
*               emulation code with bank switching routines that require
*               a selector to the memory mapped registers passed in ES.
*
****************************************************************************/
{
    int     len;
    uchar   *code;
    uchar   *p;

    InitPMCode();
    if (state->VBEVersion >= 0x200 && state->pmInfo32 && !state->MMIOSel) {
	code = (uchar*)state->pmInfo32 + state->pmInfo32->setWindow;
	if (state->pmInfo32->extensionSig == VBE20_EXT_SIG)
	    len = state->pmInfo32->setWindowLen-1;
	else {
	    /* We are running on a system without the UniVBE 5.2 extension.
	     * We do as best we can by scanning through the code for the
	     * ret function to determine the length. This is not foolproof,
	     * but is the best we can do.
	     */
	    p = code;
	    while (*p != 0xC3)
		p++;
	    len = p - code;
	    }
	if ((len + sizeof(VBE20A_bankFunc32_Start) + sizeof(VBE20_bankFunc32_End)) > sizeof(bankFunc32))
	    PM_fatalError("32-bit bank switch function too long!");
	copy(p,bankFunc32,VBE20A_bankFunc32_Start);
	memcpy(p,code,len);
	p += len;
	copy(p,p,VBE20_bankFunc32_End);
	*codeLen = p - bankFunc32;
	bankFunc32[VBE20_adjustOffset] = (uchar)bankAdjust;
	*bankFunc = bankFunc32;
	return true;
	}
    return false;
}

#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?