;  biosdata.S
;
;  Copyright 2002-2004 John Coffman
;  Copyright 2009-2011 Joachim Wiedorn
;  All rights reserved.
;
;  Licensed under the terms contained in the file 'COPYING'
;  in the source directory.
;


io_sig:	.long	0		; space for CRC
	.ascii	PROBE_SIGNATURE	; "LiLo"
	.word	PROBE_VERSION	; sanity check
io_lth:	.word	0		; byte count overall
io_good_disk:
	.byte	0	; last good drive (in low byte)
	.byte	BD_GET_VIDEO
	.byte	BD_MAX_FLOPPY
	.byte	BD_MAX_HARD
io_flp:	.word	0
io_hrd:	.word	0
io_pt:	.word	0

#if PROBE_VERSION >= 5
io_eqp:	.word	0
io_vid:	.word	0
#endif

io_l_sig	= *-io_sig

; read partition table of device in DL
;
; save PT
;
io_get_pt:
	push	ds
	push	es

	push	#0
	pop	es
	mov	bx,#BOOTSEG*16+SECTOR_SIZE
	mov	cx,#1
	mov	dh,#0
	mov	ax,#0x201		; read 1 sector
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Read partition table\n"
	.byte	0
	popa
#endif
	call	dsk_do_rw		; make 5 tries
	push	es
	pop	ds

	pop	es
#if  PROBE_VERSION == 3
	lea	si,(bx+PART_TABLE_OFFSET)
	mov	cx,#4*16
#elif  PROBE_VERSION >= 4
	lea	si,(bx+PART_TABLE_OFFSET-8)
	mov	cx,#4*16+8
#endif
	jc	io_get_pt_err
	rep
	  movsb
io_get_pt_ret:
	pop	ds
	ret

io_get_pt_err:
	mov	al,#-1
	rep
	  stosb
	jmp	io_get_pt_ret



; check a hard drive for EDD support
;
;	device code is in DL
;
;
io_do_edd_check:
	push	dx
	mov	ah,#0x41
	mov	bx,#0x55AA
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Check EDD present\n"
	.byte	0
	popa
#endif
	int	0x13

	xchg	al,ah
	lahf
	pop	dx

	stosw
	mov	ax,bx
	stosw
	xchg	ax,cx
	stosw

	jc	io_do_edd_check_ret
	cmp	bx,#0xAA55
	jne	io_do_edd_check_ret
#if PROBE_VERSION < 6
	test	al,#EDD_SUBSET	; test for EDD call supported
	jz	io_do_edd_check_ret
#endif

; get the EDD parameters

	push	dx		; paranoia, protect DL
	push	es		; more paranoia
	push	ds

	push	es
	pop	ds
	mov	si,di		; DS:SI points at return area
	push	di
	mov	ah,#0x48
	mov	word (si),#EDD_LTH	; set max count to return
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get EDD parameters\n"
	.byte	0
	popa
#endif
	int	0x13
	pop	di

	xchg	al,ah
	lahf
	
	add	di,#EDD_LTH
	stosw			; save the return flags

	pop	ds
	pop	es
	pop	dx

io_do_edd_check_ret:
	ret



;
; io_biosdata:	examine hard disk BIOS devices
;		and video state
;
;  Enter with:
;		DS == CS
;		direction flag clear
;
;
;  Exit with:
;		All registers preserved
;		
;		Side effect is to write the low memory disk data area
;
;
;

io_biosdata:
	pusha			;save all registers
	push	es

	push	#PROBESEG	;save area is at 0060:0000 (0x000600)
	pop	es
	mov	di,#io_l_sig	;skip over header area

; get the equipment configuration flags

#if PROBE_VERSION >= 5
	mov	io_eqp,di	;save equipment pointer
	push	dx		; protect this register
#endif
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get equipment configuration\n"
	.byte	0
	popa
#endif
	int	0x11
	stosw

; get the conventional memory size

#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get conventional memory size\n"
	.byte	0
	popa
