;	[]===========================================================[]
;
;	NOTICE: THIS PROGRAM BELONGS TO AWARD SOFTWARE INTERNATIONAL(R)
;	        INC. IT IS CONSIDERED A TRADE SECRET AND IS NOT TO BE
;	        DIVULGED OR USED BY PARTIES WHO HAVE NOT RECEIVED
;	        WRITTEN AUTHORIZATION FROM THE OWNER.
;
; 	[]===========================================================[]
;

;----------------------------------------------------------------------------
;Rev	Date	 Name	Description
;----------------------------------------------------------------------------
;R04	12/26/97 DRS	Move Ct_Enable_C_Shadow hook from chiprun.asm to chipboot.asm
;R03	12/09/97 DRS	Change max pci bus range
;R02	12/08/97 DRS	Some chipset don't want support run PCI/AGP VGA in bootblock
;R01	12/08/97 DRS	For save code
;R00	12/08/97 DRS	Initial version
;			     1. Support 16K_8K_8K_Unit of 2M Flash 
;				run PCI Vga in bootblock  		
;				AGP Vga please define Support_AGP_For_BootBlock EQU 1
;			     2. Support PCI 1A Function call in bootblock					
;			     3. Add Ct_Enable_C_Shadow	hook in [chiprun.asm]
;				Add AGP_P2P_Bridge parameter in [bios.cfg]
;				APG P2P Bridge of Intel/SiS/VIA use 
;	Intel LX -- AGP_P2P_Bridge EQU (0 shl 8)+(01h shl 3)	(Bus 0 + Dev 1)
;	SIS 5591 -- AGP_P2P_Bridge EQU (0 shl 8)+(02h shl 3)	(Bus 0 + Dev 2)
;	VIA 597  -- AGP_P2P_Bridge EQU (0 shl 8)+(01h shl 3)	(Bus 0 + Dev 1)
;	ALi M1541-- AGP_P2P_Bridge EQU (0 shl 8)+(01h shl 3)	(Bus 0 + Dev 1)
;	ALi M1621-- AGP_P2P_Bridge EQU (0 shl 8)+(01h shl 3)	(Bus 0 + Dev 1)

ifndef	No_Support_PCI_VGA_in_Bootblock		;R02
ifdef	PCI_BUS
;[]-----------------------------------------------------------------[]
;Function : Check if PCI VGA installed, if yes , copy video ROM into
;	    shadow RAM at location 0C0000H
;[]-----------------------------------------------------------------[]
InitPciVga	proc	near

	;check if ISA/VGA installed     
		call	CheckVideoRom
		je	IsaVgaFound	

		call	Find_Vga_Card
		jnc	Find_PCI_Slot_Vga_Card

ifdef	Support_AGP_For_BootBlock
 	;------------------------------------------------------------	
	;Now, assign resource to P2P Bridge
			
		mov	ax,0B109h			; Read Word
		mov	bx,AGP_P2P_Bridge		; 
		mov	di,0Ah
		int	1Ah
		cmp	cx,0604h			; Class PP Bridge ?
		jne	short @f			; No

		mov	bx,AGP_P2P_Bridge		; 
		mov	si,offset DGROUP:MinP2PReg	
		call	PrgRegTbl			
@@:
	;------------------------------------------------------------	
	;Find Vga card 
		call	Find_Vga_Card
		jc	No_AGP_Card

else	;Support_AGP_For_BootBlock
		jmp	No_PCI_VGA_Card
endif	;Support_AGP_For_BootBlock

Find_PCI_Slot_Vga_Card:

		;Enable ROM and Set Expansion ROM Base Address
		mov	si,offset DGROUP:VgaReg_Tbl	
		call	PrgRegTbl			

;R04		extrn	Ct_Enable_C_Shadow:near	;set C0000H-CFFFF to shadow
		call	Ct_Enable_C_Shadow	;R/W. in chiprun.asm

		;-------------------------------;
		;  Switch to Proctected Mode	;
		;-------------------------------;
		cli				

                lgdt    fword ptr cs:A_GDTR	; Load descriptor table

                mov     eax,cr0                 ; Enter protected mode
                or      al,1
                mov     cr0,eax

		jmp	short $+2

                mov     ax,B_DATA1_INDEX
                mov     ds,ax                   ; DS = 00000000h
	
		mov	esi,0f0000000H		; ROM location
		cmp	word ptr [esi],0AA55H	; ROM signature
		jne	short NoVideoRom

		mov	edi,0000C0000h		; shadow RAM address

		mov	ecx,64*1024/4		;copy 64Kb video ROM
		cld
		db	67h
		rep	movsd			;copy ROM to shadow RAM

