format MZ

;------------------------------------------------------------------------------
; VESA DPMS power states:
;---------------+-----------+-----------+-----------+-----------+
;               | NORMAL    | STANDBY   | SUSPENDED | OFF       |
;---------------+-----------+-----------+-----------+-----------+
; H-sync        | On        | Off       | On        | Off       |
; V-sync        | On        | On        | Off       | Off       |
; Power level   | 100%      | 80%       | <30W      | <8W       |
; Recovery time | N/A       | ~1 sec    | ~4 sec    | ~8-20 sec |
;---------------+-----------+-----------+-----------+-----------+--------------

struc VBE_VGAInfo {
  .VESASignature	  dd ?	  ; char
  .VESAVersion		  dw ?	  ; short
  .OemStringPtr 	  dd ?	  ; char *
  .Capabilities 	  dd ?	  ; ulong
  .VideoModePtr 	  dd ?	  ; ulong
  .TotalMemory		  dw ?	  ; short
  ; VBE 2.0+
  .OemSoftwareRev	  dw ?	  ; short
  .OemVendorNamePtr	  dd ?	  ; char *
  .OemProductNamePtr	  dd ?	  ; char *
  .OemProductRevPtr	  dd ?	  ; char *
  .reserved		  rb 222  ; char
  .OemData		  rb 256  ; char
}

struc VBE_ModeInfo {
  .ModeAttributes	  dw ?	  ; short
  .WinAAttributes	  db ?	  ; char
  .WinBAttributes	  db ?	  ; char
  .WinGranularity	  dw ?	  ; short
  .WinSize		  dw ?	  ; short
  .WinASegment		  dw ?	  ; ushort
  .WinBSegment		  dw ?	  ; ushort
  .WinFuncPtr		  dd ?	  ; void *
  .BytesPerScanLine	  dw ?	  ; short
  .XRes 		  dw ?	  ; short
  .YRes 		  dw ?	  ; short
  .XCharSize		  db ?	  ; char
  .YCharSize		  db ?	  ; char
  .NumberOfPlanes	  db ?	  ; char
  .BitsPerPixel 	  db ?	  ; char
  .NumberOfBanks	  db ?	  ; char
  .MemoryModel		  db ?	  ; char
  .BankSize		  db ?	  ; char
  .NumberOfImagePages	  db ?	  ; char
  .res1 		  db ?	  ; char
  .RedMaskSize		  db ?	  ; char
  .RedFieldPosition	  db ?	  ; char
  .GreenMaskSize	  db ?	  ; char
  .GreenFieldPosition	  db ?	  ; char
  .BlueMaskSize 	  db ?	  ; char
  .BlueFieldPosition	  db ?	  ; char
  .RsvedMaskSize	  db ?	  ; char
  .RsvedFieldPosition	  db ?	  ; char
  .DirectColorModeInfo	  db ?	  ; char ; MISSED IN THIS TUTORIAL!! SEE ABOVE
  ; VBE 2.0+
  .PhysBasePtr		  dd ?	  ; ulong
  .OffScreenMemOffset	  dd ?	  ; ulong
  .OffScreenMemSize	  dw ?	  ; short
  ; VBE 3.0+
  .LinbytesPerScanLine	  dw ?	  ; short
  .BankNumberOfImagePages db ?	  ; char
  .LinNumberOfImagePages  db ?	  ; char
  .LinRedMaskSize	  db ?	  ; char
  .LinRedFieldPosition	  db ?	  ; char
  .LingreenMaskSize	  db ?	  ; char
  .LinGreenFieldPosition  db ?	  ; char
  .LinBlueMaskSize	  db ?	  ; char
  .LinBlueFieldPosition   db ?	  ; char
  .LinRsvdMaskSize	  db ?	  ; char
  .LinRsvdFieldPosition   db ?	  ; char
  .MaxPixelClock	  dd ?	  ; ulong
  .res2 		  rb 190  ; char
}

