int10.c 49.7 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2
/*
 * BIOS interrupt 10h handler
3
 *
4
 * Copyright 1998 Ove Kåven
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright 1998 Joseph Pranevich
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
20 21
 */

22 23
#include "config.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <stdlib.h>
25

26
#include "vga.h"
27
#include "wine/debug.h"
28
#include "dosexe.h"
29

30
WINE_DEFAULT_DEBUG_CHANNEL(int);
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
/*
 * Display combination code for active display.
 *
 * Values (hex):
 * 00 - no display
 * 01 - monochrome adapter w/ monochrome display
 * 02 - CGA w/ color display
 * 03 - reserved
 * 04 - EGA w/ color display
 * 05 - EGA w/ monochrome display
 * 06 - PGA w/ color display
 * 07 - VGA w/ monochrome analog display
 * 08 - VGA w/ color analog display
 * 09 - reserved
 * 0A - MCGA w/ digital color display
 * 0B - MCGA w/ monochrome analog display
 * 0C - MCGA w/ color analog display
 * FF - unknown display type
 */
#define INT10_DCC 0x08

#include "pshpack1.h"

/*
 * Structure for DOS data that can be accessed directly from applications.
 * This structure must be correctly packed.
 */
typedef struct _INT10_HEAP {
    BYTE  StaticModeSupport[7];     /* modes supported 1..7 */
    BYTE  StaticScanlineSupport;    /* scan lines supported */
    BYTE  StaticNumberCharBlocks;   /* total number of char blocks */
    BYTE  StaticActiveCharBlocks;   /* max number of active char blocks */
    WORD  StaticMiscFlags;          /* misc function support flags */
    WORD  StaticReserved1;          /* reserved */
    BYTE  StaticSavePointerFlags;   /* save pointer function flags */
    BYTE  StaticReserved2;          /* reserved */

    WORD  VesaCurrentMode;
    WORD  VesaModeList[64];
    char  VesaOEMName[32];
    char  VesaProductName[32];
    char  VesaProductRev[32];
    char  VesaVendorName[32];

    WORD  WineHeapSegment;
} INT10_HEAP;

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
/*
 * Structure for VBE Mode Info Block. See the VBE 3.0 standard for details.
 * This structure must be correctly packed.
 */
struct _ModeInfoBlock {
    WORD  ModeAttributes;       /* 0x00 */
    BYTE  WinAAttributes;       /* 0x02 */
    BYTE  WinBAttributes;       /* 0x03 */
    WORD  WinGranularity;       /* 0x04 */
    WORD  WinSize;              /* 0x06 */
    WORD  WinASegment;          /* 0x08 */
    WORD  WinBSegment;          /* 0x0A */
    DWORD WinFuncPtr;           /* 0x0C */
    WORD  BytesPerScanLine;     /* 0x10 */
    /* mandatory for VBE 1.2+ */
    WORD  XResolution;          /* 0x12 */
    WORD  YResolution;          /* 0x14 */
    BYTE  XCharSize;            /* 0x16 */
    BYTE  YCharSize;            /* 0x17 */
    BYTE  NumberOfPlanes;       /* 0x18 */
    BYTE  BitsPerPixel;         /* 0x19 */
    BYTE  NumberOfBanks;        /* 0x1A */
    BYTE  MemoryModel;          /* 0x1B */
    BYTE  BankSize;             /* 0x1C */
    BYTE  NumberOfImagePages;   /* 0x1D */
    BYTE  Reserved1;            /* 0x1E */
    BYTE  RedMaskSize;          /* 0x1F */
    BYTE  RedFieldPosition;     /* 0x20 */
    BYTE  GreenMaskSize;        /* 0x21 */
    BYTE  GreenFieldPosition;   /* 0x22 */
    BYTE  BlueMaskSize;         /* 0x23 */
    BYTE  BlueFieldPosition;    /* 0x24 */
    BYTE  RsvdMaskSize;         /* 0x25 */
    BYTE  RsvdFieldPosition;    /* 0x26 */
    BYTE  DirectColorModeInfo;  /* 0x27 */
    /* mandatory for VBE 2.0+ */
    DWORD PhysBasePtr;          /* 0x28 */
    DWORD Reserved2;            /* 0x2C */
    WORD  Reserved3;            /* 0x30 */
    /* mandatory for VBE 3.0+ */
    WORD  LinBytesPerScanLine;  /* 0x32 */
    BYTE  BnkNumberOfImagePages;/* 0x34 */
    BYTE  LinNumberOfImagePages;/* 0x35 */
    BYTE  LinRedMaskSize;       /* 0x36 */
    BYTE  LinRedFieldPosition;  /* 0x37 */
    BYTE  LinGreenMaskSize;     /* 0x38 */
    BYTE  LinGreenFieldPosition;/* 0x39 */
    BYTE  LinBlueMaskSize;      /* 0x3A */
    BYTE  LinBlueFieldPosition; /* 0x3B */
    BYTE  LinRsvdMaskSize;      /* 0x3C */
    BYTE  LinRsvdFieldPosition; /* 0x3D */
    DWORD MaxPixelClock;        /* 0x3E */
    BYTE  Reserved4[190];       /* 0x42 */
};

134
#include "poppack.h"
135

136 137 138 139 140
/* True if video mode is a vesa mode, false otherwise.
 * More correct would be to use something like (x > 0xff || x == 0x6a)
 * but as long as we have only the standard VGA and VESA modes this is ok too */
#define IS_VESA_MODE(x)         ((x) >= 0x6a)

141 142
/* Forward declarations. */
static INT10_HEAP *INT10_GetHeap(void);
143 144
static void INT10_SetCursorPos(BIOSDATA*, unsigned, unsigned, unsigned);

145 146 147 148 149 150 151 152
/**********************************************************************
 *         INT10_FillControllerInformation
 *
 * Fill 256-byte (VBE1.x) or 512-byte buffer (VBE2.0+) with
 * capabilities of the video controller.
 */
static void INT10_FillControllerInformation( BYTE *buffer )
{
153 154 155 156 157 158 159 160 161 162 163 164 165
    INT10_HEAP *heap = INT10_GetHeap();

    /* 00 - BYTE[4]: signature */
    memmove( buffer, "VESA", 4 );

    /* 04 - WORD: version number */
    *(WORD*)(buffer + 4) = 0x0300; /* version 3.0 */
    
    /* 06 - DWORD: pointer to OEM name */
    *(SEGPTR*)(buffer + 6) = MAKESEGPTR( heap->WineHeapSegment,
                                         offsetof(INT10_HEAP,
                                                  VesaOEMName) );

166
    /*
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
     * 10 - DWORD: capabilities flags 
     * Bits:
     *    0 - DAC can be switched into 8-bit mode
     *    1 - non-VGA controller
     *    2 - programmed DAC with blank bit
     *    3 - controller supports hardware stereoscopic signalling
     *    4 - =0 stereo signalling via external VESA stereo connector
     *        =1 stereo signalling via VESA EVC connector
     *    5 - controller supports hardware mouse cursor
     *    6 - controller supports hardware clipping
     *    7 - controller supports transparent BitBLT
     * 8-31 - reserved (0)
     */
    *(DWORD*)(buffer + 10) = 0; /* FIXME */
    
    /* 14 - DWORD: pointer to list of supported VESA and OEM video modes */
    *(SEGPTR*)(buffer + 14) = MAKESEGPTR( heap->WineHeapSegment,
                                          offsetof(INT10_HEAP,
                                                   VesaModeList) );

    /* 18 - WORD: total amount of video memory in 64K blocks */
    *(WORD*)(buffer + 18) = 16; /* FIXME */

    /* 20 - WORD: OEM software version (BCD, high byte = major) */
    *(WORD*)(buffer + 20) = 0x0100; /* version 1.0 */

    /* 22 - DWORD: pointer to vendor name */
    *(SEGPTR*)(buffer + 22) = MAKESEGPTR( heap->WineHeapSegment,
                                          offsetof(INT10_HEAP,
                                                   VesaVendorName) );

    /* 26 - DWORD: pointer to product name */
    *(SEGPTR*)(buffer + 26) = MAKESEGPTR( heap->WineHeapSegment,
                                          offsetof(INT10_HEAP,
                                                   VesaProductName) );

    /* 30 - DWORD: pointer to product revision string */
    *(SEGPTR*)(buffer + 30) = MAKESEGPTR( heap->WineHeapSegment,
                                          offsetof(INT10_HEAP,
                                                   VesaProductRev) );

    /* 34 - WORD: VBE/AF version (if capabilities bit 3 set) */
    *(WORD*)(buffer + 34) = 0;

    /*
     * 36 - DWORD: pointer to list of accelerated modes 
     *             (if capabilities bit 3 set) 
     */
    *(SEGPTR*)(buffer + 36) = 0;

    /* 40 - BYTE[216]: reserved for VBE implementation, set to zero */
218
    memset( buffer + 40, 0, 216 );
219 220 221 222

    /* 
     * 256 - BYTE[256]: reserved for VBE3.0 implementation, 
     *                  ignored in order to support older programs
223 224 225 226 227 228 229 230 231 232 233 234
     */
}


