Metropoli BBS
VIEWER: vesa.asm MODE: TEXT (ASCII)
; Simple VESA Driver
; Version 2.00  (from video.asm in QLIB v1.2)

; Supports : VESA 2.0 and 1.2 fully

.data?
bankshift db ?
align 4
PmodeSetStart           DD ?
ProgramBaseAddress      DD ?
vesamode                DW ?
Total64Kblocks          DW ?
vesa_current_bank       DB ?
VBE_StarPerPixelFactor  DB ?
vesa_ver                DW ?
vesa_info vesa_infoblock <>
vesa_modeinfo vesa_modeinfoblock <>

.data
vesa_list               dd 0  ;list of video modes
vesa_list_pos           dd 0  ;current POS when using first/next mode()

align 4
vbesetbank              DD Offset SetBank_RealMode
vesa_setstart_proc      DD Offset SetStart_RealMode

_800_ DD 0      ;this is the linear addr returned by DPMI func #800h

std_list label word   ;VESA standard video mode list
  dw 10fh
  dw 112h
  dw 104h
  dw 0ffffh

.code
vesa_uninit proc private
  .if _800_
    pushad
    mov ax,801h
    mov bx,wptr cs:[_800_+2]
    mov cx,wptr cs:[_800_]
    int 31h
    mov _800_,0
    popad
  .endif
  mov exitmode,NULLPROC
  ret
vesa_uninit endp
 
vesa_init proc
  pushad

  mov ax,_8kbufferseg
  mov _es_,ax
  mov ax,4F00h
  xor edi,edi   ; (real mode) ES:DI -> 256 byte buffer
  int 10h       ;  GET VESA INFORMATION
   ;c0.asm always loads DS,ES in RMODE with _es_,_ds_
   ;      when using int  10h
  cmp ax,004Fh
  jne bad
  mov esi,_8kbuffer
  mov edi,offset vesa_info
  mov ecx,512/4
  rep movsd

  mov dx,vesa_info.VbeVersion
  mov vesa_ver,dx

  mov dx,vesa_info.TotalMemory
  mov Total64Kblocks,dx

  xor edx,edx
  mov dx,wptr [vesa_info.VideoModePtr + 2]
  xor ebx,ebx
  mov bx,wptr [vesa_info.VideoModePtr]
  .if dx==_8kbufferseg  ;some VESA BIOS return the list right in the vesa_info block
    mov edx,offset vesa_info
    add edx,ebx
  .else
    shl edx,4
    add edx,ebx                 ; EDX points to video mode list.
  .endif
  mov vesa_list,edx

  popad
  xor eax,eax
  mov ax,vesa_ver
  ret
bad:  ;Vesa not detected
  popad
  mov eax,ERROR
  ret
vesa_init endp

getinfo proc private,mode:word
  mov ax,_8kbufferseg
  mov _es_,ax
  mov ax,4F01h
  mov cx,mode
  and cx,01ffh                     ; read bits 0..8
  xor edi,edi                      ; ES:DI -> 256 byte buffer
  int 10h
  cmp ax,004Fh
  .if !zero?
    mov eax,ERROR
    ret
  .endif
  mov esi,_8kbuffer
  mov edi,offset vesa_modeinfo
  mov ecx,256/4
  rep movsd
  xor eax,eax
  ret
getinfo endp

vesa_getmode PROC private,x:word,y:word,bpp:byte

  local using_std:byte

  .if !vesa_list
    mov eax,ERROR
    ret
  .endif

  pushad

     ;
     ; Search video mode list for the required mode.
     ; The vesa driver Func 4F00h fills in the buffer with the information.
     ; Offset 0Eh of this buffer contains a real mode SEG:OFS of the video
     ; mode list. This list consists of each supported VESA mode and
     ; terminates with 0FFFFh.
     ;

     ; Get the real mode far pointer of the video mode list and
     ; convert the real mode SEG:OFS address into a 32bit near pointer.

  mov using_std,0
  mov edx,vesa_list
  xor eax,eax
@@:
  mov   ax,[edx]                     ; Read video mode from list
  cmp   ax,0FFFFh
  .if zero?
    .if using_std
      jmp bad
    .endif
    inc using_std  ;set using_std
    mov edx,offset std_list
    jmp @b
  .endif
  push edx
  callp getinfo,ax  ;does not preserve regs
  pop edx

  mov ax,vesa_modeinfo.WinSize
  cmp ax,64
  jnz try_next   ;require 64K window sizes  (this should never be a problem)

  mov ax,vesa_modeinfo.ModeAttributes
  test ax,1
  jz try_next  ;hardware does not support this mode
  mov al,vesa_modeinfo.WinAAttributes
  and al,0110b
  cmp al,0110b
  jnz try_next        ;mode not supported or not usable

  mov ax,vesa_modeinfo.XResolution
  .if ax!=x
    jmp try_next
  .endif
  mov ax,vesa_modeinfo.YResolution
  .if ax!=y
    jmp try_next
  .endif
  mov al,vesa_modeinfo.BitsPerPixel
  .if al!=bpp
    jmp try_next
  .endif

