Modules/VESA - Rework to handle boot-time modes (EGA text too)
authorJohn Hodge <[email protected]>
Sat, 21 Dec 2013 07:33:17 +0000 (15:33 +0800)
committerJohn Hodge <[email protected]>
Sat, 21 Dec 2013 07:33:17 +0000 (15:33 +0800)
KernelLand/Modules/Display/VESA/main.c

index 8cb3728..25616da 100644 (file)
@@ -2,7 +2,7 @@
  * AcessOS 1\r
  * Video BIOS Extensions (Vesa) Driver\r
  */\r
-#define DEBUG  0\r
+#define DEBUG  1\r
 #define VERSION        0x100\r
 \r
 #include <acess.h>\r
@@ -35,6 +35,9 @@ size_t        Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buff
 void   Vesa_int_HideCursor(void);\r
 void   Vesa_int_ShowCursor(void);\r
 void   Vesa_FlipCursor(void *Arg);\r
+Uint16 VBE_int_GetWord(const tVT_Char *Char);\r
+void   VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);\r
+void   VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);\r
 \r
 // === GLOBALS ===\r
 MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);\r
@@ -51,6 +54,7 @@ tVM8086       *gpVesa_BiosState;
  int   giVesaDriverId = -1;\r
 // --- Video Modes ---\r
  int   giVesaCurrentMode = 0;\r
+tVesa_Mode     gVesa_BootMode = {0x03, 80*8, 25*16, 80*8*2, 12, FLAG_POPULATED, 80*25*2, 0xB8000};\r
 tVesa_Mode     *gVesa_Modes;\r
 tVesa_Mode     *gpVesaCurMode;\r
  int   giVesaModeCount = 0;\r
@@ -67,7 +71,13 @@ tTimer       *gpVesaCursorTimer;
  int   gbVesa_CursorVisible = 0;\r
 // --- 2D Video Stream Handlers ---\r
 tDrvUtil_Video_BufInfo gVesa_BufInfo;\r
+tDrvUtil_Video_2DHandlers      gVBE_Text2DFunctions = {\r
+       NULL,\r
+       VBE_int_Text_2D_Fill,\r
+       VBE_int_Text_2D_Blit\r
+};\r
 // --- Settings ---\r
+bool   gbVesa_DisableBIOSCalls;        // Disables calls to the BIOS\r
 // int gbVesa_DisableFBCache;  // Disables the main-memory framebuffer cache\r
 \r
 // === CODE ===\r
@@ -75,16 +85,24 @@ int Vesa_Install(char **Arguments)
 {\r
         int    rv;\r
 \r
-//     for( int i = 0; Arguments[i]; i ++ )\r
-//     {\r
-//             if( strcmp(Aguments[i], "nocache") == 0 )\r
-//                     gbVesa_DisableFBCache = 1;\r
-//     }\r
-       \r
-       gpVesa_BiosState = VM8086_Init();\r
-       \r
-       if( (rv = VBE_int_GetModeList()) )\r
-               return rv;\r
+       for( int i = 0; Arguments && Arguments[i]; i ++ )\r
+       {\r
+               if( strcmp(Arguments[i], "nobios") == 0 )\r
+                       gbVesa_DisableBIOSCalls = 1;\r
+               //else if( strcmp(Arguments[i], "nocache") == 0 )\r
+               //      gbVesa_DisableFBCache = 1;\r
+               else {\r
+                       Log_Notice("VBE", "Unknown argument '%s'", Arguments[i]);\r
+               }\r
+       }\r
+\r
+       if( !gbVesa_DisableBIOSCalls )\r
+       {\r
+               gpVesa_BiosState = VM8086_Init();\r
+               \r
+               if( (rv = VBE_int_GetModeList()) )\r
+                       return rv;\r
+       }\r
                \r
        #if BLINKING_CURSOR\r
        // Create blink timer\r
@@ -103,7 +121,6 @@ int VBE_int_GetModeList(void)
        tVesa_CallInfo  *info;\r
        tFarPtr infoPtr;\r
        Uint16  *modes;\r
-       int     i;\r
        \r
        // Allocate Info Block\r
        info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);\r
@@ -115,7 +132,7 @@ int VBE_int_GetModeList(void)
        // Call Interrupt\r
        VM8086_Int(gpVesa_BiosState, 0x10);\r
        if(gpVesa_BiosState->AX != 0x004F) {\r
-               Log_Warning("VESA", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);\r
+               Log_Warning("VBE", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);\r
                return MODULE_ERR_NOTNEEDED;\r
        }\r
        \r