/**********************************************************************
 *         INT10_FillModeInformation
 *
 * Fill 256-byte buffer with extended information about display mode.
 *
 * Returns FALSE if mode is unknown and TRUE is mode is known
 * even if it is not supported.
 */
235
static BOOL INT10_FillModeInformation( struct _ModeInfoBlock *mib, WORD mode )
236
{
237
    const VGA_MODE *ptr = VGA_GetModeInfo( mode );
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
    if (!ptr)
        return FALSE;

    /*
     * 00 - WORD: mode attributes
     * Bits:
     *     0 - Mode supported by present hardware configuration.
     *     1 - Optional information available. Must be =1 for VBE v1.2+.
     *     2 - BIOS output supported.
     *         Int10 functions 01, 02, 06, 07, 09, 0a and 0e are supported.
     *     3 - Set if color, clear if monochrome.
     *     4 - Set if graphics mode, clear if text mode.
     *     5 - Mode is not VGA-compatible if set.
     *         VGA-compatible modes support standard VGA I/O ports.
     *     6 - Bank-switched (or windowed) mode is not supported if set.
     *     7 - Linear framebuffer mode supported.
     *     8 - Double scanning supported.
     *     9 - Interlaced operation supported.
     *    10 - Triple buffering supported.
     *    11 - Stereoscopic display supported.
     *    12 - Dual display start address supported.
     * 13-15 - Reserved.
     */
    {
262 263 264 265 266 267
        WORD attr = 0x0002; /* set optional info available */
        /* Enable color mode - if both Colors & Depth are 0, then assume monochrome*/
        if (ptr->Colors || ptr->Depth)
        {
            attr |= 0x0008;
        }
268 269 270 271 272

        /*
         * FIXME: Attribute handling is incomplete.
         */

273 274 275 276 277
        /* Mode supported? */
        if (ptr->Supported)
        {
            attr |= 0x0001;  /* set display mode supported */
        }
278 279

        /* Graphical mode? */
280 281 282 283
        if (ptr->ModeType != TEXT)
        {
            attr |= 0x0010;  /* set graphics mode on (text mode off) */
        }
284 285

        /* Not VGA-compatible? */
286
        if (IS_VESA_MODE(mode))
287
            attr |= 0x0020;    /* disable VGA ports */
288

289
        mib->ModeAttributes = attr;
290 291 292 293 294 295 296 297 298 299
    }

    /*
     * 02 - BYTE[2]: window attributes, window A and window B
     * Bits:
     *   0 - Window exists.
     *   1 - Window is readable.
     *   2 - Window is writable.
     * 3-7 - Reserved.
     */
300 301
    mib->WinAAttributes = 0x07; /* window A exists, readable and writable */
    mib->WinBAttributes = 0x00; /* window B not supported */
302 303

    /* 04 - WORD: window granularity in KB */
304
    mib->WinGranularity = 64;
305 306

    /* 06 - WORD: window size in KB */
307
    mib->WinSize = 64;
308 309

    /* 08 - WORD[2]: start segments, window A and window B */
310 311
    mib->WinASegment = 0xa000; /* window A segment */
    mib->WinBSegment = 0x0000; /* window B not supported */
312 313

    /* 12 - DWORD: window positioning function */
314
    mib->WinFuncPtr = 0; /* not supported */
315 316
    
    /* 16 - WORD: bytes per scan line */
317
    /* FIXME: is this always correct? */
318
    mib->BytesPerScanLine = ptr->Width * (ptr->Depth ? (ptr->Depth + 7) / 8 : 1);
319 320

    /* 18 - WORD: width in pixels (graphics) or characters (text) */
321 322 323 324 325 326 327 328
    if (ptr->ModeType == TEXT)
    {
        mib->XResolution = ptr->TextCols;
    }
    else
    {
        mib->XResolution = ptr->Width;
    }
329 330

    /* 20 - WORD: height in pixels (graphics) or characters (text) */
331 332 333 334 335 336 337 338
    if (ptr->ModeType == TEXT)
    {
        mib->YResolution = ptr->TextRows;
    }
    else
    {
        mib->YResolution = ptr->Height;
    }
339 340

    /* 22 - BYTE: width of character cell in pixels */
341
    mib->XCharSize = ptr->CharWidth;
342 343

    /* 23 - BYTE: height of character cell in pixels */
344
    mib->YCharSize = ptr->CharHeight;
345 346

    /* 24 - BYTE: number of memory planes */
347
    mib->NumberOfPlanes = 1; /* FIXME */
348 349

    /* 25 - BYTE: number of bits per pixel */
350
    mib->BitsPerPixel = ptr->Depth; /* FIXME: text modes? reserved bits? */
351 352

    /* 26 - BYTE: number of banks */
353
    mib->NumberOfBanks = 1; /* FIXME */
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

    /*
     * 27 - BYTE: memory model type
     * Values (hex):
     *    00 - Text mode
     *    01 - CGA graphics
     *    02 - Hercules graphics
     *    03 - Planar
     *    04 - Packed pixel
     *    05 - Non-chain 4, 256 color
     *    06 - Direct color
     *    07 - YUV
     * 08-0F - Reserved for VESA.
     * 10-FF - OEM memory models.
     */
369
    if (ptr->ModeType == TEXT)
370
        mib->MemoryModel = 0; /* text mode */
371
    else
372
        mib->MemoryModel = 3; /* FIXME */
373 374

    /* 28 - BYTE: size of bank in KB */
375
    mib->BankSize = 0; /* FIXME */
376 377

    /* 29 - BYTE: number of image pages (less one) in video RAM */
378
    mib->NumberOfImagePages = (ptr->ScreenPages)-1;
379 380

    /* 30 - BYTE: reserved (0x00 for VBE 1.0-2.0, 0x01 for VBE 3.0) */
381
    mib->Reserved1 = 0x01;
382 383

    /* 
384 385 386 387 388
     * 31,33,35 - BYTE: red/green/blue mask size 
     * Size of red/green/blue color component in bits.
     * 32,34,36 - BYTE: red/green/blue field position 
     * Bit position of the least significant bit of red/green/blue color
     * component.
389 390 391 392
     * Both should be only used when the memory model is direct color or YUV
     * but "Imperium Romanum" uses this field even when the memory model is
     * planar. So always fill this field when we have a depth bigger than 8,
     * otherwise set them to zero.
393
     */
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
    switch (ptr->Depth) {
        case 24:
            mib->RedMaskSize = 8;
            mib->GreenMaskSize = 8;
            mib->BlueMaskSize = 8;
            mib->RsvdMaskSize = 0;
            mib->RedFieldPosition = 16;
            mib->GreenFieldPosition = 8;
            mib->BlueFieldPosition = 0;
            mib->RsvdFieldPosition = 0;
            break;
        case 16:
            mib->RedMaskSize = 5;
            mib->GreenMaskSize = 6;
            mib->BlueMaskSize = 5;
            mib->RsvdMaskSize = 0;
            mib->RedFieldPosition = 11;
            mib->GreenFieldPosition = 5;
            mib->BlueFieldPosition = 0;
            mib->RsvdFieldPosition = 0;
            break;
        case 15:
            mib->RedMaskSize = 5;
            mib->GreenMaskSize = 5;
            mib->BlueMaskSize = 5;
            mib->RsvdMaskSize = 1;
            mib->RedFieldPosition = 10;
            mib->GreenFieldPosition = 5;
            mib->BlueFieldPosition = 0;
            mib->RsvdFieldPosition = 15;
            break;
        default:
            mib->RedMaskSize = 0;
            mib->GreenMaskSize = 0;
            mib->BlueMaskSize = 0;
            mib->RsvdMaskSize = 0;
            mib->RedFieldPosition = 0;
            mib->GreenFieldPosition = 0;
            mib->BlueFieldPosition = 0;
            mib->RsvdFieldPosition = 0;
            break;
    }
436 437 438 439 440 441 442

    /*
     * 39 - BYTE: direct color mode info 
     * Bits:
     * 0 - Set if color ramp is programmable.
     * 1 - Set if bytes in reserved field may be used by application.
     */
443
    mib->DirectColorModeInfo = 0; /* not supported */
444 445

    /* 40 - DWORD: physical address of linear video buffer */
446
    mib->PhysBasePtr = 0; /* not supported */
447 448

    /* 44 - DWORD: reserved, always zero */
449
    mib->Reserved2 = 0;
450 451

    /* 48 - WORD: reserved, always zero */
452
    mib->Reserved3 = 0;
453 454

    /* 50 - WORD: bytes per scan line in linear modes */
455
    mib->LinBytesPerScanLine = mib->BytesPerScanLine;
456 457

    /* 52 - BYTE: number of images (less one) for banked video modes */
458
    mib->BnkNumberOfImagePages = 0; /* FIXME */
459 460

    /* 53 - BYTE: number of images (less one) for linear video modes */
461
    mib->LinNumberOfImagePages = mib->BnkNumberOfImagePages;
462 463

    /* 54 - BYTE: red mask size (linear modes) */
464
    mib->LinRedMaskSize = mib->RedMaskSize;
465 466

    /* 55 - BYTE: red field position (linear modes) */
467
    mib->LinRedFieldPosition = mib->RedFieldPosition;
468 469

    /* 56 - BYTE: green mask size (linear modes) */
470
    mib->LinGreenMaskSize = mib->GreenMaskSize;
471 472

    /* 57 - BYTE: green field size (linear modes) */
473
    mib->LinGreenFieldPosition = mib->GreenFieldPosition;
474 475

    /* 58 - BYTE: blue mask size (linear modes) */
476
    mib->LinBlueMaskSize = mib->BlueMaskSize;
477 478

    /* 59 - BYTE: blue field position (linear modes) */
479
    mib->LinBlueFieldPosition = mib->BlueFieldPosition;
480 481

    /* 60 - BYTE: reserved mask size (linear modes) */
482
    mib->LinRsvdMaskSize = mib->RsvdMaskSize;
483 484

    /* 61 - BYTE: reserved mask position (linear modes) */
485
    mib->LinRsvdFieldPosition = mib->RsvdFieldPosition;
486 487

    /* 62 - DWORD: maximum pixel clock for graphics video mode, in Hz */
488
    mib->MaxPixelClock = 0; /* FIXME */
489

490
    /* 66 - BYTE[190]: reserved, set to zero */
491
    memset( mib->Reserved4, 0, 190 );
492

493 494 495 496 497 498 499 500 501 502 503
    return TRUE;
}