NoVideoRom:
		;-------------------------------;
		;  Leave Proctected Mode	;
		;-------------------------------;
                mov     eax,cr0
                and     al, NOT 1
                mov     cr0,eax

		jmp	short $+2		;flush queue

IsaVgaFound:
No_AGP_Card:
No_PCI_VGA_Card:

		ret

InitPciVga	endp
;[]======================================================[]
;[]======================================================[]
MinP2PReg:
		db	18h
		dw	0100h			;set bus 1
		db	1ah
		dw	04001h

		db	1ch
		dw	0d0d0h			;set I/O to D000H-DFFFH
		db	20h
		dw	0F000H			;memory low limit
		db	22h
		dw	0FC00H			;memory high limit
		db	24h
		dw	0FFF0H			;disable prefetch memory
		db	26h
		dw	0

		db	3eh			;;;;;;
		dw	0bh			;;;;;;

		db	04h
		dw	0003H			;enable I/O and Memory
		db	0			;end of table


	;----------------------------------------
Vga_ClassCode_Tbl:
		dw	0300h			;VGA
		dw	0301h			;XGA
		dw	0001h			;VGA Compatible
		dw	0			;end of table
				
	;----------------------------------------
VgaReg_Tbl:

		db	30H			
		dw	0001H			; Enable ROM
		db	32h
		dw	0F000H			; Set ROM address F0000000h
		db	04H
		dw	00003H

		db	10h			; Set Base Address 0
		dw	0000h		
		db	12h		
		dw	0D800h		
		db	14h			; Set Base Address 1
		dw	0000h		
		db	16h		
		dw	0DA00h		

		db	0			;end of table

CheckVideoRom	proc	near
		mov	ax,0c000h		;Video ROM segment address
		mov	ds,ax
		cmp	word ptr ds:[0],0aa55h	;Video ROM existed ?
		ret
CheckVideoRom	endp

;----------------------------------------------------------
;Function : Find Vga Card
;Input    : None
;Output	  : BH -- VGA Bus Number    
;	    BL -- VGA Device Number(upper 5bit) + Function Number(bottom 3bit)
;	    CF set - error cleared - success	
;----------------------------------------------------------
Find_Vga_Card	proc	near

		mov	di,offset DGROUP:Vga_ClassCode_Tbl
Find_Vga_Loop:
		xor	ecx,ecx
		mov	cx,cs:[di]
		cmp	cx,0
		je	short Vga_No_Exist

		; Get Bus no. + Device no. to BX
		shl	ecx,8				;;;;;;
		mov	ax,0B103h			; Find PCI Class Code
		xor	si,si
		int 	1Ah				
		cmp	ah, DEVICE_NOT_FOUND		; VGA no find ?
		jne	short VGA_Exist			; yes

		add	di,2
		jmp	short Find_Vga_Loop

VGA_Exist:
		clc
		ret

VGA_No_Exist:
	       	stc
	       	ret

Find_Vga_Card	endp

;----------------------------------------------------------
;Function : Program PCI configuration space
;Input    : SI - register table
;	    BH - bus identification no.
;	    BL - current (device no. + function no.)
;Output   : AH - 00 (successful)
;----------------------------------------------------------
PrgRegTbl	proc	near
NextBytePrg:
		movzx	di,byte ptr cs:[si]	; DI -- Register No.
		or	di,di			;end of table ?
		jz	short EndTblPrg		;no, continue

		mov	ah,0B1h
		mov	al,0Ch			; write configuration word
		mov	cx,cs:[si+1]		; CX -- Word Value Write
		int	1Ah
		cmp	ah,0
		jne	short @f
		add	si,3			;next register to program
		jmp	short NextBytePrg
EndTblPrg:
		ret

@@:
PrgRegTbl	endp
endif;	PCI_BUS


;[]================================================================[]
;			EQUATES
;[]================================================================[]
BUS_ID			EQU	0		;Assume bus identification number = 0 ;???
LAST_DEVICE_NO		EQU	31

SUCCESSFUL		EQU	00h
PCI_FUNCTION_ID 	EQU	0B1H
FUNC_NOT_SUPPORTED	EQU	81H
BAD_DEVICE_ID		EQU	82H
BAD_VENDOR_ID		EQU	83H
BAD_BUS_ID		EQU	84H
BAD_SLOT_ID		EQU	85H
DEVICE_NOT_FOUND	EQU	86H
BAD_REGISTER_NUMBER	EQU	87H
NO_INTERRUPT_ASSIGNED	EQU	88H
SET_FAILED		EQU	88H
BUFFER_TO_SMALL		EQU	89H