@@ -125,49 +142,45 @@ int VBE_int_GetModeList(void)
 //     VM8086_Deallocate( gpVesa_BiosState, info );\r
        \r
        // Count Modes\r
-       for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ );\r
-       giVesaModeCount ++;     // First text mode\r
+       for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ )\r
+               ;\r
        gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );\r
        \r
        Log_Debug("VBE", "%i Modes", giVesaModeCount);\r
 \r
        // Insert Text Mode\r
-       gVesa_Modes[0].width = 80;\r
-       gVesa_Modes[0].height = 25;\r
-       gVesa_Modes[0].bpp = 12;\r
-       gVesa_Modes[0].code = 0x3;\r
-       gVesa_Modes[0].flags = 1;\r
-       gVesa_Modes[0].fbSize = 80*25*2;\r
-       gVesa_Modes[0].framebuffer = 0xB8000;\r
-       \r
-       for( i = 1; i < giVesaModeCount; i++ )\r
+       \r
+       for( int i = 0; i < giVesaModeCount; i++ )\r
        {\r
-               gVesa_Modes[i].code = modes[i-1];\r
+               gVesa_Modes[i].code = modes[i];\r
        }\r
        \r
        return 0;\r
 }\r
 \r
-void VBE_int_FillMode_Int(int Index, tVesa_CallModeInfo *vbeinfo, tFarPtr *BufPtr)\r
+int VBE_int_GetModeInfo(Uint16 Code, tFarPtr *BufPtr)\r
 {\r
-       tVesa_Mode      *mode = &gVesa_Modes[Index];\r
-\r
        // Get Mode info\r
        gpVesa_BiosState->AX = 0x4F01;\r
-       gpVesa_BiosState->CX = mode->code;\r
+       gpVesa_BiosState->CX = Code;\r
        gpVesa_BiosState->ES = BufPtr->seg;\r
        gpVesa_BiosState->DI = BufPtr->ofs;\r
        VM8086_Int(gpVesa_BiosState, 0x10);\r
 \r
        if( gpVesa_BiosState->AX != 0x004F ) {\r
-               Log_Error("VESA", "Getting info on mode 0x%x failed (AX=0x%x)",\r
-                       mode->code, gpVesa_BiosState->AX);\r
-               return ;\r
+               Log_Error("VBE", "Getting info on mode 0x%x failed (AX=0x%x)",\r
+                       Code, gpVesa_BiosState->AX);\r
+               return 1;\r
        }\r
+       return 0;\r
+}\r
 \r