/**********************************************************************
 *         INT10_FillStateInformation
 *
 * Fill 64-byte buffer with VGA state and functionality information.
 */
static void INT10_FillStateInformation( BYTE *buffer, BIOSDATA *data )
{
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
    INT10_HEAP *heap = INT10_GetHeap();

    /* 00 - DWORD: address of static functionality table */
    *(SEGPTR*)(buffer + 0) = MAKESEGPTR( heap->WineHeapSegment,
                                         offsetof(INT10_HEAP, 
                                                  StaticModeSupport) );

    /* 04 - BYTE[30]: copy of BIOS data starting from 0x49 (VideoMode) */
    memmove( buffer + 4, &data->VideoMode, 30 );

    /* 34 - BYTE: number of rows - 1 */
    buffer[34] = data->RowsOnScreenMinus1;

    /* 35 - WORD: bytes/character */
    *(WORD*)(buffer + 35) = data->BytesPerChar;

    /* 37 - BYTE: display combination code of active display */
    buffer[37] = INT10_DCC;

    /* 38 - BYTE: DCC of alternate display */
    buffer[38] = 0; /* no secondary display */

    /* 39 - WORD: number of colors supported in current mode (0000h = mono) */
    *(WORD*)(buffer + 39) = 16; /* FIXME */

    /* 41 - BYTE: number of pages supported in current mode */
    buffer[41] = 1; /* FIXME */

532
    /*
533 534 535 536 537 538
     * 42 - BYTE: number of scan lines active
     * Values (hex):
     * 00 = 200
     * 01 = 350
     * 02 = 400
     * 03 = 480
539
     */
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
    buffer[42] = 3; /* FIXME */

    /* 43 - BYTE: primary character block */
    buffer[43] = 0; /* FIXME */

    /* 44 - BYTE: secondary character block */
    buffer[44] = 0; /* FIXME */

    /*
     * 45 - BYTE: miscellaneous flags
     * Bits:
     * 0 - all modes on all displays on
     * 1 - gray summing on
     * 2 - monochrome display attached
     * 3 - default palette loading disabled
     * 4 - cursor emulation enabled
     * 5 - 0 = intensity; 1 = blinking
     * 6 - flat-panel display is active
     * 7 - unused (0)
     */
    /* FIXME: Correct value? */
    buffer[45] =
        (data->VGASettings & 0x0f) |
        ((data->ModeOptions & 1) << 4); /* cursor emulation */

    /*
     * 46 - BYTE: non-VGA mode support 
     * Bits:
     *   0 - BIOS supports information return for adapter interface
     *   1 - adapter interface driver required
     *   2 - 16-bit VGA graphics present
     *   3 - =1 MFI attributes enabled
     *       =0 VGA attributes enabled
     *   4 - 132-column mode supported
     * 5-7 - reserved
     */
     buffer[46] = 0; /* FIXME: correct value? */

     /* 47 - BYTE[2]: reserved, set to zero */
579
     memset( buffer + 47, 0, 2 );
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615

     /*
      * 49 - BYTE: video memory available
      * Values (hex):
      * 00 - 64K
      * 01 - 128K
      * 02 - 192K
      * 03 - 256K
      */
     buffer[49] = (data->ModeOptions & 0x60) >> 5; /* FIXME */

     /*
      * 50 - BYTE: save pointer state flags
      * Bits:
      *   0 - 512 character set active
      *   1 - dynamic save area present
      *   2 - alpha font override active
      *   3 - graphics font override active
      *   4 - palette override active
      *   5 - DCC override active
      * 6-7 - unused (0)
      */
     buffer[50] = heap->StaticSavePointerFlags;

     /*
      * 51 - BYTE: display information and status 
      * Bits:
      *   0 - flat-panel display attached
      *   1 - flat-panel display active
      *   2 - color display
      * 3-6 - reserved
      *   7 - 640x480 flat-panel can be used simultaneously with CRT
      */
     buffer[51] = 4; /* FIXME: correct value? */

     /* 52 - BYTE[12]: reserved, set to zero */
616
     memset( buffer + 52, 0, 12 );
617 618 619 620 621 622
}


