2aed670af8109ed57104ca2c0a4a7d179b3e3131
[tpg/acess2.git] / Kernel / drv / bochsvbe.c
1 /**\r
2  * \file drv_bochsvbe.c\r
3  * \brief BGA (Bochs Graphic Adapter) Driver\r
4  * \note for AcessOS Version 1\r
5  * \warning This driver does NOT support the Bochs PCI VGA driver\r
6 */\r
7 #include <common.h>\r
8 #include <modules.h>\r
9 #include <vfs.h>\r
10 #include <fs_devfs.h>\r
11 #include <drv_pci.h>\r
12 #include <tpl_drv_video.h>\r
13 \r
14 #define DEBUG   0\r
15 #if DEBUG\r
16 # define DEBUGS(v...)   SysDebug(v)\r
17 #else\r
18 # define DEBUGS(v...)\r
19 #endif\r
20 \r
21 //#define INT   static\r
22 #define INT\r
23 \r
24 // === TYPEDEFS ===\r
25 typedef struct {\r
26         Uint16  width;\r
27         Uint16  height;\r
28         Uint16  bpp;\r
29         Uint16  flags;\r
30         Uint32  fbSize;\r
31 } t_bga_mode;\r
32 \r
33 \r
34 // === PROTOTYPES ===\r
35 // Driver\r
36  int    BGA_Install(char **Arguments);\r
37 void    BGA_Uninstall();\r
38 // Internal\r
39 void    BGA_int_WriteRegister(Uint16 reg, Uint16 value);\r
40 Uint16  BGA_int_ReadRegister(Uint16 reg);\r
41 void    BGA_int_SetBank(Uint16 bank);\r
42 void    BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp);\r
43  int    BGA_int_UpdateMode(int id);\r
44  int    BGA_int_FindMode(tVideo_IOCtl_Mode *info);\r
45  int    BGA_int_ModeInfo(tVideo_IOCtl_Mode *info);\r
46  int    BGA_int_MapFB(void *Dest);\r
47 // Filesystem\r
48 Uint64  BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
49 Uint64  BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
50  int    BGA_Ioctl(tVFS_Node *node, int id, void *data);\r
51 \r
52 // === CONSTANTS ===\r
53 const t_bga_mode        BGA_MODES[] = {\r
54         {640,480,8, 0, 640*480},\r
55         {640,480,32, 0, 640*480*4},\r
56         {800,600,8, 0, 800*600},\r
57         {800,600,32, 0, 800*600*4},\r
58 };\r
59 #define BGA_MODE_COUNT  (sizeof(BGA_MODES)/sizeof(BGA_MODES[0]))\r
60 #define BGA_LFB_MAXSIZE (1024*768*4)\r
61 #define VBE_DISPI_BANK_ADDRESS  0xA0000\r
62 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000\r
63 #define VBE_DISPI_IOPORT_INDEX  0x01CE\r
64 #define VBE_DISPI_IOPORT_DATA   0x01CF\r
65 #define VBE_DISPI_DISABLED      0x00\r
66 #define VBE_DISPI_ENABLED       0x01\r
67 #define VBE_DISPI_LFB_ENABLED   0x40\r
68 #define VBE_DISPI_NOCLEARMEM    0x80\r
69 enum {\r
70         VBE_DISPI_INDEX_ID,\r
71         VBE_DISPI_INDEX_XRES,\r
72         VBE_DISPI_INDEX_YRES,\r
73         VBE_DISPI_INDEX_BPP,\r
74         VBE_DISPI_INDEX_ENABLE,\r
75         VBE_DISPI_INDEX_BANK,\r
76         VBE_DISPI_INDEX_VIRT_WIDTH,\r
77         VBE_DISPI_INDEX_VIRT_HEIGHT,\r
78         VBE_DISPI_INDEX_X_OFFSET,\r
79         VBE_DISPI_INDEX_Y_OFFSET\r
80 };\r
81 \r
82 // GLOBALS\r
83 MODULE_DEFINE(0, 0x0032, BochsVBE, BGA_Install, NULL, NULL);\r
84 tDevFS_Driver   gBGA_DriverStruct = {\r
85         NULL, "BochsGA",\r
86         {\r
87         .Read = BGA_Read,\r
88         .Write = BGA_Write,\r
89         .IOCtl = BGA_Ioctl\r
90         }\r
91 };\r
92  int    giBGA_CurrentMode = -1;\r
93  int    giBGA_DriverId = -1;\r
94 Uint    *gBGA_Framebuffer;\r
95 \r
96 // === CODE ===\r
97 /**\r
98  * \fn int BGA_Install(char **Arguments)\r
99  */\r
100 int BGA_Install(char **Arguments)\r
101 {\r
102          int    bga_version = 0;\r
103         \r
104         // Check BGA Version\r
105         bga_version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);\r
106         // NOTE: This driver was written for 0xB0C4, but they seem to be backwards compatable\r
107         if(bga_version < 0xB0C4 || bga_version > 0xB0C5) {\r
108                 Warning("[BGA ] Bochs Adapter Version is not 0xB0C4 or 0xB0C5, instead 0x%x", bga_version);\r
109                 return 0;\r
110         }\r
111         \r
112         // Install Device\r
113         giBGA_DriverId = DevFS_AddDevice( &gBGA_DriverStruct );\r
114         if(giBGA_DriverId == -1) {\r
115                 Warning("[BGA ] Unable to register with DevFS, maybe already loaded?");\r
116                 return 0;\r
117         }\r
118         \r
119         // Map Framebuffer to hardware address\r
120         gBGA_Framebuffer = (void *) MM_MapHWPage(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768);  // 768 pages (3Mb)\r
121         \r
122         return 1;\r
123 }\r
124 \r
125 /**\r
126  * \fn void BGA_Uninstall()\r
127  */\r
128 void BGA_Uninstall()\r
129 {\r
130         //DevFS_DelDevice( giBGA_DriverId );\r
131         MM_UnmapHWPage( VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768 );\r
132 }\r
133 \r
134 /**\r
135  * \fn Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
136  * \brief Read from the framebuffer\r
137  */\r
138 Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
139 {\r
140         // Check Mode\r
141         if(giBGA_CurrentMode == -1)     return -1;\r
142         \r
143         // Check Offset and Length against Framebuffer Size\r
144         if(off+len > BGA_MODES[giBGA_CurrentMode].fbSize)\r
145                 return -1;\r
146         \r
147         // Copy from Framebuffer\r
148         memcpy(buffer, (void*)((Uint)gBGA_Framebuffer + (Uint)off), len);\r
149         return len;\r
150 }\r
151 \r
152 /**\r
153  * \fn Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
154  * \brief Write to the framebuffer\r
155  */\r
156 Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
157 {\r
158         Uint8   *destBuf;\r
159         \r
160         DEBUGS("BGA_Write: (off=%i, len=0x%x)\n", off, len);\r
161         \r
162         // Check Mode\r
163         if(giBGA_CurrentMode == -1)\r
164                 return -1;\r
165         // Check Input against Frambuffer Size\r
166         if(off+len > BGA_MODES[giBGA_CurrentMode].fbSize)\r
167                 return -1;\r
168         \r
169         destBuf = (Uint8*) ((Uint)gBGA_Framebuffer + (Uint)off);\r
170         \r
171         DEBUGS(" BGA_Write: *buffer = 0x%x\n", *(Uint*)buffer);\r
172         DEBUGS(" BGA_Write: Updating Framebuffer (0x%x - 0x%x bytes)\n", \r
173                 destBuf, destBuf + (Uint)len);\r
174         \r
175         \r
176         // Copy to Frambuffer\r
177         memcpy(destBuf, buffer, len);\r
178         \r
179         DEBUGS("BGA_Write: BGA Framebuffer updated\n");\r
180         \r
181         return len;\r
182 }\r
183 \r
184 /**\r
185  * \fn INT int BGA_Ioctl(tVFS_Node *node, int id, void *data)\r
186  * \brief Handle messages to the device\r
187  */\r
188 INT int BGA_Ioctl(tVFS_Node *node, int id, void *data)\r
189 {\r
190          int    ret = -2;\r
191         ENTER("pNode iId pData", node, id, data);\r
192         \r
193         switch(id)\r
194         {\r
195         case DRV_IOCTL_TYPE:\r
196                 ret = DRV_TYPE_VIDEO;\r
197                 break;\r
198         case DRV_IOCTL_IDENT:\r
199                 memcpy(data, "BGA1", 4);\r
200                 ret = 1;\r
201                 break;\r
202         case DRV_IOCTL_VERSION:\r
203                 ret = 0x100;\r
204                 break;\r
205         case DRV_IOCTL_LOOKUP:  // TODO: Implement\r
206                 ret = 0;\r
207                 break;\r
208                 \r
209         case VIDEO_IOCTL_SETMODE:\r
210                 ret = BGA_int_UpdateMode(*(int*)(data));\r
211                 break;\r
212                 \r
213         case VIDEO_IOCTL_GETMODE:\r
214                 ret = giBGA_CurrentMode;\r
215                 break;\r
216         \r
217         case VIDEO_IOCTL_FINDMODE:\r
218                 ret = BGA_int_FindMode((tVideo_IOCtl_Mode*)data);\r
219                 break;\r
220         \r
221         case VIDEO_IOCTL_MODEINFO:\r
222                 ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)data);\r
223                 break;\r
224         \r
225         // Request Access to LFB\r
226         case VIDEO_IOCTL_REQLFB:\r
227                 ret = BGA_int_MapFB( *(void**)data );\r
228                 break;\r
229         \r
230         default:\r
231                 LEAVE('i', -2);\r
232                 return -2;\r
233         }\r
234         \r
235         LEAVE('i', ret);\r
236         return ret;\r
237 }\r
238 \r
239 //== Internal Functions ==\r
240 /**\r
241  * \fn void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\r
242  * \brief Writes to a BGA register\r
243  */\r
244 void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\r
245 {\r
246         outw(VBE_DISPI_IOPORT_INDEX, reg);\r
247         outw(VBE_DISPI_IOPORT_DATA, value);\r
248 }\r
249 \r
250 INT Uint16 BGA_int_ReadRegister(Uint16 reg)\r
251 {\r
252         outw(VBE_DISPI_IOPORT_INDEX, reg);\r
253         return inw(VBE_DISPI_IOPORT_DATA);\r
254 }\r
255 \r
256 #if 0\r
257 INT void BGA_int_SetBank(Uint16 bank)\r
258 {\r
259         BGA_int_WriteRegister(VBE_DISPI_INDEX_BANK, bank);\r
260 }\r
261 #endif\r
262 \r
263 /**\r
264  * \fn void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp)\r
265  * \brief Sets the video mode from the dimensions and bpp given\r
266  */\r
267 void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp)\r
268 {\r
269         DEBUGS("BGA_int_SetMode: (width=%i, height=%i, bpp=%i)\n", width, height, bpp);\r
270         BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);\r
271     BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, width);\r
272     BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, height);\r
273     BGA_int_WriteRegister(VBE_DISPI_INDEX_BPP,  bpp);\r
274     BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED);\r
275     //BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM);\r
276 }\r
277 \r
278 /**\r
279  * \fn int BGA_int_UpdateMode(int id)\r
280  * \brief Set current vide mode given a mode id\r
281  */\r
282 int BGA_int_UpdateMode(int id)\r
283 {\r
284         if(id < 0 || id >= BGA_MODE_COUNT)      return -1;\r
285         BGA_int_SetMode(BGA_MODES[id].width, BGA_MODES[id].height, BGA_MODES[id].bpp);\r
286         giBGA_CurrentMode = id;\r
287         return id;\r
288 }\r
289 \r
290 /**\r
291  * \fn int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
292  * \brief Find a mode matching the given options\r
293  */\r
294 int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
295 {\r
296          int    i;\r
297          int    best = -1, bestFactor = 1000;\r
298          int    factor, tmp;\r
299          int    rqdProduct = info->width * info->height * info->bpp;\r
300         \r
301         DEBUGS("BGA_int_FindMode: (info={width:%i,height:%i,bpp:%i})\n", info->width, info->height, info->bpp);\r
302         \r
303         for(i = 0; i < BGA_MODE_COUNT; i++)\r
304         {\r
305                 #if DEBUG >= 2\r
306                 LogF("Mode %i (%ix%ix%i), ", i, BGA_MODES[i].width, BGA_MODES[i].height, BGA_MODES[i].bpp);\r
307                 #endif\r
308         \r
309                 if(BGA_MODES[i].width == info->width\r
310                 && BGA_MODES[i].height == info->height\r
311                 && BGA_MODES[i].bpp == info->bpp)\r
312                 {\r
313                         #if DEBUG >= 2\r
314                         LogF("Perfect!\n");\r
315                         #endif\r
316                         best = i;\r
317                         break;\r
318                 }\r
319                 \r
320                 tmp = BGA_MODES[i].width * BGA_MODES[i].height * BGA_MODES[i].bpp;\r
321                 tmp -= rqdProduct;\r
322                 tmp = tmp < 0 ? -tmp : tmp;\r
323                 factor = tmp * 100 / rqdProduct;\r
324                 \r
325                 #if DEBUG >= 2\r
326                 LogF("factor = %i\n", factor);\r
327                 #endif\r
328                 \r
329                 if(factor < bestFactor)\r
330                 {\r
331                         bestFactor = factor;\r
332                         best = i;\r
333                 }\r
334         }\r
335         info->id = best;\r
336         info->width = BGA_MODES[best].width;\r
337         info->height = BGA_MODES[best].height;\r
338         info->bpp = BGA_MODES[best].bpp;\r
339         return best;\r
340 }\r
341 \r
342 /**\r
343  * \fn int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
344  * \brief Get mode information\r
345  */\r
346 int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
347 {\r
348         if(!info)       return -1;\r
349         if(MM_GetPhysAddr((Uint)info) == 0)\r
350                 return -1;\r
351         \r
352         if(info->id < 0 || info->id >= BGA_MODE_COUNT)  return -1;\r
353         \r
354         info->width = BGA_MODES[info->id].width;\r
355         info->height = BGA_MODES[info->id].height;\r
356         info->bpp = BGA_MODES[info->id].bpp;\r
357         \r
358         return 1;\r
359 }\r
360 \r
361 /**\r
362  * \fn int BGA_int_MapFB(void *Dest)\r
363  * \brief Map the framebuffer into a process's space\r
364  * \param Dest  User address to load to\r
365  */\r
366 int BGA_int_MapFB(void *Dest)\r
367 {\r
368         Uint    i;\r
369         Uint    pages;\r
370         \r
371         // Sanity Check\r
372         if((Uint)Dest > 0xC0000000)     return 0;\r
373         if(BGA_MODES[giBGA_CurrentMode].bpp < 15)       return 0;       // Only non-pallete modes are supported\r
374         \r
375         // Count required pages\r
376         pages = (BGA_MODES[giBGA_CurrentMode].fbSize + 0xFFF) >> 12;\r
377         \r
378         // Check if there is space\r
379         for( i = 0; i < pages; i++ )\r
380         {\r
381                 if(MM_GetPhysAddr( (Uint)Dest + (i << 12) ))\r
382                         return 0;\r
383         }\r
384         \r
385         // Map\r
386         for( i = 0; i < pages; i++ )\r
387                 MM_Map( (Uint)Dest + (i<<12), VBE_DISPI_LFB_PHYSICAL_ADDRESS + (i<<12) );\r
388         \r
389         return 1;\r
390 }\r

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