-       #if 0\r
+\r
+void VBE_int_FillMode_Int(tVesa_Mode *Mode, const tVesa_CallModeInfo *vbeinfo)\r
+{\r
+       #if 1\r
        #define S_LOG(s, fld, fmt)      LOG(" ."#fld" = "fmt, (s).fld)\r
-       LOG("vbeinfo[0x%x] = {", mode->code);\r
+       LOG("vbeinfo[0x%x] = {", Mode->code);\r
        S_LOG(*vbeinfo, attributes, "0x%02x");\r
        S_LOG(*vbeinfo, winA, "0x%02x");\r
        S_LOG(*vbeinfo, winB, "0x%02x");\r
@@ -208,53 +221,68 @@ void VBE_int_FillMode_Int(int Index, tVesa_CallModeInfo *vbeinfo, tFarPtr *BufPt
        LOG("}");\r
        #endif\r
 \r
-       mode->flags = FLAG_POPULATED;\r
-       if( !(vbeinfo->attributes & 1) ) {\r
+       Mode->flags = FLAG_POPULATED;\r
+       if( !(vbeinfo->attributes & 1) )\r
+       {\r
                #if DEBUG\r
-               Log_Log("VESA", "0x%x - not supported", mode->code);\r
+               Log_Log("VBE", "0x%x - not supported", Mode->code);\r
                #endif\r
-               mode->width = 0;\r
-               mode->height = 0;\r
-               mode->bpp = 0;\r
+               Mode->width = 0;\r
+               Mode->height = 0;\r
+               Mode->bpp = 0;\r
                return ;\r
        }\r
 \r
        // Parse Info\r
-       mode->flags |= FLAG_VALID;\r
-       if ( (vbeinfo->attributes & 0x90) == 0x90 )\r
+       Mode->flags |= FLAG_VALID;\r
+       switch( vbeinfo->attributes & 0x90 )    // LFB, Graphics\r
        {\r
-               mode->flags |= FLAG_LFB;\r
-               mode->framebuffer = vbeinfo->physbase;\r
-               mode->fbSize = vbeinfo->Yres*vbeinfo->pitch;\r
-       } else {\r
-               mode->framebuffer = 0;\r
-               mode->fbSize = 0;\r
+       case 0x00:      // Banked, Text\r
+       case 0x10:      // Banked, Graphics\r
+       case 0x80:      // Linear, Text (?)\r
+               Mode->width = 0;\r
+               Mode->height = 0;\r
+               Mode->bpp = 0;\r
+               return ;\r
+       case 0x90:\r
+               Mode->flags |= FLAG_LFB;\r
+               Mode->framebuffer = vbeinfo->physbase;\r
+               Mode->fbSize = vbeinfo->Yres*vbeinfo->pitch;\r
+               break;\r
        }\r
        \r
-       mode->pitch = vbeinfo->pitch;\r
-       mode->width = vbeinfo->Xres;\r
-       mode->height = vbeinfo->Yres;\r
-       mode->bpp = vbeinfo->bpp;\r
+       Mode->pitch = vbeinfo->pitch;\r
+       Mode->width = vbeinfo->Xres;\r
+       Mode->height = vbeinfo->Yres;\r
+       Mode->bpp = vbeinfo->bpp;\r
        \r
        #if DEBUG\r
-       Log_Log("VESA", "#%i 0x%x - %ix%ix%i (%x)",\r
-               Index, mode->code, mode->width, mode->height, mode->bpp, mode->flags);\r
+       Log_Log("VBE", "0x%x - %ix%ix%i (%x)",\r
+               Mode->code, Mode->width, Mode->height, Mode->bpp, Mode->flags);\r
        #endif\r
 \r
 } \r
 \r
+void VBE_int_SetBootMode(Uint16 ModeID, const void *ModeInfo)\r
+{\r
+       gVesa_BootMode.code = ModeID;\r
+       VBE_int_FillMode_Int(&gVesa_BootMode, ModeInfo);\r
+}\r
+\r
 void Vesa_int_FillModeList(void)\r
 {\r
-       if( !gbVesaModesChecked )\r
+       if( !gbVesaModesChecked && !gbVesa_DisableBIOSCalls )\r
        {\r
-                int    i;\r
                tVesa_CallModeInfo      *modeinfo;\r
                tFarPtr modeinfoPtr;\r
                \r
                modeinfo = VM8086_Allocate(gpVesa_BiosState, 256, &modeinfoPtr.seg, &modeinfoPtr.ofs);\r
-               for( i = 1; i < giVesaModeCount; i ++ )\r
+               for( int i = 0; i < giVesaModeCount; i ++ )\r
                {\r
-                       VBE_int_FillMode_Int(i, modeinfo, &modeinfoPtr);\r
+                       if( VBE_int_GetModeInfo(gVesa_Modes[i].code, &modeinfoPtr) == 0 )\r
+                       {\r
+                               VBE_int_FillMode_Int( &gVesa_Modes[i], modeinfo );\r
+                       }\r
                }       \r
 //             VM8086_Deallocate( gpVesa_BiosState, modeinfo );\r
                \r
@@ -267,12 +295,35 @@ void Vesa_int_FillModeList(void)
  */\r
 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)\r
 {\r
-       if( gVesa_Modes[giVesaCurrentMode].framebuffer == 0 ) {\r
-               Log_Warning("VESA", "Vesa_Write - Non-LFB Modes not yet supported.");\r
+       // Framebuffer modes - just pass on\r
+       if( gpVesaCurMode->flags & FLAG_LFB )\r
+               return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);\r
+       \r
+       // EGA text mode translation\r
+       switch( gVesa_BufInfo.BufferFormat )\r
+       {\r
+       case VIDEO_BUFFMT_TEXT: {\r
+                int    num = Length / sizeof(tVT_Char);\r
+                int    ofs = Offset / sizeof(tVT_Char);\r
+                int    i = 0;\r
+               const tVT_Char  *chars = Buffer;\r
+               Uint16  word;\r
+               \r
+               for( ; num--; i ++, ofs ++)\r
+               {\r
+                       word = VBE_int_GetWord( &chars[i] );\r
+                       ((Uint16*)gVesa_BufInfo.Framebuffer)[ ofs ] = word;\r
+               }\r
+               \r
+               return Length; }\r
+       case VIDEO_BUFFMT_2DSTREAM:\r
+               return DrvUtil_Video_2DStream(NULL, Buffer, Length,\r
+                       &gVBE_Text2DFunctions, sizeof(gVBE_Text2DFunctions));\r
+       default:\r
+               Log_Warning("VBE", "TODO: Alternate modes in EGA text mode");\r
                return 0;\r
        }\r
 \r
-       return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);\r
 }\r
 \r
 const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
@@ -284,7 +335,7 @@ int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)
         int    ret;\r
        switch(ID)\r
        {\r
-       BASE_IOCTLS(DRV_TYPE_VIDEO, "VESA", VERSION, csaVESA_IOCtls);\r
+       BASE_IOCTLS(DRV_TYPE_VIDEO, "VBE", VERSION, csaVESA_IOCtls);\r
 \r
        case VIDEO_IOCTL_GETSETMODE:\r
                if( !Data )     return giVesaCurrentMode;\r
@@ -322,13 +373,19 @@ int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)
  * \brief Updates the video mode\r
  */\r
 int Vesa_Int_SetMode(int mode)\r
-{      \r
-       // Sanity Check values\r
-       if(mode < 0 || mode > giVesaModeCount)  return -1;\r
-\r
+{\r
+       tVesa_Mode      *modeptr;\r
        // Check for fast return\r
        if(mode == giVesaCurrentMode)   return 1;\r
        \r
+       // Special case: Boot mode\r
+       if( mode == -1 )\r
+               modeptr = &gVesa_BootMode;\r
+       else if( 0 <= mode && mode < giVesaModeCount )\r
+               modeptr = &gVesa_Modes[mode];\r
+       else\r
+               return -1;\r
+       \r
        Vesa_int_FillModeList();\r
 \r
        #if BLINKING_CURSOR\r
@@ -337,152 +394,197 @@ int Vesa_Int_SetMode(int mode)
        \r
        Mutex_Acquire( &glVesa_Lock );\r
        \r
-       gpVesa_BiosState->AX = 0x4F02;\r
-       gpVesa_BiosState->BX = gVesa_Modes[mode].code;\r
-       if(gVesa_Modes[mode].flags & FLAG_LFB) {\r
-               gpVesa_BiosState->BX |= 1 << 14;        // Use LFB\r
+       if( gbVesa_DisableBIOSCalls )\r
+       {\r
+               ASSERT(mode == -1);\r
        }\r
-       LOG("In : AX=%04x/BX=%04x",\r
-               gpVesa_BiosState->AX, gpVesa_BiosState->BX);\r
-       \r
-       // Set Mode\r
-       VM8086_Int(gpVesa_BiosState, 0x10);\r
+       else\r
+       {\r
+               gpVesa_BiosState->AX = 0x4F02;\r
+               gpVesa_BiosState->BX = modeptr->code;\r
+               if(modeptr->flags & FLAG_LFB) {\r
+                       gpVesa_BiosState->BX |= 1 << 14;        // Use LFB\r
+               }\r
+               LOG("In : AX=%04x/BX=%04x", gpVesa_BiosState->AX, gpVesa_BiosState->BX);\r
+               \r
+               // Set Mode\r
+               VM8086_Int(gpVesa_BiosState, 0x10);\r
 \r
-       LOG("Out: AX = %04x", gpVesa_BiosState->AX);\r
+               LOG("Out: AX = %04x", gpVesa_BiosState->AX);\r
+       }\r
        \r
        // Map Framebuffer\r
-       if( (tVAddr)gpVesa_Framebuffer != VESA_DEFAULT_FRAMEBUFFER )\r
-               MM_UnmapHWPages((tVAddr)gpVesa_Framebuffer, giVesaPageCount);\r
-       giVesaPageCount = (gVesa_Modes[mode].fbSize + 0xFFF) >> 12;\r
-       gpVesa_Framebuffer = (void*)MM_MapHWPages(gVesa_Modes[mode].framebuffer, giVesaPageCount);\r
-       \r
-       Log_Log("VESA", "Setting mode to %i 0x%x (%ix%i %ibpp) %p[0x%x] maps %P",\r
-               mode, gVesa_Modes[mode].code,\r
-               gVesa_Modes[mode].width, gVesa_Modes[mode].height,\r
-               gVesa_Modes[mode].bpp,\r
-               gpVesa_Framebuffer, giVesaPageCount << 12, gVesa_Modes[mode].framebuffer\r
+       if( gpVesaCurMode )\r
+       {\r
+               if( gpVesaCurMode->framebuffer < 1024*1024 )\r
+                       ;\r
+               else\r
+                       MM_UnmapHWPages((tVAddr)gpVesa_Framebuffer, giVesaPageCount);\r
+       }\r
+       giVesaPageCount = (modeptr->fbSize + 0xFFF) >> 12;\r
+       if( modeptr->framebuffer < 1024*1024 )\r
+               gpVesa_Framebuffer = (void*)(KERNEL_BASE|modeptr->framebuffer);\r
+       else\r
+               gpVesa_Framebuffer = (void*)MM_MapHWPages(modeptr->framebuffer, giVesaPageCount);\r
+       \r
+       Log_Log("VBE", "Setting mode to %i 0x%x (%ix%i %ibpp) %p[0x%x] maps %P",\r
+               mode, modeptr->code,\r
+               modeptr->width, modeptr->height,\r
+               modeptr->bpp,\r
+               gpVesa_Framebuffer, giVesaPageCount << 12, modeptr->framebuffer\r
                );\r
        \r
        // Record Mode Set\r
        giVesaCurrentMode = mode;\r
-       gpVesaCurMode = &gVesa_Modes[giVesaCurrentMode];\r
+       gpVesaCurMode = modeptr;\r
        \r
        Mutex_Release( &glVesa_Lock );\r
 \r
+       // TODO: Disableable backbuffer\r
        gVesa_BufInfo.BackBuffer  = realloc(gVesa_BufInfo.BackBuffer,\r
-               gVesa_Modes[mode].height * gVesa_Modes[mode].pitch);\r
+               modeptr->height * modeptr->pitch);\r
        gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;\r
-       gVesa_BufInfo.Pitch = gVesa_Modes[mode].pitch;\r
-       gVesa_BufInfo.Width = gVesa_Modes[mode].width;\r
-       gVesa_BufInfo.Height = gVesa_Modes[mode].height;\r
-       gVesa_BufInfo.Depth = gVesa_Modes[mode].bpp;    \r
+       gVesa_BufInfo.Pitch = modeptr->pitch;\r
+       gVesa_BufInfo.Width = modeptr->width;\r
+       gVesa_BufInfo.Height = modeptr->height;\r
+       gVesa_BufInfo.Depth = modeptr->bpp;     \r
 \r
        return 1;\r
 }\r
 \r
-int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)\r
+int VBE_int_MatchModes(tVideo_IOCtl_Mode *ReqMode, tVesa_Mode *ThisMode)\r
 {\r
-        int    i;\r
-        int    best = -1, tmp;\r
-       unsigned int factor, bestFactor = -1;\r
-       \r
-       ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);\r
-\r
-       Vesa_int_FillModeList();\r
-       \r
-       for(i = 0; i < giVesaModeCount; i ++)\r
+       LOG("Matching %ix%i %ibpp", ThisMode->width, ThisMode->height, ThisMode->bpp);\r
+       if(ThisMode->width == ReqMode->width && ThisMode->height == ReqMode->height)\r
        {\r
-               LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
-       \r
-               if(gVesa_Modes[i].width == data->width && gVesa_Modes[i].height == data->height)\r
+               //if( (data->bpp == 32 || data->bpp == 24)\r
+               // && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )\r
+               if( ReqMode->bpp == ThisMode->bpp )\r
                {\r
-                       //if( (data->bpp == 32 || data->bpp == 24)\r
-                       // && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )\r
-                       if( data->bpp == gVesa_Modes[i].bpp )\r
-                       {\r
-                               LOG("Perfect!");\r
-                               best = i;\r
-                               break;\r
-                       }\r
+                       LOG("Perfect!");\r
+                       return -1;\r
                }\r
+       }\r
+       \r
+       int tmp = ThisMode->width * ThisMode->height - ReqMode->width * ReqMode->height;\r
+       tmp = tmp < 0 ? -tmp : tmp;\r
+       unsigned int factor = (Uint64)tmp * 1000 / (ReqMode->width * ReqMode->height);\r
+       if( ThisMode->bpp > ReqMode->bpp )\r
+               factor += ThisMode->bpp - ReqMode->bpp;\r
+       else\r
+               factor += ReqMode->bpp - ThisMode->bpp;\r
+\r
+       if( ReqMode->bpp == ThisMode->bpp )\r
+               factor /= 2;\r
+       else\r
+       {\r
+               if( ReqMode->bpp == 8 && ThisMode->bpp != 8 )   factor *= 4;\r
+               if( ReqMode->bpp == 16 && ThisMode->bpp != 16 ) factor *= 4;\r
                \r
-               tmp = gVesa_Modes[i].width * gVesa_Modes[i].height;\r
-               tmp -= data->width * data->height;\r
-               tmp = tmp < 0 ? -tmp : tmp;\r
-               factor = (Uint64)tmp * 1000 / (data->width * data->height);\r
-               \r
-               if( data->bpp == 8 && gVesa_Modes[i].bpp != 8 ) continue;\r
-               if( data->bpp == 16 && gVesa_Modes[i].bpp != 16 )       continue;\r
-               \r
-               if( (data->bpp == 32 || data->bpp == 24)\r
-                && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )\r
+               if( (ReqMode->bpp == 32 || ReqMode->bpp == 24)\r
+                && (ThisMode->bpp == 32 || ThisMode->bpp == 24) )\r
                {\r
-                       if( data->bpp == gVesa_Modes[i].bpp )\r
-                               factor /= 2;\r
+                       // NC\r
                }\r
                else {\r
-                       if( data->bpp != gVesa_Modes[i].bpp )\r
-                               continue ;\r
+                       if( ReqMode->bpp < ThisMode->bpp )\r
+                               factor *= ThisMode->bpp / ReqMode->bpp + 1;\r
+                       else\r
+                               factor *= ReqMode->bpp / ThisMode->bpp + 1;\r
                }\r
+       }\r
+       \r
+       return factor;\r
+}\r
+\r
+int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)\r
+{\r
+        int    best = -1;\r
+       \r
+       ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);\r
+\r
+       Vesa_int_FillModeList();\r
+\r
+       int bestFactor = VBE_int_MatchModes(data, &gVesa_BootMode);     \r
+       tVesa_Mode *bestPtr = &gVesa_BootMode;\r
+\r
+       for(int i = 0; bestFactor > 0 && i < giVesaModeCount; i ++)\r
+       {\r
+               LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
+       \r
+               int factor = VBE_int_MatchModes(data, &gVesa_Modes[i]);\r
                \r
-               LOG("factor = %i", factor);\r
+               LOG("factor = %i, bestFactor = %i", factor, bestFactor);\r
                \r
                if(factor < bestFactor)\r
                {\r
                        bestFactor = factor;\r
                        best = i;\r
+                       bestPtr = &gVesa_Modes[i];\r
                }\r
        }\r
        data->id = best;\r
