]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/common/vesavbe.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / common / vesavbe.c
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) {
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         }
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)
132         PM_fatalError("You *MUST* call VBE_init() before you can call the VESAVBE.C module!");
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)
160         *p++ = *v++;
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)
181         *p++ = *v++;
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) {
203         regs.x.bx = 0x1234;
204         regs.x.cx = 0x4321;
205         }
206     else {
207         regs.x.bx = 0;
208         regs.x.cx = 0;
209         }
210     strncpy(vgaInfo->VESASignature,"VBE2",4);
211     VBE_callESDI(&regs, vgaInfo, sizeof(*vgaInfo));
212     if (regs.x.ax != VBE_SUCCESS)
213         return 0;
214     if (strncmp(vgaInfo->VESASignature,"VESA",4) != 0)
215         return 0;
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)
222         vgaInfo->VESAVersion = 0x102;
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     {
230         char *p,*p2;
231      p2 = VBE_copyStrToLocal(localBuf,vgaInfo->OemStringPtr,MAX_LOCAL_BUF);
232      vgaInfo->OemStringPtr = localBuf;
233      if (vgaInfo->VESAVersion >= 0x200) {
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          }
243      else {
244          VBE_copyShortToLocal((ushort*)p2,vgaInfo->VideoModePtr);
245          vgaInfo->VideoModePtr = (ushort*)p2;
246          }
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 &&
256            (strstr(vgaInfo->OemStringPtr,"NVidia") != NULL ||
257             strstr(vgaInfo->OemStringPtr,"Riva") != NULL)) {
258         haveRiva128 = true;
259         }
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))
266         vgaInfo->VESAVersion = 0x200;
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(&regs, modeInfo, sizeof(*modeInfo));
307     if (regs.x.ax != VBE_SUCCESS)
308         return false;
309     if ((modeInfo->ModeAttributes & vbeMdAvailable) == 0)
310         return false;
311
312     /* Map out triple buffer and stereo flags for NVidia Riva128
313      * chips.
314      */
315     if (haveRiva128) {
316         modeInfo->ModeAttributes &= ~vbeMdTripleBuf;
317         modeInfo->ModeAttributes &= ~vbeMdStereo;
318         }
319
320     /* Support old style RGB definitions for VBE 1.1 BIOSes */
321     bits = modeInfo->BitsPerPixel;
322     if (modeInfo->MemoryModel == vbeMemPK && bits > 8) {
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         }
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)
362         modeInfo->BitsPerPixel = 15;
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)) {
369         modeInfo->RsvdMaskSize = 1;
370         modeInfo->RsvdFieldPosition = 15;
371         }
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) {
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         }
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) {
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,&regs,&regs);
435         }
436     else {
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(&regs, crtc, sizeof(*crtc));
443         else
444             PM_int86(0x10,&regs,&regs);
445         if (regs.x.ax != VBE_SUCCESS)
446             return false;
447         }
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,&regs,&regs);
477     if (regs.x.ax != VBE_SUCCESS)
478         return -1;
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,&regs,&regs);
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,&regs,&regs);
517     if (regs.x.ax != VBE_SUCCESS)
518         return -1;
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,&regs,&regs);
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,&regs,&regs);
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,&regs,&regs);
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,&regs,&regs);
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)
640         regs.x.bx = 0x80;
641     else regs.x.bx = 0x00;
642     regs.x.cx = x;
643     regs.x.dx = y;
644     PM_int86(0x10,&regs,&regs);
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,&regs,&regs);
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) {
688         regs.x.ax = 0x4F07;
689         regs.x.bx = waitVRT ? 0x82 : 0x02;
690         regs.e.ecx = startAddr;
691         PM_int86(0x10,&regs,&regs);
692         return regs.x.ax == VBE_SUCCESS;
693         }
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) {
715         regs.x.ax = 0x4F07;
716         regs.x.bx = 0x0004;
717         PM_int86(0x10,&regs,&regs);
718         if (regs.x.ax == VBE_SUCCESS)
719             return (regs.x.cx != 0);
720         }
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) {
741         regs.x.ax = 0x4F07;
742         regs.x.bx = 0x0005;
743         PM_int86(0x10,&regs,&regs);
744         return regs.x.ax == VBE_SUCCESS;
745         }
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) {
765         regs.x.ax = 0x4F07;
766         regs.x.bx = 0x0006;
767         PM_int86(0x10,&regs,&regs);
768         return regs.x.ax == VBE_SUCCESS;
769         }
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) {
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,&regs,&regs);
801         return regs.x.ax == VBE_SUCCESS;
802         }
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) {
835         regs.x.ax = 0x4F0B;
836         regs.h.bl = 0x00;
837         regs.e.ecx = pixelClock;
838         regs.x.dx = mode;
839         PM_int86(0x10,&regs,&regs);
840         if (regs.x.ax == VBE_SUCCESS)
841             return regs.e.ecx;
842         }
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,&regs,&regs);
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,&regs,&regs);
877     if (regs.x.ax != VBE_SUCCESS)
878         return -1;
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(&regs, 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) {
930         if (seg == 0xA000)
931             return (void*)PM_getA0000Pointer();
932         else
933             return (void*)PM_mapPhysicalAddr(seg << 4,0xFFFF,true);
934         }
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++) {
959         if (physPtr[i] == modeInfo->PhysBasePtr)
960             return linPtr[i];
961         }
962     if (numPtrs < MAX_LIN_PTRS) {
963         physPtr[numPtrs] = modeInfo->PhysBasePtr;
964         linPtr[numPtrs] = PM_mapPhysicalAddr(modeInfo->PhysBasePtr,(state->VBEMemory * 1024L)-1,true);
965         return linPtr[numPtrs++];
966         }
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) {
992         regs.x.ax = 0x4F0A;
993         regs.x.bx = 0;
994         PM_int86x(0x10,&regs,&regs,&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         }
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) {
1053         InitPMCode();
1054         if (state->pmInfo)
1055             return (uchar*)state->pmInfo + state->pmInfo->setWindow;
1056         }
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) {
1069         InitPMCode();
1070         if (state->pmInfo)
1071             return (uchar*)state->pmInfo + state->pmInfo->setDisplayStart;
1072         }
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) {
1085         InitPMCode();
1086         if (state->pmInfo)
1087             return (uchar*)state->pmInfo + state->pmInfo->setPalette;
1088         }
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) {
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         }
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) {
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         }
1211     return false;
1212 }
1213
1214 #endif