]>
Commit | Line | Data |
---|---|---|
c7de829c WD |
1 | /**************************************************************************** |
2 | * | |
3 | * The SuperVGA Kit - UniVBE Software Development Kit | |
4 | * | |
5 | * ======================================================================== | |
6 | * | |
7 | * The contents of this file are subject to the SciTech MGL Public | |
8 | * License Version 1.0 (the "License"); you may not use this file | |
9 | * except in compliance with the License. You may obtain a copy of | |
10 | * the License at http://www.scitechsoft.com/mgl-license.txt | |
11 | * | |
12 | * Software distributed under the License is distributed on an | |
13 | * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | |
14 | * implied. See the License for the specific language governing | |
15 | * rights and limitations under the License. | |
16 | * | |
17 | * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. | |
18 | * | |
19 | * The Initial Developer of the Original Code is SciTech Software, Inc. | |
20 | * All Rights Reserved. | |
21 | * | |
22 | * ======================================================================== | |
23 | * | |
24 | * Language: ANSI C | |
25 | * Environment: IBM PC Real Mode and 16/32 bit Protected Mode. | |
26 | * | |
27 | * Description: Module to implement a C callable interface to the standard | |
28 | * VESA VBE routines. You should rip out this module and use it | |
29 | * directly in your own applications, or you can use the | |
30 | * high level SDK functions. | |
31 | * | |
32 | * MUST be compiled in the LARGE or FLAT models. | |
33 | * | |
34 | ****************************************************************************/ | |
35 | ||
36 | #include <stdio.h> | |
37 | #include <stdlib.h> | |
38 | #include <string.h> | |
39 | #include "vesavbe.h" | |
40 | #include "pmapi.h" | |
41 | #include "drvlib/os/os.h" | |
42 | ||
43 | /*---------------------------- Global Variables ---------------------------*/ | |
44 | ||
45 | #define VBE_SUCCESS 0x004F | |
46 | #define MAX_LIN_PTRS 10 | |
47 | ||
48 | static uint VESABuf_len = 1024;/* Length of the VESABuf buffer */ | |
49 | static ibool haveRiva128; /* True if we have a Riva128 */ | |
50 | static VBE_state defState = {0}; /* Default state buffer */ | |
51 | static VBE_state *state = &defState; /* Pointer to current buffer */ | |
52 | static int VBE_shared = 0; | |
53 | #ifndef REALMODE | |
54 | static char localBuf[512]; /* Global PM string translate buf */ | |
55 | #define MAX_LOCAL_BUF &localBuf[511] | |
56 | #endif | |
57 | ||
58 | /*----------------------------- Implementation ----------------------------*/ | |
59 | ||
60 | /* static function in WinDirect for passing 32-bit registers to BIOS */ | |
61 | int PMAPI WD_int386(int intno, RMREGS *in, RMREGS *out); | |
62 | ||
63 | void VBEAPI VBE_init(void) | |
64 | /**************************************************************************** | |
65 | * | |
66 | * Function: VBE_init | |
67 | * | |
68 | * Description: Initialises the VBE transfer buffer in real mode DC.memory. | |
69 | * This routine is called by the VESAVBE module every time | |
70 | * it needs to use the transfer buffer, so we simply allocate | |
71 | * it once and then return. | |
72 | * | |
73 | ****************************************************************************/ | |
74 | { | |
75 | if (!state->VESABuf_ptr) { | |
8bde7f77 WD |
76 | /* Allocate a global buffer for communicating with the VESA VBE */ |
77 | if ((state->VESABuf_ptr = PM_getVESABuf(&VESABuf_len, &state->VESABuf_rseg, &state->VESABuf_roff)) == NULL) | |
78 | PM_fatalError("VESAVBE.C: Real mode memory allocation failed!"); | |
79 | } | |
c7de829c WD |
80 | } |
81 | ||
82 | void * VBEAPI VBE_getRMBuf(uint *len,uint *rseg,uint *roff) | |
83 | /**************************************************************************** | |
84 | * | |
85 | * Function: VBE_getRMBuf | |
86 | * | |
87 | * Description: This function returns the location and length of the real | |
88 | * mode memory buffer for calling real mode functions. | |
89 | * | |
90 | ****************************************************************************/ | |
91 | { | |
92 | *len = VESABuf_len; | |
93 | *rseg = state->VESABuf_rseg; | |
94 | *roff = state->VESABuf_roff; | |
95 | return state->VESABuf_ptr; | |
96 | } | |
97 | ||
98 | void VBEAPI VBE_setStateBuffer(VBE_state *s) | |
99 | /**************************************************************************** | |
100 | * | |
101 | * Function: VBE_setStateBuffer | |
102 | * | |
103 | * Description: This functions sets the internal state buffer for the | |
104 | * VBE module to the passed in buffer. By default the internal | |
105 | * global buffer is used, but you must use separate buffers | |
106 | * for each device in a multi-controller environment. | |
107 | * | |
108 | ****************************************************************************/ | |
109 | { | |
110 | state = s; | |
111 | } | |
112 | ||
113 | void VBEAPI VBE_callESDI(RMREGS *regs, void *buffer, int size) | |
114 | /**************************************************************************** | |
115 | * | |
116 | * Function: VBE_callESDI | |
117 | * Parameters: regs - Registers to load when calling VBE | |
118 | * buffer - Buffer to copy VBE info block to | |
119 | * size - Size of buffer to fill | |
120 | * | |
121 | * Description: Calls the VESA VBE and passes in a buffer for the VBE to | |
122 | * store information in, which is then copied into the users | |
123 | * buffer space. This works in protected mode as the buffer | |
124 | * passed to the VESA VBE is allocated in conventional | |
125 | * memory, and is then copied into the users memory block. | |
126 | * | |
127 | ****************************************************************************/ | |
128 | { | |
129 | RMSREGS sregs; | |
130 | ||
131 | if (!state->VESABuf_ptr) | |
8bde7f77 | 132 | PM_fatalError("You *MUST* call VBE_init() before you can call the VESAVBE.C module!"); |
c7de829c WD |
133 | sregs.es = (ushort)state->VESABuf_rseg; |
134 | regs->x.di = (ushort)state->VESABuf_roff; | |
135 | memcpy(state->VESABuf_ptr, buffer, size); | |
136 | PM_int86x(0x10, regs, regs, &sregs); | |
137 | memcpy(buffer, state->VESABuf_ptr, size); | |
138 | } | |
139 | ||
140 | #ifndef REALMODE | |
141 | static char *VBE_copyStrToLocal(char *p,char *realPtr,char *max) | |
142 | /**************************************************************************** | |
143 | * | |
144 | * Function: VBE_copyStrToLocal | |
145 | * Parameters: p - Flat model buffer to copy to | |
146 | * realPtr - Real mode pointer to copy | |
147 | * Returns: Pointer to the next byte after string | |
148 | * | |
149 | * Description: Copies the string from the real mode location pointed to | |
150 | * by 'realPtr' into the flat model buffer pointed to by | |
151 | * 'p'. We return a pointer to the next byte past the copied | |
152 | * string. | |
153 | * | |
154 | ****************************************************************************/ | |
155 | { | |
156 | uchar *v; | |
157 | ||
158 | v = PM_mapRealPointer((uint)((ulong)realPtr >> 16), (uint)((ulong)realPtr & 0xFFFF)); | |
159 | while (*v != 0 && p < max) | |
8bde7f77 | 160 | *p++ = *v++; |
c7de829c WD |
161 | *p++ = 0; |
162 | return p; | |
163 | } | |
164 | ||
165 | static void VBE_copyShortToLocal(ushort *p,ushort *realPtr) | |
166 | /**************************************************************************** | |
167 | * | |
168 | * Function: VBE_copyShortToLocal | |
169 | * Parameters: p - Flat model buffer to copy to | |
170 | * realPtr - Real mode pointer to copy | |
171 | * | |
172 | * Description: Copies the mode table from real mode memory to the flat | |
173 | * model buffer. | |
174 | * | |
175 | ****************************************************************************/ | |
176 | { | |
177 | ushort *v; | |
178 | ||
179 | v = PM_mapRealPointer((uint)((ulong)realPtr >> 16),(uint)((ulong)realPtr & 0xFFFF)); | |
180 | while (*v != 0xFFFF) | |
8bde7f77 | 181 | *p++ = *v++; |
c7de829c WD |
182 | *p = 0xFFFF; |
183 | } | |
184 | #endif | |
185 | ||
186 | int VBEAPI VBE_detectEXT(VBE_vgaInfo *vgaInfo,ibool forceUniVBE) | |
187 | /**************************************************************************** | |
188 | * | |
189 | * Function: VBE_detect | |
190 | * Parameters: vgaInfo - Place to store the VGA information block | |
191 | * Returns: VBE version number, or 0 if not detected. | |
192 | * | |
193 | * Description: Detects if a VESA VBE is out there and functioning | |
194 | * correctly. If we detect a VBE interface we return the | |
195 | * VGAInfoBlock returned by the VBE and the VBE version number. | |
196 | * | |
197 | ****************************************************************************/ | |
198 | { | |
199 | RMREGS regs; | |
200 | ||
201 | regs.x.ax = 0x4F00; /* Get SuperVGA information */ | |
202 | if (forceUniVBE) { | |
8bde7f77 WD |
203 | regs.x.bx = 0x1234; |
204 | regs.x.cx = 0x4321; | |
205 | } | |
c7de829c | 206 | else { |
8bde7f77 WD |
207 | regs.x.bx = 0; |
208 | regs.x.cx = 0; | |
209 | } | |
c7de829c WD |
210 | strncpy(vgaInfo->VESASignature,"VBE2",4); |
211 | VBE_callESDI(®s, vgaInfo, sizeof(*vgaInfo)); | |
212 | if (regs.x.ax != VBE_SUCCESS) | |
8bde7f77 | 213 | return 0; |
c7de829c | 214 | if (strncmp(vgaInfo->VESASignature,"VESA",4) != 0) |
8bde7f77 | 215 | return 0; |
c7de829c WD |
216 | |
217 | /* Check for bogus BIOSes that return a VBE version number that is | |
218 | * not correct, and fix it up. We also check the OemVendorNamePtr for a | |
219 | * valid value, and if it is invalid then we also reset to VBE 1.2. | |
220 | */ | |
221 | if (vgaInfo->VESAVersion >= 0x200 && vgaInfo->OemVendorNamePtr == 0) | |
8bde7f77 | 222 | vgaInfo->VESAVersion = 0x102; |
c7de829c WD |
223 | #ifndef REALMODE |
224 | /* Relocate all the indirect information (mode tables, OEM strings | |
225 | * etc) from the low 1Mb memory region into a static buffer in | |
226 | * our default data segment. We do this to insulate the application | |
227 | * from mapping the strings from real mode to protected mode. | |
228 | */ | |
229 | { | |
8bde7f77 | 230 | char *p,*p2; |
c7de829c WD |
231 | p2 = VBE_copyStrToLocal(localBuf,vgaInfo->OemStringPtr,MAX_LOCAL_BUF); |
232 | vgaInfo->OemStringPtr = localBuf; | |
233 | if (vgaInfo->VESAVersion >= 0x200) { | |
8bde7f77 WD |
234 | p = VBE_copyStrToLocal(p2,vgaInfo->OemVendorNamePtr,MAX_LOCAL_BUF); |
235 | vgaInfo->OemVendorNamePtr = p2; | |
236 | p2 = VBE_copyStrToLocal(p,vgaInfo->OemProductNamePtr,MAX_LOCAL_BUF); | |
237 | vgaInfo->OemProductNamePtr = p; | |
238 | p = VBE_copyStrToLocal(p2,vgaInfo->OemProductRevPtr,MAX_LOCAL_BUF); | |
239 | vgaInfo->OemProductRevPtr = p2; | |
240 | VBE_copyShortToLocal((ushort*)p,vgaInfo->VideoModePtr); | |
241 | vgaInfo->VideoModePtr = (ushort*)p; | |
242 | } | |
c7de829c | 243 | else { |
8bde7f77 WD |
244 | VBE_copyShortToLocal((ushort*)p2,vgaInfo->VideoModePtr); |
245 | vgaInfo->VideoModePtr = (ushort*)p2; | |
246 | } | |
c7de829c WD |
247 | } |
248 | #endif | |
249 | state->VBEMemory = vgaInfo->TotalMemory * 64; | |
250 | ||
251 | /* Check for Riva128 based cards since they have broken triple buffering | |
252 | * and stereo support. | |
253 | */ | |
254 | haveRiva128 = false; | |
255 | if (vgaInfo->VESAVersion >= 0x300 && | |
8bde7f77 WD |
256 | (strstr(vgaInfo->OemStringPtr,"NVidia") != NULL || |
257 | strstr(vgaInfo->OemStringPtr,"Riva") != NULL)) { | |
258 | haveRiva128 = true; | |
259 | } | |
c7de829c WD |
260 | |
261 | /* Check for Matrox G400 cards which claim to be VBE 3.0 | |
262 | * compliant yet they don't implement the refresh rate control | |
263 | * functions. | |
264 | */ | |
265 | if (vgaInfo->VESAVersion >= 0x300 && (strcmp(vgaInfo->OemProductNamePtr,"Matrox G400") == 0)) | |
8bde7f77 | 266 | vgaInfo->VESAVersion = 0x200; |
c7de829c WD |
267 | return (state->VBEVersion = vgaInfo->VESAVersion); |
268 | } | |
269 | ||
270 | int VBEAPI VBE_detect(VBE_vgaInfo *vgaInfo) | |
271 | /**************************************************************************** | |
272 | * | |
273 | * Function: VBE_detect | |
274 | * Parameters: vgaInfo - Place to store the VGA information block | |
275 | * Returns: VBE version number, or 0 if not detected. | |
276 | * | |
277 | * Description: Detects if a VESA VBE is out there and functioning | |
278 | * correctly. If we detect a VBE interface we return the | |
279 | * VGAInfoBlock returned by the VBE and the VBE version number. | |
280 | * | |
281 | ****************************************************************************/ | |
282 | { | |
283 | return VBE_detectEXT(vgaInfo,false); | |
284 | } | |
285 | ||
286 | ibool VBEAPI VBE_getModeInfo(int mode,VBE_modeInfo *modeInfo) | |
287 | /**************************************************************************** | |
288 | * | |
289 | * Function: VBE_getModeInfo | |
290 | * Parameters: mode - VBE mode to get information for | |
291 | * modeInfo - Place to store VBE mode information | |
292 | * Returns: True on success, false if function failed. | |
293 | * | |
294 | * Description: Obtains information about a specific video mode from the | |
295 | * VBE. You should use this function to find the video mode | |
296 | * you wish to set, as the new VBE 2.0 mode numbers may be | |
297 | * completely arbitrary. | |
298 | * | |
299 | ****************************************************************************/ | |
300 | { | |
301 | RMREGS regs; | |
302 | int bits; | |
303 | ||
304 | regs.x.ax = 0x4F01; /* Get mode information */ | |
305 | regs.x.cx = (ushort)mode; | |
306 | VBE_callESDI(®s, modeInfo, sizeof(*modeInfo)); | |
307 | if (regs.x.ax != VBE_SUCCESS) | |
8bde7f77 | 308 | return false; |
c7de829c | 309 | if ((modeInfo->ModeAttributes & vbeMdAvailable) == 0) |
8bde7f77 | 310 | return false; |
c7de829c WD |
311 | |
312 | /* Map out triple buffer and stereo flags for NVidia Riva128 | |
313 | * chips. | |
314 | */ | |
315 | if (haveRiva128) { | |
8bde7f77 WD |
316 | modeInfo->ModeAttributes &= ~vbeMdTripleBuf; |
317 | modeInfo->ModeAttributes &= ~vbeMdStereo; | |
318 | } | |
c7de829c WD |
319 | |
320 | /* Support old style RGB definitions for VBE 1.1 BIOSes */ | |
321 | bits = modeInfo->BitsPerPixel; | |
322 | if (modeInfo->MemoryModel == vbeMemPK && bits > 8) { | |
8bde7f77 WD |
323 | modeInfo->MemoryModel = vbeMemRGB; |
324 | switch (bits) { | |
325 | case 15: | |
326 | modeInfo->RedMaskSize = 5; | |
327 | modeInfo->RedFieldPosition = 10; | |
328 | modeInfo->GreenMaskSize = 5; | |
329 | modeInfo->GreenFieldPosition = 5; | |
330 | modeInfo->BlueMaskSize = 5; | |
331 | modeInfo->BlueFieldPosition = 0; | |
332 | modeInfo->RsvdMaskSize = 1; | |
333 | modeInfo->RsvdFieldPosition = 15; | |
334 | break; | |
335 | case 16: | |
336 | modeInfo->RedMaskSize = 5; | |
337 | modeInfo->RedFieldPosition = 11; | |
338 | modeInfo->GreenMaskSize = 5; | |
339 | modeInfo->GreenFieldPosition = 5; | |
340 | modeInfo->BlueMaskSize = 5; | |
341 | modeInfo->BlueFieldPosition = 0; | |
342 | modeInfo->RsvdMaskSize = 0; | |
343 | modeInfo->RsvdFieldPosition = 0; | |
344 | break; | |
345 | case 24: | |
346 | modeInfo->RedMaskSize = 8; | |
347 | modeInfo->RedFieldPosition = 16; | |
348 | modeInfo->GreenMaskSize = 8; | |
349 | modeInfo->GreenFieldPosition = 8; | |
350 | modeInfo->BlueMaskSize = 8; | |
351 | modeInfo->BlueFieldPosition = 0; | |
352 | modeInfo->RsvdMaskSize = 0; | |
353 | modeInfo->RsvdFieldPosition = 0; | |
354 | break; | |
355 | } | |
356 | } | |
c7de829c WD |
357 | |
358 | /* Convert the 32k direct color modes of VBE 1.2+ BIOSes to | |
359 | * be recognised as 15 bits per pixel modes. | |
360 | */ | |
361 | if (bits == 16 && modeInfo->RsvdMaskSize == 1) | |
8bde7f77 | 362 | modeInfo->BitsPerPixel = 15; |
c7de829c WD |
363 | |
364 | /* Fix up bogus BIOS'es that report incorrect reserved pixel masks | |
365 | * for 32K color modes. Quite a number of BIOS'es have this problem, | |
366 | * and this affects our OS/2 drivers in VBE fallback mode. | |
367 | */ | |
368 | if (bits == 15 && (modeInfo->RsvdMaskSize != 1 || modeInfo->RsvdFieldPosition != 15)) { | |
8bde7f77 WD |
369 | modeInfo->RsvdMaskSize = 1; |
370 | modeInfo->RsvdFieldPosition = 15; | |
371 | } | |
c7de829c WD |
372 | return true; |
373 | } | |
374 | ||
375 | long VBEAPI VBE_getPageSize(VBE_modeInfo *mi) | |
376 | /**************************************************************************** | |
377 | * | |
378 | * Function: VBE_getPageSize | |
379 | * Parameters: mi - Pointer to mode information block | |
380 | * Returns: Caculated page size in bytes rounded to correct boundary | |
381 | * | |
382 | * Description: Computes the page size in bytes for the specified mode | |
383 | * information block, rounded up to the appropriate boundary | |
384 | * (8k, 16k, 32k or 64k). Pages >= 64k in size are always | |
385 | * rounded to the nearest 64k boundary (so the start of a | |
386 | * page is always bank aligned). | |
387 | * | |
388 | ****************************************************************************/ | |
389 | { | |
390 | long size; | |
391 | ||
392 | size = (long)mi->BytesPerScanLine * (long)mi->YResolution; | |
393 | if (mi->BitsPerPixel == 4) { | |
8bde7f77 WD |
394 | /* We have a 16 color video mode, so round up the page size to |
395 | * 8k, 16k, 32k or 64k boundaries depending on how large it is. | |
396 | */ | |
397 | ||
398 | size = (size + 0x1FFFL) & 0xFFFFE000L; | |
399 | if (size != 0x2000) { | |
400 | size = (size + 0x3FFFL) & 0xFFFFC000L; | |
401 | if (size != 0x4000) { | |
402 | size = (size + 0x7FFFL) & 0xFFFF8000L; | |
403 | if (size != 0x8000) | |
404 | size = (size + 0xFFFFL) & 0xFFFF0000L; | |
405 | } | |
406 | } | |
407 | } | |
c7de829c WD |
408 | else size = (size + 0xFFFFL) & 0xFFFF0000L; |
409 | return size; | |
410 | } | |
411 | ||
412 | ibool VBEAPI VBE_setVideoModeExt(int mode,VBE_CRTCInfo *crtc) | |
413 | /**************************************************************************** | |
414 | * | |
415 | * Function: VBE_setVideoModeExt | |
416 | * Parameters: mode - SuperVGA video mode to set. | |
417 | * Returns: True if the mode was set, false if not. | |
418 | * | |
419 | * Description: Attempts to set the specified video mode. This version | |
420 | * includes support for the VBE/Core 3.0 refresh rate control | |
421 | * mechanism. | |
422 | * | |
423 | ****************************************************************************/ | |
424 | { | |
425 | RMREGS regs; | |
426 | ||
427 | if (state->VBEVersion < 0x200 && mode < 0x100) { | |
8bde7f77 WD |
428 | /* Some VBE implementations barf terribly if you try to set non-VBE |
429 | * video modes with the VBE set mode call. VBE 2.0 implementations | |
430 | * must be able to handle this. | |
431 | */ | |
432 | regs.h.al = (ushort)mode; | |
433 | regs.h.ah = 0; | |
434 | PM_int86(0x10,®s,®s); | |
435 | } | |
c7de829c | 436 | else { |
8bde7f77 WD |
437 | if (state->VBEVersion < 0x300 && (mode & vbeRefreshCtrl)) |
438 | return false; | |
439 | regs.x.ax = 0x4F02; | |
440 | regs.x.bx = (ushort)mode; | |
441 | if ((mode & vbeRefreshCtrl) && crtc) | |
442 | VBE_callESDI(®s, crtc, sizeof(*crtc)); | |
443 | else | |
444 | PM_int86(0x10,®s,®s); | |
445 | if (regs.x.ax != VBE_SUCCESS) | |
446 | return false; | |
447 | } | |
c7de829c WD |
448 | return true; |
449 | } | |
450 | ||
451 | ibool VBEAPI VBE_setVideoMode(int mode) | |
452 | /**************************************************************************** | |
453 | * | |
454 | * Function: VBE_setVideoMode | |
455 | * Parameters: mode - SuperVGA video mode to set. | |
456 | * Returns: True if the mode was set, false if not. | |
457 | * | |
458 | * Description: Attempts to set the specified video mode. | |
459 | * | |
460 | ****************************************************************************/ | |
461 | { | |
462 | return VBE_setVideoModeExt(mode,NULL); | |
463 | } | |
464 | ||
465 | int VBEAPI VBE_getVideoMode(void) | |
466 | /**************************************************************************** | |
467 | * | |
468 | * Function: VBE_getVideoMode | |
469 | * Returns: Current video mode | |
470 | * | |
471 | ****************************************************************************/ | |
472 | { | |
473 | RMREGS regs; | |
474 | ||
475 | regs.x.ax = 0x4F03; | |
476 | PM_int86(0x10,®s,®s); | |
477 | if (regs.x.ax != VBE_SUCCESS) | |
8bde7f77 | 478 | return -1; |
c7de829c WD |
479 | return regs.x.bx; |
480 | } | |
481 | ||
482 | ibool VBEAPI VBE_setBank(int window,int bank) | |
483 | /**************************************************************************** | |
484 | * | |
485 | * Function: VBE_setBank | |
486 | * Parameters: window - Window to set | |
487 | * bank - Bank number to set window to | |
488 | * Returns: True on success, false on failure. | |
489 | * | |
490 | ****************************************************************************/ | |
491 | { | |
492 | RMREGS regs; | |
493 | ||
494 | regs.x.ax = 0x4F05; | |
495 | regs.h.bh = 0; | |
496 | regs.h.bl = window; | |
497 | regs.x.dx = bank; | |
498 | PM_int86(0x10,®s,®s); | |
499 | return regs.x.ax == VBE_SUCCESS; | |
500 | } | |
501 | ||
502 | int VBEAPI VBE_getBank(int window) | |
503 | /**************************************************************************** | |
504 | * | |
505 | * Function: VBE_setBank | |
506 | * Parameters: window - Window to read | |
507 | * Returns: Bank number for the window (-1 on failure) | |
508 | * | |
509 | ****************************************************************************/ | |
510 | { | |
511 | RMREGS regs; | |
512 | ||
513 | regs.x.ax = 0x4F05; | |
514 | regs.h.bh = 1; | |
515 | regs.h.bl = window; | |
516 | PM_int86(0x10,®s,®s); | |
517 | if (regs.x.ax != VBE_SUCCESS) | |
8bde7f77 | 518 | return -1; |
c7de829c WD |
519 | return regs.x.dx; |
520 | } | |
521 | ||
522 | ibool VBEAPI VBE_setPixelsPerLine(int pixelsPerLine,int *newBytes, | |
523 | int *newPixels,int *maxScanlines) | |
524 | /**************************************************************************** | |
525 | * | |
526 | * Function: VBE_setPixelsPerLine | |
527 | * Parameters: pixelsPerLine - Pixels per scanline | |
528 | * newBytes - Storage for bytes per line value set | |
529 | * newPixels - Storage for pixels per line value set | |
530 | * maxScanLines - Storage for maximum number of scanlines | |
531 | * Returns: True on success, false on failure | |
532 | * | |
533 | * Description: Sets the scanline length for the video mode to the specified | |
534 | * number of pixels per scanline. If you need more granularity | |
535 | * in TrueColor modes, use the VBE_setBytesPerLine routine | |
536 | * (only valid for VBE 2.0). | |
537 | * | |
538 | ****************************************************************************/ | |
539 | { | |
540 | RMREGS regs; | |
541 | ||
542 | regs.x.ax = 0x4F06; | |
543 | regs.h.bl = 0; | |
544 | regs.x.cx = pixelsPerLine; | |
545 | PM_int86(0x10,®s,®s); | |
546 | *newBytes = regs.x.bx; | |
547 | *newPixels = regs.x.cx; | |
548 | *maxScanlines = regs.x.dx; | |
549 | return regs.x.ax == VBE_SUCCESS; | |
550 | } | |
551 | ||
552 | ibool VBEAPI VBE_setBytesPerLine(int bytesPerLine,int *newBytes, | |
553 | int *newPixels,int *maxScanlines) | |
554 | /**************************************************************************** | |
555 | * | |
556 | * Function: VBE_setBytesPerLine | |
557 | * Parameters: pixelsPerLine - Pixels per scanline | |
558 | * newBytes - Storage for bytes per line value set | |
559 | * newPixels - Storage for pixels per line value set | |
560 | * maxScanLines - Storage for maximum number of scanlines | |
561 | * Returns: True on success, false on failure | |
562 | * | |
563 | * Description: Sets the scanline length for the video mode to the specified | |
564 | * number of bytes per scanline (valid for VBE 2.0 only). | |
565 | * | |
566 | ****************************************************************************/ | |
567 | { | |
568 | RMREGS regs; | |
569 | ||
570 | regs.x.ax = 0x4F06; | |
571 | regs.h.bl = 2; | |
572 | regs.x.cx = bytesPerLine; | |
573 | PM_int86(0x10,®s,®s); | |
574 | *newBytes = regs.x.bx; | |
575 | *newPixels = regs.x.cx; | |
576 | *maxScanlines = regs.x.dx; | |
577 | return regs.x.ax == VBE_SUCCESS; | |
578 | } | |
579 | ||
580 | ibool VBEAPI VBE_getScanlineLength(int *bytesPerLine,int *pixelsPerLine, | |
581 | int *maxScanlines) | |
582 | /**************************************************************************** | |
583 | * | |
584 | * Function: VBE_getScanlineLength | |
585 | * Parameters: bytesPerLine - Storage for bytes per scanline | |
586 | * pixelsPerLine - Storage for pixels per scanline | |
587 | * maxScanLines - Storage for maximum number of scanlines | |
588 | * Returns: True on success, false on failure | |
589 | * | |
590 | ****************************************************************************/ | |
591 | { | |
592 | RMREGS regs; | |
593 | ||
594 | regs.x.ax = 0x4F06; | |
595 | regs.h.bl = 1; | |
596 | PM_int86(0x10,®s,®s); | |
597 | *bytesPerLine = regs.x.bx; | |
598 | *pixelsPerLine = regs.x.cx; | |
599 | *maxScanlines = regs.x.dx; | |
600 | return regs.x.ax == VBE_SUCCESS; | |
601 | } | |
602 | ||
603 | ibool VBEAPI VBE_getMaxScanlineLength(int *maxBytes,int *maxPixels) | |
604 | /**************************************************************************** | |
605 | * | |
606 | * Function: VBE_getMaxScanlineLength | |
607 | * Parameters: maxBytes - Maximum scanline width in bytes | |
608 | * maxPixels - Maximum scanline width in pixels | |
609 | * Returns: True if successful, false if function failed | |
610 | * | |
611 | ****************************************************************************/ | |
612 | { | |
613 | RMREGS regs; | |
614 | ||
615 | regs.x.ax = 0x4F06; | |
616 | regs.h.bl = 3; | |
617 | PM_int86(0x10,®s,®s); | |
618 | *maxBytes = regs.x.bx; | |
619 | *maxPixels = regs.x.cx; | |
620 | return regs.x.ax == VBE_SUCCESS; | |
621 | } | |
622 | ||
623 | ibool VBEAPI VBE_setDisplayStart(int x,int y,ibool waitVRT) | |
624 | /**************************************************************************** | |
625 | * | |
626 | * Function: VBE_setDisplayStart | |
627 | * Parameters: x,y - Position of the first pixel to display | |
628 | * waitVRT - True to wait for retrace, false if not | |
629 | * Returns: True if function was successful. | |
630 | * | |
631 | * Description: Sets the new starting display position to implement | |
632 | * hardware scrolling. | |
633 | * | |
634 | ****************************************************************************/ | |
635 | { | |
636 | RMREGS regs; | |
637 | ||
638 | regs.x.ax = 0x4F07; | |
639 | if (waitVRT) | |
8bde7f77 | 640 | regs.x.bx = 0x80; |
c7de829c WD |
641 | else regs.x.bx = 0x00; |
642 | regs.x.cx = x; | |
643 | regs.x.dx = y; | |
644 | PM_int86(0x10,®s,®s); | |
645 | return regs.x.ax == VBE_SUCCESS; | |
646 | } | |
647 | ||
648 | ibool VBEAPI VBE_getDisplayStart(int *x,int *y) | |
649 | /**************************************************************************** | |
650 | * | |
651 | * Function: VBE_getDisplayStart | |
652 | * Parameters: x,y - Place to store starting address value | |
653 | * Returns: True if function was successful. | |
654 | * | |
655 | ****************************************************************************/ | |
656 | { | |
657 | RMREGS regs; | |
658 | ||
659 | regs.x.ax = 0x4F07; | |
660 | regs.x.bx = 0x01; | |
661 | PM_int86(0x10,®s,®s); | |
662 | *x = regs.x.cx; | |
663 | *y = regs.x.dx; | |
664 | return regs.x.ax == VBE_SUCCESS; | |
665 | } | |
666 | ||
667 | ibool VBEAPI VBE_setDisplayStartAlt(ulong startAddr,ibool waitVRT) | |
668 | /**************************************************************************** | |
669 | * | |
670 | * Function: VBE_setDisplayStartAlt | |
671 | * Parameters: startAddr - 32-bit starting address in display memory | |
672 | * waitVRT - True to wait for vertical retrace, false if not | |
673 | * Returns: True if function was successful, false if not supported. | |
674 | * | |
675 | * Description: Sets the new starting display position to the specified | |
676 | * 32-bit display start address. Note that this function is | |
677 | * different the the version above, since it takes a 32-bit | |
678 | * byte offset in video memory as the starting address which | |
679 | * gives the programmer maximum control over the stat address. | |
680 | * | |
681 | * NOTE: Requires VBE/Core 3.0 | |
682 | * | |
683 | ****************************************************************************/ | |
684 | { | |
685 | RMREGS regs; | |
686 | ||
687 | if (state->VBEVersion >= 0x300) { | |
8bde7f77 WD |
688 | regs.x.ax = 0x4F07; |
689 | regs.x.bx = waitVRT ? 0x82 : 0x02; | |
690 | regs.e.ecx = startAddr; | |
691 | PM_int86(0x10,®s,®s); | |
692 | return regs.x.ax == VBE_SUCCESS; | |
693 | } | |
c7de829c WD |
694 | return false; |
695 | } | |
696 | ||
697 | int VBEAPI VBE_getDisplayStartStatus(void) | |
698 | /**************************************************************************** | |
699 | * | |
700 | * Function: VBE_getDisplayStartStatus | |
701 | * Returns: 0 if last flip not occurred, 1 if already flipped | |
702 | * -1 if not supported | |
703 | * | |
704 | * Description: Returns the status of the previous display start request. | |
705 | * If this function is supported the programmer can implement | |
706 | * hardware triple buffering using this function. | |
707 | * | |
708 | * NOTE: Requires VBE/Core 3.0 | |
709 | * | |
710 | ****************************************************************************/ | |
711 | { | |
712 | RMREGS regs; | |
713 | ||
714 | if (state->VBEVersion >= 0x300) { | |
8bde7f77 WD |
715 | regs.x.ax = 0x4F07; |
716 | regs.x.bx = 0x0004; | |
717 | PM_int86(0x10,®s,®s); | |
718 | if (regs.x.ax == VBE_SUCCESS) | |
719 | return (regs.x.cx != 0); | |
720 | } | |
c7de829c WD |
721 | return -1; |
722 | } | |
723 | ||
724 | ibool VBEAPI VBE_enableStereoMode(void) | |
725 | /**************************************************************************** | |
726 | * | |
727 | * Function: VBE_enableStereoMode | |
728 | * Returns: True if stereo mode enabled, false if not supported. | |
729 | * | |
730 | * Description: Puts the system into hardware stereo mode for LC shutter | |
731 | * glasses, where the display swaps between two display start | |
732 | * addresses every vertical retrace. | |
733 | * | |
734 | * NOTE: Requires VBE/Core 3.0 | |
735 | * | |
736 | ****************************************************************************/ | |
737 | { | |
738 | RMREGS regs; | |
739 | ||
740 | if (state->VBEVersion >= 0x300) { | |
8bde7f77 WD |
741 | regs.x.ax = 0x4F07; |
742 | regs.x.bx = 0x0005; | |
743 | PM_int86(0x10,®s,®s); | |
744 | return regs.x.ax == VBE_SUCCESS; | |
745 | } | |
c7de829c WD |
746 | return false; |
747 | } | |
748 | ||
749 | ibool VBEAPI VBE_disableStereoMode(void) | |
750 | /**************************************************************************** | |
751 | * | |
752 | * Function: VBE_disableStereoMode | |
753 | * Returns: True if stereo mode disabled, false if not supported. | |
754 | * | |
755 | * Description: Puts the system back into normal, non-stereo display mode | |
756 | * after having stereo mode enabled. | |
757 | * | |
758 | * NOTE: Requires VBE/Core 3.0 | |
759 | * | |
760 | ****************************************************************************/ | |
761 | { | |
762 | RMREGS regs; | |
763 | ||
764 | if (state->VBEVersion >= 0x300) { | |
8bde7f77 WD |
765 | regs.x.ax = 0x4F07; |
766 | regs.x.bx = 0x0006; | |
767 | PM_int86(0x10,®s,®s); | |
768 | return regs.x.ax == VBE_SUCCESS; | |
769 | } | |
c7de829c WD |
770 | return false; |
771 | } | |
772 | ||
773 | ibool VBEAPI VBE_setStereoDisplayStart(ulong leftAddr,ulong rightAddr, | |
774 | ibool waitVRT) | |
775 | /**************************************************************************** | |
776 | * | |
777 | * Function: VBE_setStereoDisplayStart | |
778 | * Parameters: leftAddr - 32-bit start address for left image | |
779 | * rightAddr - 32-bit start address for right image | |
780 | * waitVRT - True to wait for vertical retrace, false if not | |
781 | * Returns: True if function was successful, false if not supported. | |
782 | * | |
783 | * Description: Sets the new starting display position to the specified | |
784 | * 32-bit display start address. Note that this function is | |
785 | * different the the version above, since it takes a 32-bit | |
786 | * byte offset in video memory as the starting address which | |
787 | * gives the programmer maximum control over the stat address. | |
788 | * | |
789 | * NOTE: Requires VBE/Core 3.0 | |
790 | * | |
791 | ****************************************************************************/ | |
792 | { | |
793 | RMREGS regs; | |
794 | ||
795 | if (state->VBEVersion >= 0x300) { | |
8bde7f77 WD |
796 | regs.x.ax = 0x4F07; |
797 | regs.x.bx = waitVRT ? 0x83 : 0x03; | |
798 | regs.e.ecx = leftAddr; | |
799 | regs.e.edx = rightAddr; | |
800 | PM_int86(0x10,®s,®s); | |
801 | return regs.x.ax == VBE_SUCCESS; | |
802 | } | |
c7de829c WD |
803 | return false; |
804 | } | |
805 | ||
806 | ulong VBEAPI VBE_getClosestClock(ushort mode,ulong pixelClock) | |
807 | /**************************************************************************** | |
808 | * | |
809 | * Function: VBE_getClosestClock | |
810 | * Parameters: mode - VBE mode to be used (include vbeLinearBuffer) | |
811 | * pixelClock - Desired pixel clock | |
812 | * Returns: Closest pixel clock to desired clock (-1 if not supported) | |
813 | * | |
814 | * Description: Calls the VBE/Core 3.0 interface to determine the closest | |
815 | * pixel clock to the requested value. The BIOS will always | |
816 | * search for a pixel clock that is no more than 1% below the | |
817 | * requested clock or somewhere higher than the clock. If the | |
818 | * clock is higher note that it may well be many Mhz higher | |
819 | * that requested and the application will have to check that | |
820 | * the returned value is suitable for it's needs. This function | |
821 | * returns the actual pixel clock that will be programmed by | |
822 | * the hardware. | |
823 | * | |
824 | * Note that if the pixel clock will be used with a linear | |
825 | * framebuffer mode, make sure you pass in the linear | |
826 | * framebuffer flag to this function. | |
827 | * | |
828 | * NOTE: Requires VBE/Core 3.0 | |
829 | * | |
830 | ****************************************************************************/ | |
831 | { | |
832 | RMREGS regs; | |
833 | ||
834 | if (state->VBEVersion >= 0x300) { | |
8bde7f77 WD |
835 | regs.x.ax = 0x4F0B; |
836 | regs.h.bl = 0x00; | |
837 | regs.e.ecx = pixelClock; | |
838 | regs.x.dx = mode; | |
839 | PM_int86(0x10,®s,®s); | |
840 | if (regs.x.ax == VBE_SUCCESS) | |
841 | return regs.e.ecx; | |
842 | } | |
c7de829c WD |
843 | return -1; |
844 | } | |
845 | ||
846 | ibool VBEAPI VBE_setDACWidth(int width) | |
847 | /**************************************************************************** | |
848 | * | |
849 | * Function: VBE_setDACWidth | |
850 | * Parameters: width - Width to set the DAC to | |
851 | * Returns: True on success, false on failure | |
852 | * | |
853 | ****************************************************************************/ | |
854 | { | |
855 | RMREGS regs; | |
856 | ||
857 | regs.x.ax = 0x4F08; | |
858 | regs.h.bl = 0x00; | |
859 | regs.h.bh = width; | |
860 | PM_int86(0x10,®s,®s); | |
861 | return regs.x.ax == VBE_SUCCESS; | |
862 | } | |
863 | ||
864 | int VBEAPI VBE_getDACWidth(void) | |
865 | /**************************************************************************** | |
866 | * | |
867 | * Function: VBE_getDACWidth | |
868 | * Returns: Current width of the palette DAC | |
869 | * | |
870 | ****************************************************************************/ | |
871 | { | |
872 | RMREGS regs; | |
873 | ||
874 | regs.x.ax = 0x4F08; | |
875 | regs.h.bl = 0x01; | |
876 | PM_int86(0x10,®s,®s); | |
877 | if (regs.x.ax != VBE_SUCCESS) | |
8bde7f77 | 878 | return -1; |
c7de829c WD |
879 | return regs.h.bh; |
880 | } | |
881 | ||
882 | ibool VBEAPI VBE_setPalette(int start,int num,VBE_palette *pal,ibool waitVRT) | |
883 | /**************************************************************************** | |
884 | * | |
885 | * Function: VBE_setPalette | |
886 | * Parameters: start - Starting palette index to program | |
887 | * num - Number of palette indexes to program | |
888 | * pal - Palette buffer containing values | |
889 | * waitVRT - Wait for vertical retrace flag | |
890 | * Returns: True on success, false on failure | |
891 | * | |
892 | * Description: Sets a block of palette registers by calling the VBE 2.0 | |
893 | * BIOS. This function will fail on VBE 1.2 implementations. | |
894 | * | |
895 | ****************************************************************************/ | |
896 | { | |
897 | RMREGS regs; | |
898 | ||
899 | regs.x.ax = 0x4F09; | |
900 | regs.h.bl = waitVRT ? 0x80 : 0x00; | |
901 | regs.x.cx = num; | |
902 | regs.x.dx = start; | |
903 | VBE_callESDI(®s, pal, sizeof(VBE_palette) * num); | |
904 | return regs.x.ax == VBE_SUCCESS; | |
905 | } | |
906 | ||
907 | void * VBEAPI VBE_getBankedPointer(VBE_modeInfo *modeInfo) | |
908 | /**************************************************************************** | |
909 | * | |
910 | * Function: VBE_getBankedPointer | |
911 | * Parameters: modeInfo - Mode info block for video mode | |
912 | * Returns: Selector to the linear framebuffer (0 on failure) | |
913 | * | |
914 | * Description: Returns a near pointer to the VGA framebuffer area. | |
915 | * | |
916 | ****************************************************************************/ | |
917 | { | |
918 | /* We just map the pointer every time, since the pointer will always | |
919 | * be in real mode memory, so we wont actually be mapping any real | |
920 | * memory. | |
921 | * | |
922 | * NOTE: We cannot currently map a near pointer to the banked frame | |
923 | * buffer for Watcom Win386, so we create a 16:16 far pointer to | |
924 | * the video memory. All the assembler code will render to the | |
925 | * video memory by loading the selector rather than using a | |
926 | * near pointer. | |
927 | */ | |
928 | ulong seg = (ushort)modeInfo->WinASegment; | |
929 | if (seg != 0) { | |
8bde7f77 WD |
930 | if (seg == 0xA000) |
931 | return (void*)PM_getA0000Pointer(); | |
932 | else | |
933 | return (void*)PM_mapPhysicalAddr(seg << 4,0xFFFF,true); | |
934 | } | |
c7de829c WD |
935 | return NULL; |
936 | } | |
937 | ||
938 | #ifndef REALMODE | |
939 | ||
940 | void * VBEAPI VBE_getLinearPointer(VBE_modeInfo *modeInfo) | |
941 | /**************************************************************************** | |
942 | * | |
943 | * Function: VBE_getLinearPointer | |
944 | * Parameters: modeInfo - Mode info block for video mode | |
945 | * Returns: Selector to the linear framebuffer (0 on failure) | |
946 | * | |
947 | * Description: Returns a near pointer to the linear framebuffer for the video | |
948 | * mode. | |
949 | * | |
950 | ****************************************************************************/ | |
951 | { | |
952 | static ulong physPtr[MAX_LIN_PTRS] = {0}; | |
953 | static void *linPtr[MAX_LIN_PTRS] = {0}; | |
954 | static int numPtrs = 0; | |
955 | int i; | |
956 | ||
957 | /* Search for an already mapped pointer */ | |
958 | for (i = 0; i < numPtrs; i++) { | |
8bde7f77 WD |
959 | if (physPtr[i] == modeInfo->PhysBasePtr) |
960 | return linPtr[i]; | |
961 | } | |
c7de829c | 962 | if (numPtrs < MAX_LIN_PTRS) { |
8bde7f77 WD |
963 | physPtr[numPtrs] = modeInfo->PhysBasePtr; |
964 | linPtr[numPtrs] = PM_mapPhysicalAddr(modeInfo->PhysBasePtr,(state->VBEMemory * 1024L)-1,true); | |
965 | return linPtr[numPtrs++]; | |
966 | } | |
c7de829c WD |
967 | return NULL; |
968 | } | |
969 | ||
970 | static void InitPMCode(void) | |
971 | /**************************************************************************** | |
972 | * | |
973 | * Function: InitPMCode - 32 bit protected mode version | |
974 | * | |
975 | * Description: Finds the address of and relocates the protected mode | |
976 | * code block from the VBE 2.0 into a local memory block. The | |
977 | * memory block is allocated with malloc() and must be freed | |
978 | * with VBE_freePMCode() after graphics processing is complete. | |
979 | * | |
980 | * Note that this buffer _must_ be recopied after each mode set, | |
981 | * as the routines will change depending on the underlying | |
982 | * video mode. | |
983 | * | |
984 | ****************************************************************************/ | |
985 | { | |
986 | RMREGS regs; | |
987 | RMSREGS sregs; | |
988 | uchar *code; | |
989 | int pmLen; | |
990 | ||
991 | if (!state->pmInfo && state->VBEVersion >= 0x200) { | |
8bde7f77 WD |
992 | regs.x.ax = 0x4F0A; |
993 | regs.x.bx = 0; | |
994 | PM_int86x(0x10,®s,®s,&sregs); | |
995 | if (regs.x.ax != VBE_SUCCESS) | |
996 | return; | |
997 | if (VBE_shared) | |
998 | state->pmInfo = PM_mallocShared(regs.x.cx); | |
999 | else | |
1000 | state->pmInfo = PM_malloc(regs.x.cx); | |
1001 | if (state->pmInfo == NULL) | |
1002 | return; | |
1003 | state->pmInfo32 = state->pmInfo; | |
1004 | pmLen = regs.x.cx; | |
1005 | ||
1006 | /* Relocate the block into our local data segment */ | |
1007 | code = PM_mapRealPointer(sregs.es,regs.x.di); | |
1008 | memcpy(state->pmInfo,code,pmLen); | |
1009 | ||
1010 | /* Now do a sanity check on the information we recieve to ensure | |
1011 | * that is is correct. Some BIOS return totally bogus information | |
1012 | * in here (Matrox is one)! Under DOS this works OK, but under OS/2 | |
1013 | * we are screwed. | |
1014 | */ | |
1015 | if (state->pmInfo->setWindow >= pmLen || | |
1016 | state->pmInfo->setDisplayStart >= pmLen || | |
1017 | state->pmInfo->setPalette >= pmLen || | |
1018 | state->pmInfo->IOPrivInfo >= pmLen) { | |
1019 | if (VBE_shared) | |
1020 | PM_freeShared(state->pmInfo); | |
1021 | else | |
1022 | PM_free(state->pmInfo); | |
1023 | state->pmInfo32 = state->pmInfo = NULL; | |
1024 | return; | |
1025 | } | |
1026 | ||
1027 | /* Read the IO priveledge info and determine if we need to | |
1028 | * pass a selector to MMIO registers to the bank switch code. | |
1029 | * Since we no longer support selector allocation, we no longer | |
1030 | * support this mechanism so we disable the protected mode | |
1031 | * interface in this case. | |
1032 | */ | |
1033 | if (state->pmInfo->IOPrivInfo && !state->MMIOSel) { | |
1034 | ushort *p = (ushort*)((uchar*)state->pmInfo + state->pmInfo->IOPrivInfo); | |
1035 | while (*p != 0xFFFF) | |
1036 | p++; | |
1037 | p++; | |
1038 | if (*p != 0xFFFF) | |
1039 | VBE_freePMCode(); | |
1040 | } | |
1041 | } | |
c7de829c WD |
1042 | } |
1043 | ||
1044 | void * VBEAPI VBE_getSetBank(void) | |
1045 | /**************************************************************************** | |
1046 | * | |
1047 | * Function: VBE_getSetBank | |
1048 | * Returns: Pointer to the 32 VBE 2.0 bit bank switching routine. | |
1049 | * | |
1050 | ****************************************************************************/ | |
1051 | { | |
1052 | if (state->VBEVersion >= 0x200) { | |
8bde7f77 WD |
1053 | InitPMCode(); |
1054 | if (state->pmInfo) | |
1055 | return (uchar*)state->pmInfo + state->pmInfo->setWindow; | |
1056 | } | |
c7de829c WD |
1057 | return NULL; |
1058 | } | |
1059 | ||
1060 | void * VBEAPI VBE_getSetDisplayStart(void) | |
1061 | /**************************************************************************** | |
1062 | * | |
1063 | * Function: VBE_getSetDisplayStart | |
1064 | * Returns: Pointer to the 32 VBE 2.0 bit CRT start address routine. | |
1065 | * | |
1066 | ****************************************************************************/ | |
1067 | { | |
1068 | if (state->VBEVersion >= 0x200) { | |
8bde7f77 WD |
1069 | InitPMCode(); |
1070 | if (state->pmInfo) | |
1071 | return (uchar*)state->pmInfo + state->pmInfo->setDisplayStart; | |
1072 | } | |
c7de829c WD |
1073 | return NULL; |
1074 | } | |
1075 | ||
1076 | void * VBEAPI VBE_getSetPalette(void) | |
1077 | /**************************************************************************** | |
1078 | * | |
1079 | * Function: VBE_getSetPalette | |
1080 | * Returns: Pointer to the 32 VBE 2.0 bit palette programming routine. | |
1081 | * | |
1082 | ****************************************************************************/ | |
1083 | { | |
1084 | if (state->VBEVersion >= 0x200) { | |
8bde7f77 WD |
1085 | InitPMCode(); |
1086 | if (state->pmInfo) | |
1087 | return (uchar*)state->pmInfo + state->pmInfo->setPalette; | |
1088 | } | |
c7de829c WD |
1089 | return NULL; |
1090 | } | |
1091 | ||
1092 | void VBEAPI VBE_freePMCode(void) | |
1093 | /**************************************************************************** | |
1094 | * | |
1095 | * Function: VBE_freePMCode | |
1096 | * | |
1097 | * Description: This routine frees the protected mode code blocks that | |
1098 | * we copied from the VBE 2.0 interface. This routine must | |
1099 | * be after you have finished graphics processing to free up | |
1100 | * the memory occupied by the routines. This is necessary | |
1101 | * because the PM info memory block must be re-copied after | |
1102 | * every video mode set from the VBE 2.0 implementation. | |
1103 | * | |
1104 | ****************************************************************************/ | |
1105 | { | |
1106 | if (state->pmInfo) { | |
8bde7f77 WD |
1107 | if (VBE_shared) |
1108 | PM_freeShared(state->pmInfo); | |
1109 | else | |
1110 | PM_free(state->pmInfo); | |
1111 | state->pmInfo = NULL; | |
1112 | state->pmInfo32 = NULL; | |
1113 | } | |
c7de829c WD |
1114 | } |
1115 | ||
1116 | void VBEAPI VBE_sharePMCode(void) | |
1117 | /**************************************************************************** | |
1118 | * | |
1119 | * Function: VBE_sharePMCode | |
1120 | * | |
1121 | * Description: Enables internal sharing of the PM code buffer for OS/2. | |
1122 | * | |
1123 | ****************************************************************************/ | |
1124 | { | |
1125 | VBE_shared = true; | |
1126 | } | |
1127 | ||
1128 | /* Set of code stubs used to build the final bank switch code */ | |
1129 | ||
1130 | #define VBE20_adjustOffset 7 | |
1131 | ||
1132 | static uchar VBE20A_bankFunc32_Start[] = { | |
1133 | 0x53,0x51, /* push ebx,ecx */ | |
1134 | 0x8B,0xD0, /* mov edx,eax */ | |
1135 | 0x33,0xDB, /* xor ebx,ebx */ | |
1136 | 0xB1,0x00, /* mov cl,0 */ | |
1137 | 0xD2,0xE2, /* shl dl,cl */ | |
1138 | }; | |
1139 | ||
1140 | static uchar VBE20_bankFunc32_End[] = { | |
1141 | 0x59,0x5B, /* pop ecx,ebx */ | |
1142 | }; | |
1143 | ||
1144 | static uchar bankFunc32[100]; | |
1145 | ||
1146 | #define copy(p,b,a) memcpy(b,a,sizeof(a)); (p) = (b) + sizeof(a) | |
1147 | ||
1148 | ibool VBEAPI VBE_getBankFunc32(int *codeLen,void **bankFunc,int dualBanks, | |
1149 | int bankAdjust) | |
1150 | /**************************************************************************** | |
1151 | * | |
1152 | * Function: VBE_getBankFunc32 | |
1153 | * Parameters: codeLen - Place to store length of code | |
1154 | * bankFunc - Place to store pointer to bank switch code | |
1155 | * dualBanks - True if dual banks are in effect | |
1156 | * bankAdjust - Bank shift adjustment factor | |
1157 | * Returns: True on success, false if not compatible. | |
1158 | * | |
1159 | * Description: Creates a local 32 bit bank switch function from the | |
1160 | * VBE 2.0 bank switch code that is compatible with the | |
1161 | * virtual flat framebuffer devices (does not have a return | |
1162 | * instruction at the end and takes the bank number in EAX | |
1163 | * not EDX). Note that this 32 bit code cannot include int 10h | |
1164 | * instructions, so we can only do this if we have VBE 2.0 | |
1165 | * or later. | |
1166 | * | |
1167 | * Note that we need to know the length of the 32 bit | |
1168 | * bank switch function, which the standard VBE 2.0 spec | |
1169 | * does not provide. In order to support this we have | |
1170 | * extended the VBE 2.0 state->pmInfo structure in UniVBE 5.2 in a | |
1171 | * way to support this, and we hope that this will become | |
1172 | * a VBE 2.0 ammendment. | |
1173 | * | |
1174 | * Note also that we cannot run the linear framebuffer | |
1175 | * emulation code with bank switching routines that require | |
1176 | * a selector to the memory mapped registers passed in ES. | |
1177 | * | |
1178 | ****************************************************************************/ | |
1179 | { | |
1180 | int len; | |
1181 | uchar *code; | |
1182 | uchar *p; | |
1183 | ||
1184 | InitPMCode(); | |
1185 | if (state->VBEVersion >= 0x200 && state->pmInfo32 && !state->MMIOSel) { | |
8bde7f77 WD |
1186 | code = (uchar*)state->pmInfo32 + state->pmInfo32->setWindow; |
1187 | if (state->pmInfo32->extensionSig == VBE20_EXT_SIG) | |
1188 | len = state->pmInfo32->setWindowLen-1; | |
1189 | else { | |
1190 | /* We are running on a system without the UniVBE 5.2 extension. | |
1191 | * We do as best we can by scanning through the code for the | |
1192 | * ret function to determine the length. This is not foolproof, | |
1193 | * but is the best we can do. | |
1194 | */ | |
1195 | p = code; | |
1196 | while (*p != 0xC3) | |
1197 | p++; | |
1198 | len = p - code; | |
1199 | } | |
1200 | if ((len + sizeof(VBE20A_bankFunc32_Start) + sizeof(VBE20_bankFunc32_End)) > sizeof(bankFunc32)) | |
1201 | PM_fatalError("32-bit bank switch function too long!"); | |
1202 | copy(p,bankFunc32,VBE20A_bankFunc32_Start); | |
1203 | memcpy(p,code,len); | |
1204 | p += len; | |
1205 | copy(p,p,VBE20_bankFunc32_End); | |
1206 | *codeLen = p - bankFunc32; | |
1207 | bankFunc32[VBE20_adjustOffset] = (uchar)bankAdjust; | |
1208 | *bankFunc = bankFunc32; | |
1209 | return true; | |
1210 | } | |
c7de829c WD |
1211 | return false; |
1212 | } | |
1213 | ||
1214 | #endif |