;; -----------------------------------------------------------------------
;;
;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
;; Boston MA 02111-1307, USA; either version 2 of the License, or
;; (at your option) any later version; incorporated herein by reference.
;;
;; -----------------------------------------------------------------------
; ----------------------------------------------------------------------------
; VGA splash screen code
; ----------------------------------------------------------------------------
;
; vgadisplayfile:
; Display a graphical splash screen.
; The file is already opened on the top of the getc stack.
;
; Assumes CS == DS == ES.
;
section .text16
vgadisplayfile:
; This is a cheap and easy way to make sure the screen is
; cleared in case we were in graphics mode already
call vgaclearmode
call vgasetmode
jnz .error_nz
.graphalready:
; Load the header.
mov cx,4+2*2+16*3
mov di,LSSHeader
.gethdr:
call getc
stosb
loop .gethdr
jc .error
; The header WILL be in the first chunk.
cmp dword [LSSMagic],0x1413f33d ; Magic number
.error_nz: jne .error
mov dx,GraphColorMap ; Color map offset
mov ax,1012h ; Set RGB registers
xor bx,bx ; First register number
mov cx,16 ; 16 registers
int 10h
.movecursor:
mov ax,[GraphYSize] ; Number of pixel rows
mov dx,[VGAFontSize]
add ax,dx
dec ax
div dl
xor dx,dx ; Set column to 0
cmp al,[VidRows]
jb .rowsok
mov al,[VidRows]
dec al
.rowsok:
mov dh,al
mov ah,2
xor bx,bx
int 10h ; Set cursor below image
mov cx,[GraphYSize] ; Number of graphics rows
mov word [VGAPos],0
.drawpixelrow:
push cx
mov di,VGARowBuffer
; Pre-clear the row buffer
push di
push di
mov cx,640/4
xor eax,eax
rep stosd
pop di
mov cx,[GraphXSize]
call rledecode ; Decode one row
pop si
mov di,VGAPlaneBuffer
push di
mov bp,640
call packedpixel2vga
pop si
push es
mov di,0A000h ; VGA segment
mov es,di
mov di,[VGAPos]
call outputvga
pop es
add word [VGAPos],640/8
pop cx
loop .drawpixelrow
.error:
jmp close ; Tailcall!
;
; rledecode:
; Decode a pixel row in RLE16 format.
;
; getc stack -> input
; CX -> pixel count
; ES:DI -> output (packed pixel)
;
rledecode:
xor dx,dx ; DL = last pixel, DH = nybble buffer
.loop:
call .getnybble
cmp al,dl
je .run ; Start of run sequence
stosb
mov dl,al
dec cx
jnz .loop
.done:
ret
.run:
xor bx,bx
call .getnybble
or bl,al
jz .longrun
.dorun:
push cx
mov cx,bx
mov al,dl
rep stosb
pop cx
sub cx,bx
ja .loop
jmp short .done
.longrun:
call .getnybble
mov bl,al
call .getnybble
shl al,4
or bl,al
add bx,16
jmp short .dorun
.getnybble:
test dh,10h
jz .low
and dh,0Fh
mov al,dh
ret
.low:
call getc
mov dh,al
shr dh,4
or dh,10h ; Nybble already read
and al,0Fh
ret
;
; packedpixel2vga:
; Convert packed-pixel to VGA bitplanes
;
; DS:SI -> packed pixel string
; BP -> pixel count (multiple of 8)
; DS:DI -> output (four planes)
;
packedpixel2vga:
xor cx,cx
.planeloop:
inc cx
push si
push bp
.loop1:
mov bx,8
.loop2:
lodsb
shr al,cl
rcl dl,1 ; VGA is bigendian. Sigh.
dec bx
jnz .loop2
mov [di],dl
inc di
sub bp,byte 8
ja .loop1
pop bp
pop si
cmp cl,3
jbe .planeloop
ret
;
; outputvga:
; Output four subsequent lines of VGA data
;
; DS:SI -> four planes @ 640/8=80 bytes
; ES:DI -> pointer into VGA memory
;
outputvga:
mov dx,3C4h ; VGA Sequencer Register select port
mov al,2 ; Sequencer mask
out dx,al ; Select the sequencer mask
inc dx ; VGA Sequencer Register data port
dec ax ; AL <- 1
.loop1:
out dx,al ; Select the bit plane to write
push di
mov cx,640/32
rep movsd
pop di
add ax,ax
cmp al,8
jbe .loop1
ret
;
; vgasetmode:
; Enable VGA graphics, if possible; return ZF=1 on success
; DS must be set to the base segment; ES is set to DS.
;
vgasetmode:
push ds
pop es
mov al,[UsingVGA]
cmp al,01h
je .success ; Nothing to do...
test al,04h
jz .notvesa
; We're in a VESA mode, which means VGA; use VESA call
; to revert the mode, and then call the conventional
; mode-setting for good measure...
mov ax,4F02h
mov bx,0012h
int 10h
jmp .setmode
.notvesa:
mov ax,1A00h ; Get video card and monitor
xor bx,bx
int 10h
sub bl, 7 ; BL=07h and BL=08h OK
cmp bl, 1
ja .error ; ZF=0
; mov bx,TextColorReg
; mov dx,1009h ; Read color registers
; int 10h
.setmode:
mov ax,0012h ; Set mode = 640x480 VGA 16 colors
int 10h
mov dx,linear_color
mov ax,1002h ; Write color registers
int 10h
mov [UsingVGA], byte 1
; Set GXPixCols and GXPixRows
mov dword [GXPixCols],640+(480 << 16)
call use_font ; Set graphics font/data
mov byte [ScrollAttribute], 00h
.success:
xor ax,ax ; Set ZF
.error:
ret
;
; vgaclearmode:
; Disable VGA graphics. It is not safe to assume any value
; for DS or ES.
;
vgaclearmode:
push ds
push es
pushad
mov ax,cs
mov ds,ax
mov es,ax
mov al,[UsingVGA]
and al,al ; Already in text mode?
jz .done
test al,04h
jz .notvesa
mov ax,4F02h ; VESA return to normal video mode
mov bx,0003h
int 10h
.notvesa:
mov ax,0003h ; Return to normal video mode
int 10h
; mov dx,TextColorReg ; Restore color registers
; mov ax,1002h
; int 10h
mov [UsingVGA], byte 0
mov byte [ScrollAttribute], 07h
call use_font ; Restore text font/data
.done:
popad
pop es
pop ds
ret
;
; vgashowcursor/vgahidecursor:
; If VGA graphics is enabled, draw a cursor/clear a cursor
;
vgashowcursor:
pushad
mov al,'_'
jmp short vgacursorcommon
vgahidecursor:
pushad
mov al,' '
vgacursorcommon:
cmp [UsingVGA], byte 1
jne .done
mov ah,09h
mov bx,0007h
mov cx,1
int 10h
.done:
popad
ret
section .data16
; Map colors to consecutive DAC registers
linear_color db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
; See comboot.doc, INT 22h AX=0017h for the semantics
; of this byte.
UsingVGA db 0
section .bss16
alignb 4
LSSHeader equ $
LSSMagic resd 1 ; Magic number
GraphXSize resw 1 ; Width of splash screen file
GraphYSize resw 1 ; Height of splash screen file
GraphColorMap resb 3*16
VGAPos resw 1 ; Pointer into VGA memory
VGAFilePtr resw 1 ; Pointer into VGAFileBuf
; TextColorReg resb 17 ; VGA color registers for text mode
%if IS_SYSLINUX
VGAFileBuf resb FILENAME_MAX+2 ; Unmangled VGA image name
%else
VGAFileBuf resb FILENAME_MAX ; Unmangled VGA image name
%endif
VGAFileBufEnd equ $
VGAFileMBuf resb FILENAME_MAX ; Mangled VGA image name
alignb 4
VGARowBuffer resb 640+80 ; Decompression buffer
VGAPlaneBuffer resb (640/8)*4 ; Plane buffers