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
10 #include <fs_devfs.h>
\r
11 #include <drv_pci.h>
\r
12 #include <tpl_drv_video.h>
\r
16 # define DEBUGS(v...) SysDebug(v)
\r
18 # define DEBUGS(v...)
\r
21 //#define INT static
\r
34 // === PROTOTYPES ===
\r
36 int BGA_Install(char **Arguments);
\r
37 void BGA_Uninstall();
\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
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
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
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
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
83 MODULE_DEFINE(0, 0x0032, BochsVBE, BGA_Install, NULL, NULL);
\r
84 tDevFS_Driver gBGA_DriverStruct = {
\r
92 int giBGA_CurrentMode = -1;
\r
93 int giBGA_DriverId = -1;
\r
94 Uint *gBGA_Framebuffer;
\r
98 * \fn int BGA_Install(char **Arguments)
\r
100 int BGA_Install(char **Arguments)
\r
102 int bga_version = 0;
\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
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
119 // Map Framebuffer to hardware address
\r
120 gBGA_Framebuffer = (void *) MM_MapHWPage(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768); // 768 pages (3Mb)
\r
126 * \fn void BGA_Uninstall()
\r
128 void BGA_Uninstall()
\r
130 //DevFS_DelDevice( giBGA_DriverId );
\r
131 MM_UnmapHWPage( VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768 );
\r
135 * \fn Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
\r
136 * \brief Read from the framebuffer
\r
138 Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
\r
141 if(giBGA_CurrentMode == -1) return -1;
\r
143 // Check Offset and Length against Framebuffer Size
\r
144 if(off+len > BGA_MODES[giBGA_CurrentMode].fbSize)
\r
147 // Copy from Framebuffer
\r
148 memcpy(buffer, (void*)((Uint)gBGA_Framebuffer + (Uint)off), len);
\r
153 * \fn Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
\r
154 * \brief Write to the framebuffer
\r
156 Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)
\r
160 DEBUGS("BGA_Write: (off=%i, len=0x%x)\n", off, len);
\r
163 if(giBGA_CurrentMode == -1)
\r
165 // Check Input against Frambuffer Size
\r
166 if(off+len > BGA_MODES[giBGA_CurrentMode].fbSize)
\r
169 destBuf = (Uint8*) ((Uint)gBGA_Framebuffer + (Uint)off);
\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
176 // Copy to Frambuffer
\r
177 memcpy(destBuf, buffer, len);
\r
179 DEBUGS("BGA_Write: BGA Framebuffer updated\n");
\r
185 * \fn INT int BGA_Ioctl(tVFS_Node *node, int id, void *data)
\r
186 * \brief Handle messages to the device
\r
188 INT int BGA_Ioctl(tVFS_Node *node, int id, void *data)
\r
191 ENTER("pNode iId pData", node, id, data);
\r
195 case DRV_IOCTL_TYPE:
\r
196 ret = DRV_TYPE_VIDEO;
\r
198 case DRV_IOCTL_IDENT:
\r
199 memcpy(data, "BGA1", 4);
\r
202 case DRV_IOCTL_VERSION:
\r
205 case DRV_IOCTL_LOOKUP: // TODO: Implement
\r
209 case VIDEO_IOCTL_SETMODE:
\r
210 ret = BGA_int_UpdateMode(*(int*)(data));
\r
213 case VIDEO_IOCTL_GETMODE:
\r
214 ret = giBGA_CurrentMode;
\r
217 case VIDEO_IOCTL_FINDMODE:
\r
218 ret = BGA_int_FindMode((tVideo_IOCtl_Mode*)data);
\r
221 case VIDEO_IOCTL_MODEINFO:
\r
222 ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)data);
\r
225 // Request Access to LFB
\r
226 case VIDEO_IOCTL_REQLFB:
\r
227 ret = BGA_int_MapFB( *(void**)data );
\r
239 //== Internal Functions ==
\r
241 * \fn void BGA_int_WriteRegister(Uint16 reg, Uint16 value)
\r
242 * \brief Writes to a BGA register
\r
244 void BGA_int_WriteRegister(Uint16 reg, Uint16 value)
\r
246 outw(VBE_DISPI_IOPORT_INDEX, reg);
\r
247 outw(VBE_DISPI_IOPORT_DATA, value);
\r
250 INT Uint16 BGA_int_ReadRegister(Uint16 reg)
\r
252 outw(VBE_DISPI_IOPORT_INDEX, reg);
\r
253 return inw(VBE_DISPI_IOPORT_DATA);
\r
257 INT void BGA_int_SetBank(Uint16 bank)
\r
259 BGA_int_WriteRegister(VBE_DISPI_INDEX_BANK, bank);
\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
267 void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp)
\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
279 * \fn int BGA_int_UpdateMode(int id)
\r
280 * \brief Set current vide mode given a mode id
\r
282 int BGA_int_UpdateMode(int id)
\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
291 * \fn int BGA_int_FindMode(tVideo_IOCtl_Mode *info)
\r
292 * \brief Find a mode matching the given options
\r
294 int BGA_int_FindMode(tVideo_IOCtl_Mode *info)
\r
297 int best = -1, bestFactor = 1000;
\r
299 int rqdProduct = info->width * info->height * info->bpp;
\r
301 DEBUGS("BGA_int_FindMode: (info={width:%i,height:%i,bpp:%i})\n", info->width, info->height, info->bpp);
\r
303 for(i = 0; i < BGA_MODE_COUNT; i++)
\r
306 LogF("Mode %i (%ix%ix%i), ", i, BGA_MODES[i].width, BGA_MODES[i].height, BGA_MODES[i].bpp);
\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
314 LogF("Perfect!\n");
\r
320 tmp = BGA_MODES[i].width * BGA_MODES[i].height * BGA_MODES[i].bpp;
\r
322 tmp = tmp < 0 ? -tmp : tmp;
\r
323 factor = tmp * 100 / rqdProduct;
\r
326 LogF("factor = %i\n", factor);
\r
329 if(factor < bestFactor)
\r
331 bestFactor = factor;
\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
343 * \fn int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)
\r
344 * \brief Get mode information
\r
346 int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)
\r
348 if(!info) return -1;
\r
349 if(MM_GetPhysAddr((Uint)info) == 0)
\r
352 if(info->id < 0 || info->id >= BGA_MODE_COUNT) return -1;
\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
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
366 int BGA_int_MapFB(void *Dest)
\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
375 // Count required pages
\r
376 pages = (BGA_MODES[giBGA_CurrentMode].fbSize + 0xFFF) >> 12;
\r
378 // Check if there is space
\r
379 for( i = 0; i < pages; i++ )
\r
381 if(MM_GetPhysAddr( (Uint)Dest + (i << 12) ))
\r
386 for( i = 0; i < pages; i++ )
\r
387 MM_Map( (Uint)Dest + (i<<12), VBE_DISPI_LFB_PHYSICAL_ADDRESS + (i<<12) );
\r