struc VBE_SupInfo {
  .SupVbeSignature	  rb 7
  .SupVbeVersion	  dw ?
  .SupVbeSubFunc	  rb 8
  .OemSoftwareRev	  dw ?
  .OemVendorNamePtr	  dd ?
  .OemProductNamePtr	  dd ?
  .OemProductRevPtr	  dd ?
  .OemStringPtr 	  dd ?
			  rb 221
}

struc EDID_Block {
  ; [+00  8] Header
  .Header		  rb 8 ; 00,FF,FF,FF,FF,FF,FF,00
  ; [+08 10] Vendor/Product Identification
  .ManufacturerName	  dw ? ; EISA, 3-char ID
  .ProductCode		  dw ?
  .SerialNumber 	  dd ?
  .WeekOfManufacture	  db ?
  .YearOfManufacture	  db ?
  ; [+12  2] EDID Structure Version/Revision
  .EDIDVersionNumber	  db ?
  .EDIDRevisionNumber	  db ?
  ; [+14  5] Basic Display Parameters/Features
  .VideoInputType	  db ?
  .MaxHorzImageSize	  db ? ; cm
  .MaxVertImageSize	  db ? ; cm
  .GammaFactor		  db ? ; gamma = 1.0+factor/100 (max = 3.55)
  .FeatureSupport	  db ? ; DPMS features etc.
  ; [+19 10] Color Characteristics
  .RedGreenLowBits	  db ? ; Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1 Gy0
  .BlueWhiteLowBits	  db ? ; Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
  .RedX 		  db ? ; Rx9-Rx2
  .RedY 		  db ? ; Ry9-Ry2
  .GreenX		  db ? ; Gx9-Gx2
  .GreenY		  db ? ; Gy9-Gy2
  .BlueX		  db ? ; Bx9-Bx2
  .BlueY		  db ? ; By9-By2
  .WhiteX		  db ? ; Wx9-Wx2
  .WhiteY		  db ? ; Wy9-Wy2
  ; [+23  3] Established Timings
  .EstablishedTimings1	  db ?
  .EstablishedTimings2	  db ?
  .ManufacturerResTimings db ?
  ; [+26 16] Standard Timing Identification
  .StandardTimingIdent1   dw ?
  .StandardTimingIdent2   dw ?
  .StandardTimingIdent3   dw ?
  .StandardTimingIdent4   dw ?
  .StandardTimingIdent5   dw ?
  .StandardTimingIdent6   dw ?
  .StandardTimingIdent7   dw ?
  .StandardTimingIdent8   dw ?
  ; [+36 72] Detailed Timing Descriptions
  .DetailedTimingDescr1   rb 18
  .DetailedTimingDescr2   rb 18
  .DetailedTimingDescr3   rb 18
  .DetailedTimingDescr4   rb 18
  ; [+7E  1] Extension Flag
  .ExtensionBlocksNumber  db ?
  ; [+7F  1] Checksum
  .CheckSum		  db ?
}

	push	cs cs
	pop	es ds

	mov	ax,$1112
	int	$10

	mov	[vi.VESASignature],'VBE2'
	mov	ax,$4F00
	mov	di,vi
	int	$10
	cmp	ax,0x004F
	je	@f
	mov	[vi.VESASignature],'VESA'
	mov	ax,$4F00
	mov	di,vi
	int	$10
	cmp	ax,0x004F
	jne	.exit
  @@:
	cmp	[vi.VESASignature],'VESA'
	jne	.exit
	cmp	[vi.VESAVersion],$0100
	jb	.exit

