32022efa6b7caaaea79ebda5218c33b9ddfb0877
[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   0\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 #include <limits.h>\r
17 \r
18 // === CONSTANTS ===\r
19 #define USE_BIOS        1\r
20 #define VESA_DEFAULT_FRAMEBUFFER        (KERNEL_BASE|0xA0000)\r
21 #define BLINKING_CURSOR 0\r
22 #if BLINKING_CURSOR\r
23 # define VESA_CURSOR_PERIOD     1000\r
24 #endif\r
25 \r
26 // === PROTOTYPES ===\r
27  int    Vesa_Install(char **Arguments);\r
28  int    VBE_int_GetModeList(void);\r
29 size_t  Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);\r
30  int    Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
31  int    Vesa_Int_SetMode(int Mode);\r
32  int    Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);\r
33  int    Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);\r
34 void    Vesa_int_HideCursor(void);\r
35 void    Vesa_int_ShowCursor(void);\r
36 void    Vesa_FlipCursor(void *Arg);\r
37 Uint16  VBE_int_GetWord(const tVT_Char *Char);\r
38 void    VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);\r
39 void    VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);\r
40 \r
41 // === GLOBALS ===\r
42 MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);\r
43 tVFS_NodeType   gVesa_NodeType = {\r
44         .Write = Vesa_Write,\r
45         .IOCtl = Vesa_IOCtl\r
46         };\r
47 tDevFS_Driver   gVesa_DriverStruct = {\r
48         NULL, "Vesa",\r
49         {.Type = &gVesa_NodeType}\r
50         };\r
51 tMutex  glVesa_Lock;\r
52 tVM8086 *gpVesa_BiosState;\r
53  int    giVesaDriverId = -1;\r
54 // --- Video Modes ---\r
55  int    giVesaCurrentMode = 0;\r
56 tVesa_Mode      gVesa_BootMode = {0x03, 80*8, 25*16, 80*8*2, 12, FLAG_POPULATED, 80*25*2, 0xB8000};\r
57 tVesa_Mode      *gVesa_Modes;\r
58 tVesa_Mode      *gpVesaCurMode = &gVesa_BootMode;\r
59  int    giVesaModeCount = 0;\r
60  int    gbVesaModesChecked;\r
61 // --- Framebuffer ---\r
62 char    *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER;\r
63  int    giVesaPageCount = 0;    //!< Framebuffer size in pages\r
64 // --- Cursor Control ---\r
65  int    giVesaCursorX = -1;\r
66  int    giVesaCursorY = -1;\r
67 #if BLINKING_CURSOR\r
68 tTimer  *gpVesaCursorTimer;\r
69 #endif\r
70  int    gbVesa_CursorVisible = 0;\r
71 // --- 2D Video Stream Handlers ---\r
72 tDrvUtil_Video_BufInfo  gVesa_BufInfo;\r
73 tDrvUtil_Video_2DHandlers       gVBE_Text2DFunctions = {\r
74         NULL,\r
75         VBE_int_Text_2D_Fill,\r
76         VBE_int_Text_2D_Blit\r
77 };\r
78 // --- Settings ---\r
79 bool    gbVesa_DisableBIOSCalls;        // Disables calls to the BIOS\r
80 // int  gbVesa_DisableFBCache;  // Disables the main-memory framebuffer cache\r
81 \r
82 // === CODE ===\r
83 int Vesa_Install(char **Arguments)\r
84 {\r
85         for( int i = 0; Arguments && Arguments[i]; i ++ )\r
86         {\r
87                 if( strcmp(Arguments[i], "nobios") == 0 )\r
88                         gbVesa_DisableBIOSCalls = 1;\r
89                 //else if( strcmp(Arguments[i], "nocache") == 0 )\r
90                 //      gbVesa_DisableFBCache = 1;\r
91                 else {\r
92                         Log_Notice("VBE", "Unknown argument '%s'", Arguments[i]);\r
93                 }\r
94         }\r
95 \r
96         #if USE_BIOS\r
97         if( !gbVesa_DisableBIOSCalls )\r
98         {\r
99                 gpVesa_BiosState = VM8086_Init();\r
100                 \r
101                 int rv = VBE_int_GetModeList();\r
102                 if(rv)  return rv;\r
103         }\r
104         #endif\r
105                 \r
106         #if BLINKING_CURSOR\r
107         // Create blink timer\r
108         gpVesaCursorTimer = Time_AllocateTimer( Vesa_FlipCursor, NULL );\r
109         #endif\r
110 \r
111         // Install Device\r
112         giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );\r
113         if(giVesaDriverId == -1)        return MODULE_ERR_MISC;\r
114 \r
115         return MODULE_ERR_OK;\r
116 }\r
117 \r
118 #if USE_BIOS\r
119 int VBE_int_GetModeList(void)\r
120 {\r
121         tVesa_CallInfo  *info;\r
122         tFarPtr infoPtr;\r
123         Uint16  *modes;\r
124         \r
125         // Allocate Info Block\r
126         info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);\r
127         // Set Requested Version\r
128         memcpy(info->signature, "VBE2", 4);\r
129         // Set Registers\r
130         gpVesa_BiosState->AX = 0x4F00;\r
131         gpVesa_BiosState->ES = infoPtr.seg;     gpVesa_BiosState->DI = infoPtr.ofs;\r
132         // Call Interrupt\r
133         VM8086_Int(gpVesa_BiosState, 0x10);\r
134         if(gpVesa_BiosState->AX != 0x004F) {\r
135                 Log_Warning("VBE", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);\r
136                 return MODULE_ERR_NOTNEEDED;\r
137         }\r
138         \r
139         modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);\r
140         LOG("Virtual addres of mode list from %04x:%04x is %p",\r
141                 info->VideoModes.seg, info->VideoModes.ofs, modes);\r
142 //      VM8086_Deallocate( gpVesa_BiosState, info );\r
143         \r
144         // Count Modes\r
145         for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ )\r
146                 ;\r
147         gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );\r
148         \r
149         Log_Debug("VBE", "%i Modes", giVesaModeCount);\r
150 \r
151         // Insert Text Mode\r
152         \r
153         for( int i = 0; i < giVesaModeCount; i++ )\r
154         {\r
155                 gVesa_Modes[i].code = modes[i];\r
156         }\r
157         \r
158         return 0;\r
159 }\r
160 \r
161 int VBE_int_GetModeInfo(Uint16 Code, tFarPtr *BufPtr)\r
162 {\r
163         // Get Mode info\r
164         gpVesa_BiosState->AX = 0x4F01;\r
165         gpVesa_BiosState->CX = Code;\r
166         gpVesa_BiosState->ES = BufPtr->seg;\r
167         gpVesa_BiosState->DI = BufPtr->ofs;\r
168         VM8086_Int(gpVesa_BiosState, 0x10);\r
169 \r
170         if( gpVesa_BiosState->AX != 0x004F ) {\r
171                 Log_Error("VBE", "Getting info on mode 0x%x failed (AX=0x%x)",\r
172                         Code, gpVesa_BiosState->AX);\r
173                 return 1;\r
174         }\r
175         return 0;\r
176 }\r
177 #endif\r
178 \r
179 \r
180 void VBE_int_FillMode_Int(tVesa_Mode *Mode, const tVesa_CallModeInfo *vbeinfo)\r
181 {\r
182         #if 1\r
183         #define S_LOG(s, fld, fmt)      LOG(" ."#fld" = "fmt, (s).fld)\r
184         LOG("vbeinfo[0x%x] = {", Mode->code);\r
185         S_LOG(*vbeinfo, attributes, "0x%02x");\r
186         S_LOG(*vbeinfo, winA, "0x%02x");\r
187         S_LOG(*vbeinfo, winB, "0x%02x");\r
188         S_LOG(*vbeinfo, granularity, "0x%04x");\r
189         S_LOG(*vbeinfo, winsize, "0x%04x");\r
190         S_LOG(*vbeinfo, segmentA, "0x%04x");\r
191         S_LOG(*vbeinfo, segmentB, "0x%04x");\r
192         LOG(" .realFctPtr = %04x:%04x", vbeinfo->realFctPtr.seg, vbeinfo->realFctPtr.ofs);\r
193         S_LOG(*vbeinfo, pitch, "0x%04x");\r
194 \r
195         // -- Extended\r
196         S_LOG(*vbeinfo, Xres, "%i");\r
197         S_LOG(*vbeinfo, Yres, "%i");\r
198         S_LOG(*vbeinfo, Wchar, "%i");\r
199         S_LOG(*vbeinfo, Ychar, "%i");\r
200         S_LOG(*vbeinfo, planes, "%i");\r
201         S_LOG(*vbeinfo, bpp, "%i");\r
202         S_LOG(*vbeinfo, banks, "%i");\r
203         S_LOG(*vbeinfo, memory_model, "%i");\r
204         S_LOG(*vbeinfo, bank_size, "%i");\r
205         S_LOG(*vbeinfo, image_pages, "%i");\r
206         // -- VBE 1.2+\r
207         LOG(" Red   = %i bits at %i", vbeinfo->red_mask,   vbeinfo->red_position  );\r
208         LOG(" Green = %i bits at %i", vbeinfo->green_mask, vbeinfo->green_position);\r
209         LOG(" Blue  = %i bits at %i", vbeinfo->blue_mask,  vbeinfo->blue_position );\r
210         #if 0\r
211         Uint8   rsv_mask, rsv_position;\r
212         Uint8   directcolor_attributes;\r
213         #endif\r
214         // --- VBE 2.0+\r
215         S_LOG(*vbeinfo, physbase, "0x%08x");\r
216         S_LOG(*vbeinfo, offscreen_ptr, "0x%08x");\r
217         S_LOG(*vbeinfo, offscreen_size_kb, "0x%04x");\r
218         // --- VBE 3.0+\r
219         S_LOG(*vbeinfo, lfb_pitch, "0x%04x");\r
220         S_LOG(*vbeinfo, image_count_banked, "%i");\r
221         S_LOG(*vbeinfo, image_count_lfb, "%i");\r
222         LOG("}");\r
223         #endif\r
224         \r
225         Mode->flags = FLAG_POPULATED;\r
226         // Check if this mode is supported by hardware\r
227         if( !(vbeinfo->attributes & 1) )\r
228         {\r
229                 #if DEBUG\r
230                 Log_Log("VBE", "0x%x - not supported", Mode->code);\r
231                 #endif\r
232                 Mode->width = 0;\r
233                 Mode->height = 0;\r
234                 Mode->bpp = 0;\r
235                 return ;\r
236         }\r
237 \r
238         // Parse Info\r
239         Mode->flags |= FLAG_VALID;\r
240         switch( vbeinfo->attributes & 0x90 )    // LFB, Graphics\r
241         {\r
242         case 0x00:      // Banked, Text\r
243         case 0x10:      // Banked, Graphics\r
244         case 0x80:      // Linear, Text (?)\r
245                 Mode->width = 0;\r
246                 Mode->height = 0;\r
247                 Mode->bpp = 0;\r
248                 return ;\r
249         case 0x90:\r
250                 Mode->flags |= FLAG_LFB|FLAG_GRAPHICS;\r
251                 Mode->framebuffer = vbeinfo->physbase;\r
252                 Mode->fbSize = vbeinfo->Yres*vbeinfo->pitch;\r
253                 break;\r
254         }\r
255         \r
256         Mode->pitch = vbeinfo->pitch;\r
257         Mode->width = vbeinfo->Xres;\r
258         Mode->height = vbeinfo->Yres;\r
259         Mode->bpp = vbeinfo->bpp;\r
260         \r
261         #if DEBUG\r
262         Log_Log("VBE", "0x%x - %ix%ix%i (%x)",\r
263                 Mode->code, Mode->width, Mode->height, Mode->bpp, Mode->flags);\r
264         #endif\r
265 \r
266\r
267 \r
268 void VBE_int_SetBootMode(Uint16 ModeID, const void *ModeInfo)\r
269 {\r
270         gVesa_BootMode.code = ModeID;\r
271         VBE_int_FillMode_Int(&gVesa_BootMode, ModeInfo);\r
272 }\r
273 \r
274 void Vesa_int_FillModeList(void)\r
275 {\r
276         #if USE_BIOS\r
277         if( !gbVesaModesChecked && !gbVesa_DisableBIOSCalls )\r
278         {\r
279                 tVesa_CallModeInfo      *modeinfo;\r
280                 tFarPtr modeinfoPtr;\r
281                 \r
282                 modeinfo = VM8086_Allocate(gpVesa_BiosState, 256, &modeinfoPtr.seg, &modeinfoPtr.ofs);\r
283                 for( int i = 0; i < giVesaModeCount; i ++ )\r
284                 {\r
285                         if( VBE_int_GetModeInfo(gVesa_Modes[i].code, &modeinfoPtr) == 0 )\r
286                         {\r
287                                 VBE_int_FillMode_Int( &gVesa_Modes[i], modeinfo );\r
288                         }\r
289                 }       \r
290 //              VM8086_Deallocate( gpVesa_BiosState, modeinfo );\r
291                 \r
292                 gbVesaModesChecked = 1;\r
293         }\r
294         #endif\r
295 }\r
296 \r
297 /**\r
298  * \brief Write to the framebuffer\r
299  */\r
300 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)\r
301 {\r
302         switch( gpVesaCurMode->flags & (FLAG_LFB|FLAG_GRAPHICS) )\r
303         {\r
304         case 0:\r
305                 // EGA text mode translation\r
306                 switch( gVesa_BufInfo.BufferFormat )\r
307                 {\r
308                 case VIDEO_BUFFMT_TEXT: {\r
309                          int    num = Length / sizeof(tVT_Char);\r
310                          int    ofs = Offset / sizeof(tVT_Char);\r
311                          int    i = 0;\r
312                         const tVT_Char  *chars = Buffer;\r
313                         \r
314                         for( ; num--; i ++, ofs ++)\r
315                         {\r
316                                 Uint16  word = VBE_int_GetWord( &chars[i] );\r
317                                 ((Uint16*)gVesa_BufInfo.Framebuffer)[ ofs ] = word;\r
318                         }\r
319                         \r
320                         return Length; }\r
321                 case VIDEO_BUFFMT_2DSTREAM:\r
322                         return DrvUtil_Video_2DStream(NULL, Buffer, Length,\r
323                                 &gVBE_Text2DFunctions, sizeof(gVBE_Text2DFunctions));\r
324                 default:\r
325                         Log_Warning("VBE", "TODO: Alternate modes in EGA text mode");\r
326                         return 0;\r
327                 }\r
328                 return 0;\r
329         case FLAG_LFB|FLAG_GRAPHICS:\r
330                 // Framebuffer modes - use DrvUtil Video\r
331                 return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);\r
332         default:\r
333                 Log_Warning("VBE", "TODO: _Write %s%s",\r
334                         (gpVesaCurMode->flags & FLAG_LFB ? "FLAG_LFB" : ""),\r
335                         (gpVesaCurMode->flags & FLAG_GRAPHICS ? "FLAG_GRAPHICS" : "")\r
336                         );\r
337                 return 0;\r
338         }\r
339 }\r
340 \r
341 const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
342 /**\r
343  * \brief Handle messages to the device\r
344  */\r
345 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
346 {\r
347          int    ret;\r
348         switch(ID)\r
349         {\r
350         BASE_IOCTLS(DRV_TYPE_VIDEO, "VBE", VERSION, csaVESA_IOCtls);\r
351 \r
352         case VIDEO_IOCTL_GETSETMODE:\r
353                 if( !Data )     return giVesaCurrentMode;\r
354                 return Vesa_Int_SetMode( *(int*)Data );\r
355         \r
356         case VIDEO_IOCTL_FINDMODE:\r
357                 return Vesa_Int_FindMode((tVideo_IOCtl_Mode*)Data);\r
358         case VIDEO_IOCTL_MODEINFO:\r
359                 return Vesa_Int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
360         \r
361         case VIDEO_IOCTL_SETBUFFORMAT:\r
362                 Vesa_int_HideCursor();\r
363                 ret = gVesa_BufInfo.BufferFormat;\r
364                 if(Data)        gVesa_BufInfo.BufferFormat = *(int*)Data;\r
365                 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
366                         DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor );\r
367                 Vesa_int_ShowCursor();\r
368                 return ret;\r
369         \r
370         case VIDEO_IOCTL_SETCURSOR:     // Set cursor position\r
371                 Vesa_int_HideCursor();\r
372                 giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;\r
373                 giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;\r
374                 Vesa_int_ShowCursor();\r
375                 return 0;\r
376         \r
377         case VIDEO_IOCTL_SETCURSORBITMAP:\r
378                 if( gpVesaCurMode->flags & FLAG_LFB )\r
379                         DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data );\r
380                 return 0;\r
381         }\r
382         return 0;\r
383 }\r
384 \r
385 /**\r
386  * \brief Updates the video mode\r
387  */\r
388 int Vesa_Int_SetMode(int mode)\r
389 {\r
390         tVesa_Mode      *modeptr;\r
391         // Check for fast return\r
392         if(mode == giVesaCurrentMode)   return 1;\r
393         \r
394         // Special case: Boot mode\r
395         if( mode == -1 )\r
396                 modeptr = &gVesa_BootMode;\r
397         else if( 0 <= mode && mode < giVesaModeCount )\r
398                 modeptr = &gVesa_Modes[mode];\r
399         else\r
400                 return -1;\r
401         \r
402         Vesa_int_FillModeList();\r
403 \r
404         #if BLINKING_CURSOR\r
405         Time_RemoveTimer(gpVesaCursorTimer);\r
406         #endif\r
407         \r
408         Mutex_Acquire( &glVesa_Lock );\r
409 \r
410         #if USE_BIOS\r
411         if( gbVesa_DisableBIOSCalls )\r
412         {\r
413                 ASSERT(mode == -1);\r
414         }\r
415         else\r
416         {\r
417                 gpVesa_BiosState->AX = 0x4F02;\r
418                 gpVesa_BiosState->BX = modeptr->code;\r
419                 if(modeptr->flags & FLAG_LFB) {\r
420                         gpVesa_BiosState->BX |= 1 << 14;        // Use LFB\r
421                 }\r
422                 LOG("In : AX=%04x/BX=%04x", gpVesa_BiosState->AX, gpVesa_BiosState->BX);\r
423                 \r
424                 // Set Mode\r
425                 VM8086_Int(gpVesa_BiosState, 0x10);\r
426 \r
427                 LOG("Out: AX = %04x", gpVesa_BiosState->AX);\r
428         }\r
429         #else\r
430         ASSERT(mode == -1);\r
431         #endif\r
432         \r
433         // Map Framebuffer\r
434         if( gpVesaCurMode )\r
435         {\r
436                 MM_UnmapHWPages(gpVesa_Framebuffer, giVesaPageCount);\r
437         }\r
438         giVesaPageCount = (modeptr->fbSize + 0xFFF) >> 12;\r
439         gpVesa_Framebuffer = MM_MapHWPages(modeptr->framebuffer, giVesaPageCount);\r
440         \r
441         Log_Log("VBE", "Setting mode to %i 0x%x (%ix%i %ibpp) %p[0x%x] maps %P",\r
442                 mode, modeptr->code,\r
443                 modeptr->width, modeptr->height,\r
444                 modeptr->bpp,\r
445                 gpVesa_Framebuffer, giVesaPageCount << 12, modeptr->framebuffer\r
446                 );\r
447         \r
448         // Record Mode Set\r
449         giVesaCurrentMode = mode;\r
450         gpVesaCurMode = modeptr;\r
451         \r
452         Mutex_Release( &glVesa_Lock );\r
453 \r
454         // TODO: Disableable backbuffer\r
455         gVesa_BufInfo.BackBuffer  = realloc(gVesa_BufInfo.BackBuffer,\r
456                 modeptr->height * modeptr->pitch);\r
457         gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;\r
458         gVesa_BufInfo.Pitch = modeptr->pitch;\r
459         gVesa_BufInfo.Width = modeptr->width;\r
460         gVesa_BufInfo.Height = modeptr->height;\r
461         gVesa_BufInfo.Depth = modeptr->bpp;     \r
462 \r
463         return 1;\r
464 }\r
465 \r
466 int VBE_int_MatchModes(tVideo_IOCtl_Mode *ReqMode, tVesa_Mode *ThisMode)\r
467 {\r
468         if( ThisMode->bpp == 0 ) {\r
469                 Log_Warning("VBE", "VESA mode %x (%ix%i) has 0bpp",\r
470                         ThisMode->code, ThisMode->width, ThisMode->height);\r
471                 return INT_MAX;\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 && 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 && 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