3 * Video BIOS Extensions (Vesa) Driver
\r
6 #define VERSION 0x100
\r
10 #include <api_drv_video.h>
\r
11 #include <fs_devfs.h>
\r
12 #include <modules.h>
\r
18 // === CONSTANTS ===
\r
19 #ifdef ARCHDIR_is_x86
\r
24 #define VESA_DEFAULT_FRAMEBUFFER (KERNEL_BASE|0xA0000)
\r
25 #define BLINKING_CURSOR 0
\r
27 # define VESA_CURSOR_PERIOD 1000
\r
30 // === PROTOTYPES ===
\r
31 int Vesa_Install(char **Arguments);
\r
32 int VBE_int_GetModeList(void);
\r
33 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
\r
34 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);
\r
35 int Vesa_Int_SetMode(int Mode);
\r
36 int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);
\r
37 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);
\r
38 void Vesa_int_HideCursor(void);
\r
39 void Vesa_int_ShowCursor(void);
\r
40 int Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor);
\r
41 void Vesa_FlipCursor(void *Arg);
\r
42 Uint16 VBE_int_GetWord(const tVT_Char *Char);
\r
43 void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
\r
44 void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
\r
47 MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);
\r
48 tVFS_NodeType gVesa_NodeType = {
\r
49 .Write = Vesa_Write,
\r
52 tDevFS_Driver gVesa_DriverStruct = {
\r
54 {.Type = &gVesa_NodeType}
\r
57 tVM8086 *gpVesa_BiosState;
\r
58 int giVesaDriverId = -1;
\r
59 // --- Video Modes ---
\r
60 int giVesaCurrentMode = 0;
\r
61 tVesa_Mode gVesa_BootMode = {0x03, 80*8, 25*16, 80*8*2, 12, FLAG_POPULATED, 80*25*2, 0xB8000};
\r
62 tVesa_Mode *gVesa_Modes;
\r
63 tVesa_Mode *gpVesaCurMode = &gVesa_BootMode;
\r
64 int giVesaModeCount = 0;
\r
65 int gbVesaModesChecked;
\r
66 // --- Framebuffer ---
\r
67 char *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER;
\r
68 int giVesaPageCount = 0; //!< Framebuffer size in pages
\r
69 // --- Cursor Control ---
\r
70 int giVesaCursorX = -1;
\r
71 int giVesaCursorY = -1;
\r
73 tTimer *gpVesaCursorTimer;
\r
75 int gbVesa_CursorVisible = 0;
\r
76 // --- 2D Video Stream Handlers ---
\r
77 tDrvUtil_Video_BufInfo gVesa_BufInfo;
\r
78 tDrvUtil_Video_2DHandlers gVBE_Text2DFunctions = {
\r
80 VBE_int_Text_2D_Fill,
\r
81 VBE_int_Text_2D_Blit
\r
84 bool gbVesa_DisableBIOSCalls; // Disables calls to the BIOS
\r
85 // int gbVesa_DisableFBCache; // Disables the main-memory framebuffer cache
\r
88 int Vesa_Install(char **Arguments)
\r
90 for( int i = 0; Arguments && Arguments[i]; i ++ )
\r
92 if( strcmp(Arguments[i], "nobios") == 0 )
\r
93 gbVesa_DisableBIOSCalls = 1;
\r
94 //else if( strcmp(Arguments[i], "nocache") == 0 )
\r
95 // gbVesa_DisableFBCache = 1;
\r
97 Log_Notice("VBE", "Unknown argument '%s'", Arguments[i]);
\r
102 if( !gbVesa_DisableBIOSCalls )
\r
104 gpVesa_BiosState = VM8086_Init();
\r
106 int rv = VBE_int_GetModeList();
\r
111 #if BLINKING_CURSOR
\r
112 // Create blink timer
\r
113 gpVesaCursorTimer = Time_AllocateTimer( Vesa_FlipCursor, NULL );
\r
117 giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );
\r
118 if(giVesaDriverId == -1) return MODULE_ERR_MISC;
\r
120 return MODULE_ERR_OK;
\r
124 int VBE_int_GetModeList(void)
\r
126 tVesa_CallInfo *info;
\r
130 // Allocate Info Block
\r
131 info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);
\r
132 if( info == NULL ) {
\r
133 Log_Warning("VBE", "VM8086 allocation error");
\r
134 return MODULE_ERR_NOTNEEDED;
\r
136 // Set Requested Version
\r
137 memcpy(info->signature, "VBE2", 4);
\r
139 gpVesa_BiosState->AX = 0x4F00;
\r
140 gpVesa_BiosState->ES = infoPtr.seg; gpVesa_BiosState->DI = infoPtr.ofs;
\r
142 VM8086_Int(gpVesa_BiosState, 0x10);
\r
143 if(gpVesa_BiosState->AX != 0x004F) {
\r
144 Log_Warning("VBE", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);
\r
145 return MODULE_ERR_NOTNEEDED;
\r
148 modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);
\r
149 LOG("Virtual addres of mode list from %04x:%04x is %p",
\r
150 info->VideoModes.seg, info->VideoModes.ofs, modes);
\r
151 // VM8086_Deallocate( gpVesa_BiosState, info );
\r
154 for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ )
\r
156 gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );
\r
158 Log_Debug("VBE", "%i Modes", giVesaModeCount);
\r
160 // Insert Text Mode
\r
162 for( int i = 0; i < giVesaModeCount; i++ )
\r
164 gVesa_Modes[i].code = modes[i];
\r
170 int VBE_int_GetModeInfo(Uint16 Code, tFarPtr *BufPtr)
\r
173 gpVesa_BiosState->AX = 0x4F01;
\r
174 gpVesa_BiosState->CX = Code;
\r
175 gpVesa_BiosState->ES = BufPtr->seg;
\r
176 gpVesa_BiosState->DI = BufPtr->ofs;
\r
177 VM8086_Int(gpVesa_BiosState, 0x10);
\r
179 if( gpVesa_BiosState->AX != 0x004F ) {
\r
180 Log_Error("VBE", "Getting info on mode 0x%x failed (AX=0x%x)",
\r
181 Code, gpVesa_BiosState->AX);
\r
189 void VBE_int_FillMode_Int(tVesa_Mode *Mode, const tVesa_CallModeInfo *vbeinfo)
\r
192 #define S_LOG(s, fld, fmt) LOG(" ."#fld" = "fmt, (s).fld)
\r
193 LOG("vbeinfo[0x%x] = {", Mode->code);
\r
194 S_LOG(*vbeinfo, attributes, "0x%02x");
\r
195 S_LOG(*vbeinfo, winA, "0x%02x");
\r
196 S_LOG(*vbeinfo, winB, "0x%02x");
\r
197 S_LOG(*vbeinfo, granularity, "0x%04x");
\r
198 S_LOG(*vbeinfo, winsize, "0x%04x");
\r
199 S_LOG(*vbeinfo, segmentA, "0x%04x");
\r
200 S_LOG(*vbeinfo, segmentB, "0x%04x");
\r
201 LOG(" .realFctPtr = %04x:%04x", vbeinfo->realFctPtr.seg, vbeinfo->realFctPtr.ofs);
\r
202 S_LOG(*vbeinfo, pitch, "0x%04x");
\r
205 S_LOG(*vbeinfo, Xres, "%i");
\r
206 S_LOG(*vbeinfo, Yres, "%i");
\r
207 S_LOG(*vbeinfo, Wchar, "%i");
\r
208 S_LOG(*vbeinfo, Ychar, "%i");
\r
209 S_LOG(*vbeinfo, planes, "%i");
\r
210 S_LOG(*vbeinfo, bpp, "%i");
\r
211 S_LOG(*vbeinfo, banks, "%i");
\r
212 S_LOG(*vbeinfo, memory_model, "%i");
\r
213 S_LOG(*vbeinfo, bank_size, "%i");
\r
214 S_LOG(*vbeinfo, image_pages, "%i");
\r
216 LOG(" Red = %i bits at %i", vbeinfo->red_mask, vbeinfo->red_position );
\r
217 LOG(" Green = %i bits at %i", vbeinfo->green_mask, vbeinfo->green_position);
\r
218 LOG(" Blue = %i bits at %i", vbeinfo->blue_mask, vbeinfo->blue_position );
\r
220 Uint8 rsv_mask, rsv_position;
\r
221 Uint8 directcolor_attributes;
\r
224 S_LOG(*vbeinfo, physbase, "0x%08x");
\r
225 S_LOG(*vbeinfo, offscreen_ptr, "0x%08x");
\r
226 S_LOG(*vbeinfo, offscreen_size_kb, "0x%04x");
\r
228 S_LOG(*vbeinfo, lfb_pitch, "0x%04x");
\r
229 S_LOG(*vbeinfo, image_count_banked, "%i");
\r
230 S_LOG(*vbeinfo, image_count_lfb, "%i");
\r
234 Mode->flags = FLAG_POPULATED;
\r
235 // Check if this mode is supported by hardware
\r
236 if( !(vbeinfo->attributes & 1) )
\r
239 Log_Log("VBE", "0x%x - not supported", Mode->code);
\r
248 Mode->flags |= FLAG_VALID;
\r
249 switch( vbeinfo->attributes & 0x90 ) // LFB, Graphics
\r
251 case 0x00: // Banked, Text
\r
252 case 0x10: // Banked, Graphics
\r
253 case 0x80: // Linear, Text (?)
\r
259 Mode->flags |= FLAG_LFB|FLAG_GRAPHICS;
\r
260 Mode->framebuffer = vbeinfo->physbase;
\r
261 Mode->fbSize = vbeinfo->Yres*vbeinfo->pitch;
\r
265 Mode->pitch = vbeinfo->pitch;
\r
266 Mode->width = vbeinfo->Xres;
\r
267 Mode->height = vbeinfo->Yres;
\r
268 Mode->bpp = vbeinfo->bpp;
\r
271 Log_Log("VBE", "0x%x - %ix%ix%i (%x)",
\r
272 Mode->code, Mode->width, Mode->height, Mode->bpp, Mode->flags);
\r
277 void VBE_int_SetBootMode(Uint16 ModeID, const void *ModeInfo)
\r
279 gVesa_BootMode.code = ModeID;
\r
280 VBE_int_FillMode_Int(&gVesa_BootMode, ModeInfo);
\r
283 void Vesa_int_FillModeList(void)
\r
286 if( !gbVesaModesChecked && !gbVesa_DisableBIOSCalls )
\r
288 tVesa_CallModeInfo *modeinfo;
\r
289 tFarPtr modeinfoPtr;
\r
291 modeinfo = VM8086_Allocate(gpVesa_BiosState, 256, &modeinfoPtr.seg, &modeinfoPtr.ofs);
\r
292 for( int i = 0; i < giVesaModeCount; i ++ )
\r
294 if( VBE_int_GetModeInfo(gVesa_Modes[i].code, &modeinfoPtr) == 0 )
\r
296 VBE_int_FillMode_Int( &gVesa_Modes[i], modeinfo );
\r
299 // VM8086_Deallocate( gpVesa_BiosState, modeinfo );
\r
301 gbVesaModesChecked = 1;
\r
307 * \brief Write to the framebuffer
\r
309 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
\r
311 switch( gpVesaCurMode->flags & (FLAG_LFB|FLAG_GRAPHICS) )
\r
314 // EGA text mode translation
\r
315 switch( gVesa_BufInfo.BufferFormat )
\r
317 case VIDEO_BUFFMT_TEXT: {
\r
318 int num = Length / sizeof(tVT_Char);
\r
319 int ofs = Offset / sizeof(tVT_Char);
\r
321 const tVT_Char *chars = Buffer;
\r
323 for( ; num--; i ++, ofs ++)
\r
325 Uint16 word = VBE_int_GetWord( &chars[i] );
\r
326 ((Uint16*)gVesa_BufInfo.Framebuffer)[ ofs ] = word;
\r
330 case VIDEO_BUFFMT_2DSTREAM:
\r
331 return DrvUtil_Video_2DStream(NULL, Buffer, Length,
\r
332 &gVBE_Text2DFunctions, sizeof(gVBE_Text2DFunctions));
\r
334 Log_Warning("VBE", "TODO: Alternate modes in EGA text mode");
\r
338 case FLAG_LFB|FLAG_GRAPHICS:
\r
339 // Framebuffer modes - use DrvUtil Video
\r
340 return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);
\r
342 Log_Warning("VBE", "TODO: _Write %s%s",
\r
343 (gpVesaCurMode->flags & FLAG_LFB ? "FLAG_LFB" : ""),
\r
344 (gpVesaCurMode->flags & FLAG_GRAPHICS ? "FLAG_GRAPHICS" : "")
\r
350 const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
\r
352 * \brief Handle messages to the device
\r
354 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
359 BASE_IOCTLS(DRV_TYPE_VIDEO, "VBE", VERSION, csaVESA_IOCtls);
\r
361 case VIDEO_IOCTL_GETSETMODE:
\r
362 if( !Data ) return giVesaCurrentMode;
\r
363 return Vesa_Int_SetMode( *(int*)Data );
\r
365 case VIDEO_IOCTL_FINDMODE:
\r
366 return Vesa_Int_FindMode((tVideo_IOCtl_Mode*)Data);
\r
367 case VIDEO_IOCTL_MODEINFO:
\r
368 return Vesa_Int_ModeInfo((tVideo_IOCtl_Mode*)Data);
\r
370 case VIDEO_IOCTL_SETBUFFORMAT:
\r
371 Vesa_int_HideCursor();
\r
372 ret = gVesa_BufInfo.BufferFormat;
\r
374 gVesa_BufInfo.BufferFormat = *(int*)Data;
\r
375 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
376 Vesa_int_SetCursor(&gDrvUtil_TextModeCursor);
\r
377 Vesa_int_ShowCursor();
\r
380 case VIDEO_IOCTL_SETCURSOR: // Set cursor position
\r
381 if( !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )
\r
383 Vesa_int_HideCursor();
\r
384 giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;
\r
385 giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;
\r
386 Vesa_int_ShowCursor();
\r
389 case VIDEO_IOCTL_SETCURSORBITMAP:
\r
390 return Vesa_int_SetCursor(Data);
\r
396 * \brief Updates the video mode
\r
398 int Vesa_Int_SetMode(int mode)
\r
400 tVesa_Mode *modeptr;
\r
401 // Check for fast return
\r
402 if(mode == giVesaCurrentMode) return 1;
\r
404 // Special case: Boot mode
\r
406 modeptr = &gVesa_BootMode;
\r
407 else if( 0 <= mode && mode < giVesaModeCount )
\r
408 modeptr = &gVesa_Modes[mode];
\r
412 Vesa_int_FillModeList();
\r
414 #if BLINKING_CURSOR
\r
415 Time_RemoveTimer(gpVesaCursorTimer);
\r
418 Mutex_Acquire( &glVesa_Lock );
\r
421 if( gbVesa_DisableBIOSCalls )
\r
423 ASSERT(mode == -1);
\r
427 gpVesa_BiosState->AX = 0x4F02;
\r
428 gpVesa_BiosState->BX = modeptr->code;
\r
429 if(modeptr->flags & FLAG_LFB) {
\r
430 gpVesa_BiosState->BX |= 1 << 14; // Use LFB
\r
432 LOG("In : AX=%04x/BX=%04x", gpVesa_BiosState->AX, gpVesa_BiosState->BX);
\r
435 VM8086_Int(gpVesa_BiosState, 0x10);
\r
437 LOG("Out: AX = %04x", gpVesa_BiosState->AX);
\r
440 ASSERT(mode == -1);
\r
444 if( gpVesaCurMode )
\r
446 MM_UnmapHWPages(gpVesa_Framebuffer, giVesaPageCount);
\r
448 giVesaPageCount = (modeptr->fbSize + 0xFFF) >> 12;
\r
449 gpVesa_Framebuffer = MM_MapHWPages(modeptr->framebuffer, giVesaPageCount);
\r
451 Log_Log("VBE", "Setting mode to %i 0x%x (%ix%i %ibpp) %p[0x%x] maps %P",
\r
452 mode, modeptr->code,
\r
453 modeptr->width, modeptr->height,
\r
455 gpVesa_Framebuffer, giVesaPageCount << 12, modeptr->framebuffer
\r
459 giVesaCurrentMode = mode;
\r
460 gpVesaCurMode = modeptr;
\r
462 Mutex_Release( &glVesa_Lock );
\r
464 // TODO: Allow disabling of back-buffer
\r
465 gVesa_DriverStruct.RootNode.Size = modeptr->height * modeptr->pitch;
\r
466 gVesa_BufInfo.BackBuffer = realloc(gVesa_BufInfo.BackBuffer, modeptr->height * modeptr->pitch);
\r
467 gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;
\r
468 gVesa_BufInfo.Pitch = modeptr->pitch;
\r
469 gVesa_BufInfo.Width = modeptr->width;
\r
470 gVesa_BufInfo.Height = modeptr->height;
\r
471 gVesa_BufInfo.Depth = modeptr->bpp;
\r
476 int VBE_int_MatchModes(tVideo_IOCtl_Mode *ReqMode, tVesa_Mode *ThisMode)
\r
478 if( ThisMode->bpp == 0 ) {
\r
479 Log_Warning("VBE", "VESA mode %x (%ix%i) has 0bpp",
\r
480 ThisMode->code, ThisMode->width, ThisMode->height);
\r
483 LOG("Matching %ix%i %ibpp", ThisMode->width, ThisMode->height, ThisMode->bpp);
\r
484 if(ThisMode->width == ReqMode->width && ThisMode->height == ReqMode->height)
\r
486 //if( (data->bpp == 32 || data->bpp == 24)
\r
487 // && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )
\r
488 if( ReqMode->bpp == ThisMode->bpp )
\r
495 int tmp = ThisMode->width * ThisMode->height - ReqMode->width * ReqMode->height;
\r
496 tmp = tmp < 0 ? -tmp : tmp;
\r
497 unsigned int factor = (Uint64)tmp * 1000 / (ReqMode->width * ReqMode->height);
\r
498 if( ThisMode->bpp > ReqMode->bpp )
\r
499 factor += ThisMode->bpp - ReqMode->bpp;
\r
501 factor += ReqMode->bpp - ThisMode->bpp;
\r
503 if( ReqMode->bpp == ThisMode->bpp )
\r
507 if( ReqMode->bpp == 8 && ThisMode->bpp != 8 ) factor *= 4;
\r
508 if( ReqMode->bpp == 16 && ThisMode->bpp != 16 ) factor *= 4;
\r
510 if( (ReqMode->bpp == 32 || ReqMode->bpp == 24)
\r
511 && (ThisMode->bpp == 32 || ThisMode->bpp == 24) )
\r
516 if( ReqMode->bpp < ThisMode->bpp )
\r
517 factor *= ThisMode->bpp / ReqMode->bpp + 1;
\r
519 factor *= ReqMode->bpp / ThisMode->bpp + 1;
\r
526 int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)
\r
530 ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);
\r
532 Vesa_int_FillModeList();
\r
534 int bestFactor = VBE_int_MatchModes(data, &gVesa_BootMode);
\r
535 tVesa_Mode *bestPtr = &gVesa_BootMode;
\r
537 for(int i = 0; bestFactor > 0 && i < giVesaModeCount; i ++)
\r
539 LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);
\r
541 int factor = VBE_int_MatchModes(data, &gVesa_Modes[i]);
\r
543 LOG("factor = %i, bestFactor = %i", factor, bestFactor);
\r
545 if(factor < bestFactor)
\r
547 bestFactor = factor;
\r
549 bestPtr = &gVesa_Modes[i];
\r
553 data->width = bestPtr->width;
\r
554 data->height = bestPtr->height;
\r
555 data->bpp = bestPtr->bpp;
\r
560 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)
\r
562 tVesa_Mode *modeptr;
\r
563 if( data->id == -1 )
\r
564 modeptr = &gVesa_BootMode;
\r
565 else if( 0 <= data->id && data->id < giVesaModeCount)
\r
566 modeptr = &gVesa_Modes[data->id];
\r
570 Vesa_int_FillModeList();
\r
572 data->width = modeptr->width;
\r
573 data->height = modeptr->height;
\r
574 data->bpp = modeptr->bpp;
\r
578 void Vesa_int_HideCursor(void)
\r
580 DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );
\r
581 if( gpVesaCurMode->flags & FLAG_LFB )
\r
583 #if BLINKING_CURSOR
\r
584 if(gpVesaCursorTimer) {
\r
585 Time_RemoveTimer(gpVesaCursorTimer);
\r
591 void Vesa_int_ShowCursor(void)
\r
593 if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB )
\r
595 gbVesa_CursorVisible = (giVesaCursorX >= 0);
\r
596 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
598 DrvUtil_Video_DrawCursor(
\r
600 giVesaCursorX*giVT_CharWidth,
\r
601 giVesaCursorY*giVT_CharHeight
\r
603 #if BLINKING_CURSOR
\r
604 Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );
\r
608 DrvUtil_Video_DrawCursor(
\r
616 DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );
\r
620 int Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor)
\r
622 if( !CheckMem(Cursor, sizeof(tVideo_IOCtl_Bitmap)) )
\r
625 if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB )
\r
627 DrvUtil_Video_SetCursor( &gVesa_BufInfo, Cursor );
\r
636 * \brief Swaps the text cursor on/off
\r
638 void Vesa_FlipCursor(void *Arg)
\r
640 if( gVesa_BufInfo.BufferFormat != VIDEO_BUFFMT_TEXT )
\r
643 if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB )
\r
645 if( gbVesa_CursorVisible )
\r
646 DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);
\r
648 DrvUtil_Video_DrawCursor(&gVesa_BufInfo,
\r
649 giVesaCursorX*giVT_CharWidth,
\r
650 giVesaCursorY*giVT_CharHeight
\r
652 gbVesa_CursorVisible = !gbVesa_CursorVisible;
\r
654 #if BLINKING_CURSOR
\r
655 Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );
\r
661 // Helpers for text mode
\r
665 * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)
\r
666 * \brief Converts a 12-bit colour into a VGA 4-bit colour
\r
668 Uint8 VBE_int_GetColourNibble(Uint16 col)
\r
674 col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);
\r
675 bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;
\r
680 case 0x00: ret = 0x0; break;
\r
682 case 0x15: ret = 0x8; break;
\r
685 case 0x02: ret = 0x1; break;
\r
686 case 0x03: ret = 0x9; break;
\r
689 case 0x08: ret = 0x2; break;
\r
690 case 0x0C: ret = 0xA; break;
\r
693 case 0x20: ret = 0x4; break;
\r
694 case 0x30: ret = 0xC; break;
\r
696 case 0x2A: ret = 0x7; break;
\r
698 case 0x3F: ret = 0xF; break;
\r
701 ret |= (col & 0x03 ? 1 : 0);
\r
702 ret |= (col & 0x0C ? 2 : 0);
\r
703 ret |= (col & 0x30 ? 4 : 0);
\r
704 ret |= (bright ? 8 : 0);
\r
711 * \brief Convers a character structure to a VGA character word
\r
713 Uint16 VBE_int_GetWord(const tVT_Char *Char)
\r
724 default: ret = 0; break;
\r
728 col = VBE_int_GetColourNibble(Char->BGCol);
\r
731 col = VBE_int_GetColourNibble(Char->FGCol);
\r
737 void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
\r
739 const int charw = 8;
\r
740 const int charh = 16;
\r
741 const int tw = gpVesaCurMode->width / charw;
\r
742 const int th = gpVesaCurMode->height / charh;
\r
751 ch.BGCol = (Colour & 0x0F0000) >> (16-8);
\r
752 ch.BGCol |= (Colour & 0x000F00) >> (8-4);
\r
753 ch.BGCol |= (Colour & 0x00000F);
\r
755 Uint16 word = VBE_int_GetWord(&ch);
\r
757 Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
\r
759 if( X >= tw || Y >= th ) return ;
\r
760 if( X + W > tw ) W = tw - X;
\r
761 if( Y + H > th ) H = th - Y;
\r
763 Uint16 *buf = (Uint16*)gpVesa_Framebuffer + Y*tw + X;
\r
767 for( int i = 0; i < W; i ++ )
\r
773 void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
\r
775 const int charw = 8;
\r
776 const int charh = 16;
\r
777 const int tw = gpVesaCurMode->width / charw;
\r
778 const int th = gpVesaCurMode->height / charh;
\r
788 // Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);
\r
790 if( SrcX >= tw || SrcY >= th ) return ;
\r
791 if( SrcX + W > tw ) W = tw - SrcX;
\r
792 if( SrcY + H > th ) H = th - SrcY;
\r
793 if( DstX >= tw || DstY >= th ) return ;
\r
794 if( DstX + W > tw ) W = tw - DstX;
\r
795 if( DstY + H > th ) H = th - DstY;
\r
798 Uint16 *src = (Uint16*)gpVesa_Framebuffer + SrcY*tw + SrcX;
\r
799 Uint16 *dst = (Uint16*)gpVesa_Framebuffer + DstY*tw + DstX;
\r
805 memcpy(dst, src, W*2);
\r
817 for( int i = W; i --; ) *--dst = *--src;
\r