-       data->width = gVesa_Modes[best].width;\r
-       data->height = gVesa_Modes[best].height;\r
-       data->bpp = gVesa_Modes[best].bpp;\r
+       data->width = bestPtr->width;\r
+       data->height = bestPtr->height;\r
+       data->bpp = bestPtr->bpp;\r
        LEAVE('i', best);\r
        return best;\r
 }\r
 \r
 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)\r
 {\r
-       if(data->id < 0 || data->id > giVesaModeCount)  return -1;\r
+       tVesa_Mode      *modeptr;\r
+       if( data->id == -1 )\r
+               modeptr = &gVesa_BootMode;\r
+       else if( 0 <= data->id && data->id < giVesaModeCount)\r
+               modeptr = &gVesa_Modes[data->id];\r
+       else\r
+               return 0;\r
 \r
        Vesa_int_FillModeList();\r
 \r
-       data->width = gVesa_Modes[data->id].width;\r
-       data->height = gVesa_Modes[data->id].height;\r
-       data->bpp = gVesa_Modes[data->id].bpp;\r
+       data->width  = modeptr->width;\r
+       data->height = modeptr->height;\r
+       data->bpp    = modeptr->bpp;\r
        return 1;\r
 }\r
 \r
 void Vesa_int_HideCursor(void)\r
 {\r
-       DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );\r
-       #if BLINKING_CURSOR\r
-       if(gpVesaCursorTimer) {\r
-               Time_RemoveTimer(gpVesaCursorTimer);\r
+       if( gpVesaCurMode->flags & FLAG_LFB )\r
+       {\r
+               DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );\r
+               #if BLINKING_CURSOR\r
+               if(gpVesaCursorTimer) {\r
+                       Time_RemoveTimer(gpVesaCursorTimer);\r
+               }\r
+               #endif\r
        }\r