/**********************************************************************
 *         INT10_GetHeap
 */
623
static INT10_HEAP *INT10_GetHeap( void )
624 625 626 627 628 629 630 631 632
{
    static INT10_HEAP *heap_pointer = 0;

    if (!heap_pointer)
    {
        WORD segment;
        int  i;

        heap_pointer = DOSVM_AllocDataUMB( sizeof(INT10_HEAP), 
633 634
                                           &segment,
                                           0 );
635 636 637 638 639 640 641 642 643 644 645 646 647 648

        for (i = 0; i < 7; i++)
            heap_pointer->StaticModeSupport[i] = 0xff; /* FIXME */

        heap_pointer->StaticScanlineSupport = 7;  /* FIXME */
        heap_pointer->StaticNumberCharBlocks = 0; /* FIXME */
        heap_pointer->StaticActiveCharBlocks = 0; /* FIXME */
        heap_pointer->StaticMiscFlags = 0x8ff;    /* FIXME */
        heap_pointer->StaticReserved1 = 0;
        heap_pointer->StaticSavePointerFlags = 0x3f; /* FIXME */
        heap_pointer->StaticReserved2 = 0;

        for (i=0; TRUE; i++)
        {
649 650
            heap_pointer->VesaModeList[i] = VGA_modelist[i].Mode;
            if (VGA_modelist[i].Mode == 0xffff)
651 652 653 654 655 656
                break;
        }

        strcpy( heap_pointer->VesaOEMName, "WINE SVGA BOARD" );
        strcpy( heap_pointer->VesaVendorName, "WINE" );
        strcpy( heap_pointer->VesaProductName, "WINE SVGA" );
657
        strcpy( heap_pointer->VesaProductRev, "2008" );
658 659 660 661 662 663
        
        heap_pointer->VesaCurrentMode = 0; /* Initialized later. */
        heap_pointer->WineHeapSegment = segment;
    }

    return heap_pointer;
664 665 666
}


667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
/**********************************************************************
 *         INT10_SetVideoMode
 *
 * Change current video mode to any VGA or VESA mode.
 * Returns TRUE if mode is supported.
 *
 * Mode bitfields:
 * 0-6: .. Mode number (combined with bit 8).
 *   7: =0 Clear screen.
 *      =1 Preserve display memory on mode change (VGA modes).
 *   8: =0 VGA mode.
 *      =1 VESA mode.
 *   9: .. Reserved, must be zero.
 *  10: .. Reserved, must be zero.
 *  11: =0 Use default refresh rate.
 *      =1 Use user specified refresh rate.
 *  12: .. Reserved, must be zero.
 *  13: .. Reserved, must be zero.
 *  14: =0 Use windowed frame buffer model.
 *      =1 Use linear frame buffer model.
 *  15: =0 Clear screen.
 *      =1 Preserve display memory on mode change (VESA modes).
 */
static BOOL INT10_SetVideoMode( BIOSDATA *data, WORD mode )
{
692
    const VGA_MODE *ptr = VGA_GetModeInfo( mode );
693
    INT10_HEAP *heap = INT10_GetHeap();
694
    BOOL clearScreen = TRUE;
695 696 697 698 699 700

    if (!ptr)
        return FALSE;

    /*
     * Linear framebuffer is not supported.
701 702
     * FIXME - not sure this is valid since mode 19 is 256 color & linear
     *   of course only 1 window is addressable.
703 704 705 706
     */
    if (mode & 0x4000)
        return FALSE;

707 708 709 710 711 712
    /*
     * Check for VGA and VESA preserve video memory flag.
     */
    if ((mode & 0x0080) || (mode & 0x8000))
        clearScreen = FALSE;

713 714 715
    /*
     * Note that we do not mask out flags here on purpose.
     */
716
    heap->VesaCurrentMode = mode;
717 718 719 720 721
    if (mode <= 0xff)
        data->VideoMode = mode;
    else
        data->VideoMode = 0;

722
    if (ptr->ModeType == TEXT)
723 724
    {
        /* Text mode. */
725
        TRACE( "Setting %s %dx%d text mode (screen %s)\n", 
726
               IS_VESA_MODE(mode) ? "VESA" : "VGA", 
727
               ptr->TextCols, ptr->TextRows,
728 729
               clearScreen ? "cleared" : "preserved" );

730 731 732
        /*
         * FIXME: We should check here if alpha mode could be set.
         */
733
        VGA_SetAlphaMode( ptr->TextCols, ptr->TextRows );
734

735 736
        data->VideoColumns = ptr->TextCols;
        data->RowsOnScreenMinus1 = ptr->TextRows - 1;
737 738 739

        if (clearScreen)
        {            
740
            VGA_ClearText( 0, 0, ptr->TextCols-1, ptr->TextRows-1, 0x07 );
741 742 743
            INT10_SetCursorPos( data, 0, 0, 0 );
            VGA_SetCursorPos( 0, 0 );            
        }
744 745 746 747
    }
    else
    {
        /* Graphics mode. */
748
        TRACE( "Setting %s %dx%dx%d graphics mode (screen %s)\n", 
749
               IS_VESA_MODE(mode) ? "VESA" : "VGA", 
750 751 752
               ptr->Width, ptr->Height, ptr->Depth,
               clearScreen ? "cleared" : "preserved" );

753
        if ( VGA_SetMode(mode) )
754 755 756 757 758 759 760
            return FALSE;
    }

    return TRUE;
}


761 762 763 764
/**********************************************************************
 *         INT10_GetCursorPos
 */
static void INT10_GetCursorPos(BIOSDATA*data,unsigned page,unsigned*X,unsigned*Y)
765
{
766 767
    *X = data->VideoCursorPos[page*2];   /* column */
    *Y = data->VideoCursorPos[page*2+1]; /* row */
768 769
}

770 771 772 773 774

/**********************************************************************
 *         INT10_SetCursorPos
 */
static void INT10_SetCursorPos(BIOSDATA*data,unsigned page,unsigned X,unsigned Y)
775
{
776 777
    data->VideoCursorPos[page*2] = X;
    data->VideoCursorPos[page*2+1] = Y;
778 779
}

780 781

/**********************************************************************
782
 *         INT10_InitializeVideoMode
783 784 785 786
 *
 * The first time this function is called VGA emulation is set to the
 * default text mode.
 */
787
static void INT10_InitializeVideoMode( BIOSDATA *data )
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
{
  static BOOL already_initialized = FALSE;
  unsigned    width;
  unsigned    height;

  if(already_initialized)
    return;
  already_initialized = TRUE;

  VGA_InitAlphaMode(&width, &height);

  /*
   * FIXME: Add more mappings between initial size and
   *        text modes.
   */
803 804 805 806
  if (width >= 80 && height >= 25)
      INT10_SetVideoMode( data, 0x03 );
  else
      INT10_SetVideoMode( data, 0x01 );
807 808 809
}


Alexandre Julliard's avatar
Alexandre Julliard committed
810
/**********************************************************************
811
 *          INT10_HandleVESA
812
 *
813
 * Handler for VESA functions (int10 function 0x4f).
814
 */