;----------------------------[ VESA ]----------------------------

	mov	dx,_vesa_bios_detected
	call	print

	mov	ax,[vi.VESAVersion]
	add	ax,0x3030
	mov	[_vesa_vbe.version+10],al
	mov	[_vesa_vbe.version+8],ah

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.version
	call	print

	movzx	eax,[vi.TotalMemory]
	shl	eax,6
	mov	di,_buffer
	mov	ecx,10
	call	int2str

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.total_mem
	call	print
	mov	dx,_buffer
	call	print
	mov	dx,_kbytes
	call	print

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.oem
	call	print
	mov	esi,[vi.OemStringPtr]
	call	print_str
	mov	dx,_crlf
	call	print

	cmp	[_vesa_vbe.version+8],'2'
	jb	.no_vesa2

	mov	ax,[vi.OemSoftwareRev]
	push	ax
	shr	ax,8
	mov	bl,10
	idiv    bl
	add	ax,0x3030
	mov	[_vesa_vbe.oem_sw_rev+18],al
	mov	[_vesa_vbe.oem_sw_rev+19],ah
	pop	ax
	cbw
	mov	bl,10
	idiv    bl
	add	ax,0x3030
	mov	[_vesa_vbe.oem_sw_rev+21],al
	mov	[_vesa_vbe.oem_sw_rev+22],ah

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.oem_sw_rev
	call	print

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.oem_vendor
	call	print
	mov	esi,[vi.OemVendorNamePtr]
	call	print_str
	mov	dx,_crlf
	call	print

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.oem_pr
	call	print
	mov	esi,[vi.OemProductNamePtr]
	call	print_str
	mov	dx,_crlf
	call	print

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.oem_pr_rev
	call	print
	mov	esi,[vi.OemProductRevPtr]
	call	print_str
	mov	dx,_crlf
	call	print

	mov	dx,_crlf
	call	print
  .no_vesa2:

;-------------------------[ DDC & EDID ]-------------------------

	mov	ax,0x4F15
	xor	bx,bx
	xor	cx,cx
	push	0 0
	pop	es di
	int	0x10

	cmp	ax,0x004F
	jne	.no_ddc
	test	bl,00000011b
	jz	.no_ddc

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.ddc_supported
	call	print

	and	bl,00000011b
	add	bl,'0'
	mov	[_vesa_vbe.ddc_level+10],bl

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.ddc_level
	call	print

	movzx	eax,bh
	mov	di,_buffer
	mov	ecx,10
	call	int2str

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.ddc_transfer
	call	print
	mov	dx,_buffer
	call	print
	mov	dx,_sec
	call	print

	push	cs
	pop	es

	mov	ax,0x4F15
	mov	bl,1
	xor	cx,cx
	xor	dx,dx
	mov	di,ed
	int	0x10

	cmp	dword[ed.Header],0xFFFFFF00
	jne	.exit
	cmp	dword[ed.Header+4],0x00FFFFFF
	jne	.exit

	mov	dx,_vesa_vbe
	call	print
	mov	dx,_vesa_vbe.ddc_read_ok
	call	print

	mov	ax,[ed.ManufacturerName]
	and	ax,0001111101111100b
	mov	[_display.manufacturer+16],ah
	shr	al,2
	mov	[_display.manufacturer+14],al
	mov	ax,[ed.ManufacturerName]
	xchg	al,ah
	shr	ax,5
	and	al,00011111b
	mov	[_display.manufacturer+15],al
	add	dword[_display.manufacturer+14],'@@@'

	movzx	eax,[ed.ProductCode]
	mov	di,_display.manufacturer+26
	mov	ecx,16
	mov	bl,4
	call	int2str_fixed

	mov	eax,[ed.SerialNumber]
	mov	di,_buffer
	mov	ecx,10
	call	int2str

	mov	dx,_display.manufacturer
	call	print
	mov	dx,_buffer
	call	print
	mov	dx,_crlf
	call	print

	movzx	eax,[ed.YearOfManufacture]
	add	ax,1990
	mov	di,_display.date+6
	mov	ecx,10
	mov	bl,4
	call	int2str_fixed

	movzx	eax,[ed.WeekOfManufacture]
	mov	di,_buffer
	mov	ecx,10
	call	int2str

	mov	dx,_display.date
	call	print
	mov	dx,_buffer
	call	print
	mov	dx,_crlf
	call	print

	mov	al,[ed.EDIDVersionNumber]
	add	al,0x30
	mov	[_display.edid_version+14],al

	movzx	eax,[ed.EDIDRevisionNumber]
	mov	di,_display.edid_version+16
	mov	ecx,10
	call	int2str

	mov	dx,_display.edid_version
	call	print
	mov	dx,_crlf
	call	print

	mov	al,[ed.VideoInputType]
	mov	dx,_display.analog
	test	al,10000000b
	jz	@f
	mov	dx,_display.digital
    @@: call	print
	mov	dx,_display.display_input
	call	print
	mov	dx,_undefined
	and	al,01100000b
	cmp	al,00000000b
	jne	@f
	mov	dx,_display.voltage00
    @@: cmp	al,00100000b
	jne	@f
	mov	dx,_display.voltage01
    @@: cmp	al,01000000b
	jne	@f
	mov	dx,_display.voltage10
    @@: call	print
	mov	dx,_volts
	call	print

	mov	dx,_display.sync
	call	print
	mov	al,[ed.VideoInputType]
	test	al,10000000b
	jz	@f
	test	al,00000001b
	jz	.okok
	mov	dx,_display.serration_vsync
	call	print
	jmp	.okok
    @@: test	al,00011111b
	jnz	@f
	mov	dx,_undefined
	call	print
    @@: test	al,00000001b
	jz	@f
	mov	dx,_display.serration_vsync
	call	print
    @@: test	al,00000010b
	jz	@f
	mov	dx,_display.sync_on_green
	call	print
    @@: test	al,00000100b
	jz	@f
	mov	dx,_display.composite_sync
	call	print
    @@: test	al,00001000b
	jz	@f
	mov	dx,_display.separate_syncs
	call	print
    @@: test	al,00010000b
	jz	@f
	mov	dx,_display.blank_to_black
	call	print
    @@:
  .okok:
	mov	dx,_crlf
	call	print

	movzx	eax,[ed.MaxHorzImageSize]
	mov	di,_buffer
	mov	ecx,10
	call	int2str

	movzx	eax,[ed.MaxVertImageSize]
	mov	di,_buffer+20
	mov	ecx,10
	call	int2str

	mov	dx,_display.max_image_horz
	call	print
	mov	dx,_buffer
	call	print
	mov	dx,_display.max_image_vert
	call	print
	mov	dx,_buffer+20
	call	print
	mov	dx,_crlf
	call	print

	movzx	ax,[ed.GammaFactor]
	mov	cl,100
	div	cl
	add	al,0x31
	mov	[_display.gamma+7],al
	shr	ax,8
	mov	cl,10
	div	cl
	add	ax,0x3030
	mov	word[_display.gamma+9],ax

	mov	dx,_display.gamma
	call	print

	mov	dx,_display.dpms_caps
	call	print
	mov	al,[ed.FeatureSupport]
	test	al,10000000b
	jz	@f
	mov	dx,_display.standby
	call	print
    @@: test	al,01000000b
	jz	@f
	mov	dx,_display.suspend
	call	print
    @@: test	al,00100000b
	jz	@f
	mov	dx,_display.off
	call	print
    @@: mov	dx,_display.rgb_color
	test	al,00001000b
	jnz	@f
	mov	dx,_display.non_rgb_mclr
    @@: call	print

  .no_ddc:
	push	cs
	pop	es