-       #endif\r
 }\r
 \r
 void Vesa_int_ShowCursor(void)\r
 {\r
-       gbVesa_CursorVisible = (giVesaCursorX >= 0);\r
-       if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+       if( gpVesaCurMode->flags & FLAG_LFB )\r
        {\r
-               DrvUtil_Video_DrawCursor(\r
-                       &gVesa_BufInfo,\r
-                       giVesaCursorX*giVT_CharWidth,\r
-                       giVesaCursorY*giVT_CharHeight\r
-                       );\r
-               #if BLINKING_CURSOR\r
-               Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );\r
-               #endif\r
+               gbVesa_CursorVisible = (giVesaCursorX >= 0);\r
+               if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+               {\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gVesa_BufInfo,\r
+                               giVesaCursorX*giVT_CharWidth,\r
+                               giVesaCursorY*giVT_CharHeight\r
+                               );\r
+                       #if BLINKING_CURSOR\r
+                       Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );\r
+                       #endif\r
+               }\r
+               else\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gVesa_BufInfo,\r
+                               giVesaCursorX,\r
+                               giVesaCursorY\r
+                               );\r
        }\r
-       else\r
-               DrvUtil_Video_DrawCursor(\r
-                       &gVesa_BufInfo,\r
-                       giVesaCursorX,\r
-                       giVesaCursorY\r
-                       );\r
 }\r
 \r
 /**\r
@@ -493,17 +595,182 @@ void Vesa_FlipCursor(void *Arg)
        if( gVesa_BufInfo.BufferFormat != VIDEO_BUFFMT_TEXT )\r
                return ;\r
 \r
-       if( gbVesa_CursorVisible )\r
-               DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);\r
+       if( gpVesaCurMode->flags & FLAG_LFB )\r
+       {\r
+               if( gbVesa_CursorVisible )\r
+                       DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);\r
+               else\r
+                       DrvUtil_Video_DrawCursor(&gVesa_BufInfo,\r
+                               giVesaCursorX*giVT_CharWidth,\r
+                               giVesaCursorY*giVT_CharHeight\r
+                               );\r
+               gbVesa_CursorVisible = !gbVesa_CursorVisible;\r
+                       \r
+               #if BLINKING_CURSOR\r
+               Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );\r
+               #endif\r
+       }\r
+}\r
+\r
+// ---\r
+// Helpers for text mode\r
+// ---\r
+\r
+/**\r
+ * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)\r
+ * \brief Converts a 12-bit colour into a VGA 4-bit colour\r
+ */\r
+Uint8 VBE_int_GetColourNibble(Uint16 col)\r
+{\r
+       Uint8   ret = 0;\r
+        int    bright = 0;\r
+       \r
+       col = col & 0xCCC;\r
+       col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);\r
+       bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;\r
+       \r
+       switch(col)\r
+       {\r
+       //      Black\r
+       case 0x00:      ret = 0x0;      break;\r
+       // Dark Grey\r
+       case 0x15:      ret = 0x8;      break;\r
+       // Blues\r
+       case 0x01:\r
+       case 0x02:      ret = 0x1;      break;\r
+       case 0x03:      ret = 0x9;      break;\r
+       // Green\r
+       case 0x04:\r
+       case 0x08:      ret = 0x2;      break;\r
+       case 0x0C:      ret = 0xA;      break;\r
+       // Reds\r
+       case 0x10:\r
+       case 0x20:      ret = 0x4;      break;\r
+       case 0x30:      ret = 0xC;      break;\r
+       // Light Grey\r
+       case 0x2A:      ret = 0x7;      break;\r
+       // White\r
+       case 0x3F:      ret = 0xF;      break;\r
+       \r
+       default:\r
+               ret |= (col & 0x03 ? 1 : 0);\r
+               ret |= (col & 0x0C ? 2 : 0);\r
+               ret |= (col & 0x30 ? 4 : 0);\r
+               ret |= (bright ? 8 : 0);\r
+               break;\r
+       }\r
+       return ret;\r
+}\r
+\r
+/**\r
+ * \brief Convers a character structure to a VGA character word\r
+ */\r
+Uint16 VBE_int_GetWord(const tVT_Char *Char)\r
+{\r
+       Uint16  ret;\r
+       Uint16  col;\r
+       \r
+       // Get Character\r
+       if(Char->Ch < 128)\r
+               ret = Char->Ch;\r
+       else {\r
+               switch(Char->Ch)\r
+               {\r
+               default:        ret = 0;        break;\r
+               }\r
+       }\r
+       \r
+       col = VBE_int_GetColourNibble(Char->BGCol);\r
+       ret |= col << 12;\r
+       \r
+       col = VBE_int_GetColourNibble(Char->FGCol);\r
+       ret |= col << 8;\r
+       \r
+       return ret;\r
+}\r
+\r
+void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)\r
+{\r
+       const int       charw = 8;\r
+       const int       charh = 16;\r
+       const int       tw = gpVesaCurMode->width / charw;\r
+       const int       th = gpVesaCurMode->height / charh;\r
+\r
+       X /= charw;\r
+       W /= charw;\r
+       Y /= charh;\r
+       H /= charh;\r
+\r
+       tVT_Char        ch;\r
+       ch.Ch = 0x20;\r
+       ch.BGCol  = (Colour & 0x0F0000) >> (16-8);\r
+       ch.BGCol |= (Colour & 0x000F00) >> (8-4);\r
+       ch.BGCol |= (Colour & 0x00000F);\r
+       ch.FGCol = 0;\r
+       Uint16 word = VBE_int_GetWord(&ch);\r
+\r
+       Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);\r
+\r
+       if( X >= tw || Y >= th )        return ;\r
+       if( X + W > tw )        W = tw - X;\r
+       if( Y + H > th )        H = th - Y;\r
+\r
+       Uint16  *buf = (Uint16*)gpVesa_Framebuffer + Y*tw + X;\r
+\r
+       \r
+       while( H -- ) {\r
+               for( int i = 0; i < W; i ++ )\r
+                       *buf++ = word;\r
+               buf += tw - W;\r
+       }\r
+}\r
+\r
+void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)\r
+{\r
+       const int       charw = 8;\r
+       const int       charh = 16;\r
+       const int       tw = gpVesaCurMode->width / charw;\r
+       const int       th = gpVesaCurMode->height / charh;\r
+\r
+       DstX /= charw;\r
+       SrcX /= charw;\r
+       W    /= charw;\r
+\r
+       DstY /= charh;\r
+       SrcY /= charh;\r
+       H    /= charh;\r
+\r
+//     Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);\r
+\r
+       if( SrcX >= tw || SrcY >= th )  return ;\r
+       if( SrcX + W > tw )     W = tw - SrcX;\r
+       if( SrcY + H > th )     H = th - SrcY;\r
+       if( DstX >= tw || DstY >= th )  return ;\r
+       if( DstX + W > tw )     W = tw - DstX;\r
+       if( DstY + H > th )     H = th - DstY;\r
+\r
+\r
+       Uint16  *src = (Uint16*)gpVesa_Framebuffer + SrcY*tw + SrcX;\r
+       Uint16  *dst = (Uint16*)gpVesa_Framebuffer + DstY*tw + DstX;\r
+\r
+       if( src > dst )\r
+       {\r
+               // Simple copy\r
+               while( H-- ) {\r
+                       memcpy(dst, src, W*2);\r
+                       dst += tw;\r
+                       src += tw;\r
+               }\r
+       }\r
        else\r
-               DrvUtil_Video_DrawCursor(&gVesa_BufInfo,\r
-                       giVesaCursorX*giVT_CharWidth,\r
-                       giVesaCursorY*giVT_CharHeight\r
-                       );\r
-       gbVesa_CursorVisible = !gbVesa_CursorVisible;\r
-               \r
-       #if BLINKING_CURSOR\r
-       Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );\r
-       #endif\r
+       {\r
+               dst += H*tw;\r
+               src += H*tw;\r
+               while( H -- ) {\r
+                       dst -= tw-W;\r
+                       src -= tw-W;\r
+                       for( int i = W; i --; ) *--dst = *--src;\r
+               }\r
+       }\r
 }\r
 \r

UCC git Repository :: git.ucc.asn.au