Writes to stdout and VGA_WriteChars routine now update both VGA
[wine/hacks.git] / dlls / winedos / vga.c
bloba2d7e2b26f6f82a7da84eca5298e43bba9330302
1 /*
2 * VGA hardware emulation
3 *
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <string.h>
22 #include "winbase.h"
23 #include "wingdi.h"
24 #include "winuser.h"
25 #include "wincon.h"
26 #include "miscemu.h"
27 #include "dosexe.h"
28 #include "vga.h"
29 #include "ddraw.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
34 static IDirectDraw *lpddraw = NULL;
35 static IDirectDrawSurface *lpddsurf;
36 static IDirectDrawPalette *lpddpal;
37 static DDSURFACEDESC sdesc;
38 static LONG vga_refresh;
39 static HANDLE poll_timer;
41 static int vga_width;
42 static int vga_height;
43 static int vga_depth;
44 static BYTE vga_text_attr;
46 static CRITICAL_SECTION vga_lock = CRITICAL_SECTION_INIT("VGA");
48 typedef HRESULT (WINAPI *DirectDrawCreateProc)(LPGUID,LPDIRECTDRAW *,LPUNKNOWN);
49 static DirectDrawCreateProc pDirectDrawCreate;
51 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high );
54 * For simplicity, I'm creating a second palette.
55 * 16 color accesses will use these pointers and insert
56 * entries from the 64-color palette into the default
57 * palette. --Robert 'Admiral' Coeyman
60 static char vga_16_palette[17]={
61 0x00, /* 0 - Black */
62 0x01, /* 1 - Blue */
63 0x02, /* 2 - Green */
64 0x03, /* 3 - Cyan */
65 0x04, /* 4 - Red */
66 0x05, /* 5 - Magenta */
67 0x14, /* 6 - Brown */
68 0x07, /* 7 - Light gray */
69 0x38, /* 8 - Dark gray */
70 0x39, /* 9 - Light blue */
71 0x3a, /* A - Light green */
72 0x3b, /* B - Light cyan */
73 0x3c, /* C - Light red */
74 0x3d, /* D - Light magenta */
75 0x3e, /* E - Yellow */
76 0x3f, /* F - White */
77 0x00 /* Border Color */
80 static PALETTEENTRY vga_def_palette[256]={
81 /* red green blue */
82 {0x00, 0x00, 0x00}, /* 0 - Black */
83 {0x00, 0x00, 0x80}, /* 1 - Blue */
84 {0x00, 0x80, 0x00}, /* 2 - Green */
85 {0x00, 0x80, 0x80}, /* 3 - Cyan */
86 {0x80, 0x00, 0x00}, /* 4 - Red */
87 {0x80, 0x00, 0x80}, /* 5 - Magenta */
88 {0x80, 0x80, 0x00}, /* 6 - Brown */
89 {0xC0, 0xC0, 0xC0}, /* 7 - Light gray */
90 {0x80, 0x80, 0x80}, /* 8 - Dark gray */
91 {0x00, 0x00, 0xFF}, /* 9 - Light blue */
92 {0x00, 0xFF, 0x00}, /* A - Light green */
93 {0x00, 0xFF, 0xFF}, /* B - Light cyan */
94 {0xFF, 0x00, 0x00}, /* C - Light red */
95 {0xFF, 0x00, 0xFF}, /* D - Light magenta */
96 {0xFF, 0xFF, 0x00}, /* E - Yellow */
97 {0xFF, 0xFF, 0xFF}, /* F - White */
98 {0,0,0} /* FIXME: a series of continuous rainbow hues should follow */
102 * This palette is the dos default, converted from 18 bit color to 24.
103 * It contains only 64 entries of colors--all others are zeros.
104 * --Robert 'Admiral' Coeyman
106 static PALETTEENTRY vga_def64_palette[256]={
107 /* red green blue */
108 {0x00, 0x00, 0x00}, /* 0x00 Black */
109 {0x00, 0x00, 0xaa}, /* 0x01 Blue */
110 {0x00, 0xaa, 0x00}, /* 0x02 Green */
111 {0x00, 0xaa, 0xaa}, /* 0x03 Cyan */
112 {0xaa, 0x00, 0x00}, /* 0x04 Red */
113 {0xaa, 0x00, 0xaa}, /* 0x05 Magenta */
114 {0xaa, 0xaa, 0x00}, /* 0x06 */
115 {0xaa, 0xaa, 0xaa}, /* 0x07 Light Gray */
116 {0x00, 0x00, 0x55}, /* 0x08 */
117 {0x00, 0x00, 0xff}, /* 0x09 */
118 {0x00, 0xaa, 0x55}, /* 0x0a */
119 {0x00, 0xaa, 0xff}, /* 0x0b */
120 {0xaa, 0x00, 0x55}, /* 0x0c */
121 {0xaa, 0x00, 0xff}, /* 0x0d */
122 {0xaa, 0xaa, 0x55}, /* 0x0e */
123 {0xaa, 0xaa, 0xff}, /* 0x0f */
124 {0x00, 0x55, 0x00}, /* 0x10 */
125 {0x00, 0x55, 0xaa}, /* 0x11 */
126 {0x00, 0xff, 0x00}, /* 0x12 */
127 {0x00, 0xff, 0xaa}, /* 0x13 */
128 {0xaa, 0x55, 0x00}, /* 0x14 Brown */
129 {0xaa, 0x55, 0xaa}, /* 0x15 */
130 {0xaa, 0xff, 0x00}, /* 0x16 */
131 {0xaa, 0xff, 0xaa}, /* 0x17 */
132 {0x00, 0x55, 0x55}, /* 0x18 */
133 {0x00, 0x55, 0xff}, /* 0x19 */
134 {0x00, 0xff, 0x55}, /* 0x1a */
135 {0x00, 0xff, 0xff}, /* 0x1b */
136 {0xaa, 0x55, 0x55}, /* 0x1c */
137 {0xaa, 0x55, 0xff}, /* 0x1d */
138 {0xaa, 0xff, 0x55}, /* 0x1e */
139 {0xaa, 0xff, 0xff}, /* 0x1f */
140 {0x55, 0x00, 0x00}, /* 0x20 */
141 {0x55, 0x00, 0xaa}, /* 0x21 */
142 {0x55, 0xaa, 0x00}, /* 0x22 */
143 {0x55, 0xaa, 0xaa}, /* 0x23 */
144 {0xff, 0x00, 0x00}, /* 0x24 */
145 {0xff, 0x00, 0xaa}, /* 0x25 */
146 {0xff, 0xaa, 0x00}, /* 0x26 */
147 {0xff, 0xaa, 0xaa}, /* 0x27 */
148 {0x55, 0x00, 0x55}, /* 0x28 */
149 {0x55, 0x00, 0xff}, /* 0x29 */
150 {0x55, 0xaa, 0x55}, /* 0x2a */
151 {0x55, 0xaa, 0xff}, /* 0x2b */
152 {0xff, 0x00, 0x55}, /* 0x2c */
153 {0xff, 0x00, 0xff}, /* 0x2d */
154 {0xff, 0xaa, 0x55}, /* 0x2e */
155 {0xff, 0xaa, 0xff}, /* 0x2f */
156 {0x55, 0x55, 0x00}, /* 0x30 */
157 {0x55, 0x55, 0xaa}, /* 0x31 */
158 {0x55, 0xff, 0x00}, /* 0x32 */
159 {0x55, 0xff, 0xaa}, /* 0x33 */
160 {0xff, 0x55, 0x00}, /* 0x34 */
161 {0xff, 0x55, 0xaa}, /* 0x35 */
162 {0xff, 0xff, 0x00}, /* 0x36 */
163 {0xff, 0xff, 0xaa}, /* 0x37 */
164 {0x55, 0x55, 0x55}, /* 0x38 Dark Gray */
165 {0x55, 0x55, 0xff}, /* 0x39 Light Blue */
166 {0x55, 0xff, 0x55}, /* 0x3a Light Green */
167 {0x55, 0xff, 0xff}, /* 0x3b Light Cyan */
168 {0xff, 0x55, 0x55}, /* 0x3c Light Red */
169 {0xff, 0x55, 0xff}, /* 0x3d Light Magenta */
170 {0xff, 0xff, 0x55}, /* 0x3e Yellow */
171 {0xff, 0xff, 0xff}, /* 0x3f White */
172 {0,0,0} /* The next 192 entries are all zeros */
175 static HANDLE VGA_timer;
176 static HANDLE VGA_timer_thread;
178 /* set the timer rate; called in the polling thread context */
179 static void CALLBACK set_timer_rate( ULONG_PTR arg )
181 LARGE_INTEGER when;
183 when.s.LowPart = when.s.HighPart = 0;
184 SetWaitableTimer( VGA_timer, &when, arg, VGA_Poll, 0, FALSE );
187 static DWORD CALLBACK VGA_TimerThread( void *dummy )
189 for (;;) WaitForMultipleObjectsEx( 0, NULL, FALSE, INFINITE, TRUE );
192 static void VGA_DeinstallTimer(void)
194 if (VGA_timer_thread)
196 CancelWaitableTimer( VGA_timer );
197 CloseHandle( VGA_timer );
198 TerminateThread( VGA_timer_thread, 0 );
199 CloseHandle( VGA_timer_thread );
200 VGA_timer_thread = 0;
204 static void VGA_InstallTimer(unsigned Rate)
206 if (!VGA_timer_thread)
208 VGA_timer = CreateWaitableTimerA( NULL, FALSE, NULL );
209 VGA_timer_thread = CreateThread( NULL, 0, VGA_TimerThread, NULL, 0, NULL );
211 QueueUserAPC( set_timer_rate, VGA_timer_thread, (ULONG_PTR)Rate );
214 HANDLE VGA_AlphaConsole(void)
216 /* this assumes that no Win32 redirection has taken place, but then again,
217 * only 16-bit apps are likely to use this part of Wine... */
218 return GetStdHandle(STD_OUTPUT_HANDLE);
221 char*VGA_AlphaBuffer(void)
223 return DOSMEM_MapDosToLinear(0xb8000);
226 /*** GRAPHICS MODE ***/
228 typedef struct {
229 unsigned Xres, Yres, Depth;
230 int ret;
231 } ModeSet;
233 static void WINAPI VGA_DoSetMode(ULONG_PTR arg)
235 LRESULT res;
236 HWND hwnd;
237 ModeSet *par = (ModeSet *)arg;
238 par->ret=1;
240 if (lpddraw) VGA_Exit();
241 if (!lpddraw) {
242 if (!pDirectDrawCreate)
244 HMODULE hmod = LoadLibraryA( "ddraw.dll" );
245 if (hmod) pDirectDrawCreate = (DirectDrawCreateProc)GetProcAddress( hmod, "DirectDrawCreate" );
246 if (!pDirectDrawCreate) {
247 ERR("Can't lookup DirectDrawCreate from ddraw.dll.\n");
248 return;
251 res = pDirectDrawCreate(NULL,&lpddraw,NULL);
252 if (!lpddraw) {
253 ERR("DirectDraw is not available (res = %lx)\n",res);
254 return;
256 hwnd = CreateWindowExA(0,"STATIC","WINEDOS VGA",WS_POPUP|WS_BORDER|WS_CAPTION|WS_SYSMENU,0,0,par->Xres,par->Yres,0,0,0,NULL);
257 if (!hwnd) {
258 ERR("Failed to create user window.\n");
260 if ((res=IDirectDraw_SetCooperativeLevel(lpddraw,hwnd,DDSCL_FULLSCREEN|DDSCL_EXCLUSIVE))) {
261 ERR("Could not set cooperative level to exclusive (%lx)\n",res);
264 if ((res=IDirectDraw_SetDisplayMode(lpddraw,par->Xres,par->Yres,par->Depth))) {
265 ERR("DirectDraw does not support requested display mode (%dx%dx%d), res = %lx!\n",par->Xres,par->Yres,par->Depth,res);
266 IDirectDraw_Release(lpddraw);
267 lpddraw=NULL;
268 return;
271 res=IDirectDraw_CreatePalette(lpddraw,DDPCAPS_8BIT,NULL,&lpddpal,NULL);
272 if (res) {
273 ERR("Could not create palette (res = %lx)\n",res);
274 IDirectDraw_Release(lpddraw);
275 lpddraw=NULL;
276 return;
278 if ((res=IDirectDrawPalette_SetEntries(lpddpal,0,0,256,vga_def_palette))) {
279 ERR("Could not set default palette entries (res = %lx)\n", res);
282 memset(&sdesc,0,sizeof(sdesc));
283 sdesc.dwSize=sizeof(sdesc);
284 sdesc.dwFlags = DDSD_CAPS;
285 sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
286 if (IDirectDraw_CreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
287 ERR("DirectDraw surface is not available\n");
288 IDirectDraw_Release(lpddraw);
289 lpddraw=NULL;
290 return;
292 IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
293 vga_refresh=0;
294 /* poll every 20ms (50fps should provide adequate responsiveness) */
295 VGA_InstallTimer(20);
297 par->ret=0;
298 return;
301 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
303 ModeSet par;
305 vga_width = Xres;
306 vga_height = Yres;
307 vga_depth = Depth;
309 if(Xres >= 640 || Yres >= 480) {
310 par.Xres = Xres;
311 par.Yres = Yres;
312 } else {
313 par.Xres = 640;
314 par.Yres = 480;
317 par.Depth = (Depth < 8) ? 8 : Depth;
319 MZ_RunInThread(VGA_DoSetMode, (ULONG_PTR)&par);
320 return par.ret;
323 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
325 if (!lpddraw) return 1;
326 if (!lpddsurf) return 1;
327 if (Height) *Height=sdesc.dwHeight;
328 if (Width) *Width=sdesc.dwWidth;
329 if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
330 return 0;
333 static void WINAPI VGA_DoExit(ULONG_PTR arg)
335 VGA_DeinstallTimer();
336 IDirectDrawSurface_SetPalette(lpddsurf,NULL);
337 IDirectDrawSurface_Release(lpddsurf);
338 lpddsurf=NULL;
339 IDirectDrawPalette_Release(lpddpal);
340 lpddpal=NULL;
341 IDirectDraw_Release(lpddraw);
342 lpddraw=NULL;
345 void VGA_Exit(void)
347 if (lpddraw) MZ_RunInThread(VGA_DoExit, 0);
350 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
352 if (!lpddraw) return;
353 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
356 /* set a single color in 16 color mode. */
357 void VGA_SetColor16(int reg,int color)
359 PALETTEENTRY *pal;
361 if (!lpddraw) return;
362 pal= &vga_def64_palette[color];
363 IDirectDrawPalette_SetEntries(lpddpal,0,reg,1,pal);
364 vga_16_palette[reg]=(char)color;
367 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
369 PALETTEENTRY pal[256];
370 int c;
372 if (!lpddraw) return;
373 for (c=0; c<len; c++) {
374 pal[c].peRed =color[c].rgbRed;
375 pal[c].peGreen=color[c].rgbGreen;
376 pal[c].peBlue =color[c].rgbBlue;
377 pal[c].peFlags=0;
379 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
382 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
384 if (!lpddraw) return NULL;
385 if (!lpddsurf) return NULL;
386 if (IDirectDrawSurface_Lock(lpddsurf,NULL,&sdesc,0,0)) {
387 ERR("could not lock surface!\n");
388 return NULL;
390 if (Pitch) *Pitch=sdesc.u1.lPitch;
391 if (Height) *Height=sdesc.dwHeight;
392 if (Width) *Width=sdesc.dwWidth;
393 if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
394 return sdesc.lpSurface;
397 void VGA_Unlock(void)
399 IDirectDrawSurface_Unlock(lpddsurf,sdesc.lpSurface);
402 /*** TEXT MODE ***/
404 int VGA_SetAlphaMode(unsigned Xres,unsigned Yres)
406 COORD siz;
408 if (lpddraw) VGA_Exit();
410 /* FIXME: Where to initialize text attributes? */
411 VGA_SetTextAttribute(0xf);
413 /* the xterm is slow, so refresh only every 200ms (5fps) */
414 VGA_InstallTimer(200);
416 siz.X = Xres;
417 siz.Y = Yres;
418 SetConsoleScreenBufferSize(VGA_AlphaConsole(),siz);
419 return 0;
422 void VGA_GetAlphaMode(unsigned*Xres,unsigned*Yres)
424 CONSOLE_SCREEN_BUFFER_INFO info;
425 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info);
426 if (Xres) *Xres=info.dwSize.X;
427 if (Yres) *Yres=info.dwSize.Y;
430 void VGA_SetCursorPos(unsigned X,unsigned Y)
432 COORD pos;
434 if (!poll_timer) VGA_SetAlphaMode(80, 25);
435 pos.X = X;
436 pos.Y = Y;
437 SetConsoleCursorPosition(VGA_AlphaConsole(),pos);
440 void VGA_GetCursorPos(unsigned*X,unsigned*Y)
442 CONSOLE_SCREEN_BUFFER_INFO info;
443 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info);
444 if (X) *X=info.dwCursorPosition.X;
445 if (Y) *Y=info.dwCursorPosition.Y;
448 void VGA_WriteChars(unsigned X,unsigned Y,unsigned ch,int attr,int count)
450 CHAR_INFO info;
451 COORD siz, off;
452 SMALL_RECT dest;
453 unsigned XR, YR;
454 char *dat;
456 EnterCriticalSection(&vga_lock);
458 info.Char.AsciiChar = ch;
459 info.Attributes = (WORD)attr;
460 siz.X = 1;
461 siz.Y = 1;
462 off.X = 0;
463 off.Y = 0;
464 dest.Top=Y;
465 dest.Bottom=Y;
467 VGA_GetAlphaMode(&XR, &YR);
468 dat = VGA_AlphaBuffer() + ((XR*Y + X) * 2);
469 while (count--) {
470 dest.Left = X + count;
471 dest.Right = X + count;
473 *dat++ = ch;
474 if (attr>=0)
475 *dat = attr;
476 else
477 info.Attributes = *dat;
478 dat++;
480 WriteConsoleOutputA(VGA_AlphaConsole(), &info, siz, off, &dest);
483 LeaveCriticalSection(&vga_lock);
486 static void VGA_PutCharAt(BYTE ascii, unsigned x, unsigned y)
488 unsigned width, height;
489 char *dat;
491 VGA_GetAlphaMode(&width, &height);
492 dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
493 dat[0] = ascii;
494 dat[1] = vga_text_attr;
497 void VGA_PutChar(BYTE ascii)
499 unsigned width, height, x, y, nx, ny;
501 EnterCriticalSection(&vga_lock);
503 VGA_GetAlphaMode(&width, &height);
504 VGA_GetCursorPos(&x, &y);
506 switch(ascii) {
507 case '\b':
508 VGA_PutCharAt(' ', x, y);
509 x--;
510 break;
512 case '\t':
513 x += ((x + 8) & ~7) - x;
514 break;
516 case '\n':
517 y++;
518 x = 0;
519 break;
521 case '\a':
522 break;
524 case '\r':
525 x = 0;
526 break;
528 default:
529 VGA_PutCharAt(ascii, x, y);
530 x++;
534 * FIXME: add line wrapping and scrolling
537 WriteFile(VGA_AlphaConsole(), &ascii, 1, NULL, NULL);
540 * The following is just a sanity check.
542 VGA_GetCursorPos(&nx, &ny);
543 if(nx != x || ny != y)
544 WARN("VGA emulator and text console have become unsynchronized.\n");
546 LeaveCriticalSection(&vga_lock);
549 void VGA_SetTextAttribute(BYTE attr)
551 vga_text_attr = attr;
552 SetConsoleTextAttribute(VGA_AlphaConsole(), attr);
555 /*** CONTROL ***/
557 static void VGA_Poll_Graphics(void)
559 unsigned int Pitch, Height, Width, X, Y;
560 char *surf;
561 char *dat = DOSMEM_MapDosToLinear(0xa0000);
563 surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
564 if (!surf) return;
566 if(vga_width == 320 && vga_depth <= 4)
567 for (Y=0; Y<vga_height; Y++,surf+=Pitch*2,dat+=vga_width/8) {
568 for(X=0; X<vga_width; X+=8) {
569 int offset = X/8;
570 int Z;
571 for(Z=0; Z<8; Z++) {
572 int b0 = (dat[offset] >> Z) & 0x1;
573 int index = 7-Z;
574 surf[(X+index)*2] = b0;
575 surf[(X+index)*2+1] = b0;
576 surf[(X+index)*2+Pitch] = b0;
577 surf[(X+index)*2+Pitch+1] = b0;
582 if(vga_width == 320 && vga_depth == 8)
583 for (Y=0; Y<vga_height; Y++,surf+=Pitch*2,dat+=vga_width) {
584 for(X=0; X<vga_width; X++) {
585 int b0 = dat[X];
586 surf[X*2] = b0;
587 surf[X*2+1] = b0;
588 surf[X*2+Pitch] = b0;
589 surf[X*2+Pitch+1] = b0;
593 if(vga_depth <= 4)
594 for (Y=0; Y<vga_height; Y++,surf+=Pitch,dat+=vga_width/8) {
595 for(X=0; X<vga_width; X+=8) {
596 int offset = X/8;
597 int Z;
598 for(Z=0; Z<8; Z++) {
599 int b0 = (dat[offset] >> Z) & 0x1;
600 int index = 7-Z;
601 surf[X+index] = b0;
606 VGA_Unlock();
609 static void VGA_Poll_Text(void)
611 char *dat;
612 unsigned int Height,Width,Y,X;
613 CHAR_INFO ch[80];
614 COORD siz, off;
615 SMALL_RECT dest;
616 HANDLE con = VGA_AlphaConsole();
618 VGA_GetAlphaMode(&Width,&Height);
619 dat = VGA_AlphaBuffer();
620 siz.X = 80; siz.Y = 1;
621 off.X = 0; off.Y = 0;
622 /* copy from virtual VGA frame buffer to console */
623 for (Y=0; Y<Height; Y++) {
624 dest.Top=Y; dest.Bottom=Y;
625 for (X=0; X<Width; X++) {
626 ch[X].Char.AsciiChar = *dat++;
627 /* WriteConsoleOutputA doesn't like "dead" chars */
628 if (ch[X].Char.AsciiChar == '\0')
629 ch[X].Char.AsciiChar = ' ';
630 ch[X].Attributes = *dat++;
632 dest.Left=0; dest.Right=Width+1;
633 WriteConsoleOutputA(con, ch, siz, off, &dest);
637 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high )
639 if(!TryEnterCriticalSection(&vga_lock))
640 return;
642 /* FIXME: optimize by doing this only if the data has actually changed
643 * (in a way similar to DIBSection, perhaps) */
644 if (lpddraw) {
645 VGA_Poll_Graphics();
646 } else {
647 VGA_Poll_Text();
650 vga_refresh=1;
651 LeaveCriticalSection(&vga_lock);
654 static BYTE palreg,palcnt;
655 static PALETTEENTRY paldat;
657 void VGA_ioport_out( WORD port, BYTE val )
659 switch (port) {
660 case 0x3c8:
661 palreg=val; palcnt=0; break;
662 case 0x3c9:
663 ((BYTE*)&paldat)[palcnt++]=val << 2;
664 if (palcnt==3) {
665 VGA_SetPalette(&paldat,palreg++,1);
666 palcnt=0;
668 break;
672 BYTE VGA_ioport_in( WORD port )
674 BYTE ret;
676 switch (port) {
677 case 0x3da:
678 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
679 we need to fake the occurrence of the vertical refresh */
680 ret=vga_refresh?0x00:0x08;
681 vga_refresh=0;
682 break;
683 default:
684 ret=0xff;
686 return ret;
689 void VGA_Clean(void)
691 VGA_Exit();
692 VGA_DeinstallTimer();