ifndef	Special_PCI_Slot_Range
MIN_PCI_SLOT		EQU	0
MAX_PCI_SLOT		EQU	31
endif	;Special_PCI_Slot_Range

ifdef	PCI_BUS
ifdef	CONFIG_MECHANISM_1
;[]========================================================================[]
;[]========================================================================[]
Pci1a_Func_Tbl:
		dw	offset PCI_BIOS_PRESENT		;(01)
		dw	offset FIND_PCI_DEVICE		;(02)
		dw	offset PCI_CLASS_CODE		;(03)
		dw	offset INVALID_FUNC		;(04)
		dw	offset INVALID_FUNC		;(05)

;R01		dw	offset GENERATE_SPECIAL_CYCLE	;(06)
		dw	offset INVALID_FUNC		;(06)	;R01

		dw	offset INVALID_FUNC		;(07)
		dw	offset READ_CONFIG_BYTE		;(08)
		dw	offset READ_CONFIG_WORD		;(09)
		dw	offset READ_CONFIG_DWORD	;(0A)
		dw	offset WRITE_CONFIG_BYTE	;(0B)
		dw	offset WRITE_CONFIG_WORD	;(0C)
		dw	offset WRITE_CONFIG_DWORD	;(0D)

;R01		dw	offset Get_Irq_Routing_Options	;(0E)	
		dw	offset INVALID_FUNC		;(0E)	;R01

;R01		dw	offset Set_PCI_Irq		;(0F)	
		dw	offset INVALID_FUNC		;(0F)	;R01

		ALIGN	16
PCI_Procedure	PROC	NEAR

		cmp	al,0Fh
		jg	short @f

		cmp	al,01h
		jne	short @F
		CALL	PCI_BIOS_PRESENT
		jmp	short PCI_Func_exit1

@@:
		push	edx
		push	eax
		push	si
		xor	si,si
		movzx	si,al
		dec	si
		shl	si,1
		mov	ax,cs:word ptr Pci1a_Func_Tbl[si]
		pop	si
		call	ax
		nop
		jmp	short PCI_Func_exit

	@@:
		call	INVALID_FUNC	

;[]------------- PCI Fucntion Finished --------------[]
PCI_Func_exit:
		mov	dx,ax
		pop	eax
		mov	ah,dh
		pop	edx
PCI_Func_exit1:

		jc	short Error_Return
		xchg	bp,sp
		and	word ptr [bp+4],not 01h
		xchg	bp,sp
		iret
Error_Return:
		xchg	bp,sp
		or	word ptr [bp+4],01h
		xchg	bp,sp
		iret

PCI_Procedure	ENDP

;[]-------------------------------------------------------------------------[]
; INVALID_FUNC:
;	Return flag for invalid function call
;
; ENTRY : NONE
;
; EXIT	: AH = FUNC_NOT_SUPPORTED
;	  CF = 1
;[]-------------------------------------------------------------------------[]
		ALIGN	4
INVALID_FUNC	PROC	NEAR

		mov	ah,FUNC_NOT_SUPPORTED
		stc				;set error return
		ret

INVALID_FUNC	ENDP

;[]-------------------------------------------------------------------------[]
; PCI_BIOS_PRESENT:
;	This function allows the caller to determine both whether the
;   PCI BIOS interface function set is prtsent and what current interface
;   version level is.
;
; ENTRY : AH = PCI_FUNCTION_ID		(B1h)
;	  AL = PCI_BIOS_PRESENT 	(01h)
;	       PCI_BIOS_PRESENT32	(81h)
;
; EXIT	: EDX = " ICP"
;	  EDI = Physical address of entry point to PCI BIOS function for
;		protected mode access.
;	   AH = Present Status, 00h = BIOS Present IFF DX:CX set properly
;	   AL = Hardware mechanism
;	   BH = interface level major version
;	   BL = interface level minor version
;	   CL = Number of last PCI bus in the system
;	   CF = Present Status, set  = No BIOS Present,
;			       reset = BIOS Present if DX:CX set properly.
;[]-------------------------------------------------------------------------[]
		ALIGN	4
PCI_BIOS_PRESENT	PROC	NEAR

ifndef	NO_MULTI_PCI_SUPPORT

;Scan all PCI devices to report how many PCI bus does this platform have.

		call	Get_Max_PciBus		;get maximum bus no.

endif	;NO_MULTI_PCI_SUPPORT

		mov	edx,' ICP'

		mov	ax,0011H
					;al = 11h  H/W mechanism #1
					;	   & support Special Cycle

		mov	bx,0210h	;bh = interface level major version
					;bl = interface level minor version

