diff options
author | Volker Ruppert <info@vruppert.de> | 2006-06-18 15:22:43 +0000 |
---|---|---|
committer | Volker Ruppert <info@vruppert.de> | 2006-06-18 15:22:43 +0000 |
commit | 72c270d8091fb0f09e8291cc0e7154b075b921a9 (patch) | |
tree | 833a5d7c6bb7638e67d4dbf682cb5c3c3ea646d1 | |
parent | 819d1f4cd637f34ca314ac38b165e772703df90d (diff) |
- applied patch from the qemu project (Fabrice Bellard)
* Cirrus SVGA now supports the "no clear" bit when switching to Cirrus or
VESA mode
* Bochs VBE protected mode interface improved
* save/restore video state support for Bochs VBE and standard VGA added
* Bochs VBE prepared for more modi
-rw-r--r-- | clext.c | 46 | ||||
-rw-r--r-- | vbe.c | 207 | ||||
-rw-r--r-- | vbe.h | 18 | ||||
-rw-r--r-- | vbetables.h | 6 | ||||
-rw-r--r-- | vgabios.c | 227 |
5 files changed, 468 insertions, 36 deletions
@@ -544,6 +544,13 @@ cirrus_debug_dump: cirrus_set_video_mode_extended: call cirrus_switch_mode pop ax ;; mode + test al, #0x80 + jnz cirrus_set_video_mode_extended_1 + push ax + mov ax, #0xffff ; set to 0xff to keep win 2K happy + call cirrus_clear_vram + pop ax +cirrus_set_video_mode_extended_1: and al, #0x7f push ds @@ -1011,6 +1018,13 @@ cirrus_vesa_02h_1: jnz cirrus_vesa_02h_3 call cirrus_enable_16k_granularity cirrus_vesa_02h_3: + test bx, #0x8000 ;; no clear + jnz cirrus_vesa_02h_4 + push ax + xor ax,ax + call cirrus_clear_vram + pop ax +cirrus_vesa_02h_4: pop ax push ds #ifdef CIRRUS_VESA3_PMINFO @@ -1479,6 +1493,38 @@ cirrus_get_start_addr: pop bx ret +cirrus_clear_vram: + pusha + push es + mov si, ax + + call cirrus_enable_16k_granularity + call cirrus_extbios_85h + shl al, #2 + mov bl, al + xor ah,ah +cirrus_clear_vram_1: + mov al, #0x09 + mov dx, #0x3ce + out dx, ax + push ax + mov cx, #0xa000 + mov es, cx + xor di, di + mov ax, si + mov cx, #8192 + cld + rep + stosw + pop ax + inc ah + cmp ah, bl + jne cirrus_clear_vram_1 + + pop es + popa + ret + cirrus_extbios_handlers: ;; 80h dw cirrus_extbios_80h @@ -118,21 +118,114 @@ _vbebios_mode_list: .word VBE_VESA_MODE_END_OF_LIST #endif + .align 2 vesa_pm_start: dw vesa_pm_set_window - vesa_pm_start - dw vesa_pm_set_display_strt - vesa_pm_start + dw vesa_pm_set_display_start - vesa_pm_start dw vesa_pm_unimplemented - vesa_pm_start - dw 0 + dw vesa_pm_io_ports_table - vesa_pm_start +vesa_pm_io_ports_table: + dw VBE_DISPI_IOPORT_INDEX + dw VBE_DISPI_IOPORT_INDEX + 1 + dw VBE_DISPI_IOPORT_DATA + dw VBE_DISPI_IOPORT_DATA + 1 + dw 0xffff + dw 0xffff USE32 vesa_pm_set_window: - mov ax, #0x4f05 - int #0x10 + cmp bx, #0x00 + je vesa_pm_set_display_window1 + mov ax, #0x0100 + ret +vesa_pm_set_display_window1: + mov ax, dx + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_BANK + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + mov ax, #0x004f ret vesa_pm_set_display_start: - mov ax, #0x4f07 - int #0x10 + cmp bl, #0x80 + je vesa_pm_set_display_start1 + cmp bl, #0x00 + je vesa_pm_set_display_start1 + mov ax, #0x0100 + ret +vesa_pm_set_display_start1: +; convert offset to (X, Y) coordinate +; (would be simpler to change Bochs VBE API...) + push eax + push ecx + push edx + push esi + push edi + shl edx, #16 + and ecx, #0xffff + or ecx, edx + shl ecx, #2 + mov eax, ecx + + push eax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + movzx ecx, ax + + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_BPP + out dx, ax + mov dx, # VBE_DISPI_IOPORT_DATA + in ax, dx + movzx esi, ax + pop eax + + add esi, #7 + shr esi, #3 + imul ecx, esi + xor edx, edx + div ecx + mov edi, eax + mov eax, edx + xor edx, edx + div esi + + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_X_OFFSET + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + + mov ax, di + push dx + push ax + mov dx, # VBE_DISPI_IOPORT_INDEX + mov ax, # VBE_DISPI_INDEX_Y_OFFSET + out dx, ax + pop ax + mov dx, # VBE_DISPI_IOPORT_DATA + out dx, ax + pop dx + + pop edi + pop esi + pop edx + pop ecx + pop eax + mov ax, #0x004f ret vesa_pm_unimplemented: @@ -835,6 +928,64 @@ vbe_03_ok: ASM_END +Bit16u vbe_biosfn_read_video_state_size() +{ + return 9 * 2; +} + +void vbe_biosfn_save_video_state(ES, BX) + Bit16u ES; Bit16u BX; +{ + Bit16u enable, i; + + outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); + enable = inw(VBE_DISPI_IOPORT_DATA); + write_word(ES, BX, enable); + BX += 2; + if (!(enable & VBE_DISPI_ENABLED)) + return; + for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) { + if (i != VBE_DISPI_INDEX_ENABLE) { + outw(VBE_DISPI_IOPORT_INDEX, i); + write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA)); + BX += 2; + } + } +} + + +void vbe_biosfn_restore_video_state(ES, BX) + Bit16u ES; Bit16u BX; +{ + Bit16u enable, i; + + enable = read_word(ES, BX); + BX += 2; + + if (!(enable & VBE_DISPI_ENABLED)) { + outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); + outw(VBE_DISPI_IOPORT_DATA, enable); + } else { + outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES); + outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); + BX += 2; + outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES); + outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); + BX += 2; + outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP); + outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); + BX += 2; + outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); + outw(VBE_DISPI_IOPORT_DATA, enable); + + for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) { + outw(VBE_DISPI_IOPORT_INDEX, i); + outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); + BX += 2; + } + } +} + /** Function 04h - Save/Restore State * * Input: @@ -849,10 +1000,48 @@ ASM_END * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h) * */ -void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX) +void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX) +Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX; { -} + Bit16u ss=get_SS(); + Bit16u result, val; + result = 0x4f; + switch(GET_DL()) { + case 0x00: + val = biosfn_read_video_state_size2(CX); +#ifdef DEBUG + printf("VGA state size=%x\n", val); +#endif + if (CX & 8) + val += vbe_biosfn_read_video_state_size(); + write_word(ss, BX, val); + break; + case 0x01: + val = read_word(ss, BX); + val = biosfn_save_video_state(CX, ES, val); +#ifdef DEBUG + printf("VGA save_state offset=%x\n", val); +#endif + if (CX & 8) + vbe_biosfn_save_video_state(ES, val); + break; + case 0x02: + val = read_word(ss, BX); + val = biosfn_restore_video_state(CX, ES, val); +#ifdef DEBUG + printf("VGA restore_state offset=%x\n", val); +#endif + if (CX & 8) + vbe_biosfn_restore_video_state(ES, val); + break; + default: + // function failed + result = 0x100; + break; + } + write_word(ss, AX, result); +} /** Function 05h - Display Window Control * @@ -1090,7 +1279,7 @@ void vbe_biosfn_set_get_palette_data(AX) */ ASM_START vbe_biosfn_return_protected_mode_interface: - test bx, bx + test bl, bl jnz _fail mov di, #0xc000 mov es, di @@ -14,7 +14,7 @@ Boolean vbe_has_vbe_display(); void vbe_biosfn_return_controller_information(AX, ES, DI); void vbe_biosfn_return_mode_information(AX, CX, ES, DI); void vbe_biosfn_set_mode(AX, BX, ES, DI); -void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX); +void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX); void vbe_biosfn_set_get_palette_data(AX); void vbe_biosfn_return_protected_mode_interface(AX); @@ -151,6 +151,12 @@ typedef struct ModeInfoBlock Bit8u Reserved[189]; } ModeInfoBlock; +typedef struct ModeInfoListItem +{ + Bit16u mode; + ModeInfoBlockCompact info; +} ModeInfoListItem; + // VBE Return Status Info // AL #define VBE_RETURN_STATUS_SUPPORTED 0x4F @@ -193,6 +199,10 @@ typedef struct ModeInfoBlock #define VBE_VESA_MODE_1280X1024X1555 0x119 #define VBE_VESA_MODE_1280X1024X565 0x11A #define VBE_VESA_MODE_1280X1024X888 0x11B +#define VBE_VESA_MODE_1600X1200X8 0x11C +#define VBE_VESA_MODE_1600X1200X1555 0x11D +#define VBE_VESA_MODE_1600X1200X565 0x11E +#define VBE_VESA_MODE_1600X1200X888 0x11F // BOCHS/PLEX86 'own' mode numbers #define VBE_OWN_MODE_320X200X8888 0x140 @@ -202,6 +212,12 @@ typedef struct ModeInfoBlock #define VBE_OWN_MODE_1024X768X8888 0x144 #define VBE_OWN_MODE_1280X1024X8888 0x145 #define VBE_OWN_MODE_320X200X8 0x146 +#define VBE_OWN_MODE_1600X1200X8888 0x147 +#define VBE_OWN_MODE_1152X864X8 0x148 +#define VBE_OWN_MODE_1152X864X1555 0x149 +#define VBE_OWN_MODE_1152X864X565 0x14a +#define VBE_OWN_MODE_1152X864X888 0x14b +#define VBE_OWN_MODE_1152X864X8888 0x14c #define VBE_VESA_MODE_END_OF_LIST 0xFFFF diff --git a/vbetables.h b/vbetables.h index a742ac7..a62d464 100644 --- a/vbetables.h +++ b/vbetables.h @@ -8,12 +8,6 @@ */ -typedef struct ModeInfoListItem -{ - Bit16u mode; - ModeInfoBlockCompact info; -} ModeInfoListItem; - // FIXME: check all member variables to be correct for the different modi // FIXME: add more modi static ModeInfoListItem mode_info_list[]= @@ -109,8 +109,8 @@ static void biosfn_enable_video_refresh_control(); static void biosfn_write_string(); static void biosfn_read_state_info(); static void biosfn_read_video_state_size(); -static void biosfn_save_video_state(); -static void biosfn_restore_video_state(); +static Bit16u biosfn_save_video_state(); +static Bit16u biosfn_restore_video_state(); extern Bit8u video_save_pointer_table[]; // This is for compiling with gcc2 and gcc3 @@ -748,12 +748,7 @@ static void int10_func(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS) vbe_biosfn_set_mode(&AX,BX,ES,DI); break; case 0x04: - //FIXME -#ifdef DEBUG - unimplemented(); -#endif - // function failed - AX=0x100; + vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX); break; case 0x09: //FIXME @@ -3138,23 +3133,215 @@ Bit16u BX;Bit16u ES;Bit16u DI; } // -------------------------------------------------------------------------------------------- -static void biosfn_read_video_state_size (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; +// -------------------------------------------------------------------------------------------- +static Bit16u biosfn_read_video_state_size2 (CX) + Bit16u CX; { -#ifdef DEBUG - unimplemented(); -#endif + Bit16u size; + size = 0; + if (CX & 1) { + size += 0x46; + } + if (CX & 2) { + size += (5 + 8 + 5) * 2 + 6; + } + if (CX & 4) { + size += 3 + 256 * 3 + 1; } -static void biosfn_save_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; + return size; +} + +static void biosfn_read_video_state_size (CX, BX) + Bit16u CX; Bit16u *BX; { -#ifdef DEBUG - unimplemented(); -#endif + Bit16u ss=get_SS(); + write_word(ss, BX, biosfn_read_video_state_size2(CX)); } -static void biosfn_restore_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; + +static Bit16u biosfn_save_video_state (CX,ES,BX) + Bit16u CX;Bit16u ES;Bit16u BX; { -#ifdef DEBUG - unimplemented(); -#endif + Bit16u i, v, crtc_addr, ar_index; + + crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS); + if (CX & 1) { + write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++; + write_byte(ES, BX, inb(crtc_addr)); BX++; + write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++; + inb(VGAREG_ACTL_RESET); + ar_index = inb(VGAREG_ACTL_ADDRESS); + write_byte(ES, BX, ar_index); BX++; + write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++; + + for(i=1;i<=4;i++){ + outb(VGAREG_SEQU_ADDRESS, i); + write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++; + } + outb(VGAREG_SEQU_ADDRESS, 0); + write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++; + + for(i=0;i<=0x18;i++) { + outb(crtc_addr,i); + write_byte(ES, BX, inb(crtc_addr+1)); BX++; + } + + for(i=0;i<=0x13;i++) { + inb(VGAREG_ACTL_RESET); + outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20)); + write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++; + } + inb(VGAREG_ACTL_RESET); + + for(i=0;i<=8;i++) { + outb(VGAREG_GRDC_ADDRESS,i); + write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++; + } + + write_word(ES, BX, crtc_addr); BX+= 2; + + /* XXX: read plane latches */ + write_byte(ES, BX, 0); BX++; + write_byte(ES, BX, 0); BX++; + write_byte(ES, BX, 0); BX++; + write_byte(ES, BX, 0); BX++; + } + if (CX & 2) { + write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++; + write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2; + write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2; + write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2; + write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++; + write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2; + write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++; + write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++; + write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++; + write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2; + for(i=0;i<8;i++) { + write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i)); + BX += 2; + } + write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2; + write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++; + /* current font */ + write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2; + write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2; + write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2; + write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2; + } + if (CX & 4) { + /* XXX: check this */ + write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */ + write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */ + write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++; + // Set the whole dac always, from 0 + outb(VGAREG_DAC_WRITE_ADDRESS,0x00); + for(i=0;i<256*3;i++) { + write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++; + } + write_byte(ES, BX, 0); BX++; /* color select register */ + } + return BX; +} + +static Bit16u biosfn_restore_video_state (CX,ES,BX) + Bit16u CX;Bit16u ES;Bit16u BX; +{ + Bit16u i, crtc_addr, v, addr1, ar_index; + + if (CX & 1) { + // Reset Attribute Ctl flip-flop + inb(VGAREG_ACTL_RESET); + + crtc_addr = read_word(ES, BX + 0x40); + addr1 = BX; + BX += 5; + + for(i=1;i<=4;i++){ + outb(VGAREG_SEQU_ADDRESS, i); + outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++; + } + outb(VGAREG_SEQU_ADDRESS, 0); + outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++; + + // Disable CRTC write protection + outw(crtc_addr,0x0011); + // Set CRTC regs + for(i=0;i<=0x18;i++) { + if (i != 0x11) { + outb(crtc_addr,i); + outb(crtc_addr+1, read_byte(ES, BX)); + } + BX++; + } + // select crtc base address + v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01; + if (crtc_addr = 0x3d4) + v |= 0x01; + outb(VGAREG_WRITE_MISC_OUTPUT, v); + + // enable write protection if needed + outb(crtc_addr, 0x11); + outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11)); + + // Set Attribute Ctl + ar_index = read_byte(ES, addr1 + 0x03); + inb(VGAREG_ACTL_RESET); + for(i=0;i<=0x13;i++) { + outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20)); + outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++; + } + outb(VGAREG_ACTL_ADDRESS, ar_index); + inb(VGAREG_ACTL_RESET); + + for(i=0;i<=8;i++) { + outb(VGAREG_GRDC_ADDRESS,i); + outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++; + } + BX += 2; /* crtc_addr */ + BX += 4; /* plane latches */ + + outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++; + outb(crtc_addr, read_byte(ES, addr1)); addr1++; + outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++; + addr1++; + outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++; + } + if (CX & 2) { + write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++; + write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2; + write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2; + write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2; + write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++; + write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2; + write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++; + write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++; + write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++; + write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2; + for(i=0;i<8;i++) { + write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX)); + BX += 2; + } + write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2; + write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++; + /* current font */ + write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2; + write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2; + write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2; + write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2; + } + if (CX & 4) { + BX++; + v = read_byte(ES, BX); BX++; + outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++; + // Set the whole dac always, from 0 + outb(VGAREG_DAC_WRITE_ADDRESS,0x00); + for(i=0;i<256*3;i++) { + outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++; + } + BX++; + outb(VGAREG_DAC_WRITE_ADDRESS, v); + } + return BX; } // ============================================================================================ |