2 * Acess2 Bochs graphics adapter Driver
\r
3 * - By John Hodge (thePowersGang)
\r
9 #define VERSION VER2(0,10)
\r
13 #include <modules.h>
\r
15 #include <fs_devfs.h>
\r
16 #include <drv_pci.h>
\r
17 #include <api_drv_video.h>
\r
20 typedef struct sBGA_Mode {
\r
27 // === CONSTANTS ===
\r
28 #define BGA_LFB_MAXSIZE (1024*768*4)
\r
29 #define VBE_DISPI_BANK_ADDRESS 0xA0000
\r
30 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
\r
31 #define VBE_DISPI_IOPORT_INDEX 0x01CE
\r
32 #define VBE_DISPI_IOPORT_DATA 0x01CF
\r
33 #define VBE_DISPI_DISABLED 0x00
\r
34 #define VBE_DISPI_ENABLED 0x01
\r
35 #define VBE_DISPI_LFB_ENABLED 0x40
\r
36 #define VBE_DISPI_NOCLEARMEM 0x80
\r
39 VBE_DISPI_INDEX_XRES,
\r
40 VBE_DISPI_INDEX_YRES,
\r
41 VBE_DISPI_INDEX_BPP,
\r
42 VBE_DISPI_INDEX_ENABLE,
\r
43 VBE_DISPI_INDEX_BANK,
\r
44 VBE_DISPI_INDEX_VIRT_WIDTH,
\r
45 VBE_DISPI_INDEX_VIRT_HEIGHT,
\r
46 VBE_DISPI_INDEX_X_OFFSET,
\r
47 VBE_DISPI_INDEX_Y_OFFSET
\r
50 // === PROTOTYPES ===
\r
52 int BGA_Install(char **Arguments);
\r
53 void BGA_Uninstall();
\r
55 void BGA_int_WriteRegister(Uint16 reg, Uint16 value);
\r
56 Uint16 BGA_int_ReadRegister(Uint16 reg);
\r
57 void BGA_int_SetBank(Uint16 bank);
\r
58 void BGA_int_SetMode(Uint16 width, Uint16 height);
\r
59 int BGA_int_UpdateMode(int id);
\r
60 int BGA_int_FindMode(tVideo_IOCtl_Mode *info);
\r
61 int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info);
\r
62 int BGA_int_MapFB(void *Dest);
\r
64 size_t BGA_Read(tVFS_Node *Node, off_t off, size_t len, void *buffer, Uint Flags);
\r
65 size_t BGA_Write(tVFS_Node *Node, off_t off, size_t len, const void *buffer, Uint Flags);
\r
66 int BGA_IOCtl(tVFS_Node *Node, int ID, void *Data);
\r
69 MODULE_DEFINE(0, VERSION, BochsGA, BGA_Install, NULL, "PCI", NULL);
\r
70 tVFS_NodeType gBGA_NodeType = {
\r
75 tDevFS_Driver gBGA_DriverStruct = {
\r
77 {.Type = &gBGA_NodeType}
\r
79 int giBGA_CurrentMode = -1;
\r
80 tVideo_IOCtl_Pos gBGA_CursorPos = {-1,-1};
\r
81 Uint *gBGA_Framebuffer;
\r
82 const tBGA_Mode *gpBGA_CurrentMode;
\r
83 const tBGA_Mode gBGA_Modes[] = {
\r
84 {640,480,32, 640*480*4},
\r
85 {800,480,32, 800*480*4}, // Nice mode for VM testing
\r
86 {800,600,32, 800*600*4},
\r
87 {1024,768,32, 1024*768*4}
\r
89 #define BGA_MODE_COUNT (sizeof(gBGA_Modes)/sizeof(gBGA_Modes[0]))
\r
90 tDrvUtil_Video_BufInfo gBGA_DrvUtil_BufInfo;
\r
94 * \fn int BGA_Install(char **Arguments)
\r
96 int BGA_Install(char **Arguments)
\r
102 // Check BGA Version
\r
103 version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);
\r
104 LOG("version = 0x%x", version);
\r
105 if( version == 0xFFFF ) {
\r
106 // Floating bus, nothing there
\r
107 return MODULE_ERR_NOTNEEDED;
\r
110 // NOTE: This driver was written for BGA versions >= 0xBOC2
\r
111 // NOTE: However, Qemu is braindead and doesn't return the actual version
\r
112 if( version != 0xB0C0 && ((version & 0xFFF0) != 0xB0C0 || version < 0xB0C2) ) {
\r
113 Log_Warning("BGA", "Bochs Adapter Version is not compatible (need >= 0xB0C2), instead 0x%x", version);
\r
114 return MODULE_ERR_NOTNEEDED;
\r
117 // Get framebuffer base
\r
118 dev = PCI_GetDevice(0x1234, 0x1111, 0);
\r
120 base = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
\r
122 Log_Debug("BGA", "BARs %x,%x,%x,%x,%x,%x",
\r
123 PCI_GetBAR(dev, 0), PCI_GetBAR(dev, 1), PCI_GetBAR(dev, 2),
\r
124 PCI_GetBAR(dev, 3), PCI_GetBAR(dev, 4), PCI_GetBAR(dev, 5));
\r
125 base = PCI_GetValidBAR(dev, 0, PCI_BARTYPE_MEM);
\r
126 // TODO: Qemu/bochs have MMIO versions of the registers in BAR2
\r
127 // - This range is non-indexed
\r
128 //mmio_base = PCI_GetValidBAR(dev, 2, PCI_BARTYPE_MEM);
\r
131 // Map Framebuffer to hardware address
\r
132 gBGA_Framebuffer = (void *) MM_MapHWPages(base, 768); // 768 pages (3Mb)
\r
135 if( DevFS_AddDevice( &gBGA_DriverStruct ) == -1 )
\r
137 Log_Warning("BGA", "Unable to register with DevFS, maybe already loaded?");
\r
138 return MODULE_ERR_MISC;
\r
141 return MODULE_ERR_OK;
\r
145 * \brief Clean up driver resources before destruction
\r
147 void BGA_Uninstall(void)
\r
149 DevFS_DelDevice( &gBGA_DriverStruct );
\r
150 MM_UnmapHWPages( gBGA_Framebuffer, 768 );
\r
154 * \brief Read from the framebuffer
\r
156 size_t BGA_Read(tVFS_Node *node, off_t off, size_t len, void *buffer, Uint Flags)
\r
159 if(giBGA_CurrentMode == -1) return -1;
\r
161 // Check Offset and Length against Framebuffer Size
\r
162 if(off+len > gpBGA_CurrentMode->fbSize)
\r
165 // Copy from Framebuffer
\r
166 memcpy(buffer, (void*)((Uint)gBGA_Framebuffer + (Uint)off), len);
\r
171 * \brief Write to the framebuffer
\r
173 size_t BGA_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
\r
175 if( giBGA_CurrentMode == -1 ) BGA_int_UpdateMode(0);
\r
176 return DrvUtil_Video_WriteLFB(&gBGA_DrvUtil_BufInfo, Offset, Length, Buffer);
\r
179 const char *csaBGA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
\r
181 * \brief Handle messages to the device
\r
183 int BGA_IOCtl(tVFS_Node *Node, int ID, void *Data)
\r
186 ENTER("pNode iId pData", Node, ID, Data);
\r
190 BASE_IOCTLS(DRV_TYPE_VIDEO, "BochsGA", VERSION, csaBGA_IOCtls);
\r
192 case VIDEO_IOCTL_GETSETMODE:
\r
193 if( Data ) BGA_int_UpdateMode(*(int*)(Data));
\r
194 ret = giBGA_CurrentMode;
\r
197 case VIDEO_IOCTL_FINDMODE:
\r
198 ret = BGA_int_FindMode((tVideo_IOCtl_Mode*)Data);
\r
201 case VIDEO_IOCTL_MODEINFO:
\r
202 ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)Data);
\r
205 case VIDEO_IOCTL_SETBUFFORMAT:
\r
206 DrvUtil_Video_RemoveCursor( &gBGA_DrvUtil_BufInfo );
\r
207 ret = gBGA_DrvUtil_BufInfo.BufferFormat;
\r
209 gBGA_DrvUtil_BufInfo.BufferFormat = *(int*)Data;
\r
210 if(gBGA_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
211 DrvUtil_Video_SetCursor( &gBGA_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );
\r
214 case VIDEO_IOCTL_SETCURSOR:
\r
215 DrvUtil_Video_RemoveCursor( &gBGA_DrvUtil_BufInfo );
\r
216 gBGA_CursorPos.x = ((tVideo_IOCtl_Pos*)Data)->x;
\r
217 gBGA_CursorPos.y = ((tVideo_IOCtl_Pos*)Data)->y;
\r
218 if(gBGA_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)
\r
219 DrvUtil_Video_DrawCursor(
\r
220 &gBGA_DrvUtil_BufInfo,
\r
221 gBGA_CursorPos.x*giVT_CharWidth,
\r
222 gBGA_CursorPos.y*giVT_CharHeight
\r
225 DrvUtil_Video_DrawCursor(
\r
226 &gBGA_DrvUtil_BufInfo,
\r
227 gBGA_CursorPos.x, gBGA_CursorPos.y
\r
231 case VIDEO_IOCTL_SETCURSORBITMAP:
\r
232 DrvUtil_Video_SetCursor( &gBGA_DrvUtil_BufInfo, Data );
\r
244 //== Internal Functions ==
\r
246 * \brief Writes to a BGA register
\r
248 void BGA_int_WriteRegister(Uint16 reg, Uint16 value)
\r
250 outw(VBE_DISPI_IOPORT_INDEX, reg);
\r
251 outw(VBE_DISPI_IOPORT_DATA, value);
\r
254 Uint16 BGA_int_ReadRegister(Uint16 reg)
\r
256 outw(VBE_DISPI_IOPORT_INDEX, reg);
\r
257 return inw(VBE_DISPI_IOPORT_DATA);
\r
261 * \brief Sets the video mode (32bpp only)
\r
263 void BGA_int_SetMode(Uint16 Width, Uint16 Height)
\r
265 ENTER("iWidth iHeight", Width, Height);
\r
266 BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
\r
267 BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, Width);
\r
268 BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, Height);
\r
269 BGA_int_WriteRegister(VBE_DISPI_INDEX_BPP, 32);
\r
270 BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED);
\r
275 * \fn int BGA_int_UpdateMode(int id)
\r
276 * \brief Set current vide mode given a mode id
\r
278 int BGA_int_UpdateMode(int id)
\r
281 if(id < 0 || id >= BGA_MODE_COUNT) return -1;
\r
284 gBGA_Modes[id].width,
\r
285 gBGA_Modes[id].height);
\r
287 gBGA_DrvUtil_BufInfo.Framebuffer = gBGA_Framebuffer;
\r
288 gBGA_DrvUtil_BufInfo.Pitch = gBGA_Modes[id].width * 4;
\r
289 gBGA_DrvUtil_BufInfo.Width = gBGA_Modes[id].width;
\r
290 gBGA_DrvUtil_BufInfo.Height = gBGA_Modes[id].height;
\r
291 gBGA_DrvUtil_BufInfo.Depth = gBGA_Modes[id].bpp;
\r
293 giBGA_CurrentMode = id;
\r
294 gpBGA_CurrentMode = &gBGA_Modes[id];
\r
299 * \fn int BGA_int_FindMode(tVideo_IOCtl_Mode *info)
\r
300 * \brief Find a mode matching the given options
\r
302 int BGA_int_FindMode(tVideo_IOCtl_Mode *info)
\r
305 int best = 0, bestFactor = 1000;
\r
307 int rqdProduct = info->width * info->height;
\r
309 ENTER("pinfo", info);
\r
310 LOG("info = {width:%i,height:%i,bpp:%i})\n", info->width, info->height, info->bpp);
\r
312 for(i = 0; i < BGA_MODE_COUNT; i++)
\r
315 LOG("Mode %i (%ix%i,%ibpp), ", i, gBGA_Modes[i].width, gBGA_Modes[i].height, gBGA_Modes[i].bpp);
\r
318 if( gBGA_Modes[i].bpp != info->bpp )
\r
321 // Ooh! A perfect match
\r
322 if(gBGA_Modes[i].width == info->width && gBGA_Modes[i].height == info->height)
\r
332 // If not, how close are we?
\r
333 tmp = gBGA_Modes[i].width * gBGA_Modes[i].height - rqdProduct;
\r
334 tmp = tmp < 0 ? -tmp : tmp; // tmp = ABS(tmp)
\r
337 LOG("tmp = %i", tmp);
\r
340 if(tmp < bestFactor)
\r
348 info->width = gBGA_Modes[best].width;
\r
349 info->height = gBGA_Modes[best].height;
\r
350 info->bpp = gBGA_Modes[best].bpp;
\r
357 * \fn int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)
\r
358 * \brief Get mode information
\r
360 int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)
\r
363 //if( !MM_IsUser( (Uint)info, sizeof(tVideo_IOCtl_Mode) ) ) {
\r
367 if(info->id < 0 || info->id >= BGA_MODE_COUNT) return -1;
\r
369 info->width = gBGA_Modes[info->id].width;
\r
370 info->height = gBGA_Modes[info->id].height;
\r
371 info->bpp = gBGA_Modes[info->id].bpp;
\r