| /* | 
 |  * BIOS interrupt 10h handler | 
 |  */ | 
 |  | 
 | #include <stdlib.h> | 
 | #include "miscemu.h" | 
 | #include "vga.h" | 
 | #include "debug.h" | 
 | #include "console.h" | 
 |  | 
 | static void conv_text_mode_attributes(char attribute, int *fg, int *bg, | 
 |        int *wattribute); | 
 | static void write_char_attribute_at_cursor(char output, char page_num,  | 
 |        char attribute, short times); | 
 | static void scroll_window(int direction, char lines, char row1,  | 
 |    char col1, char row2, char col2, char attribute); | 
 |  | 
 | static int color_pallet[16]; | 
 |  | 
 | #define SCROLL_UP 1 | 
 | #define SCROLL_DOWN 2 | 
 |  | 
 | /********************************************************************** | 
 |  *	    INT_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 braindamaged 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  | 
 |  */ | 
 |  | 
 | void WINAPI INT_Int10Handler( CONTEXT *context ) | 
 | { | 
 |     static int registered_colors = FALSE; | 
 |     static int video_mode = 7; | 
 |     static int video_columns = 80; | 
 |  | 
 |     if (!registered_colors) | 
 |     { | 
 |         /* Colors: | 
 |              0000b   black          1000b   dark gray | 
 |              0001b   blue           1001b   light blue | 
 |              0010b   green          1010b   light green | 
 |              0011b   cyan           1011b   light cyan | 
 |              0100b   red            1100b   light red | 
 |              0101b   magenta        1101b   light magenta | 
 |              0110b   brown          1110b   yellow | 
 |              0111b   light gray     1111b   white | 
 |         */ | 
 |          | 
 |         /* These AllocColor calls have the side-effect of triggering  | 
 |            ternimal initialization as xx_Init() is no longer called on | 
 |            startup. Which is what we want anyway. */ | 
 |  | 
 |         color_pallet[0]  = CONSOLE_AllocColor(WINE_BLACK); | 
 |         color_pallet[1]  = CONSOLE_AllocColor(WINE_BLUE); | 
 |         color_pallet[2]  = CONSOLE_AllocColor(WINE_GREEN); | 
 |         color_pallet[3]  = CONSOLE_AllocColor(WINE_CYAN); | 
 |         color_pallet[4]  = CONSOLE_AllocColor(WINE_RED); | 
 |         color_pallet[5]  = CONSOLE_AllocColor(WINE_MAGENTA); | 
 |         color_pallet[6]  = CONSOLE_AllocColor(WINE_BROWN); | 
 |         color_pallet[7]  = CONSOLE_AllocColor(WINE_LIGHT_GRAY); | 
 |         color_pallet[8]  = CONSOLE_AllocColor(WINE_DARK_GRAY); | 
 |         color_pallet[9]  = CONSOLE_AllocColor(WINE_LIGHT_BLUE); | 
 |         color_pallet[10] = CONSOLE_AllocColor(WINE_LIGHT_GREEN); | 
 |         color_pallet[11] = CONSOLE_AllocColor(WINE_LIGHT_CYAN); | 
 |         color_pallet[12] = CONSOLE_AllocColor(WINE_LIGHT_RED); | 
 |         color_pallet[13] = CONSOLE_AllocColor(WINE_LIGHT_MAGENTA); | 
 |         color_pallet[14] = CONSOLE_AllocColor(WINE_YELLOW); | 
 |         color_pallet[15] = CONSOLE_AllocColor(WINE_WHITE); | 
 |  | 
 |         registered_colors = TRUE; | 
 |     } | 
 |  | 
 |     switch(AH_reg(context)) { | 
 |  | 
 |     case 0x00: /* SET VIDEO MODE */ | 
 |         /* Text Modes: */ | 
 |         /* (mode) (text rows/cols) | 
 |             0x00 - 40x25  | 
 |             0x01 - 40x25 | 
 |             0x02 - 80x25 | 
 |             0x03 - 80x25 or 80x43 or 80x50 (assume 80x25)  | 
 |             0x07 - 80x25 | 
 |         */ | 
 |  | 
 |         switch (AL_reg(context)) { | 
 |             case 0x00: /* 40x25 */ | 
 |             case 0x01: | 
 |                 VGA_Exit(); | 
 |                 TRACE(int10, "Set Video Mode - Set to Text - 0x0%x\n", | 
 |                    AL_reg(context)); | 
 |                 CONSOLE_ResizeScreen(40, 25); | 
 |                 CONSOLE_ClearScreen(); | 
 |                 video_mode = AL_reg(context); | 
 |                 video_columns = 40; | 
 |                 break;                 | 
 |             case 0x02: | 
 |             case 0x03: | 
 |             case 0x07: | 
 |                 VGA_Exit(); | 
 |                 TRACE(int10, "Set Video Mode - Set to Text - 0x0%x\n", | 
 |                    AL_reg(context)); | 
 |                 CONSOLE_ResizeScreen(80, 25); | 
 |                 CONSOLE_ClearScreen(); | 
 |                 video_mode = AL_reg(context); | 
 |                 video_columns = 80; | 
 |                 break; | 
 |             case 0x13: | 
 |                 TRACE(int10, "Setting VGA 320x200 256-color mode\n"); | 
 |                 VGA_SetMode(320,200,8); | 
 |                 video_mode = AL_reg(context); | 
 |                 break; | 
 |             default: | 
 |                 FIXME(int10, "Set Video Mode (0x%x) - Not Supported\n",  | 
 |                    AL_reg(context)); | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x01: /* SET CURSOR SHAPE */ | 
 |         FIXME(int10, "Set Cursor Shape - Not Supported\n"); | 
 |         break; | 
 |      | 
 |     case 0x02: /* SET CURSOR POSITION */ | 
 |         /* BH = Page Number */ /* Not supported */ | 
 |         /* DH = Row */ /* 0 is left */ | 
 |         /* DL = Column */ /* 0 is top */ | 
 |         if (BH_reg(context)) | 
 |         { | 
 |            FIXME(int10, "Set Cursor Position: Cannot set to page %d\n", | 
 |               BH_reg(context)); | 
 |         } | 
 |         else | 
 |         { | 
 |            CONSOLE_MoveCursor(DH_reg(context), DL_reg(context)); | 
 |            TRACE(int10, "Set Cursor Position: %d %d\n", DH_reg(context),  | 
 |               DL_reg(context)); | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x03: /* GET CURSOR POSITION AND SIZE */ | 
 |         FIXME(int10, "Get Cursor Position and Size - Not Supported\n"); | 
 |         CX_reg(context) = 0x0000; /* Bogus cursor data */ | 
 |         DX_reg(context) = 0x0000; | 
 |         break; | 
 |  | 
 |     case 0x04: /* READ LIGHT PEN POSITION */ | 
 |         FIXME(int10, "Read Light Pen Position - Not Supported\n"); | 
 |         AH_reg(context) = 0x00; /* Not down */ | 
 |         break; | 
 |  | 
 |     case 0x05: /* SELECT ACTIVE DISPLAY PAGE */ | 
 |         FIXME(int10, "Select Active Display Page - Not Supported\n"); | 
 |         break; | 
 |  | 
 |     case 0x06: /* SCROLL UP WINDOW */ | 
 |         /* AL = Lines to scroll */ | 
 |         /* BH = Attribute */ | 
 |         /* CH,CL = row, col upper-left */ | 
 |         /* DH,DL = row, col lower-right */ | 
 |         scroll_window(SCROLL_UP, AL_reg(context), CH_reg(context),  | 
 |            CL_reg(context), DH_reg(context), DL_reg(context),  | 
 |            BH_reg(context)); | 
 |         TRACE(int10, "Scroll Up Window %d\n", AL_reg(context)); | 
 |         break; | 
 |  | 
 |     case 0x07: /* SCROLL DOWN WINDOW */ | 
 |         /* AL = Lines to scroll */ | 
 |         /* BH = Attribute */ | 
 |         /* CH,CL = row, col upper-left */ | 
 |         /* DH,DL = row, col lower-right */ | 
 |         scroll_window(SCROLL_DOWN, AL_reg(context), CH_reg(context),  | 
 |            CL_reg(context), DH_reg(context), DL_reg(context),  | 
 |            BH_reg(context)); | 
 |         TRACE(int10, "Scroll Down Window %d\n", AL_reg(context)); | 
 |         break; | 
 |  | 
 |     case 0x08: /* READ CHARACTER AND ATTRIBUTE AT CURSOR POSITION */ | 
 |         { | 
 |             /* Note here that color data returned is bogus, will fix later. */ | 
 |             char ch; | 
 |             int bg, fg, attr; | 
 |             if (BH_reg(context)) /* Write to different page */ | 
 |             { | 
 |                 FIXME(int10, "Read Character and Attribute at Cursor Position -" | 
 |                       " Can't read from non-0 page\n"); | 
 |                 AL_reg(context) = ' '; /* That page is blank */ | 
 |                 AH_reg(context) = 7; | 
 |             } | 
 |             else | 
 |             { | 
 |                 TRACE(int10,  | 
 |                       "Read Character and Attribute at Cursor Position\n"); | 
 |                 CONSOLE_GetCharacterAtCursor(&ch, &fg, &bg, &attr); | 
 |                 AL_reg(context) = ch; | 
 |                 AH_reg(context) = 7;	/* FIXME: We're assuming wh on bl */  | 
 |             } | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x09: /* WRITE CHARACTER AND ATTRIBUTE AT CURSOR POSITION */ | 
 |        /* AL = Character to display. */ | 
 |        /* BH = Page Number */ /* We can't write to non-0 pages, yet. */ | 
 |        /* BL = Attribute / Color */ | 
 |        /* CX = Times to Write Char */ | 
 |        /* Note here that the cursor is not advanced. */ | 
 |        write_char_attribute_at_cursor(AL_reg(context), BH_reg(context),  | 
 |           BL_reg(context), CX_reg(context)); | 
 |        if (CX_reg(context) > 1) | 
 |           TRACE(int10, "Write Character and Attribute at Cursor Position " | 
 |              "(Rep. %d) %c\n", CX_reg(context), AL_reg(context)); | 
 |        else | 
 |           TRACE(int10, "Write Character and Attribute at Cursor" | 
 |              "Position: %c\n", AL_reg(context)); | 
 |        break; | 
 |  | 
 |     case 0x0a: /* WRITE CHARACTER ONLY AT CURSOR POSITION */  | 
 |        /* AL = Character to display. */ | 
 |        /* BH = Page Number */ /* We can't write to non-0 pages, yet. */ | 
 |        /* CX = Times to Write Char */ | 
 |        TRACE(int10, "Write Character at Cursor\n"); | 
 |        write_char_attribute_at_cursor(AL_reg(context), BH_reg(context),  | 
 |           0, CX_reg(context)); | 
 |        break; | 
 |  | 
 |     case 0x0b:  | 
 |         switch BH_reg(context) { | 
 |         case 0x00: /* SET BACKGROUND/BORDER COLOR */ | 
 |             /* In text modes, this sets only the border... */ | 
 |             /* According to the interrupt list and one of my books. */ | 
 |             /* Funny though that Beyond Zork seems to indicate that it  | 
 |                also sets up the default background attributes for clears | 
 |                and scrolls... */ | 
 |             /* Bear in mind here that we do not want to change, | 
 |                apparantly, the foreground or attribute of the background | 
 |                with this call, so we should check first to see what the | 
 |                foreground already is... FIXME */ | 
 |             TRACE(int10, "Set Background/Border Color: %d\n",  | 
 |                BL_reg(context)); | 
 |             CONSOLE_SetBackgroundColor(color_pallet[0], | 
 |                color_pallet[BL_reg(context)]);    | 
 |             break; | 
 |         case 0x01: /* SET PALETTE */ | 
 |             FIXME(int10, "Set Palette - Not Supported\n"); | 
 |             break; | 
 |         default: | 
 |             FIXME(int10, "INT 10 AH = 0x0b BH = 0x%x - Unknown\n",  | 
 |                BH_reg(context)); | 
 |             break; | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x0c: /* WRITE GRAPHICS PIXEL */ | 
 |         /* Not in graphics mode, can ignore w/o error */ | 
 |         FIXME(int10, "Write Graphics Pixel - Not Supported\n"); | 
 |         break; | 
 |          | 
 |     case 0x0d: /* READ GRAPHICS PIXEL */ | 
 |         /* Not in graphics mode, can ignore w/o error */ | 
 |         FIXME(int10, "Read Graphics Pixel - Not Supported\n"); | 
 |         break; | 
 |                | 
 |     case 0x0e: /* TELETYPE OUTPUT */ | 
 |         TRACE(int10, "Teletype Output\n"); | 
 |         CONSOLE_Write(AL_reg(context), 0, 0, 0); | 
 |         break; | 
 |  | 
 |     case 0x0f: /* GET CURRENT VIDEO MODE */ | 
 |         TRACE(int10, "Get Current Video Mode\n"); | 
 |         /* Note: This should not be a constant value. */ | 
 |         AL_reg(context) = video_mode; | 
 |         AH_reg(context) = video_columns; | 
 |         BH_reg(context) = 0; /* Display page 0 */ | 
 |         break; | 
 |  | 
 |     case 0x10:  | 
 |         switch AL_reg(context) { | 
 |         case 0x00: /* SET SINGLE PALETTE REGISTER */ | 
 |             FIXME(int10, "Set Single Palette Register - Not Supported\n"); | 
 |             break; | 
 |         case 0x01: /* SET BORDER (OVERSCAN) */ | 
 |             /* Text terminals have no overscan */ | 
 |             TRACE(int10, "Set Border (Overscan) - Ignored\n"); | 
 |             break; | 
 |         case 0x02: /* SET ALL PALETTE REGISTERS */ | 
 |             FIXME(int10, "Set all palette registers - Not Supported\n"); | 
 |             break; | 
 |         case 0x03: /* TOGGLE INTENSITY/BLINKING BIT */ | 
 |             FIXME(int10, "Toggle Intensity/Blinking Bit - Not Supported\n"); | 
 |             break; | 
 |         case 0x07: /* GET INDIVIDUAL PALETTE REGISTER */ | 
 |             FIXME(int10, "Get Individual Palette Register - Not Supported\n"); | 
 |             break; | 
 |         case 0x08: /* READ OVERSCAN (BORDER COLOR) REGISTER */ | 
 |             FIXME(int10,  | 
 |                "Read Overscan (Border Color) Register - Not Supported\n"); | 
 |             break; | 
 |         case 0x09: /* READ ALL PALETTE REGISTERS AND OVERSCAN REGISTER */ | 
 |             FIXME(int10,  | 
 |                "Read All Palette Registers and Overscan Register " | 
 |                " - Not Supported\n"); | 
 |             break; | 
 |         case 0x10: /* SET INDIVIDUAL DAC REGISTER */ | 
 |             FIXME(int10, "Set Individual DAC register - Not Supported\n"); | 
 |             break; | 
 |         case 0x12: /* SET BLOCK OF DAC REGISTERS */ | 
 |             FIXME(int10, "Set Block of DAC registers - Not Supported\n"); | 
 |             break; | 
 |         case 0x13: /* SELECT VIDEO DAC COLOR PAGE */ | 
 |             FIXME(int10, "Select video DAC color page - Not Supported\n"); | 
 |             break; | 
 |         case 0x15: /* READ INDIVIDUAL DAC REGISTER */ | 
 |             FIXME(int10, "Read individual DAC register - Not Supported\n"); | 
 |             break; | 
 |         case 0x17: /* READ BLOCK OF DAC REGISTERS */ | 
 |             FIXME(int10, "Read block of DAC registers - Not Supported\n"); | 
 |             break; | 
 |         case 0x18: /* SET PEL MASK */ | 
 |             FIXME(int10, "Set PEL mask - Not Supported\n"); | 
 |             break; | 
 |         case 0x19: /* READ PEL MASK */ | 
 |             FIXME(int10, "Read PEL mask - Not Supported\n"); | 
 |             break; | 
 |         case 0x1a: /* GET VIDEO DAC COLOR PAGE STATE */ | 
 |             FIXME(int10, "Get video DAC color page state - Not Supported\n"); | 
 |             break; | 
 |         case 0x1b: /* PERFORM GRAY-SCALE SUMMING */ | 
 |             FIXME(int10, "Perform Gray-scale summing - Not Supported\n"); | 
 |             break; | 
 |         default: | 
 |             FIXME(int10, "INT 10 AH = 0x10 AL = 0x%x - Unknown\n",  | 
 |                AL_reg(context)); | 
 |             break; | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x11: /* TEXT MODE CHARGEN */ | 
 |         /* Note that second subfunction is *almost* identical. */ | 
 |         /* See INTERRUPT.A for details. */ | 
 |         switch AH_reg(context) { | 
 |         case 0x00: /* LOAD USER SPECIFIED PATTERNS */ | 
 |         case 0x10: | 
 |             FIXME(int10, "Load User Specified Patterns - Not Supported\n"); | 
 |             break; | 
 |         case 0x01: /* LOAD ROM MONOCHROME PATTERNS */ | 
 |         case 0x11: | 
 |             FIXME(int10, "Load ROM Monochrome Patterns - Not Supported\n"); | 
 |             break; | 
 |         case 0x02: /* LOAD ROM 8x8 DOUBLE-DOT PATTERNS */ | 
 |         case 0x12: | 
 |             FIXME(int10,  | 
 |                 "Load ROM 8x8 Double Dot Patterns - Not Supported\n");        | 
 |             break; | 
 |         case 0x03: /* SET BLOCK SPECIFIER */ | 
 |             FIXME(int10, "Set Block Specifier - Not Supported\n"); | 
 |             break; | 
 |         case 0x04: /* LOAD ROM 8x16 CHARACTER SET */ | 
 |         case 0x14: | 
 |             FIXME(int10, "Load ROM 8x16 Character Set - Not Supported\n"); | 
 |             break; | 
 |         case 0x20: /* SET USER 8x16 GRAPHICS CHARS */ | 
 |             FIXME(int10, "Set User 8x16 Graphics Chars - Not Supported\n"); | 
 |             break; | 
 |         case 0x21: /* SET USER GRAPICS CHARACTERS */ | 
 |             FIXME(int10, "Set User Graphics Characters - Not Supported\n"); | 
 |             break; | 
 |         case 0x22: /* SET ROM 8x14 GRAPHICS CHARS */ | 
 |             FIXME(int10, "Set ROM 8x14 Graphics Chars - Not Supported\n"); | 
 |             break; | 
 |         case 0x23: /* SET ROM 8x8 DBL DOT CHARS */ | 
 |             FIXME(int10,  | 
 |                 "Set ROM 8x8 Dbl Dot Chars (Graphics) - Not Supported\n"); | 
 |             break; | 
 |         case 0x24: /* LOAD 8x16 GRAPHIC CHARS */ | 
 |             FIXME(int10, "Load 8x16 Graphic Chars - Not Supported\n"); | 
 |             break; | 
 |         case 0x30: /* GET FONT INFORMATION */ | 
 |             FIXME(int10, "Get Font Information - Not Supported\n"); | 
 |             break; | 
 |         default: | 
 |             FIXME(int10, "INT 10 AH = 0x11 AL = 0x%x - Unknown\n",  | 
 |                AL_reg(context)); | 
 |             break; | 
 |         } | 
 |         break; | 
 |          | 
 |     case 0x12: /* ALTERNATE FUNCTION SELECT */ | 
 |         switch BL_reg(context) { | 
 |         case 0x10: /* GET EGA INFO */ | 
 |             TRACE(int10, "EGA Info Requested\n"); | 
 |             BH_reg(context) = 0x00;   /* Color screen */ | 
 |             BL_reg(context) = 0x03;   /* 256K EGA card */ | 
 |             CH_reg(context) = 0x00;   /* Switch settings?? */ | 
 |             CL_reg(context) = 0x09;   /* EGA+ card */ | 
 |             break; | 
 |         case 0x20: /* ALTERNATE PRTSC */ | 
 |             FIXME(int10, "Install Alternate Print Screen - Not Supported\n"); | 
 |             break; | 
 |         case 0x30: /* SELECT VERTICAL RESOULTION */ | 
 |             FIXME(int10, "Select Vertical Resoultion - Not Supported\n"); | 
 |             break; | 
 |         case 0x31: /* ENABLE/DISABLE PALETTE LOADING */ | 
 |             FIXME(int10, "Palette Loading - Not Supported\n"); | 
 |             break; | 
 |         case 0x32: /* ENABLE/DISABLE VIDEO ADDRERSSING */ | 
 |             FIXME(int10, "Video Addressing - Not Supported\n"); | 
 |             break; | 
 |         case 0x33: /* ENABLE/DISABLE GRAY SCALE SUMMING */ | 
 |             FIXME(int10, "Gray Scale Summing - Not Supported\n"); | 
 |             break; | 
 |         case 0x34: /* ENABLE/DISABLE CURSOR EMULATION */ | 
 |             FIXME(int10, "Cursor Emulation - Not Supported\n"); | 
 |             break; | 
 |         case 0x36: /* VIDEO ADDRESS CONTROL */ | 
 |             FIXME(int10, "Video Address Control - Not Supported\n"); | 
 |             break; | 
 |         default: | 
 |             FIXME(int10, "INT 10 AH = 0x11 AL = 0x%x - Unknown\n",  | 
 |                AL_reg(context)); | 
 |             break; | 
 |         } | 
 |         break; | 
 |  | 
 |     case 0x13: /* WRITE STRING */ | 
 |         /* This one does not imply that string be at cursor. */ | 
 |         FIXME(int10, "Write String - Not Supported\n"); | 
 |         break; | 
 |                               | 
 |     case 0x1a:  | 
 |         switch AL_reg(context) { | 
 |         case 0x00: /* GET DISPLAY COMBINATION CODE */ | 
 |             TRACE(int10, "Get Display Combination Code\n"); | 
 |             AL_reg(context) = 0x1a; | 
 |             BH_reg(context) = 0x08; /* VGA w/ color analog display */ | 
 |             BL_reg(context) = 0x00; /* No secondary hardware */ | 
 |             break; | 
 |         case 0x01: /* SET DISPLAY COMBINATION CODE */ | 
 |             FIXME(int10, "Set Display Combination Code - Not Supported\n"); | 
 |             break; | 
 |         default: | 
 |             FIXME(int10, "INT 10 AH = 0x1a AL = 0x%x - Unknown\n",  | 
 |                AL_reg(context)); | 
 |             break; | 
 |         } | 
 |     break; | 
 |  | 
 |     case 0x1b: /* FUNCTIONALITY/STATE INFORMATION */ | 
 |         FIXME(int10, "Get Functionality/State Information - Not Supported\n"); | 
 |         break; | 
 |  | 
 |     case 0x1c: /* SAVE/RESTORE VIDEO STATE */ | 
 |         FIXME(int10, "Save/Restore Video State - Not Supported\n"); | 
 |         break; | 
 |  | 
 |     default: | 
 |         FIXME(int10, "Unknown - 0x%x\n", AH_reg(context)); | 
 |         INT_BARF( context, 0x10 ); | 
 |     } | 
 | } | 
 |  | 
 | static void write_char_attribute_at_cursor(char output, char page_num,  | 
 |        char attribute, short times) | 
 | { | 
 |     /* Contrary to the interrupt list, this routine should not advance | 
 |        the cursor. To keep this logic simple, we won't use the | 
 |        CONSOLE_Put() routine.  | 
 |     */ | 
 |  | 
 |     int wattribute, fg_color, bg_color; | 
 |     char x, y; | 
 |  | 
 |     if (page_num) /* Only support one text page right now */ | 
 |     { | 
 |        FIXME(int10, "Cannot write to alternate page %d", page_num); | 
 |        return; | 
 |     }   | 
 |  | 
 |     conv_text_mode_attributes(attribute, &fg_color, &bg_color, | 
 |         &wattribute); | 
 |  | 
 |     TRACE(int10, "Fore: %d Back: %d\n", fg_color, bg_color); | 
 |  | 
 |     CONSOLE_GetCursorPosition(&x, &y); | 
 |  | 
 |     while (times) | 
 |     { | 
 |        CONSOLE_Write(output, fg_color, bg_color, attribute);            | 
 |        times--; | 
 |     } | 
 |    | 
 |     CONSOLE_MoveCursor(x, y); | 
 | } | 
 |  | 
 | static void conv_text_mode_attributes(char attribute, int *fg, int *bg, | 
 |    int *wattribute) | 
 | { | 
 |     /* This is a local function to convert the text-mode attributes | 
 |        to Wine's color and attribute scheme */ | 
 |  | 
 |     /* Foreground Color is stored in bits 3 through 0 */ | 
 |     /* Background Color is stored in bits 6 through 4 */ | 
 |     /* If this has bit 7 set, then we need to blink */ | 
 |  | 
 |     *fg = color_pallet[attribute & 15]; | 
 |     *bg = color_pallet[(attribute & 112) / 16]; | 
 |     *wattribute = attribute & 128; | 
 |  | 
 | } | 
 |  | 
 | static void scroll_window(int direction, char lines, char row1,  | 
 |    char col1, char row2, char col2, char attribute) | 
 | { | 
 |    int wattribute, bg_color, fg_color; | 
 |  | 
 |    conv_text_mode_attributes(attribute, &fg_color, &bg_color, | 
 |       &wattribute); | 
 |  | 
 |    if (!lines) /* Actually, clear the window */ | 
 |    { | 
 |       CONSOLE_ClearWindow(row1, col1, row2, col2, bg_color, wattribute); | 
 |    } | 
 |    else if (direction == SCROLL_UP) | 
 |    { | 
 |       CONSOLE_ScrollUpWindow(row1, col1, row2, col2, lines, bg_color, | 
 |          wattribute); | 
 |    } | 
 |    else | 
 |    { | 
 |       CONSOLE_ScrollDownWindow(row1, col1, row2, col2, lines, bg_color, | 
 |          wattribute); | 
 |    } | 
 | } | 
 |     |