#endif
	int	0x12
	stosw			; save the number

#if PROBE_VERSION >= 5
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Save boot device code\n"
	.byte	0
	popa
#endif
	pop	ax		; get saved DX register
	stosw			
#endif

; collect the video information

#if PROBE_VERSION >= 5
	mov	io_vid,di	; set the pointer
#endif
#if BD_GET_VIDEO >= 1
	mov	ah,#0x0F	; get video mode
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get video mode\n"
	.byte	0
	popa
#endif
	int	0x10

	push	ds
	push	#0x40
	pop	ds
	mov	bl,[0x84]	; get rows, too
	pop	ds

	stosw			; save AX
	xchg	ax,bx
	stosw			; save BX
	cmp	bl,#7		; is it MDA
	beq	io_floppies	; yup, skip it all
	cmp	bh,#80		; number of columns on screen
	jb	io_floppies1	; probably CGA

#endif
#if BD_GET_VIDEO >= 2
#if 1
	mov	ah,#0x12
	mov	bx,#0xFF10	; get configuration information
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get video configuration\n"
	.byte	0
	popa
#endif
	int	0x10

	stosw			; save AX
	xchg	ax,bx
	stosw			; save BX
	cmp	ah,#1
	ja	io_floppies1

#endif
	mov	ax,#0x1A00	; get display combination code
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get display combination\n"
	.byte	0
	popa
#endif
	int	0x10

	stosw			; save AX
	xchg	ax,bx
	stosw			; save BX
	cmp	bl,#0x1A	; is function supported?
#ifndef BD_VERBOSE
	jne	io_floppies
#else
	bne	io_floppies
io_floppies1	equ	*-3
#endif
	cmp	al,#4
	jb	io_floppies1

#if PROBE_VERSION >= 5

; test to see if registers get trashed (some geforce video bios trashes dx)
	push	ds
	push	es
	push	di

	mov	cx,#0x1234
	mov	dx,#0x5680
	mov	bp,#0x4321

	mov	ax,#0x1200
	mov	bx,#0x0036
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Enable Screen Refresh\n"
	.byte	0
	popa
#endif
	int	0x10		; enable screen refresh

	pop	di
	pop	es
	pop	ds
	stosw			; AX
	xchg	ax,cx
	stosw			; CX
	xchg	ax,dx
	stosw			; DX
	xchg	ax,bp
	stosw			; BP
#endif

#endif  /* BD_GET_VIDEO >= 2 */

#if BD_GET_VIDEO >= 3
	mov	ax,#0x4F00	; check VESA present
; ES:DI is already set
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Check VESA present\n"
	.byte	0
	popa
#endif
	int	0x10

	seg es
	  mov	bx,(di)		; possible "VE"
	seg es
	  mov	cx,(di+2)	; possible "SA"
	stosw			; save AX
	xchg	ax,bx
	stosw			; possible "VE"
	xchg	ax,cx		; possible "SA"
	stosw
	cmp	bx,#0x004F	; good return
	jne	io_floppies
	cmp	cx,#0x4556	; "VE"
	jne	io_floppies
	cmp	ax,#0x4153	; "SA"
	jne	io_floppies
	
	mov	ax,#0x4F01
	mov	cx,#0x0101	; get mode information
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get VESA mode information 1\n"
	.byte	0
	popa
#endif
	int	0x10	

	seg es
	  mov	bx,(di)		; get bits
	stosw			; save AX
	xchg	ax,bx
	stosw			; save bits

	mov	ax,#0x4F01
	mov	cx,#0x0103	; get mode information
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get VESA mode information 3\n"
	.byte	0
	popa
#endif
	int	0x10	

	seg es
	  mov	bx,(di)		; get bits
	stosw			; save AX
	xchg	ax,bx
	stosw			; save bits
#else
	mov	ax,#-1		; flag for VESA not present
	stosw
	stosw
	stosw
;	jmp	io_floppies	; exit to this point
#endif

; now go after the disk drive information