;current mode is acceptable
  mov ax,[edx]
  mov vesamode,ax
  jmp @f

try_next:
  add edx,2
  jmp @b

bad:
  popad
  mov eax,ERROR
  ret

@@:
  ;setup X/Y/BPP values
  ;Get bytes per scan line for the protected mode SetStart function.
  ;this is also used by v_copy

  xor eax,eax
  mov ax,vesa_modeinfo.BytesPerScanLine
  mov getmode_bpsl,ax

  popad
  mov eax,1  ;linear mode
  Test vesa_modeinfo.ModeAttributes ,10000000b  ;linear avail?
  .if zero?
    mov eax,0  ;banking mode
  .endif
  ret
vesa_getmode endp

vesa_setmode proc private
  ; Set VIDEO mode
  .if !vesamode
    mov eax,ERROR
    ret
  .endif
  pushad

  ; ******************************************************
  ; Setup for linear memory mapping mode.
  ; ******************************************************

  Test vesa_modeinfo.ModeAttributes ,10000000b  ;linear avail?
  jz DoWithBanks

  ;
  ; Calulate a near pointer to physical linear mapping address.
  ;

  add    vesamode,4000h

  Mov    ebx,vesa_modeinfo.PhysBasePtr
  mov    cx,bx
  shr    ebx,16
  mov    si,Total64Kblocks
  xor    edi,edi
  mov    ax,0800h                ; map physical memory
  int    31h
  jc     bad
  shl    ebx,16
  mov    bx,cx
  mov    eax,ebx                 ; eax = linear address
@@:
  mov    _800_,eax
  mov    _v_linear,eax
  jmp    Finished

DoWithBanks:

  ; ******************************************************
  ; Setup for windowing mode.
  ; ******************************************************

  ; check is windowing is avalible ( writable and readable )
  Test  vesa_modeinfo.ModeAttributes ,01000000b   ;available?
  jnz   bad

    ;
    ; Setup Bank Shift number  (I got idea from Dr. Dobbs)
    ;

  Movzx  ebx,vesa_modeinfo.WinGranularity
  xor    edx,edx   ;bankshift
  mov ecx,64
  .while (ecx != ebx)
    inc edx
    shr ecx,1
  .endw
  mov bankshift,dl  ;used in vesa_setbank proc

     ;
     ; Calulate 32bit linear pointer to CPU video memory WindowA
     ;

  Movzx eax,vesa_modeinfo.WinASegment
  shl eax,4
  mov _v_linear,eax

Finished:

    ;
    ; If 32bit VBE inteface is availible then use it
    ;

  mov ax,4f0ah
  mov bl,0                 ; return pmode interface
  int 10h
  cmp ax,004fh
  jne No32bitInterface
  xor esi,esi
  mov si,_es_          ; convert ES:DI to 32bit near ptr
  shl esi,4
  movzx edi,di
  add esi,edi

     ; Use protected mode bank proc only for zero length memory list.

  movzx  edi,word ptr [ESI+06]      ; get port/memory table list
  and    edi,edi
  jz     @@usePmodeBanks

@@:
  cmp    word Ptr [ESI+EDI],0FFFFh  ; search port list
  lea    edi,[edi+2]
  jne @b
  cmp    Word Ptr [ESI+EDI],0FFFFh  ; see if mem list is zero
  jne    @@SkipPmodeBanks

@@usePmodeBanks:
  movzx  eax,Word Ptr [ESI+00]
  add    eax,esi
  mov    [vbesetbank],eax         ; save Set Bank code address.

@@SkipPmodeBanks:

  ; Save Set display start code address.

  movzx  eax,Word Ptr [ESI+02]
  add    eax,esi
  mov    [PmodeSetStart],eax
  mov    [vesa_setstart_proc],Offset SetStart_ProtectedMode

  ; adjust for plane boundary for 8 bit+ modes

  mov    [VBE_StarPerPixelFactor],0
  Cmp    [vesa_modeinfo.BitsPerPixel],4
  je @f
  mov    [VBE_StarPerPixelFactor],2
@@:
  jmp @f

No32bitInterface:
  mov vbesetbank,Offset SetBank_RealMode
  mov vesa_setstart_proc,Offset SetStart_RealMode

@@:
  xor eax,eax
  xor ebx,ebx
  xor ecx,ecx
  xor edx,edx
  mov bx,vesamode
  mov ax,4f02h
  int 10h
  mov exitmode,offset vesa_uninit

  popad   ;EAX will be poped off
  xor eax,eax
  ret

bad:
  popad
  mov eax,ERROR
  ret