815
static void INT10_HandleVESA( CONTEXT *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
816
{
817
    BIOSDATA *data = DOSVM_BiosData();
818

819 820
    switch(AL_reg(context)) {

821 822 823 824 825 826 827 828 829 830
    case 0x00: /* RETURN CONTROLLER INFORMATION */
        TRACE( "VESA RETURN CONTROLLER INFORMATION\n" );
        {
            BYTE *ptr = CTX_SEG_OFF_TO_LIN(context,
                                           context->SegEs, 
                                           context->Edi);
            INT10_FillControllerInformation( ptr );
            SET_AL( context, 0x4f );
            SET_AH( context, 0x00 ); /* 0x00 = successful 0x01 = failed */
        }
831 832
        break;

833 834 835
    case 0x01: /* RETURN MODE INFORMATION */
        TRACE( "VESA RETURN MODE INFORMATION %04x\n", CX_reg(context) );
        {
836 837 838
            struct _ModeInfoBlock *ptr = CTX_SEG_OFF_TO_LIN(context,
                                                            context->SegEs, 
                                                            context->Edi);
839 840 841 842 843 844
            SET_AL( context, 0x4f );
            if (INT10_FillModeInformation( ptr, CX_reg(context) ))
                SET_AH( context, 0x00 ); /* status: success */
            else
                SET_AH( context, 0x01 ); /* status: failed */
        }
845 846 847
        break;

    case 0x02: /* SET SuperVGA VIDEO MODE */
848 849 850 851 852 853
        TRACE( "Set VESA video mode %04x\n", BX_reg(context) );
        SET_AL( context, 0x4f ); /* function supported */
        if (INT10_SetVideoMode( data, BX_reg(context) ))
            SET_AH( context, 0x00 ); /* success */
        else
            SET_AH( context, 0x01 ); /* failed */
854 855 856
        break;

    case 0x03: /* VESA SuperVGA BIOS - GET CURRENT VIDEO MODE */
857
        SET_AL( context, 0x4f );
858 859
        SET_AH( context, 0x00 );
        SET_BX( context, INT10_GetHeap()->VesaCurrentMode );
860 861 862 863 864 865 866 867 868 869 870 871
        break;

    case 0x04: /* VESA SuperVGA BIOS - SAVE/RESTORE SuperVGA VIDEO STATE */
        ERR("VESA SAVE/RESTORE Video State - Not Implemented\n");
        /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
        /* maybe we should do this instead ? */
        /* AH_reg(context = 0x01;  not implemented so just fail */
        break;

    case 0x05: /* VESA SuperVGA BIOS - CPU VIDEO MEMORY CONTROL */
        /*
         * This subfunction supports only Window A (BL_reg == 0) and
Austin English's avatar
Austin English committed
872
         * it assumes that window granularity is 64k.
873 874 875
         */
        switch(BH_reg(context)) {
        case 0x00: /* select video memory window */
876
            SET_AL( context, 0x4f ); /* function supported */
877 878
            if(BL_reg(context) == 0) {
                VGA_SetWindowStart(DX_reg(context) * 64 * 1024);
879
                SET_AH( context, 0x00 ); /* status: successful */
880
            } else
881
                SET_AH( context, 0x01 ); /* status: failed */
882 883
            break;
        case 0x01: /* get video memory window */
884
            SET_AL( context, 0x4f ); /* function supported */
885
            if(BL_reg(context) == 0) {
886 887
                SET_DX( context, VGA_GetWindowStart() / 64 / 1024 );
                SET_AH( context, 0x00 ); /* status: successful */
888
            } else
889
                SET_AH( context, 0x01 ); /* status: failed */
890
            break;
891
	default:
892
            INT_BARF( context, 0x10 );
893
	}
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
        break;

    case 0x06: /* VESA GET/SET LOGICAL SCAN LINE LENGTH */
        ERR("VESA GET/SET LOGICAL SCAN LINE LENGTH - Not Implemented\n");
        /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
        /* maybe we should do this instead ? */
        /* AH_reg(context = 0x001; not implemented so just fail */
        break;

    case 0x07: /* GET/SET DISPLAY START */
        ERR("VESA GET/SET DISPLAY START - Not Implemented\n");
        /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
        /* maybe we should do this instead ? */
        /* AH_reg(context = 0x001; not implemented so just fail */
        break;

    case 0x08: /* GET/SET DAC PALETTE CONTROL */
        ERR("VESA GET/SET DAC PALETTE CONTROL- Not Implemented\n");
        /* AL_reg(context) = 0x4f; = supported so not set since not implemented */
        /* maybe we should do this instead ? */
        /* AH_reg(context = 0x001; not implemented so just fail */
        break;

    case 0x09: /* SET PALETTE ENTRIES */
        FIXME("VESA Set palette entries - not implemented\n");
        break;

    case 0x0a: /* GET PROTECTED-MODE CODE */
        FIXME("VESA Get protected-mode code - not implemented\n");
        break;

    case 0x10: /* Display Power Management Extensions */
        FIXME("VESA Display Power Management Extensions - not implemented\n");
        break;

    case 0xef:  /* get video mode for hercules-compatibles   */
        /* There's no reason to really support this  */
        /* is there?....................(A.C.)       */
        TRACE("Just report the video not hercules compatible\n");
933
        SET_DX( context, 0xffff );
934 935 936
        break;

    case 0xff: /* Turn VESA ON/OFF */
937
        /* I don't know what to do */
938 939 940 941 942
        break;

    default:
        FIXME("VESA Function (0x%x) - Not Supported\n", AH_reg(context));
        break;
943
    }
944 945
}

946

947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
/**********************************************************************
 *	    DOSVM_Int10Handler
 *
 * Handler for int 10h (video).
 *
 * NOTE:
 *    Most INT 10 functions for text-mode, CGA, EGA, and VGA cards
 *    are present in this list. (SVGA and XGA are not) That is not
 *    to say that all these functions should be supported, but if
 *    anyone is brain-damaged enough to want to emulate one of these
 *    beasts then this should get you started.
 *
 * NOTE:
 *    Several common graphical extensions used by Microsoft hook
 *    off of here. I have *not* added them to this list (yet). They
 *    include:
 *
 *    MSHERC.COM - More functionality for Hercules cards.
 *    EGA.SYS (also MOUSE.COM) - More for EGA cards.
 *
 *    Yes, MS also added this support into their mouse driver. Don't
 *    ask me, I don't work for them.
 *
 * Joseph Pranevich - 9/98
 *
 *  Jess Haas 2/99
 *	Added support for Vesa. It is not complete but is a start.
974 975
 *	NOTE: Im not sure if I did all this right or if any of it works.
 *	Currently I don't have a program that uses Vesa that actually gets far
976 977 978 979
 *	enough without crashing to do vesa stuff.
 *
 *      Added additional vga graphic support - 3/99
 */
980
void WINAPI DOSVM_Int10Handler( CONTEXT *context )
981
{
982
    BIOSDATA *data = DOSVM_BiosData();
983

984
    INT10_InitializeVideoMode( data );
985

986
    switch(AH_reg(context)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
987

988
    case 0x00: /* SET VIDEO MODE */
989 990
        TRACE( "Set VGA video mode %02x\n", AL_reg(context) );
        if (!INT10_SetVideoMode( data, AL_reg(context) ))
991
            FIXME( "Unsupported VGA video mode requested: %#x\n", 
992
                   AL_reg(context) );
Alexandre Julliard's avatar
Alexandre Julliard committed
993 994 995
        break;

    case 0x01: /* SET CURSOR SHAPE */
996 997 998 999
        TRACE("Set Cursor Shape start %d end %d options %d\n",
              CH_reg(context) & 0x1f,
              CL_reg(context) & 0x1f,
              CH_reg(context) & 0xe0);
1000 1001
        data->VideoCursorType = CX_reg(context); /* direct copy */
	VGA_SetCursorShape(CH_reg(context), CL_reg(context));
Alexandre Julliard's avatar
Alexandre Julliard committed
1002
        break;
1003

Alexandre Julliard's avatar
Alexandre Julliard committed
1004
    case 0x02: /* SET CURSOR POSITION */
1005 1006 1007
        /* BH = Page Number */ /* Not supported */
        /* DH = Row */ /* 0 is left */
        /* DL = Column */ /* 0 is top */
1008
        INT10_SetCursorPos(data,BH_reg(context),DL_reg(context),DH_reg(context));
1009 1010
        if (BH_reg(context))
        {
1011
           FIXME("Set Cursor Position: Cannot set to page %d\n",
1012 1013 1014 1015
              BH_reg(context));
        }
        else
        {
1016
           VGA_SetCursorPos(DL_reg(context), DH_reg(context));
Andreas Mohr's avatar
Andreas Mohr committed
1017 1018
           TRACE("Set Cursor Position: %d/%d\n", DL_reg(context),
              DH_reg(context));
1019
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1020 1021 1022
        break;

    case 0x03: /* GET CURSOR POSITION AND SIZE */
1023
        {
1024
          unsigned row, col;
1025

1026
          TRACE("Get cursor position and size (page %d)\n", BH_reg(context));
1027
          SET_CX( context, data->VideoCursorType );
1028
          INT10_GetCursorPos(data,BH_reg(context),&col,&row);
1029 1030
          SET_DH( context, row );
          SET_DL( context, col );
Andreas Mohr's avatar
Andreas Mohr committed
1031
          TRACE("Cursor Position: %d/%d\n", DL_reg(context), DH_reg(context));
1032
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1033
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1034

Alexandre Julliard's avatar
Alexandre Julliard committed
1035
    case 0x04: /* READ LIGHT PEN POSITION */
1036
        FIXME("Read Light Pen Position - Not Supported\n");
1037
        SET_AH( context, 0x00 ); /* Not down */
Alexandre Julliard's avatar
Alexandre Julliard committed
1038 1039 1040
        break;

    case 0x05: /* SELECT ACTIVE DISPLAY PAGE */
Andreas Mohr's avatar
Andreas Mohr committed
1041
        FIXME("Select Active Display Page (%d) - Not Supported\n", AL_reg(context));
1042
        data->VideoCurPage = AL_reg(context);
Alexandre Julliard's avatar
Alexandre Julliard committed
1043 1044 1045
        break;

    case 0x06: /* SCROLL UP WINDOW */
1046 1047 1048 1049
        /* AL = Lines to scroll */
        /* BH = Attribute */
        /* CH,CL = row, col upper-left */
        /* DH,DL = row, col lower-right */
1050
        TRACE("Scroll Up Window %d\n", AL_reg(context));
1051 1052 1053 1054 1055 1056 1057 1058 1059

        if (AL_reg(context) == 0)
            VGA_ClearText( CH_reg(context), CL_reg(context),
                           DH_reg(context), DL_reg(context),
                           BH_reg(context) );
        else
            VGA_ScrollUpText( CH_reg(context), CL_reg(context),
                              DH_reg(context), DL_reg(context),
                              AL_reg(context), BH_reg(context) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1060 1061 1062
        break;

    case 0x07: /* SCROLL DOWN WINDOW */
1063 1064 1065 1066
        /* AL = Lines to scroll */
        /* BH = Attribute */
        /* CH,CL = row, col upper-left */
        /* DH,DL = row, col lower-right */
1067
        TRACE("Scroll Down Window %d\n", AL_reg(context));
1068 1069 1070 1071 1072 1073 1074 1075 1076

        if (AL_reg(context) == 0)
            VGA_ClearText( CH_reg(context), CL_reg(context),
                           DH_reg(context), DL_reg(context),
                           BH_reg(context) );
        else
            VGA_ScrollDownText( CH_reg(context), CL_reg(context),
                                DH_reg(context), DL_reg(context),
                                AL_reg(context), BH_reg(context) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1077 1078 1079
        break;

    case 0x08: /* READ CHARACTER AND ATTRIBUTE AT CURSOR POSITION */
1080
        {
1081 1082
            if (BH_reg(context)) /* Write to different page */
            {
1083
                FIXME("Read character and attribute at cursor position -"
1084
                      " Can't read from non-0 page\n");
1085 1086
                SET_AL( context, ' ' ); /* That page is blank */
                SET_AH( context, 7 );
1087 1088
            }
            else
1089
           {
1090
                BYTE ascii, attr;
1091
                TRACE("Read Character and Attribute at Cursor Position\n");
1092
                VGA_GetCharacterAtCursor(&ascii, &attr);
1093 1094
                SET_AL( context, ascii );
                SET_AH( context, attr );
1095
            }
1096
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1097 1098 1099
        break;

    case 0x09: /* WRITE CHARACTER AND ATTRIBUTE AT CURSOR POSITION */
1100
    case 0x0a: /* WRITE CHARACTER ONLY AT CURSOR POSITION */
1101 1102 1103 1104
       /* AL = Character to display. */
       /* BH = Page Number */ /* We can't write to non-0 pages, yet. */
       /* BL = Attribute / Color */
       /* CX = Times to Write Char */
1105
       /* Note here that the cursor is not advanced. */
1106 1107 1108
       {
           unsigned row, col;

1109
           INT10_GetCursorPos(data,BH_reg(context),&col,&row);
1110 1111 1112 1113 1114
           VGA_WriteChars(col, row,
                          AL_reg(context),
                          (AH_reg(context) == 0x09) ? BL_reg(context) : -1,
                          CX_reg(context));
           if (CX_reg(context) > 1)
1115 1116
              TRACE("Write Character%s at Cursor Position (Rep. %d): %c\n",
                    (AH_reg(context) == 0x09) ? " and Attribute" : "",
1117 1118
                 CX_reg(context), AL_reg(context));
           else
1119 1120
              TRACE("Write Character%s at Cursor Position: %c\n",
                    (AH_reg(context) == 0x09) ? " and Attribute" : "",
1121 1122
                AL_reg(context));
       }
1123
       break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1124

1125
    case 0x0b:
Alexandre Julliard's avatar
Alexandre Julliard committed
1126 1127
        switch BH_reg(context) {
        case 0x00: /* SET BACKGROUND/BORDER COLOR */
1128 1129
            /* In text modes, this sets only the border... */
            /* According to the interrupt list and one of my books. */
1130
            /* Funny though that Beyond Zork seems to indicate that it
1131 1132 1133
               also sets up the default background attributes for clears
               and scrolls... */
            /* Bear in mind here that we do not want to change,
Andreas Mohr's avatar
Andreas Mohr committed
1134
               apparently, the foreground or attribute of the background
1135 1136
               with this call, so we should check first to see what the
               foreground already is... FIXME */
1137 1138 1139 1140 1141

            /* For CGA modes, background color change is the same as writing
               to I/O address 0x3d9 bit 4  */
            if(data->VideoMode >= 4 && data->VideoMode <= 6)
            {
1142
              VGA_SetBright((BL_reg(context) & 0x10) != 0);
1143 1144 1145 1146
              VGA_UpdatePalette();
            }
            else FIXME("Set Background/Border Color: %d/%d\n",
              BH_reg(context), BL_reg(context));
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148
            break;
        case 0x01: /* SET PALETTE */
1149 1150 1151 1152 1153 1154 1155 1156 1157

            /* For CGA modes, palette color change is the same as writing
               to I/O address 0x3d9 bit 5 */
            if(data->VideoMode >= 4 && data->VideoMode <= 6)
	    {
              VGA_SetPaletteIndex(BL_reg(context) & 1);
              VGA_UpdatePalette();
            }
            else FIXME("Set Palette - Not Supported: %02X\n", BL_reg(context));
Alexandre Julliard's avatar
Alexandre Julliard committed
1158 1159
            break;
        default:
1160
            FIXME("INT 10 AH = 0x0b BH = 0x%x - Unknown\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1161 1162 1163 1164 1165 1166
               BH_reg(context));
            break;
        }
        break;

    case 0x0c: /* WRITE GRAPHICS PIXEL */
1167 1168 1169 1170 1171 1172 1173

        /* Only supported in CGA mode for now */
        if(data->VideoMode >= 4 && data->VideoMode <= 6)
        {
          VGA_WritePixel(AL_reg(context), BH_reg(context), CX_reg(context), DX_reg(context));
        }
        else FIXME("Write pixel not implemented for current mode\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1174
        break;
1175

Alexandre Julliard's avatar
Alexandre Julliard committed
1176 1177
    case 0x0d: /* READ GRAPHICS PIXEL */
        /* Not in graphics mode, can ignore w/o error */
1178
        FIXME("Read Graphics Pixel - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1179
        break;
1180

Alexandre Julliard's avatar
Alexandre Julliard committed
1181
    case 0x0e: /* TELETYPE OUTPUT */
1182
        TRACE("Teletype Output\n");
1183
        DOSVM_PutChar(AL_reg(context));
Alexandre Julliard's avatar
Alexandre Julliard committed
1184 1185 1186
        break;

    case 0x0f: /* GET CURRENT VIDEO MODE */
Andreas Mohr's avatar
Andreas Mohr committed
1187
        TRACE("Get current video mode: -> mode %d, columns %d\n", data->VideoMode, data->VideoColumns);
1188
        /* Note: This should not be a constant value. */
1189 1190 1191
        SET_AL( context, data->VideoMode );
        SET_AH( context, data->VideoColumns );
        SET_BH( context, 0 ); /* Display page 0 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1192 1193
        break;

1194
    case 0x10:
Alexandre Julliard's avatar
Alexandre Julliard committed
1195
        switch AL_reg(context) {
1196 1197 1198
        case 0x00: /* SET SINGLE PALETTE REGISTER - A.C. */
            TRACE("Set Single Palette Register - Reg 0x0%x Value 0x0%x\n",
		BL_reg(context),BH_reg(context));
1199 1200
		/* BH is the value  BL is the register */
		VGA_SetColor16((int)BL_reg(context),(int)BH_reg(context));
Alexandre Julliard's avatar
Alexandre Julliard committed
1201 1202
            break;
        case 0x01: /* SET BORDER (OVERSCAN) */
1203
            /* Text terminals have no overscan */
1204
	    /* I'm setting it anyway. - A.C.   */
1205 1206
            TRACE("Set Border (Overscan) - Ignored but set.\n");
	    VGA_SetColor16(16,(int)BH_reg(context));
Alexandre Julliard's avatar
Alexandre Julliard committed
1207
            break;
1208 1209 1210
        case 0x02: /* SET ALL PALETTE REGISTERS - A.C.*/
            TRACE("Set all palette registers\n");
		/* ES:DX points to a 17 byte table of colors */
1211 1212
		/* No return data listed */
		/* I'll have to update my table and the default palette */
1213
               VGA_Set16Palette(CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edx));
Alexandre Julliard's avatar
Alexandre Julliard committed
1214 1215
            break;
        case 0x03: /* TOGGLE INTENSITY/BLINKING BIT */
1216
            FIXME("Toggle Intensity/Blinking Bit - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1217
            break;
1218 1219
        case 0x07: /* GET INDIVIDUAL PALETTE REGISTER  - A.C.*/
            TRACE("Get Individual Palette Register 0x0%x\n",BL_reg(context));
1220
		/* BL is register to read [ 0-15 ] BH is return value */
1221
	        SET_BH( context, VGA_GetColor16((int)BL_reg(context)) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1222
            break;
1223
        case 0x08: /* READ OVERSCAN (BORDER COLOR) REGISTER  - A.C. */
1224
            TRACE("Read Overscan (Border Color) Register\n");
1225
	        SET_BH( context, VGA_GetColor16(16) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1226
            break;
1227
        case 0x09: /* READ ALL PALETTE REGISTERS AND OVERSCAN REGISTER - A.C.*/
1228
            TRACE("Read All Palette Registers and Overscan Register\n");
1229 1230 1231
		/* ES:DX points to a 17 byte table where the results */
		/*  of this call should be stored.                   */
               VGA_Get16Palette(CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edx));
Alexandre Julliard's avatar
Alexandre Julliard committed
1232 1233
            break;
        case 0x10: /* SET INDIVIDUAL DAC REGISTER */
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
            {
                PALETTEENTRY paldat;

                TRACE("Set Individual DAC register\n");
                paldat.peRed   = DH_reg(context);
                paldat.peGreen = CH_reg(context);
                paldat.peBlue  = CL_reg(context);
                paldat.peFlags = 0;
                VGA_SetPalette(&paldat,BX_reg(context)&0xFF,1);
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1244 1245
            break;
        case 0x12: /* SET BLOCK OF DAC REGISTERS */
1246 1247 1248 1249 1250 1251
            {
                int i;
                PALETTEENTRY paldat;
                BYTE *pt;

                TRACE("Set Block of DAC registers\n");
1252
                pt = CTX_SEG_OFF_TO_LIN(context,context->SegEs,context->Edx);
1253 1254 1255 1256 1257 1258 1259 1260 1261
		for (i=0;i<CX_reg(context);i++)
                {
                    paldat.peRed   = (*(pt+i*3+0)) << 2;
                    paldat.peGreen = (*(pt+i*3+1)) << 2;
                    paldat.peBlue  = (*(pt+i*3+2)) << 2;
                    paldat.peFlags = 0;
                    VGA_SetPalette(&paldat,(BX_reg(context)+i)&0xFF,1);
                }
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1262 1263
            break;
        case 0x13: /* SELECT VIDEO DAC COLOR PAGE */
1264
            FIXME("Select video DAC color page - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1265 1266
            break;
        case 0x15: /* READ INDIVIDUAL DAC REGISTER */
1267
            FIXME("Read individual DAC register - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1268 1269
            break;
        case 0x17: /* READ BLOCK OF DAC REGISTERS */
1270
            FIXME("Read block of DAC registers - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1271 1272
            break;
        case 0x18: /* SET PEL MASK */
1273
            FIXME("Set PEL mask - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1274 1275
            break;
        case 0x19: /* READ PEL MASK */
1276
            FIXME("Read PEL mask - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1277 1278
            break;
        case 0x1a: /* GET VIDEO DAC COLOR PAGE STATE */
1279
            FIXME("Get video DAC color page state - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1280 1281
            break;
        case 0x1b: /* PERFORM GRAY-SCALE SUMMING */
1282
            FIXME("Perform Gray-scale summing - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1283 1284
            break;
        default:
1285
            FIXME("INT 10 AH = 0x10 AL = 0x%x - Unknown\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1286 1287 1288 1289 1290 1291 1292 1293
               AL_reg(context));
            break;
        }
        break;

    case 0x11: /* TEXT MODE CHARGEN */
        /* Note that second subfunction is *almost* identical. */
        /* See INTERRUPT.A for details. */
Jess Haas's avatar
Jess Haas committed
1294
        switch AL_reg(context) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1295 1296
        case 0x00: /* LOAD USER SPECIFIED PATTERNS */
        case 0x10:
1297
            FIXME("Load User Specified Patterns - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1298 1299 1300
            break;
        case 0x01: /* LOAD ROM MONOCHROME PATTERNS */
        case 0x11:
1301
            FIXME("Load ROM Monochrome Patterns - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1302 1303 1304
            break;
        case 0x02: /* LOAD ROM 8x8 DOUBLE-DOT PATTERNS */
        case 0x12:
1305
            FIXME(
1306
                "Load ROM 8x8 Double Dot Patterns - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1307 1308
            break;
        case 0x03: /* SET BLOCK SPECIFIER */
1309
            FIXME("Set Block Specifier - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1310 1311 1312
            break;
        case 0x04: /* LOAD ROM 8x16 CHARACTER SET */
        case 0x14:
1313
            FIXME("Load ROM 8x16 Character Set - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1314 1315
            break;
        case 0x20: /* SET USER 8x16 GRAPHICS CHARS */
1316
            FIXME("Set User 8x16 Graphics Chars - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1317 1318
            break;
        case 0x21: /* SET USER GRAPICS CHARACTERS */
1319
            FIXME("Set User Graphics Characters - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1320 1321
            break;
        case 0x22: /* SET ROM 8x14 GRAPHICS CHARS */
1322
            FIXME("Set ROM 8x14 Graphics Chars - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1323 1324
            break;
        case 0x23: /* SET ROM 8x8 DBL DOT CHARS */
1325
            FIXME(
Alexandre Julliard's avatar
Alexandre Julliard committed
1326 1327 1328
                "Set ROM 8x8 Dbl Dot Chars (Graphics) - Not Supported\n");
            break;
        case 0x24: /* LOAD 8x16 GRAPHIC CHARS */
1329
            FIXME("Load 8x16 Graphic Chars - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1330 1331
            break;
        case 0x30: /* GET FONT INFORMATION */
1332
            FIXME("Get Font Information - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1333 1334
            break;
        default:
1335
            FIXME("INT 10 AH = 0x11 AL = 0x%x - Unknown\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1336 1337 1338 1339
               AL_reg(context));
            break;
        }
        break;
1340

Alexandre Julliard's avatar
Alexandre Julliard committed
1341 1342 1343
    case 0x12: /* ALTERNATE FUNCTION SELECT */
        switch BL_reg(context) {
        case 0x10: /* GET EGA INFO */
1344
            TRACE("EGA info requested\n");
1345 1346 1347
            SET_BH( context, 0x00 );   /* Color screen */
            SET_BL( context, data->ModeOptions >> 5 ); /* EGA memory size */
            SET_CX( context, data->FeatureBitsSwitches );
Alexandre Julliard's avatar
Alexandre Julliard committed
1348 1349
            break;
        case 0x20: /* ALTERNATE PRTSC */
1350
            FIXME("Install Alternate Print Screen - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1351
            break;
Austin English's avatar
Austin English committed
1352
        case 0x30: /* SELECT VERTICAL RESOLUTION */
1353
            FIXME("Select vertical resolution - not supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1354
            break;
1355
        case 0x31: /* ENABLE/DISABLE DEFAULT PALETTE LOADING */
1356
            FIXME("Default palette loading - not supported\n");
1357 1358
            data->VGASettings =
                (data->VGASettings & 0xf7) |
1359
                ((AL_reg(context) == 1) << 3);
Alexandre Julliard's avatar
Alexandre Julliard committed
1360
            break;
Austin English's avatar
Austin English committed
1361
        case 0x32: /* ENABLE/DISABLE VIDEO ADDRESSING */
1362
            FIXME("Video Addressing - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1363 1364
            break;
        case 0x33: /* ENABLE/DISABLE GRAY SCALE SUMMING */
1365
            FIXME("Gray Scale Summing - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1366 1367
            break;
        case 0x34: /* ENABLE/DISABLE CURSOR EMULATION */
1368
            TRACE("Set cursor emulation to %d\n", AL_reg(context));
1369 1370
            data->ModeOptions =
                (data->ModeOptions & 0xfe)|(AL_reg(context) == 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1371 1372
            break;
        case 0x36: /* VIDEO ADDRESS CONTROL */
1373
            FIXME("Video Address Control - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1374 1375
            break;
        default:
1376
            FIXME("INT 10 AH = 0x11 AL = 0x%x - Unknown\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1377 1378
               AL_reg(context));
            break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1379 1380
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1381 1382 1383

    case 0x13: /* WRITE STRING */
        /* This one does not imply that string be at cursor. */
1384
        FIXME("Write String - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1385
        break;
1386 1387

    case 0x1a:
Alexandre Julliard's avatar
Alexandre Julliard committed
1388 1389
        switch AL_reg(context) {
        case 0x00: /* GET DISPLAY COMBINATION CODE */
1390
            TRACE("Get Display Combination Code\n");
1391 1392 1393
            SET_AL( context, 0x1a );      /* Function supported */
            SET_BL( context, INT10_DCC ); /* Active display */
            SET_BH( context, 0x00 );      /* No alternate display */
Alexandre Julliard's avatar
Alexandre Julliard committed
1394 1395
            break;
        case 0x01: /* SET DISPLAY COMBINATION CODE */
1396
            FIXME("Set Display Combination Code - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1397 1398
            break;
        default:
1399
            FIXME("INT 10 AH = 0x1a AL = 0x%x - Unknown\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1400 1401 1402 1403 1404 1405
               AL_reg(context));
            break;
        }
    break;

    case 0x1b: /* FUNCTIONALITY/STATE INFORMATION */
1406
        TRACE("Get functionality/state information\n");
1407
        if (BX_reg(context) == 0x0000)
1408
        {
1409 1410 1411 1412 1413
            BYTE *ptr = CTX_SEG_OFF_TO_LIN(context,
                                           context->SegEs, 
                                           context->Edi);
            SET_AL( context, 0x1b ); /* Function is supported */
            INT10_FillStateInformation( ptr, data );
1414
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1415 1416 1417
        break;

    case 0x1c: /* SAVE/RESTORE VIDEO STATE */
1418
        FIXME("Save/Restore Video State - Not Supported\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1419
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1420

1421
        case 0xef:  /* get video mode for hercules-compatibles   */
1422 1423
                    /* There's no reason to really support this  */
                    /* is there?....................(A.C.)       */
1424
                TRACE("Just report the video not hercules compatible\n");
1425
                SET_DX( context, 0xffff );
1426
                break;
1427 1428

    case 0x4f: /* VESA */
1429
        INT10_HandleVESA(context);
1430 1431
        break;

1432
    case 0xfe: /* GET SHADOW BUFFER */
1433
        TRACE( "GET SHADOW BUFFER %x:%x - ignored\n",
1434 1435 1436
               context->SegEs, DI_reg(context) );
        break;

Alexandre Julliard's avatar
Alexandre Julliard committed
1437
    default:
1438
        FIXME("Unknown - 0x%x\n", AH_reg(context));
Alexandre Julliard's avatar
Alexandre Julliard committed
1439
        INT_BARF( context, 0x10 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1440
    }
1441
}
1442

1443

1444 1445 1446
/**********************************************************************
 *         DOSVM_PutChar
 *
1447 1448
 * Write single character to VGA console at the current 
 * cursor position and updates the BIOS cursor position.
1449
 */
1450
void DOSVM_PutChar( BYTE ascii )
1451
{
1452
  BIOSDATA *data = DOSVM_BiosData();
1453 1454
  unsigned  xpos, ypos;

1455
  TRACE("char: 0x%02x(%c)\n", ascii, ascii);
1456

1457
  INT10_InitializeVideoMode( data );
1458 1459 1460

  VGA_PutChar( ascii );
  VGA_GetCursorPos( &xpos, &ypos );
1461
  INT10_SetCursorPos( data, 0, xpos, ypos );
1462
}