Fixed a bug in the heap manager where if an exact match of the block is found, garbag...
[tpg/acess2.git] / Modules / Display / BochsGA / bochsvbe.c
1 /**\r
2  * \file drv_bochsvbe.c\r
3  * \brief BGA (Bochs Graphic Adapter) Driver for Acess2\r
4  * \warning This driver does NOT support the Bochs PCI VGA driver\r
5 */\r
6 #define DEBUG   0\r
7 #include <acess.h>\r
8 #include <errno.h>\r
9 #include <modules.h>\r
10 #include <vfs.h>\r
11 #include <fs_devfs.h>\r
12 #include <drv_pci.h>\r
13 #include <tpl_drv_video.h>\r
14 \r
15 #define INT\r
16 \r
17 // === TYPES ===\r
18 typedef struct sBGA_Mode {\r
19         Uint16  width;\r
20         Uint16  height;\r
21         Uint16  bpp;\r
22         Uint32  fbSize;\r
23 }       tBGA_Mode;\r
24 \r
25 // === CONSTANTS ===\r
26 #define BGA_LFB_MAXSIZE (1024*768*4)\r
27 #define VBE_DISPI_BANK_ADDRESS  0xA0000\r
28 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000\r
29 #define VBE_DISPI_IOPORT_INDEX  0x01CE\r
30 #define VBE_DISPI_IOPORT_DATA   0x01CF\r
31 #define VBE_DISPI_DISABLED      0x00\r
32 #define VBE_DISPI_ENABLED       0x01\r
33 #define VBE_DISPI_LFB_ENABLED   0x40\r
34 #define VBE_DISPI_NOCLEARMEM    0x80\r
35 enum {\r
36         VBE_DISPI_INDEX_ID,\r
37         VBE_DISPI_INDEX_XRES,\r
38         VBE_DISPI_INDEX_YRES,\r
39         VBE_DISPI_INDEX_BPP,\r
40         VBE_DISPI_INDEX_ENABLE,\r
41         VBE_DISPI_INDEX_BANK,\r
42         VBE_DISPI_INDEX_VIRT_WIDTH,\r
43         VBE_DISPI_INDEX_VIRT_HEIGHT,\r
44         VBE_DISPI_INDEX_X_OFFSET,\r
45         VBE_DISPI_INDEX_Y_OFFSET\r
46 };\r
47 \r
48 \r
49 // === PROTOTYPES ===\r
50 // Driver\r
51  int    BGA_Install(char **Arguments);\r
52 void    BGA_Uninstall();\r
53 // Internal\r
54 void    BGA_int_WriteRegister(Uint16 reg, Uint16 value);\r
55 Uint16  BGA_int_ReadRegister(Uint16 reg);\r
56 void    BGA_int_SetBank(Uint16 bank);\r
57 void    BGA_int_SetMode(Uint16 width, Uint16 height);\r
58  int    BGA_int_UpdateMode(int id);\r
59  int    BGA_int_FindMode(tVideo_IOCtl_Mode *info);\r
60  int    BGA_int_ModeInfo(tVideo_IOCtl_Mode *info);\r
61  int    BGA_int_MapFB(void *Dest);\r
62 // Filesystem\r
63 Uint64  BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
64 Uint64  BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
65  int    BGA_Ioctl(tVFS_Node *node, int id, void *data);\r
66 \r
67 // === GLOBALS ===\r
68 MODULE_DEFINE(0, 0x0032, BochsGA, BGA_Install, NULL, "PCI", NULL);\r
69 tDevFS_Driver   gBGA_DriverStruct = {\r
70         NULL, "BochsGA",\r
71         {\r
72         .Read = BGA_Read,\r
73         .Write = BGA_Write,\r
74         .IOCtl = BGA_Ioctl\r
75         }\r
76 };\r
77  int    giBGA_CurrentMode = -1;\r
78  int    giBGA_BufferFormat = 0;\r
79 tVideo_IOCtl_Pos        gBGA_CursorPos = {-1,-1};\r
80 Uint    *gBGA_Framebuffer;\r
81 tBGA_Mode       gpBGA_CurrentMode;\r
82 const tBGA_Mode gBGA_Modes[] = {\r
83         {},\r
84         {640,480,32, 0, 640*480*4},\r
85         {800,600,32, 0, 800*600*4},\r
86         {1024,768,32, 0, 1024*768*4}\r
87 };\r
88 #define BGA_MODE_COUNT  (sizeof(gBGA_Modes)/sizeof(gBGA_Modes[0]))\r
89 \r
90 // === CODE ===\r
91 /**\r
92  * \fn int BGA_Install(char **Arguments)\r
93  */\r
94 int BGA_Install(char **Arguments)\r
95 {\r
96          int    version = 0;\r
97         \r
98         // Check BGA Version\r
99         version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);\r
100         \r
101         // NOTE: This driver was written for 0xB0C4, but they seem to be backwards compatable\r
102         if(version < 0xB0C4 || version > 0xB0C5) {\r
103                 Log_Warning("BGA", "Bochs Adapter Version is not 0xB0C4 or 0xB0C5, instead 0x%x", version);\r
104                 return MODULE_ERR_NOTNEEDED;\r
105         }\r
106         \r
107         // Install Device\r
108         if(DevFS_AddDevice( &gBGA_DriverStruct ) == -1) {\r
109                 Log_Warning("BGA", "Unable to register with DevFS, maybe already loaded?");\r
110                 return MODULE_ERR_MISC;\r
111         }\r
112         \r
113         // Map Framebuffer to hardware address\r
114         gBGA_Framebuffer = (void *) MM_MapHWPage(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768);  // 768 pages (3Mb)\r
115         \r
116         return MODULE_ERR_OK;\r
117 }\r
118 \r
119 /**\r
120  * \fn void BGA_Uninstall()\r
121  */\r
122 void BGA_Uninstall()\r
123 {\r
124         DevFS_DelDevice( &gBGA_DriverStruct );\r
125         MM_UnmapHWPage( VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768 );\r
126 }\r
127 \r
128 /**\r
129  * \fn Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
130  * \brief Read from the framebuffer\r
131  */\r
132 Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
133 {\r
134         // Check Mode\r
135         if(giBGA_CurrentMode == -1)     return -1;\r
136         \r
137         // Check Offset and Length against Framebuffer Size\r
138         if(off+len > gpBGA_CurrentMode->fbSize)\r
139                 return -1;\r
140         \r
141         // Copy from Framebuffer\r
142         memcpy(buffer, (void*)((Uint)gBGA_Framebuffer + (Uint)off), len);\r
143         return len;\r
144 }\r
145 \r
146 /**\r
147  * \fn Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
148  * \brief Write to the framebuffer\r
149  */\r
150 Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *Buffer)\r
151 {       \r
152         ENTER("xoff xlen", off, len);\r
153         \r
154         // Check Mode\r
155         if(giBGA_CurrentMode == -1) {\r
156                 LEAVE('i', -1);\r
157                 return -1;\r
158         }\r
159         \r
160         // Text Mode\r
161         switch( giBGA_BufferFormat )\r
162         {\r
163         case VIDEO_BUFFMT_TEXT:\r
164                 {\r
165                 tVT_Char        *chars = Buffer;\r
166                  int    pitch = gpBGA_CurrentMode->width * giVT_CharWidth;\r
167                  int    x, y;\r
168                 Uint32  *dest;\r
169                 \r
170                 off /= sizeof(tVT_Char);\r
171                 dest = (void*)gBGA_Framebuffer;\r
172                 x = (off % gpBGA_CurrentMode->width) * giVT_CharWidth;\r
173                 y = (off / gpBGA_CurrentMode->width) * giVT_CharHeight;\r
174                 \r
175                 // Sanity Check\r
176                 if(y > gpBGA_CurrentMode->height) {\r
177                         LEAVE('i', 0);\r
178                         return 0;\r
179                 }\r
180                 \r
181                 dest += y * pitch;\r
182                 dest += x * giVT_CharWidth;\r
183                 len /= sizeof(tVT_Char);\r
184                 while(len--)\r
185                 {\r
186                         VT_Font_Render(\r
187                                 chars->Ch,\r
188                                 dest, pitch,\r
189                                 VT_Colour12to24(chars->BGCol),\r
190                                 VT_Colour12to24(chars->FGCol)\r
191                                 );\r
192                         \r
193                         dest += giVT_CharWidth;\r
194                         \r
195                         chars ++;\r
196                         x += giVT_CharWidth;\r
197                         if( x >= pitch ) {\r
198                                 x = 0;\r
199                                 y += giVT_CharHeight;\r
200                                 dest += pitch*(giVT_CharHeight-1);\r
201                         }\r
202                 }\r
203                 }\r
204                 break;\r
205         \r
206         case VIDEO_BUFFMT_FRAMEBUFFER:\r
207                 {\r
208                 Uint8   *destBuf = (Uint8*) ((Uint)gBGA_Framebuffer + (Uint)off);\r
209                 \r
210                 if( off + len > gpBGA_CurrentMode->fbSize ) {\r
211                         LEAVE('i', 0);\r
212                         return 0;\r
213                 }\r
214                 \r
215                 LOG("buffer = %p", Buffer);\r
216                 LOG("Updating Framebuffer (%p to %p)", destBuf, destBuf + (Uint)len);\r
217                 \r
218                 \r
219                 // Copy to Frambuffer\r
220                 memcpy(destBuf, Buffer, len);\r
221                 \r
222                 LOG("BGA Framebuffer updated");\r
223                 }\r
224                 break;\r
225         default:\r
226                 LEAVE('i', -1);\r
227                 return -1;\r
228         }\r
229         \r
230         LEAVE('i', len);\r
231         return len;\r
232 }\r
233 \r
234 /**\r
235  * \fn int BGA_Ioctl(tVFS_Node *Node, int ID, void *Data)\r
236  * \brief Handle messages to the device\r
237  */\r
238 int BGA_Ioctl(tVFS_Node *Node, int ID, void *Data)\r
239 {\r
240          int    ret = -2;\r
241         ENTER("pNode iId pData", Node, ID, Data);\r
242         \r
243         switch(ID)\r
244         {\r
245         case DRV_IOCTL_TYPE:\r
246                 ret = DRV_TYPE_VIDEO;\r
247                 break;\r
248         case DRV_IOCTL_IDENT:\r
249                 memcpy(Data, "BGA1", 4);\r
250                 ret = 1;\r
251                 break;\r
252         case DRV_IOCTL_VERSION:\r
253                 ret = 0x100;\r
254                 break;\r
255         case DRV_IOCTL_LOOKUP:  // TODO: Implement\r
256                 ret = 0;\r
257                 break;\r
258                 \r
259         case VIDEO_IOCTL_GETSETMODE:\r
260                 if( Data )\r
261                         ret = BGA_int_UpdateMode(*(int*)(Data));\r
262                 else\r
263                         ret = giBGA_CurrentMode;\r
264                 break;\r
265         \r
266         case VIDEO_IOCTL_FINDMODE:\r
267                 ret = BGA_int_FindMode((tVideo_IOCtl_Mode*)Data);\r
268                 break;\r
269         \r
270         case VIDEO_IOCTL_MODEINFO:\r
271                 ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
272                 break;\r
273         \r
274         case VIDEO_IOCTL_SETBUFFORMAT:\r
275                 ret = giBGA_BufferFormat;\r
276                 if(Data)\r
277                         giBGA_BufferFormat = *(int*)Data;\r
278                 break;\r
279         \r
280         case VIDEO_IOCTL_SETCURSOR:\r
281                 gBGA_CursorPos.x = ((tVideo_IOCtl_Pos*)Data)->x;\r
282                 gBGA_CursorPos.y = ((tVideo_IOCtl_Pos*)Data)->y;\r
283                 break;\r
284         \r
285         // Request Access to LFB\r
286         case VIDEO_IOCTL_REQLFB:\r
287                 ret = BGA_int_MapFB( *(void**)Data );\r
288                 break;\r
289         \r
290         default:\r
291                 LEAVE('i', -2);\r
292                 return -2;\r
293         }\r
294         \r
295         LEAVE('i', ret);\r
296         return ret;\r
297 }\r
298 \r
299 //== Internal Functions ==\r
300 /**\r
301  * \fn void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\r
302  * \brief Writes to a BGA register\r
303  */\r
304 void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\r
305 {\r
306         outw(VBE_DISPI_IOPORT_INDEX, reg);\r
307         outw(VBE_DISPI_IOPORT_DATA, value);\r
308 }\r
309 \r
310 Uint16 BGA_int_ReadRegister(Uint16 reg)\r
311 {\r
312         outw(VBE_DISPI_IOPORT_INDEX, reg);\r
313         return inw(VBE_DISPI_IOPORT_DATA);\r
314 }\r
315 \r
316 #if 0\r
317 void BGA_int_SetBank(Uint16 bank)\r
318 {\r
319         BGA_int_WriteRegister(VBE_DISPI_INDEX_BANK, bank);\r
320 }\r
321 #endif\r
322 \r
323 /**\r
324  * \fn void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp)\r
325  * \brief Sets the video mode from the dimensions and bpp given\r
326  */\r
327 void BGA_int_SetMode(Uint16 Width, Uint16 Height)\r
328 {\r
329         ENTER("iWidth iheight ibpp", Width, Height, bpp);\r
330         BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);\r
331     BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, Width);\r
332     BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, Height);\r
333     BGA_int_WriteRegister(VBE_DISPI_INDEX_BPP,  32);\r
334     BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED);\r
335         LEAVE('-');\r
336 }\r
337 \r
338 /**\r
339  * \fn int BGA_int_UpdateMode(int id)\r
340  * \brief Set current vide mode given a mode id\r
341  */\r
342 int BGA_int_UpdateMode(int id)\r
343 {\r
344         // Sanity Check\r
345         if(id < 0 || id >= BGA_MODE_COUNT)      return -1;\r
346         \r
347         // Check if it is a text mode\r
348         if( gBGA_Modes[id].flags & MODEFLAG_TEXT )\r
349                 BGA_int_SetMode(\r
350                         gBGA_Modes[id].width*giVT_CharWidth,\r
351                         gBGA_Modes[id].height*giVT_CharHeight);\r
352         else    // Graphics?\r
353                 BGA_int_SetMode(\r
354                         gBGA_Modes[id].width,\r
355                         gBGA_Modes[id].height);\r
356         \r
357         giBGA_CurrentMode = id;\r
358         gpBGA_CurrentMode = &gBGA_Modes[id];\r
359         return id;\r
360 }\r
361 \r
362 /**\r
363  * \fn int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
364  * \brief Find a mode matching the given options\r
365  */\r
366 int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
367 {\r
368          int    i;\r
369          int    best = 0, bestFactor = 1000;\r
370          int    factor, tmp;\r
371          int    rqdProduct = info->width * info->height * info->bpp;\r
372         \r
373         ENTER("pinfo", info);\r
374         LOG("info = {width:%i,height:%i,bpp:%i})\n", info->width, info->height, info->bpp);\r
375         \r
376         for(i = 0; i < BGA_MODE_COUNT; i++)\r
377         {\r
378                 #if DEBUG >= 2\r
379                 LogF("Mode %i (%ix%ix%i), ", i, gBGA_Modes[i].width, gBGA_Modes[i].height, gBGA_Modes[i].bpp);\r
380                 #endif\r
381                 \r
382                 // Check if this mode is the same type as what we want\r
383                 if( !(gBGA_Modes[i].flags & MODEFLAG_TEXT) != !(info->flags & VIDEO_FLAG_TEXT) )\r
384                         continue;\r
385                 \r
386                 // Ooh! A perfect match\r
387                 if(gBGA_Modes[i].width == info->width\r
388                 && gBGA_Modes[i].height == info->height\r
389                 && gBGA_Modes[i].bpp == info->bpp)\r
390                 {\r
391                         #if DEBUG >= 2\r
392                         LogF("Perfect!\n");\r
393                         #endif\r
394                         best = i;\r
395                         break;\r
396                 }\r
397                 \r
398                 // If not, how close are we?\r
399                 tmp = gBGA_Modes[i].width * gBGA_Modes[i].height * gBGA_Modes[i].bpp;\r
400                 tmp -= rqdProduct;\r
401                 tmp = tmp < 0 ? -tmp : tmp;     // tmp = ABS(tmp)\r
402                 factor = tmp * 100 / rqdProduct;\r
403                 \r
404                 #if DEBUG >= 2\r
405                 LogF("factor = %i\n", factor);\r
406                 #endif\r
407                 \r
408                 if(factor < bestFactor)\r
409                 {\r
410                         bestFactor = factor;\r
411                         best = i;\r
412                 }\r
413         }\r
414         \r
415         info->id = best;\r
416         info->width = gBGA_Modes[best].width;\r
417         info->height = gBGA_Modes[best].height;\r
418         info->bpp = gBGA_Modes[best].bpp;\r
419         \r
420         info->flags = 0;\r
421         if(gBGA_Modes[best].flags & MODEFLAG_TEXT)\r
422                 info->flags |= VIDEO_FLAG_TEXT;\r
423         \r
424         return best;\r
425 }\r
426 \r
427 /**\r
428  * \fn int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
429  * \brief Get mode information\r
430  */\r
431 int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
432 {\r
433         // Sanity Check\r
434         //if( !MM_IsUser( (Uint)info, sizeof(tVideo_IOCtl_Mode) ) ) {\r
435         //      return -EINVAL;\r
436         //}\r
437         \r
438         if(info->id < 0 || info->id >= BGA_MODE_COUNT)  return -1;\r
439         \r
440         info->width = gBGA_Modes[info->id].width;\r
441         info->height = gBGA_Modes[info->id].height;\r
442         info->bpp = gBGA_Modes[info->id].bpp;\r
443         \r
444         info->flags = 0;\r
445         if(gBGA_Modes[info->id].flags & MODEFLAG_TEXT)\r
446                 info->flags |= VIDEO_FLAG_TEXT;\r
447         \r
448         return 1;\r
449 }\r
450 \r
451 /**\r
452  * \fn int BGA_int_MapFB(void *Dest)\r
453  * \brief Map the framebuffer into a process's space\r
454  * \param Dest  User address to load to\r
455  */\r
456 int BGA_int_MapFB(void *Dest)\r
457 {\r
458         Uint    i;\r
459         Uint    pages;\r
460         \r
461         // Sanity Check\r
462         if((Uint)Dest > 0xC0000000)     return 0;\r
463         if(gpBGA_CurrentMode->bpp < 15) return 0;       // Only non-pallete modes are supported\r
464         \r
465         // Count required pages\r
466         pages = (gpBGA_CurrentMode->fbSize + 0xFFF) >> 12;\r
467         \r
468         // Check if there is space\r
469         for( i = 0; i < pages; i++ )\r
470         {\r
471                 if(MM_GetPhysAddr( (Uint)Dest + (i << 12) ))\r
472                         return 0;\r
473         }\r
474         \r
475         // Map\r
476         for( i = 0; i < pages; i++ )\r
477                 MM_Map( (Uint)Dest + (i<<12), VBE_DISPI_LFB_PHYSICAL_ADDRESS + (i<<12) );\r
478         \r
479         return 1;\r
480 }\r

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