Modules/VESA - Allowed #if-ing out VM8086 use
[tpg/acess2.git] / KernelLand / Modules / Display / VESA / main.c
1 /*\r
2  * AcessOS 1\r
3  * Video BIOS Extensions (Vesa) Driver\r
4  */\r
5 #define DEBUG   1\r
6 #define VERSION 0x100\r
7 \r
8 #include <acess.h>\r
9 #include <vfs.h>\r
10 #include <api_drv_video.h>\r
11 #include <fs_devfs.h>\r
12 #include <modules.h>\r
13 #include <vm8086.h>\r
14 #include "common.h"\r
15 #include <timers.h>\r
16 \r
17 // === CONSTANTS ===\r
18 #define USE_BIOS        1\r
19 #define VESA_DEFAULT_FRAMEBUFFER        (KERNEL_BASE|0xA0000)\r
20 #define BLINKING_CURSOR 0\r
21 #if BLINKING_CURSOR\r
22 # define VESA_CURSOR_PERIOD     1000\r
23 #endif\r
24 \r
25 // === PROTOTYPES ===\r
26  int    Vesa_Install(char **Arguments);\r
27  int    VBE_int_GetModeList(void);\r
28 size_t  Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);\r
29  int    Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
30  int    Vesa_Int_SetMode(int Mode);\r
31  int    Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);\r
32  int    Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);\r
33 void    Vesa_int_HideCursor(void);\r
34 void    Vesa_int_ShowCursor(void);\r
35 void    Vesa_FlipCursor(void *Arg);\r
36 Uint16  VBE_int_GetWord(const tVT_Char *Char);\r
37 void    VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);\r
38 void    VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);\r
39 \r
40 // === GLOBALS ===\r
41 MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);\r
42 tVFS_NodeType   gVesa_NodeType = {\r
43         .Write = Vesa_Write,\r
44         .IOCtl = Vesa_IOCtl\r
45         };\r
46 tDevFS_Driver   gVesa_DriverStruct = {\r
47         NULL, "Vesa",\r
48         {.Type = &gVesa_NodeType}\r
49         };\r
50 tMutex  glVesa_Lock;\r
51 tVM8086 *gpVesa_BiosState;\r
52  int    giVesaDriverId = -1;\r
53 // --- Video Modes ---\r
54  int    giVesaCurrentMode = 0;\r
55 tVesa_Mode      gVesa_BootMode = {0x03, 80*8, 25*16, 80*8*2, 12, FLAG_POPULATED, 80*25*2, 0xB8000};\r
56 tVesa_Mode      *gVesa_Modes;\r
57 tVesa_Mode      *gpVesaCurMode;\r
58  int    giVesaModeCount = 0;\r
59  int    gbVesaModesChecked;\r
60 // --- Framebuffer ---\r
61 char    *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER;\r
62  int    giVesaPageCount = 0;    //!< Framebuffer size in pages\r
63 // --- Cursor Control ---\r
64  int    giVesaCursorX = -1;\r
65  int    giVesaCursorY = -1;\r
66 #if BLINKING_CURSOR\r
67 tTimer  *gpVesaCursorTimer;\r
68 #endif\r
69  int    gbVesa_CursorVisible = 0;\r
70 // --- 2D Video Stream Handlers ---\r
71 tDrvUtil_Video_BufInfo  gVesa_BufInfo;\r
72 tDrvUtil_Video_2DHandlers       gVBE_Text2DFunctions = {\r
73         NULL,\r
74         VBE_int_Text_2D_Fill,\r
75         VBE_int_Text_2D_Blit\r
76 };\r
77 // --- Settings ---\r
78 bool    gbVesa_DisableBIOSCalls;        // Disables calls to the BIOS\r
79 // int  gbVesa_DisableFBCache;  // Disables the main-memory framebuffer cache\r
80 \r
81 // === CODE ===\r
82 int Vesa_Install(char **Arguments)\r
83 {\r
84         for( int i = 0; Arguments && Arguments[i]; i ++ )\r
85         {\r
86                 if( strcmp(Arguments[i], "nobios") == 0 )\r
87                         gbVesa_DisableBIOSCalls = 1;\r
88                 //else if( strcmp(Arguments[i], "nocache") == 0 )\r
89                 //      gbVesa_DisableFBCache = 1;\r
90                 else {\r
91                         Log_Notice("VBE", "Unknown argument '%s'", Arguments[i]);\r
92                 }\r
93         }\r
94 \r
95         #if USE_BIOS\r
96         if( !gbVesa_DisableBIOSCalls )\r
97         {\r
98                 gpVesa_BiosState = VM8086_Init();\r
99                 \r
100                 int rv = VBE_int_GetModeList();\r
101                 if(rv)  return rv;\r
102         }\r
103         #endif\r
104                 \r
105         #if BLINKING_CURSOR\r
106         // Create blink timer\r
107         gpVesaCursorTimer = Time_AllocateTimer( Vesa_FlipCursor, NULL );\r
108         #endif\r
109 \r
110         // Install Device\r
111         giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );\r
112         if(giVesaDriverId == -1)        return MODULE_ERR_MISC;\r
113 \r
114         return MODULE_ERR_OK;\r
115 }\r
116 \r
117 #if USE_BIOS\r
118 int VBE_int_GetModeList(void)\r
119 {\r
120         tVesa_CallInfo  *info;\r
121         tFarPtr infoPtr;\r
122         Uint16  *modes;\r
123         \r
124         // Allocate Info Block\r
125         info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);\r
126         // Set Requested Version\r
127         memcpy(info->signature, "VBE2", 4);\r
128         // Set Registers\r
129         gpVesa_BiosState->AX = 0x4F00;\r
130         gpVesa_BiosState->ES = infoPtr.seg;     gpVesa_BiosState->DI = infoPtr.ofs;\r
131         // Call Interrupt\r
132         VM8086_Int(gpVesa_BiosState, 0x10);\r
133         if(gpVesa_BiosState->AX != 0x004F) {\r
134                 Log_Warning("VBE", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);\r
135                 return MODULE_ERR_NOTNEEDED;\r
136         }\r
137         \r
138         modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);\r
139         LOG("Virtual addres of mode list from %04x:%04x is %p",\r
140                 info->VideoModes.seg, info->VideoModes.ofs, modes);\r
141 //      VM8086_Deallocate( gpVesa_BiosState, info );\r
142         \r
143         // Count Modes\r
144         for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ )\r
145                 ;\r
146         gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );\r
147         \r
148         Log_Debug("VBE", "%i Modes", giVesaModeCount);\r
149 \r
150         // Insert Text Mode\r
151         \r
152         for( int i = 0; i < giVesaModeCount; i++ )\r
153         {\r
154                 gVesa_Modes[i].code = modes[i];\r
155         }\r
156         \r
157         return 0;\r
158 }\r
159 \r
160 int VBE_int_GetModeInfo(Uint16 Code, tFarPtr *BufPtr)\r
161 {\r
162         // Get Mode info\r
163         gpVesa_BiosState->AX = 0x4F01;\r
164         gpVesa_BiosState->CX = Code;\r
165         gpVesa_BiosState->ES = BufPtr->seg;\r
166         gpVesa_BiosState->DI = BufPtr->ofs;\r
167         VM8086_Int(gpVesa_BiosState, 0x10);\r
168 \r
169         if( gpVesa_BiosState->AX != 0x004F ) {\r
170                 Log_Error("VBE", "Getting info on mode 0x%x failed (AX=0x%x)",\r
171                         Code, gpVesa_BiosState->AX);\r
172                 return 1;\r
173         }\r
174         return 0;\r
175 }\r
176 #endif\r
177 \r
178 \r
179 void VBE_int_FillMode_Int(tVesa_Mode *Mode, const tVesa_CallModeInfo *vbeinfo)\r
180 {\r
181         #if 1\r
182         #define S_LOG(s, fld, fmt)      LOG(" ."#fld" = "fmt, (s).fld)\r
183         LOG("vbeinfo[0x%x] = {", Mode->code);\r
184         S_LOG(*vbeinfo, attributes, "0x%02x");\r
185         S_LOG(*vbeinfo, winA, "0x%02x");\r
186         S_LOG(*vbeinfo, winB, "0x%02x");\r
187         S_LOG(*vbeinfo, granularity, "0x%04x");\r
188         S_LOG(*vbeinfo, winsize, "0x%04x");\r
189         S_LOG(*vbeinfo, segmentA, "0x%04x");\r
190         S_LOG(*vbeinfo, segmentB, "0x%04x");\r
191         LOG(" .realFctPtr = %04x:%04x", vbeinfo->realFctPtr.seg, vbeinfo->realFctPtr.ofs);\r
192         S_LOG(*vbeinfo, pitch, "0x%04x");\r
193 \r
194         // -- Extended\r
195         S_LOG(*vbeinfo, Xres, "%i");\r
196         S_LOG(*vbeinfo, Yres, "%i");\r
197         S_LOG(*vbeinfo, Wchar, "%i");\r
198         S_LOG(*vbeinfo, Ychar, "%i");\r
199         S_LOG(*vbeinfo, planes, "%i");\r
200         S_LOG(*vbeinfo, bpp, "%i");\r
201         S_LOG(*vbeinfo, banks, "%i");\r
202         S_LOG(*vbeinfo, memory_model, "%i");\r
203         S_LOG(*vbeinfo, bank_size, "%i");\r
204         S_LOG(*vbeinfo, image_pages, "%i");\r
205         // -- VBE 1.2+\r
206         LOG(" Red   = %i bits at %i", vbeinfo->red_mask,   vbeinfo->red_position  );\r
207         LOG(" Green = %i bits at %i", vbeinfo->green_mask, vbeinfo->green_position);\r
208         LOG(" Blue  = %i bits at %i", vbeinfo->blue_mask,  vbeinfo->blue_position );\r
209         #if 0\r
210         Uint8   rsv_mask, rsv_position;\r
211         Uint8   directcolor_attributes;\r
212         #endif\r
213         // --- VBE 2.0+\r
214         S_LOG(*vbeinfo, physbase, "0x%08x");\r
215         S_LOG(*vbeinfo, offscreen_ptr, "0x%08x");\r
216         S_LOG(*vbeinfo, offscreen_size_kb, "0x%04x");\r
217         // --- VBE 3.0+\r
218         S_LOG(*vbeinfo, lfb_pitch, "0x%04x");\r
219         S_LOG(*vbeinfo, image_count_banked, "%i");\r
220         S_LOG(*vbeinfo, image_count_lfb, "%i");\r
221         LOG("}");\r
222         #endif\r
223         \r
224         Mode->flags = FLAG_POPULATED;\r
225         // Check if this mode is supported by hardware\r
226         if( !(vbeinfo->attributes & 1) )\r
227         {\r
228                 #if DEBUG\r
229                 Log_Log("VBE", "0x%x - not supported", Mode->code);\r
230                 #endif\r
231                 Mode->width = 0;\r
232                 Mode->height = 0;\r
233                 Mode->bpp = 0;\r
234                 return ;\r
235         }\r
236 \r
237         // Parse Info\r
238         Mode->flags |= FLAG_VALID;\r
239         switch( vbeinfo->attributes & 0x90 )    // LFB, Graphics\r
240         {\r
241         case 0x00:      // Banked, Text\r
242         case 0x10:      // Banked, Graphics\r
243         case 0x80:      // Linear, Text (?)\r
244                 Mode->width = 0;\r
245                 Mode->height = 0;\r
246                 Mode->bpp = 0;\r
247                 return ;\r
248         case 0x90:\r
249                 Mode->flags |= FLAG_LFB|FLAG_GRAPHICS;\r
250                 Mode->framebuffer = vbeinfo->physbase;\r
251                 Mode->fbSize = vbeinfo->Yres*vbeinfo->pitch;\r
252                 break;\r
253         }\r
254         \r
255         Mode->pitch = vbeinfo->pitch;\r
256         Mode->width = vbeinfo->Xres;\r
257         Mode->height = vbeinfo->Yres;\r
258         Mode->bpp = vbeinfo->bpp;\r
259         \r
260         #if DEBUG\r
261         Log_Log("VBE", "0x%x - %ix%ix%i (%x)",\r
262                 Mode->code, Mode->width, Mode->height, Mode->bpp, Mode->flags);\r
263         #endif\r
264 \r
265\r
266 \r
267 void VBE_int_SetBootMode(Uint16 ModeID, const void *ModeInfo)\r
268 {\r
269         gVesa_BootMode.code = ModeID;\r
270         VBE_int_FillMode_Int(&gVesa_BootMode, ModeInfo);\r
271 }\r
272 \r
273 void Vesa_int_FillModeList(void)\r
274 {\r
275         #if USE_BIOS\r
276         if( !gbVesaModesChecked && !gbVesa_DisableBIOSCalls )\r
277         {\r
278                 tVesa_CallModeInfo      *modeinfo;\r
279                 tFarPtr modeinfoPtr;\r
280                 \r
281                 modeinfo = VM8086_Allocate(gpVesa_BiosState, 256, &modeinfoPtr.seg, &modeinfoPtr.ofs);\r
282                 for( int i = 0; i < giVesaModeCount; i ++ )\r
283                 {\r
284                         if( VBE_int_GetModeInfo(gVesa_Modes[i].code, &modeinfoPtr) == 0 )\r
285                         {\r
286                                 VBE_int_FillMode_Int( &gVesa_Modes[i], modeinfo );\r
287                         }\r
288                 }       \r
289 //              VM8086_Deallocate( gpVesa_BiosState, modeinfo );\r
290                 \r
291                 gbVesaModesChecked = 1;\r
292         }\r
293         #endif\r
294 }\r
295 \r
296 /**\r
297  * \brief Write to the framebuffer\r
298  */\r
299 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)\r
300 {\r
301         switch( gpVesaCurMode->flags & (FLAG_LFB|FLAG_GRAPHICS) )\r
302         {\r
303         case 0:\r
304                 // EGA text mode translation\r
305                 switch( gVesa_BufInfo.BufferFormat )\r
306                 {\r
307                 case VIDEO_BUFFMT_TEXT: {\r
308                          int    num = Length / sizeof(tVT_Char);\r
309                          int    ofs = Offset / sizeof(tVT_Char);\r
310                          int    i = 0;\r
311                         const tVT_Char  *chars = Buffer;\r
312                         \r
313                         for( ; num--; i ++, ofs ++)\r
314                         {\r
315                                 Uint16  word = VBE_int_GetWord( &chars[i] );\r
316                                 ((Uint16*)gVesa_BufInfo.Framebuffer)[ ofs ] = word;\r
317                         }\r
318                         \r
319                         return Length; }\r
320                 case VIDEO_BUFFMT_2DSTREAM:\r
321                         return DrvUtil_Video_2DStream(NULL, Buffer, Length,\r
322                                 &gVBE_Text2DFunctions, sizeof(gVBE_Text2DFunctions));\r
323                 default:\r
324                         Log_Warning("VBE", "TODO: Alternate modes in EGA text mode");\r
325                         return 0;\r
326                 }\r
327                 return 0;\r
328         case FLAG_LFB|FLAG_GRAPHICS:\r
329                 // Framebuffer modes - use DrvUtil Video\r
330                 return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);\r
331         default:\r
332                 Log_Warning("VBE", "TODO: _Write %s%s",\r
333                         (gpVesaCurMode->flags & FLAG_LFB ? "FLAG_LFB" : ""),\r
334                         (gpVesaCurMode->flags & FLAG_GRAPHICS ? "FLAG_GRAPHICS" : "")\r
335                         );\r
336                 return 0;\r
337         }\r
338 }\r
339 \r
340 const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
341 /**\r
342  * \brief Handle messages to the device\r
343  */\r
344 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
345 {\r
346          int    ret;\r
347         switch(ID)\r
348         {\r
349         BASE_IOCTLS(DRV_TYPE_VIDEO, "VBE", VERSION, csaVESA_IOCtls);\r
350 \r
351         case VIDEO_IOCTL_GETSETMODE:\r
352                 if( !Data )     return giVesaCurrentMode;\r
353                 return Vesa_Int_SetMode( *(int*)Data );\r
354         \r
355         case VIDEO_IOCTL_FINDMODE:\r
356                 return Vesa_Int_FindMode((tVideo_IOCtl_Mode*)Data);\r
357         case VIDEO_IOCTL_MODEINFO:\r
358                 return Vesa_Int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
359         \r
360         case VIDEO_IOCTL_SETBUFFORMAT:\r
361                 Vesa_int_HideCursor();\r
362                 ret = gVesa_BufInfo.BufferFormat;\r
363                 if(Data)        gVesa_BufInfo.BufferFormat = *(int*)Data;\r
364                 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
365                         DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor );\r
366                 Vesa_int_ShowCursor();\r
367                 return ret;\r
368         \r
369         case VIDEO_IOCTL_SETCURSOR:     // Set cursor position\r
370                 Vesa_int_HideCursor();\r
371                 giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;\r
372                 giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;\r
373                 Vesa_int_ShowCursor();\r
374                 return 0;\r
375         \r
376         case VIDEO_IOCTL_SETCURSORBITMAP:\r
377                 if( gpVesaCurMode->flags & FLAG_LFB )\r
378                         DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data );\r
379                 return 0;\r
380         }\r
381         return 0;\r
382 }\r
383 \r
384 /**\r
385  * \brief Updates the video mode\r
386  */\r
387 int Vesa_Int_SetMode(int mode)\r
388 {\r
389         tVesa_Mode      *modeptr;\r
390         // Check for fast return\r
391         if(mode == giVesaCurrentMode)   return 1;\r
392         \r
393         // Special case: Boot mode\r
394         if( mode == -1 )\r
395                 modeptr = &gVesa_BootMode;\r
396         else if( 0 <= mode && mode < giVesaModeCount )\r
397                 modeptr = &gVesa_Modes[mode];\r
398         else\r
399                 return -1;\r
400         \r
401         Vesa_int_FillModeList();\r
402 \r
403         #if BLINKING_CURSOR\r
404         Time_RemoveTimer(gpVesaCursorTimer);\r
405         #endif\r
406         \r
407         Mutex_Acquire( &glVesa_Lock );\r
408 \r
409         #if USE_BIOS\r
410         if( gbVesa_DisableBIOSCalls )\r
411         {\r
412                 ASSERT(mode == -1);\r
413         }\r
414         else\r
415         {\r
416                 gpVesa_BiosState->AX = 0x4F02;\r
417                 gpVesa_BiosState->BX = modeptr->code;\r
418                 if(modeptr->flags & FLAG_LFB) {\r
419                         gpVesa_BiosState->BX |= 1 << 14;        // Use LFB\r
420                 }\r
421                 LOG("In : AX=%04x/BX=%04x", gpVesa_BiosState->AX, gpVesa_BiosState->BX);\r
422                 \r
423                 // Set Mode\r
424                 VM8086_Int(gpVesa_BiosState, 0x10);\r
425 \r
426                 LOG("Out: AX = %04x", gpVesa_BiosState->AX);\r
427         }\r
428         #else\r
429         ASSERT(mode == -1);\r
430         #endif\r
431         \r
432         // Map Framebuffer\r
433         if( gpVesaCurMode )\r
434         {\r
435                 if( gpVesaCurMode->framebuffer < 1024*1024 )\r
436                         ;\r
437                 else\r
438                         MM_UnmapHWPages((tVAddr)gpVesa_Framebuffer, giVesaPageCount);\r
439         }\r
440         giVesaPageCount = (modeptr->fbSize + 0xFFF) >> 12;\r
441         if( modeptr->framebuffer < 1024*1024 )\r
442                 gpVesa_Framebuffer = (void*)(KERNEL_BASE|modeptr->framebuffer);\r
443         else\r
444                 gpVesa_Framebuffer = (void*)MM_MapHWPages(modeptr->framebuffer, giVesaPageCount);\r
445         \r
446         Log_Log("VBE", "Setting mode to %i 0x%x (%ix%i %ibpp) %p[0x%x] maps %P",\r
447                 mode, modeptr->code,\r
448                 modeptr->width, modeptr->height,\r
449                 modeptr->bpp,\r
450                 gpVesa_Framebuffer, giVesaPageCount << 12, modeptr->framebuffer\r
451                 );\r
452         \r
453         // Record Mode Set\r
454         giVesaCurrentMode = mode;\r
455         gpVesaCurMode = modeptr;\r
456         \r
457         Mutex_Release( &glVesa_Lock );\r
458 \r
459         // TODO: Disableable backbuffer\r
460         gVesa_BufInfo.BackBuffer  = realloc(gVesa_BufInfo.BackBuffer,\r
461                 modeptr->height * modeptr->pitch);\r
462         gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;\r
463         gVesa_BufInfo.Pitch = modeptr->pitch;\r
464         gVesa_BufInfo.Width = modeptr->width;\r
465         gVesa_BufInfo.Height = modeptr->height;\r
466         gVesa_BufInfo.Depth = modeptr->bpp;     \r
467 \r
468         return 1;\r
469 }\r
470 \r
471 int VBE_int_MatchModes(tVideo_IOCtl_Mode *ReqMode, tVesa_Mode *ThisMode)\r
472 {\r
473         LOG("Matching %ix%i %ibpp", ThisMode->width, ThisMode->height, ThisMode->bpp);\r
474         if(ThisMode->width == ReqMode->width && ThisMode->height == ReqMode->height)\r
475         {\r
476                 //if( (data->bpp == 32 || data->bpp == 24)\r
477                 // && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )\r
478                 if( ReqMode->bpp == ThisMode->bpp )\r
479                 {\r
480                         LOG("Perfect!");\r
481                         return -1;\r
482                 }\r
483         }\r
484         \r
485         int tmp = ThisMode->width * ThisMode->height - ReqMode->width * ReqMode->height;\r
486         tmp = tmp < 0 ? -tmp : tmp;\r
487         unsigned int factor = (Uint64)tmp * 1000 / (ReqMode->width * ReqMode->height);\r
488         if( ThisMode->bpp > ReqMode->bpp )\r
489                 factor += ThisMode->bpp - ReqMode->bpp;\r
490         else\r
491                 factor += ReqMode->bpp - ThisMode->bpp;\r
492 \r
493         if( ReqMode->bpp == ThisMode->bpp )\r
494                 factor /= 2;\r
495         else\r
496         {\r
497                 if( ReqMode->bpp == 8 && ThisMode->bpp != 8 )   factor *= 4;\r
498                 if( ReqMode->bpp == 16 && ThisMode->bpp != 16 ) factor *= 4;\r
499                 \r
500                 if( (ReqMode->bpp == 32 || ReqMode->bpp == 24)\r
501                  && (ThisMode->bpp == 32 || ThisMode->bpp == 24) )\r
502                 {\r
503                         // NC\r
504                 }\r
505                 else {\r
506                         if( ReqMode->bpp < ThisMode->bpp )\r
507                                 factor *= ThisMode->bpp / ReqMode->bpp + 1;\r
508                         else\r
509                                 factor *= ReqMode->bpp / ThisMode->bpp + 1;\r
510                 }\r
511         }\r
512         \r
513         return factor;\r
514 }\r
515 \r
516 int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)\r
517 {\r
518          int    best = -1;\r
519         \r
520         ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);\r
521 \r
522         Vesa_int_FillModeList();\r
523 \r
524         int bestFactor = VBE_int_MatchModes(data, &gVesa_BootMode);     \r
525         tVesa_Mode *bestPtr = &gVesa_BootMode;\r
526 \r
527         for(int i = 0; bestFactor > 0 && i < giVesaModeCount; i ++)\r
528         {\r
529                 LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
530         \r
531                 int factor = VBE_int_MatchModes(data, &gVesa_Modes[i]);\r
532                 \r
533                 LOG("factor = %i, bestFactor = %i", factor, bestFactor);\r
534                 \r
535                 if(factor < bestFactor)\r
536                 {\r
537                         bestFactor = factor;\r
538                         best = i;\r
539                         bestPtr = &gVesa_Modes[i];\r
540                 }\r
541         }\r
542         data->id = best;\r
543         data->width = bestPtr->width;\r
544         data->height = bestPtr->height;\r
545         data->bpp = bestPtr->bpp;\r
546         LEAVE('i', best);\r
547         return best;\r
548 }\r
549 \r
550 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)\r
551 {\r
552         tVesa_Mode      *modeptr;\r
553         if( data->id == -1 )\r
554                 modeptr = &gVesa_BootMode;\r
555         else if( 0 <= data->id && data->id < giVesaModeCount)\r
556                 modeptr = &gVesa_Modes[data->id];\r
557         else\r
558                 return 0;\r
559 \r
560         Vesa_int_FillModeList();\r
561 \r
562         data->width  = modeptr->width;\r
563         data->height = modeptr->height;\r
564         data->bpp    = modeptr->bpp;\r
565         return 1;\r
566 }\r
567 \r
568 void Vesa_int_HideCursor(void)\r
569 {\r
570         DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );\r
571         if( gpVesaCurMode->flags & FLAG_LFB )\r
572         {\r
573                 #if BLINKING_CURSOR\r
574                 if(gpVesaCursorTimer) {\r
575                         Time_RemoveTimer(gpVesaCursorTimer);\r
576                 }\r
577                 #endif\r
578         }\r
579 }\r
580 \r
581 void Vesa_int_ShowCursor(void)\r
582 {\r
583         if( gpVesaCurMode->flags & FLAG_LFB )\r
584         {\r
585                 gbVesa_CursorVisible = (giVesaCursorX >= 0);\r
586                 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
587                 {\r
588                         DrvUtil_Video_DrawCursor(\r
589                                 &gVesa_BufInfo,\r
590                                 giVesaCursorX*giVT_CharWidth,\r
591                                 giVesaCursorY*giVT_CharHeight\r
592                                 );\r
593                         #if BLINKING_CURSOR\r
594                         Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );\r
595                         #endif\r
596                 }\r
597                 else\r
598                         DrvUtil_Video_DrawCursor(\r
599                                 &gVesa_BufInfo,\r
600                                 giVesaCursorX,\r
601                                 giVesaCursorY\r
602                                 );\r
603         }\r
604         else\r
605         {\r
606                 DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );\r
607         }\r
608 }\r
609 \r
610 /**\r
611  * \brief Swaps the text cursor on/off\r
612  */\r
613 void Vesa_FlipCursor(void *Arg)\r
614 {\r
615         if( gVesa_BufInfo.BufferFormat != VIDEO_BUFFMT_TEXT )\r
616                 return ;\r
617 \r
618         if( gpVesaCurMode->flags & FLAG_LFB )\r
619         {\r
620                 if( gbVesa_CursorVisible )\r
621                         DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);\r
622                 else\r
623                         DrvUtil_Video_DrawCursor(&gVesa_BufInfo,\r
624                                 giVesaCursorX*giVT_CharWidth,\r
625                                 giVesaCursorY*giVT_CharHeight\r
626                                 );\r
627                 gbVesa_CursorVisible = !gbVesa_CursorVisible;\r
628                         \r
629                 #if BLINKING_CURSOR\r
630                 Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );\r
631                 #endif\r
632         }\r
633 }\r
634 \r
635 // ---\r
636 // Helpers for text mode\r
637 // ---\r
638 \r
639 /**\r
640  * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)\r
641  * \brief Converts a 12-bit colour into a VGA 4-bit colour\r
642  */\r
643 Uint8 VBE_int_GetColourNibble(Uint16 col)\r
644 {\r
645         Uint8   ret = 0;\r
646          int    bright = 0;\r
647         \r
648         col = col & 0xCCC;\r
649         col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);\r
650         bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;\r
651         \r
652         switch(col)\r
653         {\r
654         //      Black\r
655         case 0x00:      ret = 0x0;      break;\r
656         // Dark Grey\r
657         case 0x15:      ret = 0x8;      break;\r
658         // Blues\r
659         case 0x01:\r
660         case 0x02:      ret = 0x1;      break;\r
661         case 0x03:      ret = 0x9;      break;\r
662         // Green\r
663         case 0x04:\r
664         case 0x08:      ret = 0x2;      break;\r
665         case 0x0C:      ret = 0xA;      break;\r
666         // Reds\r
667         case 0x10:\r
668         case 0x20:      ret = 0x4;      break;\r
669         case 0x30:      ret = 0xC;      break;\r
670         // Light Grey\r
671         case 0x2A:      ret = 0x7;      break;\r
672         // White\r
673         case 0x3F:      ret = 0xF;      break;\r
674         \r
675         default:\r
676                 ret |= (col & 0x03 ? 1 : 0);\r
677                 ret |= (col & 0x0C ? 2 : 0);\r
678                 ret |= (col & 0x30 ? 4 : 0);\r
679                 ret |= (bright ? 8 : 0);\r
680                 break;\r
681         }\r
682         return ret;\r
683 }\r
684 \r
685 /**\r
686  * \brief Convers a character structure to a VGA character word\r
687  */\r
688 Uint16 VBE_int_GetWord(const tVT_Char *Char)\r
689 {\r
690         Uint16  ret;\r
691         Uint16  col;\r
692         \r
693         // Get Character\r
694         if(Char->Ch < 128)\r
695                 ret = Char->Ch;\r
696         else {\r
697                 switch(Char->Ch)\r
698                 {\r
699                 default:        ret = 0;        break;\r
700                 }\r
701         }\r
702         \r
703         col = VBE_int_GetColourNibble(Char->BGCol);\r
704         ret |= col << 12;\r
705         \r
706         col = VBE_int_GetColourNibble(Char->FGCol);\r
707         ret |= col << 8;\r
708         \r
709         return ret;\r
710 }\r
711 \r
712 void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)\r
713 {\r
714         const int       charw = 8;\r
715         const int       charh = 16;\r
716         const int       tw = gpVesaCurMode->width / charw;\r
717         const int       th = gpVesaCurMode->height / charh;\r
718 \r
719         X /= charw;\r
720         W /= charw;\r
721         Y /= charh;\r
722         H /= charh;\r
723 \r
724         tVT_Char        ch;\r
725         ch.Ch = 0x20;\r
726         ch.BGCol  = (Colour & 0x0F0000) >> (16-8);\r
727         ch.BGCol |= (Colour & 0x000F00) >> (8-4);\r
728         ch.BGCol |= (Colour & 0x00000F);\r
729         ch.FGCol = 0;\r
730         Uint16 word = VBE_int_GetWord(&ch);\r
731 \r
732         Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);\r
733 \r
734         if( X >= tw || Y >= th )        return ;\r
735         if( X + W > tw )        W = tw - X;\r
736         if( Y + H > th )        H = th - Y;\r
737 \r
738         Uint16  *buf = (Uint16*)gpVesa_Framebuffer + Y*tw + X;\r
739 \r
740         \r
741         while( H -- ) {\r
742                 for( int i = 0; i < W; i ++ )\r
743                         *buf++ = word;\r
744                 buf += tw - W;\r
745         }\r
746 }\r
747 \r
748 void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)\r
749 {\r
750         const int       charw = 8;\r
751         const int       charh = 16;\r
752         const int       tw = gpVesaCurMode->width / charw;\r
753         const int       th = gpVesaCurMode->height / charh;\r
754 \r
755         DstX /= charw;\r
756         SrcX /= charw;\r
757         W    /= charw;\r
758 \r
759         DstY /= charh;\r
760         SrcY /= charh;\r
761         H    /= charh;\r
762 \r
763 //      Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);\r
764 \r
765         if( SrcX >= tw || SrcY >= th )  return ;\r
766         if( SrcX + W > tw )     W = tw - SrcX;\r
767         if( SrcY + H > th )     H = th - SrcY;\r
768         if( DstX >= tw || DstY >= th )  return ;\r
769         if( DstX + W > tw )     W = tw - DstX;\r
770         if( DstY + H > th )     H = th - DstY;\r
771 \r
772 \r
773         Uint16  *src = (Uint16*)gpVesa_Framebuffer + SrcY*tw + SrcX;\r
774         Uint16  *dst = (Uint16*)gpVesa_Framebuffer + DstY*tw + DstX;\r
775 \r
776         if( src > dst )\r
777         {\r
778                 // Simple copy\r
779                 while( H-- ) {\r
780                         memcpy(dst, src, W*2);\r
781                         dst += tw;\r
782                         src += tw;\r
783                 }\r
784         }\r
785         else\r
786         {\r
787                 dst += H*tw;\r
788                 src += H*tw;\r
789                 while( H -- ) {\r
790                         dst -= tw-W;\r
791                         src -= tw-W;\r
792                         for( int i = W; i --; ) *--dst = *--src;\r
793                 }\r
794         }\r
795 }\r
796 \r

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