io_floppies:
#ifndef BD_VERBOSE
io_floppies1:
#endif
	mov	cx,#BD_MAX_FLOPPY	;test 4 floppies
	xor	dx,dx
	mov	io_flp,di		;set pointer to floppy info

io_next_drive:
	push	cx

; get the drive type

	mov	ah,#0x15
	push	dx
#ifdef BD_VERBOSE
	pusha
	test	dl,#3		; pause every 4th drive
	jnz	io_no_pause
	call	pause
io_no_pause:
	call	say
	.ascii	"Get drive type "
	.byte	0
	mov	al,dl
	call	bout
	call	say
	.byte	10,0
	popa
#endif
	int	0x13

	xchg	al,ah		;code to AL
	lahf			;flags to AH

	stosw			; save AX
	xchg	ax,dx
	stosw			; save DX (low order)
	xchg	ax,cx
	stosw			; save CX (high order)
	xchg	ax,dx		; restore code to AL
	pop	dx

	jc	io_no_disk	; error means no disk present
	dec	al		; AL==0 means no disk present
	jns	io_get_param	; if S=0, some disk type is present

io_no_disk:
	or	dl,dl
	jns	io_get_param	;do it all on floppies

	pop	cx		;premature loop termination
	jmp	io_loop_end	;skip the rest on fixed disks

io_get_param:

; get drive parameters

	push	dx
	push	es		; supposedly clobbered for floppies only
	push	di		; do not trust anyone

	mov	ah,#0x08
#ifdef BD_VERBOSE
	pusha
	call	say
	.ascii	"Get drive parameters\n"
	.byte	0
	popa
#endif
	int	0x13
	xchg	al,ah
	lahf
	
	mov	bp,di		; save floppy param pointer
	mov	bx,es

	pop	di
	pop	es

	stosw			; save return code & flags
	xchg	ax,cx
	stosw
	xchg	ax,dx
	stosw
	pop	dx

	jc	io_fh_check	; bad return above
;;;	mov	[io_good_disk],dl	; save DL

	cmp	dl,#0x80	; check for first HD
	jne	io_fh_check
	cbw			; former DL has disk count
	pop	cx		; get HD count
	push	ax		; set new HD count

io_fh_check:
	or	dl,dl		; check floppy/hard disk
	js	io_check_edd
	xchg	ax,bp		; was DI
	stosw
	xchg	ax,bx		; was ES
	stosw
	jmp	io_skip_edd

; check EDD extensions present

io_check_edd:

	call	io_do_edd_check

io_skip_edd:

	mov	[io_good_disk],dl	;save last disk checked
	pop	cx
	inc	dl
#ifndef BD_VERBOSE
	loop	io_next_drive
#else
	dec	cx
	bne	io_next_drive
#endif
io_loop_end:
	or	dl,dl		; set the S flag
	push	di		;
	mov	cx,#BD_MAX_HARD	; do not touch flags ***
	mov	dl,#0x80	; do not touch flags ***
#ifndef BD_VERBOSE
	jns	io_next_drive	; do the hard drives if not done
#else
	bpl	io_next_drive
#endif
	pop	word [io_pt]	; save pt pointer
	pop	word [io_hrd]	; save hd pointer

; now save the partition tables
	
io_get: 
	cmp	dl,io_good_disk
	ja	io_got
	call	io_get_pt
	inc	dx
	jmp	io_get
io_got:

io_checksum_it:

; now must record and checksum the results

	mov	io_lth,di		; address of end is overall count

	push	di
	xor	di,di			;move to here
	mov	si,#io_sig		;move from here
	mov	cx,#io_l_sig		;this number of bytes
	rep
	  movsb				;
	pop	di
	mov	si,#4			; skip long at beginning
	sub	di,si
#ifndef BD_VERBOSE
	push    dword #CRC_POLY1
	call	crc32

	seg	es
	mov	[0],eax			; save that crc
#endif

; restore the registers and return

	pop	es
	popa
	ret

; end biosdata.S