vesa_setmode ENDP

vesa_firstmode proc
  mov eax,vesa_list
  .if !eax
    mov eax,ERROR
    ret
  .endif
  pushad
  mov edx,eax
@@:
  mov ax,[edx]
  .if ax==0ffffh
    mov vesa_list_pos,edx
    popad
    mov eax,ERROR
    ret
  .endif
  push edx
  callp getinfo,ax
  pop edx

  mov ax,vesa_modeinfo.WinSize
  cmp ax,64
  jnz bad        ;require 64K window sizes  (this should never be a problem)

  mov al,vesa_modeinfo.WinAAttributes
  and al,0110b   ;mode read/write able?
  cmp al,0110b
  jnz bad

  mov ax,vesa_modeinfo.ModeAttributes
  test ax,1
  jz bad        ;mode not supported or not usable

  mov vesa_list_pos,edx
  popad

  xor eax,eax
  ret

bad:
  add edx,2
  jmp @b
vesa_firstmode endp

vesa_nextmode proc
  pushad
  mov edx,vesa_list_pos
  .if !edx
    popad
    mov eax,ERROR
    ret
  .endif
  mov ax,[edx]
  .if ax==0ffffh
    jmp bad
  .endif
  add edx,2  ;next
@@:
  mov ax,[edx]
  .if ax==0ffffh
    mov vesa_list_pos,edx
bad:
    popad
    mov eax,ERROR
    ret
  .endif
  push edx
  callp getinfo,ax
  pop edx

  mov ax,vesa_modeinfo.WinSize
  cmp ax,64
  jnz bad        ;require 64K window sizes  (this should never be a problem)

  mov al,vesa_modeinfo.WinAAttributes
  and al,0110b   ;mode read/write able?
  cmp al,0110b
  jnz next

  mov ax,vesa_modeinfo.ModeAttributes
  test ax,1
  jz next        ;mode not supported or not usable

  mov vesa_list_pos,edx
  popad
  xor eax,eax
  ret

next:
  add edx,2
  jmp @b
vesa_nextmode endp

;Alway consider each back to be 64K and will never overlay
;(regardless of current hardware)
;this driver will simulate the non-overlaping 64K banks

vesa_setbank PROC private,banknum:byte
  mov    al,banknum
  cmp    vesa_current_bank,al
  jz     @f
  pushad
  mov dl,al
  and    edx,01fh
  mov    vesa_current_bank,dl
  mov    cl,bankshift
  shl    edx,cl
  xor    ebx,ebx
  call   [vbesetbank]
  popad
@@:
  xor eax,eax
  ret
vesa_setbank ENDP

vesa_nextbank PROC private
  pushad
  xor    edx,edx
  mov    dl,vesa_current_bank
  inc    dl
  mov    vesa_current_bank,dl
  mov    cl,bankshift
  shl    edx,cl
  xor    ebx,ebx
  call   [vbesetbank]
  popad
  xor eax,eax
  ret
vesa_nextbank ENDP

;  VBE Function 06h - Set/Get Logical Scan Line Length
; You must call this when using Func #6 (the driver needs the BX returned from VESA)
vesa_func06 PROC
  mov  ax,4F06h
  int  10h
  cmp  ah,00h
  jne  @f
  mov  wptr[_v_bpsl],bx
@@:
  ret
vesa_func06 ENDP

;***********************************************************
; Call real mode set video bank function
; Note: very very slow....
;***********************************************************
SetBank_RealMode PROC private
        push   ebx
        xor    ebx,ebx
        mov    ax,04F05h
        int    10h
        pop    ebx
        Ret
SetBank_RealMode ENDP

;--------------------------------------------------------
; Call real mode set display start bank function
; CX=pixel in scan line
; DX=scan line number
; Note: very very slow....
;----------------------------------------------------------
SetStart_RealMode PROC private
        push   ebx
        xor    ebx,ebx
        mov    ax,04F07h
        int    10h
        pop    ebx
        Ret
SetStart_RealMode ENDP

;--------------------------------------------------------
; Call Protected mode set display start bank function
; ECX=pixel in scan line
; EDX=scan line number
;----------------------------------------------------------
SetStart_ProtectedMode PROC private
        push   ebx
        xor    ebx,ebx
        imul   edx,[_v_bpsl]
        add    edx,ecx
        mov    cl,[VBE_StarPerPixelFactor]
        shr    edx,cl
        mov    cx,dx
        shr    edx,16
        mov    ax,04F07h
        Call   [PmodeSetStart]
        pop    ebx
        Ret
SetStart_ProtectedMode ENDP

vesa_setstart proc,start:dword,scan:dword
  pushad
  mov ecx,start
  mov edx,scan
  call vesa_setstart_proc
  popad
  ret
vesa_setstart endp

[ RETURN TO DIRECTORY ]