;----------------------------------------------------------------






	mov	ah,9
	mov	dx,_enm
	int	$21

	mov	si,word[vi.VideoModePtr]
	push	word[vi.VideoModePtr+2]
	pop	fs

	mov	bx,m_info

  .next_mode:
	mov	cx,[fs:si] ; mode number
	cmp	cx,-1
	je	.modes_ok

	mov	ax,$4F01
	mov	di,mi
	int	$10

	or	ah,ah
	jnz	.exit
	test	[mi.ModeAttributes],00000001b
	jz	@f
	test	[mi.ModeAttributes],00010000b
	jz	@f

	cmp	[mi.BitsPerPixel],16
	jne	.l0
	cmp	[mi.GreenMaskSize],5
	jne	.l0
	mov	[mi.BitsPerPixel],15
  .l0:
	mov	ax,[mi.XRes]
	mov	[bx+0],ax
	mov	ax,[mi.YRes]
	mov	[bx+2],ax
	mov	ax,[mi.ModeAttributes]
	mov	[bx+4],ax
	mov	[bx+6],cx
	mov	al,[mi.BitsPerPixel]
	mov	[bx+8],al

	add	bx,10

    @@:
	add	si,2
	jmp	.next_mode

  .modes_ok:

	mov	si,m_info

    @@: add	si,10
	cmp	si,bx
	jae	@f
	mov	ax,[si+0-10]
	cmp	ax,[si+0]
	ja	.xch
	jb	@b
	mov	ax,[si+2-10]
	cmp	ax,[si+2]
	ja	.xch
	jb	@b
	mov	al,[si+8-10]
	cmp	al,[si+8]
	ja	.xch
	jmp	@b
  .xch: push	dword[si+0] dword[si+4]  word[si+8] dword[si+0-10] dword[si+4-10]  word[si+8-10]
	pop	 word[si+8] dword[si+4] dword[si+0]  word[si+8-10] dword[si+4-10] dword[si+0-10]
	mov	si,m_info
	jmp	@b

    @@: mov	ah,9
	mov	dx,_bt
	int	$21
	mov	ah,9
	mov	dx,_tl
	int	$21

	mov	word[bx],-1
	mov	si,m_info
	pushw	[si+0] [si+2]
	mov	bp,sp

    @@: cmp	word[si-10],-1
	je	@f
	mov	ax,[si+0]
	cmp	ax,[ss:bp+2]
	jne	.wr
	mov	ax,[si+2]
	cmp	ax,[ss:bp+0]
	jne	.wr

  .ww:	push	bx
	movzx	eax,word[si+0]
	mov	di,_rs+2
	mov	ecx,10
	mov	bl,4
	call	int2str_fixed
	movzx	eax,word[si+2]
	inc	di
	mov	bl,4
	call	int2str_fixed

	mov	al,[si+8]
	mov	di,_rs+16
	cmp	al,4
	je	.l1
	add	di,5
	cmp	al,8
	je	.l1
	add	di,5
	cmp	al,15
	je	.l1
	add	di,5
	cmp	al,16
	je	.l1
	add	di,5
	cmp	al,24
	je	.l1
	add	di,5
  .l1:	mov	byte[di],'+'

	pop	bx
	add	si,10
	jmp	@b

  .wr:	mov	ah,9
	mov	dx,_rs
	int	$21

	mov	byte[_rs+16+5*0],'-'
	mov	byte[_rs+16+5*1],'-'
	mov	byte[_rs+16+5*2],'-'
	mov	byte[_rs+16+5*3],'-'
	mov	byte[_rs+16+5*4],'-'
	mov	byte[_rs+16+5*5],'-'

	pushw	[si+0] [si+2]
	popw	[ss:bp+0] [ss:bp+2]

  .sk:
	jmp	.ww

    @@: add	sp,4

	mov	ah,9
	mov	dx,_bt
	int	$21

	xor	ax,ax
	int	$16

  .exit:
	mov	ax,$4C00
	int	$21

;---------------------------------------------------------------------------

  int2str: @@:
;        dec     bl
;        jz      @f
	cmp	eax,ecx
	jb	@f
	xor	edx,edx
	div	ecx
	push	edx
	call	@b
	pop	eax
    @@: cmp	al,10
	sbb	al,$69
	das
	mov	[ds:di],al
	inc	di
	mov	byte[ds:di],$24
	ret

  int2str_fixed: @@:
	dec	bl
	jz	@f
	xor	edx,edx
	div	ecx
	push	edx
	call	@b
	pop	eax
    @@: cmp	al,10
	sbb	al,$69
	das
	mov	[ds:di],al
	inc	di
	ret

  print:
	push	ax ds
	push	cs
	pop	ds
	mov	ah,9
	int	$21
	pop	ds ax
	ret

  print_str:
	push	ax dx ds
	push	esi
	pop	si ds
	cld
    @@: lodsb
	cmp	al,0
	je	@f
	mov	ah,2
	mov	dl,al
	int	$21
	jmp	@b
    @@: pop	ds dx ax
	ret

_vesa_bios_detected db 'VESA BIOS detected',13,10,$24

_vesa_vbe	 db 'VESA VBE ',$24
  .version	 db 'Version ?.?',13,10,$24
  .total_mem	 db 'Total Mem: ',$24
  .oem		 db 'OEM: ',$24
  .oem_sw_rev	 db 'OEM Software Rev: ??.??',13,10,$24
  .oem_vendor	 db 'OEM Vendor: ',$24
  .oem_pr	 db 'OEM Product: ',$24
  .oem_pr_rev	 db 'OEM Product Rev: ',$24
  .ddc_supported db 'DDC supported',13,10,$24
  .ddc_level	 db 'DDC Level ?',13,10,$24
  .ddc_transfer  db 'DDC transfer in appr. ',$24
  .ddc_read_ok	 db 'DDC read successfully',13,10,$24

_display:
  .manufacturer   db 'Manufacturer: ???  Model: ????  Serial#: ',$24
  .date 	  db 'Year: ????  Week: ',$24
  .edid_version   db 'EDID Version: ?.?  ',$24
  .display_input  db ' Display Input,  Input Voltage Level: ',$24
    .analog	  db 'Analog',$24
    .digital	  db 'Digital',$24
    .voltage00	  db '0.700/0.300',$24
    .voltage01	  db '0.714/0.286',$24
    .voltage10	  db '0.100/0.400',$24
  .sync 	  db 'Sync: ',$24
    .dfp_1_compat    db ' DFP 1.x compatible',$24
    .serration_vsync db ' SerrationVsync',$24
    .sync_on_green   db ' SyncOnGreen',$24
    .composite_sync  db ' CompositeSync',$24
    .separate_syncs  db ' SeparateSyncs',$24
    .blank_to_black  db ' BlankToBlackSetup',$24
    .rgb_color	  db '; RGB/Color Display',13,10,$24
    .non_rgb_mclr db '; Non-RGB Multicolor Display',13,10,$24
  .max_image_horz db 'Max H-Image Size [cm]: horiz.: ',$24
  .max_image_vert db '  vert.: ',$24
  .gamma	  db 'Gamma: ?.??',13,10,$24
  .dpms_caps	  db 'DPMS capabilities:',$24
    .standby	  db ' StandBy',$24
    .suspend	  db ' Suspend',$24
    .off	  db ' Off',$24

_undefined db ' undefined',$24
_volts	   db ' V',13,10,$24
_sec	   db ' sec.',13,10,$24
_kbytes    db ' kB'
_crlf	   db 13,10,$24

_ok  db 'detected: vesa version is ?.?, ??? Mbytes of video memory',13,10,10,$24
_oem db 'oem string: "',$24
_enm db 13,10,'enumerating vga-compatible video modes:',13,10,10,$24

_tl  db '| resolution |  4 |  8 | 15 | 16 | 24 | 32 |',13,10
_bt  db '+------------+----+----+----+----+----+----+',13,10,$24
_rs  db '| ????x????  |  - |  - |  - |  - |  - |  - |',13,10,$24

_buffer rb 260

vi VBE_VGAInfo
mi VBE_ModeInfo
ed EDID_Block

m_info rw 100*5