Modules/VESA - Fix calling SETCURSOR when in B8000 text mode
[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 #ifdef ARCHDIR_is_x86\r
20 # define USE_BIOS       1\r
21 #else\r
22 # define USE_BIOS       0\r
23 #endif\r
24 #define VESA_DEFAULT_FRAMEBUFFER        (KERNEL_BASE|0xA0000)\r
25 #define BLINKING_CURSOR 0\r
26 #if BLINKING_CURSOR\r
27 # define VESA_CURSOR_PERIOD     1000\r
28 #endif\r
29 \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
45 \r
46 // === GLOBALS ===\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
50         .IOCtl = Vesa_IOCtl\r
51         };\r
52 tDevFS_Driver   gVesa_DriverStruct = {\r
53         NULL, "Vesa",\r
54         {.Type = &gVesa_NodeType}\r
55         };\r
56 tMutex  glVesa_Lock;\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
72 #if BLINKING_CURSOR\r
73 tTimer  *gpVesaCursorTimer;\r
74 #endif\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
79         NULL,\r
80         VBE_int_Text_2D_Fill,\r
81         VBE_int_Text_2D_Blit\r
82 };\r
83 // --- Settings ---\r
84 bool    gbVesa_DisableBIOSCalls;        // Disables calls to the BIOS\r
85 // int  gbVesa_DisableFBCache;  // Disables the main-memory framebuffer cache\r
86 \r
87 // === CODE ===\r
88 int Vesa_Install(char **Arguments)\r
89 {\r
90         for( int i = 0; Arguments && Arguments[i]; i ++ )\r
91         {\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
96                 else {\r
97                         Log_Notice("VBE", "Unknown argument '%s'", Arguments[i]);\r
98                 }\r
99         }\r
100 \r
101         #if USE_BIOS\r
102         if( !gbVesa_DisableBIOSCalls )\r
103         {\r
104                 gpVesa_BiosState = VM8086_Init();\r
105                 \r
106                 int rv = VBE_int_GetModeList();\r
107                 if(rv)  return rv;\r
108         }\r
109         #endif\r
110                 \r
111         #if BLINKING_CURSOR\r
112         // Create blink timer\r
113         gpVesaCursorTimer = Time_AllocateTimer( Vesa_FlipCursor, NULL );\r
114         #endif\r
115 \r
116         // Install Device\r
117         giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );\r
118         if(giVesaDriverId == -1)        return MODULE_ERR_MISC;\r
119 \r
120         return MODULE_ERR_OK;\r
121 }\r
122 \r
123 #if USE_BIOS\r
124 int VBE_int_GetModeList(void)\r
125 {\r
126         tVesa_CallInfo  *info;\r
127         tFarPtr infoPtr;\r
128         Uint16  *modes;\r
129         \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
135         }\r
136         // Set Requested Version\r
137         memcpy(info->signature, "VBE2", 4);\r
138         // Set Registers\r
139         gpVesa_BiosState->AX = 0x4F00;\r
140         gpVesa_BiosState->ES = infoPtr.seg;     gpVesa_BiosState->DI = infoPtr.ofs;\r
141         // Call Interrupt\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
146         }\r
147         \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
152         \r
153         // Count Modes\r
154         for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ )\r
155                 ;\r
156         gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );\r
157         \r
158         Log_Debug("VBE", "%i Modes", giVesaModeCount);\r
159 \r
160         // Insert Text Mode\r
161         \r
162         for( int i = 0; i < giVesaModeCount; i++ )\r
163         {\r
164                 gVesa_Modes[i].code = modes[i];\r
165         }\r
166         \r
167         return 0;\r
168 }\r
169 \r
170 int VBE_int_GetModeInfo(Uint16 Code, tFarPtr *BufPtr)\r
171 {\r
172         // Get Mode info\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
178 \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
182                 return 1;\r
183         }\r
184         return 0;\r
185 }\r
186 #endif\r
187 \r
188 \r
189 void VBE_int_FillMode_Int(tVesa_Mode *Mode, const tVesa_CallModeInfo *vbeinfo)\r
190 {\r
191         #if 1\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
203 \r
204         // -- Extended\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
215         // -- VBE 1.2+\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
219         #if 0\r
220         Uint8   rsv_mask, rsv_position;\r
221         Uint8   directcolor_attributes;\r
222         #endif\r
223         // --- VBE 2.0+\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
227         // --- VBE 3.0+\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
231         LOG("}");\r
232         #endif\r
233         \r
234         Mode->flags = FLAG_POPULATED;\r
235         // Check if this mode is supported by hardware\r
236         if( !(vbeinfo->attributes & 1) )\r
237         {\r
238                 #if DEBUG\r
239                 Log_Log("VBE", "0x%x - not supported", Mode->code);\r
240                 #endif\r
241                 Mode->width = 0;\r
242                 Mode->height = 0;\r
243                 Mode->bpp = 0;\r
244                 return ;\r
245         }\r
246 \r
247         // Parse Info\r
248         Mode->flags |= FLAG_VALID;\r
249         switch( vbeinfo->attributes & 0x90 )    // LFB, Graphics\r
250         {\r
251         case 0x00:      // Banked, Text\r
252         case 0x10:      // Banked, Graphics\r
253         case 0x80:      // Linear, Text (?)\r
254                 Mode->width = 0;\r
255                 Mode->height = 0;\r
256                 Mode->bpp = 0;\r
257                 return ;\r
258         case 0x90:\r
259                 Mode->flags |= FLAG_LFB|FLAG_GRAPHICS;\r
260                 Mode->framebuffer = vbeinfo->physbase;\r
261                 Mode->fbSize = vbeinfo->Yres*vbeinfo->pitch;\r
262                 break;\r
263         }\r
264         \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
269         \r
270         #if DEBUG\r
271         Log_Log("VBE", "0x%x - %ix%ix%i (%x)",\r
272                 Mode->code, Mode->width, Mode->height, Mode->bpp, Mode->flags);\r
273         #endif\r
274 \r
275\r
276 \r
277 void VBE_int_SetBootMode(Uint16 ModeID, const void *ModeInfo)\r
278 {\r
279         gVesa_BootMode.code = ModeID;\r
280         VBE_int_FillMode_Int(&gVesa_BootMode, ModeInfo);\r
281 }\r
282 \r
283 void Vesa_int_FillModeList(void)\r
284 {\r
285         #if USE_BIOS\r
286         if( !gbVesaModesChecked && !gbVesa_DisableBIOSCalls )\r
287         {\r
288                 tVesa_CallModeInfo      *modeinfo;\r
289                 tFarPtr modeinfoPtr;\r
290                 \r
291                 modeinfo = VM8086_Allocate(gpVesa_BiosState, 256, &modeinfoPtr.seg, &modeinfoPtr.ofs);\r
292                 for( int i = 0; i < giVesaModeCount; i ++ )\r
293                 {\r
294                         if( VBE_int_GetModeInfo(gVesa_Modes[i].code, &modeinfoPtr) == 0 )\r
295                         {\r
296                                 VBE_int_FillMode_Int( &gVesa_Modes[i], modeinfo );\r
297                         }\r
298                 }       \r
299 //              VM8086_Deallocate( gpVesa_BiosState, modeinfo );\r
300                 \r
301                 gbVesaModesChecked = 1;\r
302         }\r
303         #endif\r
304 }\r
305 \r
306 /**\r
307  * \brief Write to the framebuffer\r
308  */\r
309 size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)\r
310 {\r
311         switch( gpVesaCurMode->flags & (FLAG_LFB|FLAG_GRAPHICS) )\r
312         {\r
313         case 0:\r
314                 // EGA text mode translation\r
315                 switch( gVesa_BufInfo.BufferFormat )\r
316                 {\r
317                 case VIDEO_BUFFMT_TEXT: {\r
318                          int    num = Length / sizeof(tVT_Char);\r
319                          int    ofs = Offset / sizeof(tVT_Char);\r
320                          int    i = 0;\r
321                         const tVT_Char  *chars = Buffer;\r
322                         \r
323                         for( ; num--; i ++, ofs ++)\r
324                         {\r
325                                 Uint16  word = VBE_int_GetWord( &chars[i] );\r
326                                 ((Uint16*)gVesa_BufInfo.Framebuffer)[ ofs ] = word;\r
327                         }\r
328                         \r
329                         return Length; }\r
330                 case VIDEO_BUFFMT_2DSTREAM:\r
331                         return DrvUtil_Video_2DStream(NULL, Buffer, Length,\r
332                                 &gVBE_Text2DFunctions, sizeof(gVBE_Text2DFunctions));\r
333                 default:\r
334                         Log_Warning("VBE", "TODO: Alternate modes in EGA text mode");\r
335                         return 0;\r
336                 }\r
337                 return 0;\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
341         default:\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
345                         );\r
346                 return 0;\r
347         }\r
348 }\r
349 \r
350 const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
351 /**\r
352  * \brief Handle messages to the device\r
353  */\r
354 int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
355 {\r
356          int    ret;\r
357         switch(ID)\r
358         {\r
359         BASE_IOCTLS(DRV_TYPE_VIDEO, "VBE", VERSION, csaVESA_IOCtls);\r
360 \r
361         case VIDEO_IOCTL_GETSETMODE:\r
362                 if( !Data )     return giVesaCurrentMode;\r
363                 return Vesa_Int_SetMode( *(int*)Data );\r
364         \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
369         \r
370         case VIDEO_IOCTL_SETBUFFORMAT:\r
371                 Vesa_int_HideCursor();\r
372                 ret = gVesa_BufInfo.BufferFormat;\r
373                 if(Data)\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
378                 return ret;\r
379         \r
380         case VIDEO_IOCTL_SETCURSOR:     // Set cursor position\r
381                 if( !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
382                         return -EINVAL;\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
387                 return 0;\r
388         \r
389         case VIDEO_IOCTL_SETCURSORBITMAP:\r
390                 return Vesa_int_SetCursor(Data);\r
391         }\r
392         return 0;\r
393 }\r
394 \r
395 /**\r
396  * \brief Updates the video mode\r
397  */\r
398 int Vesa_Int_SetMode(int mode)\r
399 {\r
400         tVesa_Mode      *modeptr;\r
401         // Check for fast return\r
402         if(mode == giVesaCurrentMode)   return 1;\r
403         \r
404         // Special case: Boot mode\r
405         if( mode == -1 )\r
406                 modeptr = &gVesa_BootMode;\r
407         else if( 0 <= mode && mode < giVesaModeCount )\r
408                 modeptr = &gVesa_Modes[mode];\r
409         else\r
410                 return -1;\r
411         \r
412         Vesa_int_FillModeList();\r
413 \r
414         #if BLINKING_CURSOR\r
415         Time_RemoveTimer(gpVesaCursorTimer);\r
416         #endif\r
417         \r
418         Mutex_Acquire( &glVesa_Lock );\r
419 \r
420         #if USE_BIOS\r
421         if( gbVesa_DisableBIOSCalls )\r
422         {\r
423                 ASSERT(mode == -1);\r
424         }\r
425         else\r
426         {\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
431                 }\r
432                 LOG("In : AX=%04x/BX=%04x", gpVesa_BiosState->AX, gpVesa_BiosState->BX);\r
433                 \r
434                 // Set Mode\r
435                 VM8086_Int(gpVesa_BiosState, 0x10);\r
436 \r
437                 LOG("Out: AX = %04x", gpVesa_BiosState->AX);\r
438         }\r
439         #else\r
440         ASSERT(mode == -1);\r
441         #endif\r
442         \r
443         // Map Framebuffer\r
444         if( gpVesaCurMode )\r
445         {\r
446                 MM_UnmapHWPages(gpVesa_Framebuffer, giVesaPageCount);\r
447         }\r
448         giVesaPageCount = (modeptr->fbSize + 0xFFF) >> 12;\r
449         gpVesa_Framebuffer = MM_MapHWPages(modeptr->framebuffer, giVesaPageCount);\r
450         \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
454                 modeptr->bpp,\r
455                 gpVesa_Framebuffer, giVesaPageCount << 12, modeptr->framebuffer\r
456                 );\r
457         \r
458         // Record Mode Set\r
459         giVesaCurrentMode = mode;\r
460         gpVesaCurMode = modeptr;\r
461         \r
462         Mutex_Release( &glVesa_Lock );\r
463 \r
464         // TODO: Disableable backbuffer\r
465         gVesa_BufInfo.BackBuffer  = realloc(gVesa_BufInfo.BackBuffer,\r
466                 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
472 \r
473         return 1;\r
474 }\r
475 \r
476 int VBE_int_MatchModes(tVideo_IOCtl_Mode *ReqMode, tVesa_Mode *ThisMode)\r
477 {\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
481                 return INT_MAX;\r
482         }\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
485         {\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
489                 {\r
490                         LOG("Perfect!");\r
491                         return -1;\r
492                 }\r
493         }\r
494         \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
500         else\r
501                 factor += ReqMode->bpp - ThisMode->bpp;\r
502 \r
503         if( ReqMode->bpp == ThisMode->bpp )\r
504                 factor /= 2;\r
505         else\r
506         {\r
507                 if( ReqMode->bpp == 8 && ThisMode->bpp != 8 )   factor *= 4;\r
508                 if( ReqMode->bpp == 16 && ThisMode->bpp != 16 ) factor *= 4;\r
509                 \r
510                 if( (ReqMode->bpp == 32 || ReqMode->bpp == 24)\r
511                  && (ThisMode->bpp == 32 || ThisMode->bpp == 24) )\r
512                 {\r
513                         // NC\r
514                 }\r
515                 else {\r
516                         if( ReqMode->bpp < ThisMode->bpp )\r
517                                 factor *= ThisMode->bpp / ReqMode->bpp + 1;\r
518                         else\r
519                                 factor *= ReqMode->bpp / ThisMode->bpp + 1;\r
520                 }\r
521         }\r
522         \r
523         return factor;\r
524 }\r
525 \r
526 int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)\r
527 {\r
528          int    best = -1;\r
529         \r
530         ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);\r
531 \r
532         Vesa_int_FillModeList();\r
533 \r
534         int bestFactor = VBE_int_MatchModes(data, &gVesa_BootMode);     \r
535         tVesa_Mode *bestPtr = &gVesa_BootMode;\r
536 \r
537         for(int i = 0; bestFactor > 0 && i < giVesaModeCount; i ++)\r
538         {\r
539                 LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
540         \r
541                 int factor = VBE_int_MatchModes(data, &gVesa_Modes[i]);\r
542                 \r
543                 LOG("factor = %i, bestFactor = %i", factor, bestFactor);\r
544                 \r
545                 if(factor < bestFactor)\r
546                 {\r
547                         bestFactor = factor;\r
548                         best = i;\r
549                         bestPtr = &gVesa_Modes[i];\r
550                 }\r
551         }\r
552         data->id = best;\r
553         data->width = bestPtr->width;\r
554         data->height = bestPtr->height;\r
555         data->bpp = bestPtr->bpp;\r
556         LEAVE('i', best);\r
557         return best;\r
558 }\r
559 \r
560 int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)\r
561 {\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
567         else\r
568                 return 0;\r
569 \r
570         Vesa_int_FillModeList();\r
571 \r
572         data->width  = modeptr->width;\r
573         data->height = modeptr->height;\r
574         data->bpp    = modeptr->bpp;\r
575         return 1;\r
576 }\r
577 \r
578 void Vesa_int_HideCursor(void)\r
579 {\r
580         DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );\r
581         if( gpVesaCurMode->flags & FLAG_LFB )\r
582         {\r
583                 #if BLINKING_CURSOR\r
584                 if(gpVesaCursorTimer) {\r
585                         Time_RemoveTimer(gpVesaCursorTimer);\r
586                 }\r
587                 #endif\r
588         }\r
589 }\r
590 \r
591 void Vesa_int_ShowCursor(void)\r
592 {\r
593         if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB )\r
594         {\r
595                 gbVesa_CursorVisible = (giVesaCursorX >= 0);\r
596                 if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
597                 {\r
598                         DrvUtil_Video_DrawCursor(\r
599                                 &gVesa_BufInfo,\r
600                                 giVesaCursorX*giVT_CharWidth,\r
601                                 giVesaCursorY*giVT_CharHeight\r
602                                 );\r
603                         #if BLINKING_CURSOR\r
604                         Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );\r
605                         #endif\r
606                 }\r
607                 else\r
608                         DrvUtil_Video_DrawCursor(\r
609                                 &gVesa_BufInfo,\r
610                                 giVesaCursorX,\r
611                                 giVesaCursorY\r
612                                 );\r
613         }\r
614         else\r
615         {\r
616                 DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );\r
617         }\r
618 }\r
619 \r
620 int Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor)\r
621 {\r
622         if( !CheckMem(Cursor, sizeof(tVideo_IOCtl_Bitmap)) )\r
623                 return -EINVAL;\r
624         \r
625         if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB )\r
626         {\r
627                 DrvUtil_Video_SetCursor( &gVesa_BufInfo, Cursor );\r
628         }\r
629         else\r
630         {\r
631         }\r
632         return 0;\r
633 }\r
634 \r
635 /**\r
636  * \brief Swaps the text cursor on/off\r
637  */\r
638 void Vesa_FlipCursor(void *Arg)\r
639 {\r
640         if( gVesa_BufInfo.BufferFormat != VIDEO_BUFFMT_TEXT )\r
641                 return ;\r
642 \r
643         if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB )\r
644         {\r
645                 if( gbVesa_CursorVisible )\r
646                         DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);\r
647                 else\r
648                         DrvUtil_Video_DrawCursor(&gVesa_BufInfo,\r
649                                 giVesaCursorX*giVT_CharWidth,\r
650                                 giVesaCursorY*giVT_CharHeight\r
651                                 );\r
652                 gbVesa_CursorVisible = !gbVesa_CursorVisible;\r
653                         \r
654                 #if BLINKING_CURSOR\r
655                 Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD );\r
656                 #endif\r
657         }\r
658 }\r
659 \r
660 // ---\r
661 // Helpers for text mode\r
662 // ---\r
663 \r
664 /**\r
665  * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)\r
666  * \brief Converts a 12-bit colour into a VGA 4-bit colour\r
667  */\r
668 Uint8 VBE_int_GetColourNibble(Uint16 col)\r
669 {\r
670         Uint8   ret = 0;\r
671          int    bright = 0;\r
672         \r
673         col = col & 0xCCC;\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
676         \r
677         switch(col)\r
678         {\r
679         //      Black\r
680         case 0x00:      ret = 0x0;      break;\r
681         // Dark Grey\r
682         case 0x15:      ret = 0x8;      break;\r
683         // Blues\r
684         case 0x01:\r
685         case 0x02:      ret = 0x1;      break;\r
686         case 0x03:      ret = 0x9;      break;\r
687         // Green\r
688         case 0x04:\r
689         case 0x08:      ret = 0x2;      break;\r
690         case 0x0C:      ret = 0xA;      break;\r
691         // Reds\r
692         case 0x10:\r
693         case 0x20:      ret = 0x4;      break;\r
694         case 0x30:      ret = 0xC;      break;\r
695         // Light Grey\r
696         case 0x2A:      ret = 0x7;      break;\r
697         // White\r
698         case 0x3F:      ret = 0xF;      break;\r
699         \r
700         default:\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
705                 break;\r
706         }\r
707         return ret;\r
708 }\r
709 \r
710 /**\r
711  * \brief Convers a character structure to a VGA character word\r
712  */\r
713 Uint16 VBE_int_GetWord(const tVT_Char *Char)\r
714 {\r
715         Uint16  ret;\r
716         Uint16  col;\r
717         \r
718         // Get Character\r
719         if(Char->Ch < 128)\r
720                 ret = Char->Ch;\r
721         else {\r
722                 switch(Char->Ch)\r
723                 {\r
724                 default:        ret = 0;        break;\r
725                 }\r
726         }\r
727         \r
728         col = VBE_int_GetColourNibble(Char->BGCol);\r
729         ret |= col << 12;\r
730         \r
731         col = VBE_int_GetColourNibble(Char->FGCol);\r
732         ret |= col << 8;\r
733         \r
734         return ret;\r
735 }\r
736 \r
737 void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)\r
738 {\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
743 \r
744         X /= charw;\r
745         W /= charw;\r
746         Y /= charh;\r
747         H /= charh;\r
748 \r
749         tVT_Char        ch;\r
750         ch.Ch = 0x20;\r
751         ch.BGCol  = (Colour & 0x0F0000) >> (16-8);\r
752         ch.BGCol |= (Colour & 0x000F00) >> (8-4);\r
753         ch.BGCol |= (Colour & 0x00000F);\r
754         ch.FGCol = 0;\r
755         Uint16 word = VBE_int_GetWord(&ch);\r
756 \r
757         Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);\r
758 \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
762 \r
763         Uint16  *buf = (Uint16*)gpVesa_Framebuffer + Y*tw + X;\r
764 \r
765         \r
766         while( H -- ) {\r
767                 for( int i = 0; i < W; i ++ )\r
768                         *buf++ = word;\r
769                 buf += tw - W;\r
770         }\r
771 }\r
772 \r
773 void VBE_int_Text_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)\r
774 {\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
779 \r
780         DstX /= charw;\r
781         SrcX /= charw;\r
782         W    /= charw;\r
783 \r
784         DstY /= charh;\r
785         SrcY /= charh;\r
786         H    /= charh;\r
787 \r
788 //      Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);\r
789 \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
796 \r
797 \r
798         Uint16  *src = (Uint16*)gpVesa_Framebuffer + SrcY*tw + SrcX;\r
799         Uint16  *dst = (Uint16*)gpVesa_Framebuffer + DstY*tw + DstX;\r
800 \r
801         if( src > dst )\r
802         {\r
803                 // Simple copy\r
804                 while( H-- ) {\r
805                         memcpy(dst, src, W*2);\r
806                         dst += tw;\r
807                         src += tw;\r
808                 }\r
809         }\r
810         else\r
811         {\r
812                 dst += H*tw;\r
813                 src += H*tw;\r
814                 while( H -- ) {\r
815                         dst -= tw-W;\r
816                         src -= tw-W;\r
817                         for( int i = W; i --; ) *--dst = *--src;\r
818                 }\r
819         }\r
820 }\r
821 \r

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