ifdef	NO_MULTI_PCI_SUPPORT
		mov	cl,0
endif	;NO_MULTI_PCI_SUPPORT
		clc			;set successful return

PCI_BIOS_Present_Exit:

		ret

PCI_BIOS_PRESENT	ENDP

;[]-------------------------------------------------------------------------[]
; FIND_PCI_DEVICE:
;	Given the Vendor identifier and Device identifier in the DX and CX
;   registers respectively. this function must provide the corresponding Bus
;   Number and Slot Number, if such a device exists in the system.
;
; ENTRY : AH = PCI_FUNCTION_ID		(B1h)
;	  AL = FIND_PCI_DEVICE		(02H)
;	       FIND_PCI_DEVICE32	(82H)
;	  CX = Device ID (0...65535)
;	  DX = Vendor ID (1...65534)
;	  SI = Device Index (0...N)
;
; EXIT	: BH = Bus Identification Number (0...255)
;	  BL = Device Number in upper 5 bits
;	       Function Number in lower 3 bits
;	  CF = Completion Status, set = error, cleared = success.
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : DEVICE_NOT_FOUND	(86h)
;			    BAD_DEVICE_ID	(82h)
;			    BAD_VENDOR_ID	(83h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
FIND_PCI_DEVICE PROC	NEAR
		push	edi
		push	cx
		push	si

		cmp	dx,0ffffh		;check input vendor ID = 0ffffh ?
		jne	short Vendor_ID_OK

Invalid_Vendor_ID:

		mov	ah,BAD_VENDOR_ID
		stc
		jmp	short FIND_PCI_DEVICE_Exit

Vendor_ID_OK:

		mov	di,cx			;device ID
		shl	edi,16
		mov	di,dx			;save Vendor ID

		call	Get_Max_PciBus		;get maximum bus no.
		mov	bl,cl			;now BL is the maximum PCI bus

		xor	bh,bh			;start from bus 0
Search_Next_Bus1:

		xor	ch,ch			;start device 0
Search_loop:

ifdef	FOREX613_SPECIAL
		cmp	ch,0ffH			;special port ?
		je	short Already_MF1
endif;	FOREX613_SPECIAL

		xor	cl,cl
		call	Aget_CfgSpace_Dword	;read vendor & device ID

		cmp	eax,edi 		;vendor & device ID match?
		jne	short Next_slot

		or	si,si			;check index matching?
		jz	short Device_found
		dec	si

Next_slot:

		test	ch,07h
		jnz	short already_MF1
		mov	cl,0eh
		call	Aget_CfgSpace_Byte
		test	al,80h
		jnz	Already_MF1
		add	ch,7

Already_MF1:
		add	ch,1

		jnc	short Search_Loop

ifndef	NO_MULTI_PCI_SUPPORT
		inc	bh

		cmp	bh,bl
		jbe	short Search_Next_Bus1
endif	;NO_MULTI_PCI_SUPPORT

		mov	ah,DEVICE_NOT_FOUND
		stc
		jmp	short FIND_PCI_DEVICE_Exit

Device_found:

ifdef	NO_MULTI_PCI_SUPPORT
		mov	bh,BUS_ID
endif	;NO_MULTI_PCI_SUPPORT

		mov	bl,ch			;return device no.
		mov	ah,SUCCESSFUL
		clc				;set successful return

FIND_PCI_DEVICE_Exit:

		pop	si
		pop	cx
		pop	edi
		ret

FIND_PCI_DEVICE ENDP

;[]-------------------------------------------------------------------------[]
;  PCI_CLASS_CODE:
;
; ENTRY : AH  = PCI_FUNCTION_ID 	(B1h)
;	  AL  = FIND_PCI_CLASS_CODE	(03H)
;		FIND_PCI_CLASS_CODE32	(83H)
;	  ECX = Class Code (in lower 3 bytes)
;	  SI = Device Index (0...N)
;
; EXIT	: BH = Bus Identification Number (0...255)
;	  BL = Device Number in upper 5 bits
;	       Function Number in lower 3 bits
;	  CF = Completion Status, set = error, cleared = success.
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code :  DEVICE_NOT_FOUND	(86h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
PCI_CLASS_CODE	PROC	NEAR

		push	edi
		push	cx
		push	si

		and	ecx,00FFFFFFh
		mov	edi,ecx

		xor	bh,bh			;start from bus 0

Search_Next_Bus0:
		xor	ch,ch			;start from device 0
Search_Class_Loop:

ifdef	FOREX613_SPECIAL
		cmp	ch,0ffH			;special port ?
		je	short Already_MF
endif;	FOREX613_SPECIAL
	
		mov	cl,08H			;class code index
		call	Aget_CfgSpace_Dword	;read class code

		shr	eax,8			;shift to lower 3 bytes
		cmp	eax,edi 		;class code match?
		jne	short Next_Slot_Class

		push	cx
		mov	cl,0
		call	Aget_CfgSpace_Word
		cmp	ax,0FFFFh
		pop	cx
		je	short Next_Slot_Class

		or	si,si			;check index matching?
		jz	short Class_found
		dec	si

Next_Slot_Class:

		test	ch,07h
		jnz	short already_MF
		mov	cl,0eh
		call	Aget_CfgSpace_Byte
		test	al,80h
		jnz	Already_MF
		add	ch,7

Already_MF:
		add	ch,1

		jnc	short Search_Class_Loop

		inc	bh
		call	Qualify_PciBus
		jnc	short Search_Next_Bus0

		mov	ah,DEVICE_NOT_FOUND

		jmp	short PCI_CLASS_CODE_Exit

Class_found:

ifdef	NO_MULTI_PCI_SUPPORT
		mov	bh,BUS_ID
endif	;NO_MULTI_PCI_SUPPORT

		mov	bl,ch			;return device no.
		mov	ah,SUCCESSFUL
		clc				;successful flag

PCI_CLASS_CODE_Exit:

		pop	si
		pop	cx
		pop	edi
		ret

PCI_CLASS_CODE	ENDP

;[]-------------------------------------------------------------------------[]
; READ_CONFIG_BYTE:
;	This function allows reading individual bytes from the configuration
;   space of a specific device.
;
; ENTRY : AH = PCI_FUNCTION_ID		(B1h)
;	  AL = READ_CONFIG_BYTE 	(08h)
;	       READ_CONFIG_BYTE32	(88h)
;	  BH = Bus identification Number (0...255)
;	  BL = Device Number in upper 5 bits
;	       Function Number in lower 3 bits
;	  DI = Register Number (0...255)
;
; EXIT	: CL = Byte Read
;	  CF = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : BAD_BUS_ID		(84h)
;			    BAD_SLOT_ID 	(85h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
READ_CONFIG_BYTE	PROC	NEAR

		push	edx
		push	eax

		call	Validate_Args
		jc	READ_CONFIG_BYTE_Exit

		push	cx

		mov	cx,di
		mov	ch,bl

		call	Aget_CfgSpace_Word

		pop	cx
		mov	cl,al

		mov	ah,SUCCESSFUL

READ_CONFIG_BYTE_Exit:

		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx

		or	ah,ah
		jz	@f
		cmc				;error return
@@:
		ret

READ_CONFIG_BYTE	ENDP
;
;[]-------------------------------------------------------------------------[]
; READ_CONFIG_WORD:
;	This function allows reading individual words from the configuration
;   space of a specific device. The Register Number parameter must be a
;   multiple of two (i.e., bit 0 must be set to 0).
;
; ENTRY : AH = PCI_FUNCTION_ID		(B1h)
;	  AL = READ_CONFIG_WORD 	(09h)
;	       READ_CONFIG_WORD32	(89h)
;	  BH = Bus identification Number (0...255)
;	  BL = Device Number in upper 5 bits
;	       Function Number in lower 3 bits
;	  DI = Register Number (0,2,4,...254)
;
; EXIT	: CX = Word Read
;	  CF = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : BAD_BUS_ID		(84h)
;			    BAD_SLOT_ID 	(85h)
;			    BAD_REGISTER_NUMBER (87h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
READ_CONFIG_WORD	PROC	NEAR

		push	edx
		push	eax

		call	Validate_Args
		jc	READ_CONFIG_WORD_Exit

		test	di,1			;test register number is a multiple of 4 ?
		jz	short Valid_reg_num_rw
		mov	ah,BAD_REGISTER_NUMBER
		jmp	short READ_CONFIG_WORD_Exit

Valid_reg_num_rw:

		mov	cx,di
		mov	ch,bl

		call	Aget_CfgSpace_Word

		mov	cx,ax

		mov	ah,SUCCESSFUL

READ_CONFIG_WORD_Exit:

		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx

		or	ah,ah
		jz	@f
		cmc				;error return
@@:
		ret

READ_CONFIG_WORD	ENDP

;[]-------------------------------------------------------------------------[]
; READ_CONFIG_DWORD:
;	This function allows reading individual DWORDs from the configuration
;   space of a specific device. The Register Number parameter must be a
;   multiple of four (i.e., bit 0 and 1 must be set to 0).
;
; ENTRY : AH = PCI_FUNCTION_ID		(B1h)
;	  AL = READ_CONFIG_DWORD	(0Ah)
;	       READ_CONFIG_DWORD32	(8Ah)
;	  BH = Bus identification Number (0...255)
;	  BL = Device Number in upper 5 bits
;	       Function Number in lower 3 bits
;	  DI = Register Number (0,4,8,...252)
;
; EXIT	: ECX = Dword read
;	  CF  = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : BAD_BUS_ID		(84h)
;			    BAD_SLOT_ID 	(85h)
;			    BAD_REGISTER_NUMBER (87h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
READ_CONFIG_DWORD	PROC	NEAR

		push	edx
		push	eax

		call	Validate_Args
		jc	READ_CONFIG_DWORD_Exit

		test	di,3			;test register number is a multiple of 4 ?
		jz	short Valid_reg_num_rd
		mov	ah,BAD_REGISTER_NUMBER
		jmp	short READ_CONFIG_DWORD_Exit

Valid_reg_num_rd:
		mov	cx,di
		mov	ch,bl
		call	Aget_CfgSpace_Dword

		mov	ecx,eax
		mov	ah,SUCCESSFUL

READ_CONFIG_DWORD_Exit:

		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx

		or	ah,ah
		jz	@f
		cmc				;error return
@@:

		ret

READ_CONFIG_DWORD	ENDP

;[]-------------------------------------------------------------------------[]
; WRITE_CONFIG_BYTE:
;	This function allows writing individual bytes from the configuration
;   space of a specific device.
;
; ENTRY : AH = PCI_FUNCTION_ID		(B1h)
;	  AL = WRITE_CONFIG_BYTE	(0Bh)
;	       WRITE_CONFIG_BYTE32	(8Bh)
;	  BH = Bus identification Number (0...255)
;	  BL = Device Number in upper 5 bits
;	       Function Number in lower 3 bits
;	  DI = Register Number (0...255)
;	  CL = Byte Value to Write
;
; EXIT	: CF = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : BAD_BUS_ID		(84h)
;			    BAD_SLOT_ID 	(85h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
WRITE_CONFIG_BYTE	PROC	NEAR

		push	edx
		push	eax
		push	ecx

		call	Validate_Args
		jc	WRITE_CONFIG_BYTE_Exit

		mov	al,cl

		mov	cx,di
		mov	ch,bl

		call	Aset_CfgSpace_Byte

		mov	ah,SUCCESSFUL

WRITE_CONFIG_BYTE_Exit:

		pop	ecx
		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx

		or	ah,ah
		jz	@f
		cmc				;error return
@@:
		ret

WRITE_CONFIG_BYTE	ENDP

;[]-------------------------------------------------------------------------[]
; WRITE_CONFIG_WORD:
;	This function allows writing individual words from the configuration
;   space of a specific device. The Register Number parameter must be a
;   multiple of two (i.e., bit 0 must be set to 0).
;
; ENTRY : AH = PCI_FUNCTION_ID		(B1h)
;	  AL = WRITE_CONFIG_WORD	(0Ch)
;	       WRITE_CONFIG_WORD32	(8Ch)
;	  BH = Bus identification Number (0...255)
;	  BL = Device Number in upper 5 bits
;	       Function Number in lower 3 bits
;	  DI = Register Number (0,2,4,...254)
;	  CX = Word Value Write
;
; EXIT	: CF = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : BAD_BUS_ID		(84h)
;			    BAD_SLOT_ID 	(85h)
;			    BAD_REGISTER_NUMBER (87h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
WRITE_CONFIG_WORD	PROC	NEAR

		push	edx
		push	eax
		push	ecx

		call	Validate_Args
		jc	WRITE_CONFIG_WORD_Exit

		test	di,1			;test register number is a multiple of 4 ?
		jz	short Valid_reg_num_ww
		mov	ah,BAD_REGISTER_NUMBER
		jmp	short WRITE_CONFIG_WORD_Exit

Valid_reg_num_ww:

		mov	ax,cx

		mov	cx,di
		mov	ch,bl

		call	Aset_CfgSpace_Word

		mov	ah,SUCCESSFUL

WRITE_CONFIG_WORD_Exit:

		pop	ecx
		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx

		or	ah,ah
		jz	@f
		cmc				;error return
@@:
		ret

WRITE_CONFIG_WORD	ENDP

;[]-------------------------------------------------------------------------[]
; WRITE_CONFIG_DWORD:
;	This function allows writing individual DWORDs from the configuration
;   space of a specific device. The Register Number parameter must be a
;   multiple of four (i.e., bit 0 and 1 must be set to 0).
;
; ENTRY : AH  = PCI_FUNCTION_ID 	(B1h)
;	  AL  = WRITE_CONFIG_DWORD	(0Dh)
;		WRITE_CONFIG_DWORD32	(8Dh)
;	  BH  = Bus identification Number (0...255)
;	  BL  = Device Number in upper 5 bits
;		Function Number in lower 3 bits
;	  DI  = Register Number (0,4,8,...252)
;	  ECX = Dword value to write
;
; EXIT	: CF = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : BAD_BUS_ID		(84h)
;			    BAD_SLOT_ID 	(85h)
;			    BAD_REGISTER_NUMBER (87h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
WRITE_CONFIG_DWORD	PROC	NEAR

		push	edx
		push	eax
		push	ecx

		call	Validate_Args
		jc	WRITE_CONFIG_DWORD_Exit

		test	di,3			;test register number is a multiple of 4 ?
		jz	short Valid_reg_num_wd
		mov	ah,BAD_REGISTER_NUMBER
		jmp	short WRITE_CONFIG_DWORD_Exit

Valid_reg_num_wd:

		mov	eax,ecx

		mov	cx,di
		mov	ch,bl

		call	Aset_CfgSpace_Dword

		mov	ah,SUCCESSFUL

WRITE_CONFIG_DWORD_Exit:

		pop	ecx
		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx
		or	ah,ah
		jz	@f
		cmc				;error return
@@:
		ret

WRITE_CONFIG_DWORD	ENDP

;[]-------------------------------------------------------------------------[]
; Set_PCI_Irq:
;	This function causes the specified hardware interrupt(IRQ) to be
;   connected to the specified interrupt pin of a PCI device.
;
; ENTRY : AH  = PCI_FUNCTION_ID 	(B1h)
;	  AL  = Set_PCI_Irq		(0Fh)
;	  BX  = BH - Bus number , BL - Device(upper 5 bits) and function
;	  CL  = IntPin parameter. Vaild values 0Ah..0DH
;	  CH  = Irq number. Valid values 0..0FH
;	  DS  = Segment of Selector for BIOS data
;
; EXIT	: CF = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : SET_FAILED    	(88h)
;			    FUNC_NOT_SUPPORTED	(81h)
;[]-------------------------------------------------------------------------[]

;[]-------------------------------------------------------------------------[]
; Validate_Args:
;
; ENTRY : BH = Bus ID number
;	  BL = Device number/Function number
;	  DI = Register number
;
; EXIT	: CF clear -> correct arguments
;	  CF set ---> invalid arguments
;			AH = error code
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Validate_Args	PROC	NEAR

		xor	ah,ah

ifdef	NO_MULTI_PCI_SUPPORT
		cmp	bh,BUS_ID
		je	short @f

		mov	ah,FUNC_NOT_SUPPORTED

		jmp	short Validate_Args_Exit

@@:
endif	;NO_MULTI_PCI_SUPPORT

		cmp	di,255
		jbe	short @f
		mov	ah,BAD_REGISTER_NUMBER
		jmp	short Validate_Args_Exit
@@:
		mov	al,bl
		shr	al,3

		cmp	al, LAST_DEVICE_NO
		jbe	short Validate_Args_Exit

		mov	ah,BAD_SLOT_ID

Validate_Args_Exit:

		or	ah,ah
		jz	@f
		cmc
@@:
		ret

Validate_Args	ENDP

Qualify_PciBus	proc	near
		push	cx
		call	Get_Max_PciBus
		cmp	bh, cl
		pop	cx
		ja	short Bad_PciBus
		clc
		ret
Bad_PciBus:
		stc
		ret
Qualify_PciBus	endp

CONFIG_ADDRESS	EQU	0CF8H
CONFIG_DATA	EQU	0CFCH

;[]-------------------------------------------------------------------------[]
; Aget_CfgSpace_Dword:
;
; ENTRY : CX  = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;		BH = BUS No.
; EXIT	: EAX = value of CONFIG_DATA
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Aget_CfgSpace_Dword	proc	near
		call	Check_Valid_Slot_No
		jnc	short @F

  		call	Qualify_PciBus
		jnc	short @F

		mov	eax,-1				;invalid slot number
		ret
	@@:

		push	dx
		call	Get_PCI_Port
		in	eax,dx
		pop	dx

		ret
Aget_CfgSpace_Dword	endp

;[]-------------------------------------------------------------------------[]
; Aget_CfgSpace_word:
;
; ENTRY : CX  = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;		BH = BUS No.
; EXIT	: AX = value of CONFIG_DATA
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Aget_CfgSpace_word	proc	near
		call	Check_Valid_Slot_No

		jc	short Bad_Slot_Word

  		call	Qualify_PciBus
		jnc	short @F

Bad_Slot_Word:
		mov	ax,-1				;invalid slot number
		ret
	@@:
		push	dx
		call	Get_PCI_Port
		in	ax,dx
		pop	dx

		ret
Aget_CfgSpace_word	endp

;[]-------------------------------------------------------------------------[]
; Aget_CfgSpace_Byte:
;
; ENTRY : CX  = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;		BH = BUS No.
; EXIT	: AL = value of CONFIG_DATA
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Aget_CfgSpace_Byte	proc	near
		call	Check_Valid_Slot_No
		jnc	short @F

  		call	Qualify_PciBus
		jnc	short @F

		mov	al,-1				;invalid slot number
		ret
	@@:

	ifdef	PCI1A_87410_PATCH
		call	Chk_Special_87410
		jnc	short @F
		xor	al,al
		ret
	@@:
	endif	;PCI1A_87410_PATCH

		push	dx
		call	Get_PCI_Port
		in	al,dx
		pop	dx

		ret
Aget_CfgSpace_Byte	endp

;[]-------------------------------------------------------------------------[]
; Get_PCI_Port:
;
; ENTRY : CX  = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;		BH = BUS No.
; EXIT	: set PCI configuration data port
;
;[]-------------------------------------------------------------------------[]
Get_PCI_Port	proc	near

		push	eax
		mov	ax,8000H		;enable PCI config. space
		mov	al,bh
		shl	eax,16

		mov	ax,cx
		and	al,NOT 03H
		mov	dx,CONFIG_ADDRESS	;PCI index port
		out	dx,eax
		IODELAY
		add	dl,4			;data port start from 0cfch
		mov	al,cl
		and	al,03h
		add	dl,al		  	;byte index to read

		pop	eax

		ret
Get_PCI_Port	endp

;[]-------------------------------------------------------------------------[]
; Aset_CfgSpace_Dword:
;
; ENTRY : CX  = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;		BH = BUS No.
;
; 	 EAX = value of CONFIG_DATA
; EXIT : NONE
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Aset_CfgSpace_Dword	proc	near
		call	Check_Valid_Slot_No
		jnc	short @F
		ret
	@@:
		push	dx
		call	Get_PCI_Port
		out	dx,eax
		pop	dx

		ret
Aset_CfgSpace_Dword	endp

;[]-------------------------------------------------------------------------[]
; Aset_CfgSpace_word:
;
; ENTRY : CX  = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;		BH = BUS No.
; 	 AX = value of CONFIG_DATA
; EXIT : NONE
;[]-------------------------------------------------------------------------[]
		Align	4
Aset_CfgSpace_word	proc	near
		call	Check_Valid_Slot_No
		jnc	short @F
		ret
	@@:
		push	dx
		call	Get_PCI_Port
		out	dx,ax
		pop	dx

		ret
Aset_CfgSpace_word	endp

;[]-------------------------------------------------------------------------[]
; Aset_CfgSpace_Byte:
;
; ENTRY : CX  = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;		BH = BUS No.
; 	 AL = value of CONFIG_DATA
; EXIT : NONE
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Aset_CfgSpace_Byte	proc	near
		call	Check_Valid_Slot_No
		jnc	short @F
		ret
	@@:
		push	dx
		call	Get_PCI_Port
		out	dx,al
		pop	dx

		ret
Aset_CfgSpace_Byte	endp


;drs -start
Check_Valid_Slot_No	Proc	Near

		push	cx
		or	bh,bh
		jnz	short @F
		shr	ch,3
		cmp	ch,MAX_PCI_SLOT
		ja	short Invalid_Slot
		cmp	ch,MIN_PCI_SLOT
		jae	short @F

	Invalid_Slot:

		pop	cx
		stc
		ret
	@@:
		pop	cx
		clc
		ret

Check_Valid_Slot_No	Endp


Get_Max_PciBus	proc	near

ifdef	NO_MULTI_PCI_SUPPORT
		mov	cl, 0
else	;NO_MULTI_PCI_SUPPORT
;R03		mov	cl, 128			;This instruction will
						;be modified in POST by
						;writing the shadow RAM
		mov	cl,2		;R03
							
endif	;NO_MULTI_PCI_SUPPORT
		NOP
		NOP
		ret
Get_Max_PciBus	endp

;drs -end

endif	;CONFIG_MECHANISM_1
endif	;PCI_BUS

endif	;No_Support_PCI_VGA_in_Bootblock	;R02
