;	[]===========================================================[]
;
;	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
;----------------------------------------------------------------------------
;R50A	04/10/99 ADS	Add define "Patch_PCIDIAG_For_VT586 " to Patch VIA
;			Chipset testing error for PCIDIAG.EXE & change 
;			patch method .
;R50	04/07/99 ADS	Patch VIA Chipset testing error for PCIDIAG.EXE.
;R49	02/23/99 KGN	Patch IntelMX Ver1 Chipset Bug no report Multifunc
;			at Bus0,device0,func0
;R48	02/09/99 RAY	Set the default value of assigned IRQs to be 0
;R47	08/07/98 RCH	Fixed MediaGXm/5530 testing error for PCIDIAG.EXE
;R45D	07/30/98 RCH	Fixed device can be found if the device is a multi-
;			function and the devices are not continuous.
;R45B	07/22/98 RCH	Fixed USB device not found for PIIX4 while calling
;			FIND_PCI_DEVICE. PIIX4 only implement "multi-function"
;			indicator bit on first function.
;R45A	07/20/98 RCH	Fixed some PCI/VGA or AGP card video driver installation
;			failure.
;R45	07/14/98 RCH	Fixed wrong device & function number scanning for
;			FIND_PCI_DEVICE & PCI_CLASS_CODE
;R44	03/10/98 RCH	Added SB-LINK BIOS interface for Creative PCI audio
;			support, please note that till now only Piix4 
;			platform support this feature.
;R43	12/16/97 RAY	Report the assigned PCI IRQs instead of a fix value
;			in the IRQ routing table
;			This is to to fix the ICU hang up problem
;R42A	09/12/97 RCH	Fixed system hang up while executing PCIDIAG.EXE
;R42	08/06/97 RAY	Change code for getting Routing Table Option by not 
;			referencing the compiled value: IrqTbl_Size. Instead,
;			we reference a external label: PciIrqTbl_Size in 
;			PCI21TBL.ASM for the table size. This size varies 
;			depends on whether the USB Host Controller is enabled
;			or not. 
;
;			See more information in PCI21TBL.ASM
;
;R41	08/01/97 RAY	Support PC97 test on the PCI 2.1 IRQ routing
;R40	08/01/97 RAY	Clean the Rxx for easy debugging, please find the
;			backup CD to check the old source.
;R39	07/17/97 RAY	We miss the return value BX in Get_Irq_Routing_Options
;			For the 32 bit protected mode interface, since some
;			applications do not pass in the correct BIOS selector,
;			we have to call a routine which return with BX the IRQ
;			bit map. After we assigned all PCI devices with IRQs,
;			we will hard code the machine code of the routine
;			"Get_PCI_IRQ_Record" to reflect the correct bit map.
;
;R38	06/07/97 RCH	Fixed "IRQ Holder" is not available in Memphis if 
;			Intel's chipset is used.
;R37A	05/19/97 RAY	Fix coding mistake which will cause the PCIDIAG test
;			to have a WARNING, i.e. a unmatched result from PCI1A
;			& PCI32
;R37	03/15/97 RAY	Rewrite the routine: Build_IrqTbl so that PCI1A can
;			also call it.
;R34C	12/04/96 RAY	Due to the same reason of R34B, we have to add the
;			onboard PCI VGA into the routing
;R34B	11/28/96 RAY	1. Fix system hang when running ICU in WIN31 if SCSI
;			   onboard
;
;			   - The reason is that R34 doesn't include the 
;			     SCSI slot into routing table
;
;			2. Fix system hang when running ICU in WIN31 for 
;			   NON-PIIX IDE system
;
;			   - Define "BUILD_IN_IDE_IDSEL EQU ??" in BIOS.CFG
;			     to let the routine: Get_Irq_Routing_Options
;			     to include the onboard PCI IDE into the routing
;			     table
;				
;R36	11/19/96 RAY	Support Multi-Level P2P bridge
;R35	10/11/96 RAX	Add "ONE_PCI_SLOT_ONLY" define for Notebook
;R34	09/16/96 RCH	The UNIXWARE v2.10 installation software did not pass
;			correct descriptor for data access, so don't trust
;			input DS to access data area to patch installation
;			failure.
;R33	07/05/96 RCH	Future Domain PCI/SCSI BIOS will read PCI config.
;			32(devices)*256(bus) times , it take a long time
;			so, qualify max. bus number
;R32	06/18/96 RCH	Fixed PCIDIAG testing failure if ET4000 PCI/VGA 
;			plugged.
;R31	06/13/96 RCH	Also patch Triton IDE for PCIDIAG testing failure
;R30	06/13/96 RCH	Modify function 06H to support PCI special cycle
;R29	05/27/96 RCH	Instead instruction "call" with marco "call32" to
;			prevent code error under proteced mode
;R23C	11/23/95 RAY	Fix Future Domain SCSI NT driver hang up when 
;			installing NT.
;R28	11/15/95 TNY	Add VUMA 32-bit BIOS support.
;R23B	11/09/95 RAY	Fixed error coding of R23
;R27	10/30/95 RCH	Fixed INTEL/IAL failure report of "SET_PCI_HW_INT"
;R26	08/29/95 RAY	Add switch PCI1A_87410_PATCH
;R23A	08/16/95 RCH	Fixed error coding of R23
;R24	07/20/95 RCH	Fixed NSP testing error
;R23	07/20/95 RCH	Added PCI v2.1 support
;R22A	05/25/95 DNL	Fixed BIOS coding mistake
;R22	05/20/95 RAY	only check valid slot no. for BUS 0
;R21	05/19/95 RCH	Qualified PCI Bus to avoid PCIDIAG buses testing error
;R20	03/02/95 RCH	Some PCI cards can not decode PCI TYPE 1(like Buslogic
;			BT946C). So, don't scan PCI devices that PCI bus is
;			absent.
;R18	01/04/95 DNL	Don't support multiple PCI BUS if chip not support yet
;R17	12/06/94 RCH	Set supported maximum PCI bus
;R16	11/09/94 RCH	Added multiple PCI bus support
;R15	08/29/94 RAY	Add Special PCI slot range
;R14	08/29/94 RAY	Align whole file to "PARA"
;R13	08/01/94 RCH	Fixed PCI byte write error coding
;R12	07/28/94 RCH	Added multi-function support
;R11	06/23/94 RCH	Don't support special cycle due to NCR/810 driver
;R10	06/23/94 RCH	Fixed SCO/UNIX double fault error for NCR/801 driver
;R09	06/16/94 KEN	Fixed bug for Matrox PCI/VGA card
;R08	04/12/94 KEN	Fixed BIOS32 service directory bug.
;---	03/19/94 RAY	No more Mechanism 2 code in this file
;			Mechanism 2 codes will be placed in PCI1A_M2.ASM
;R07	02/15/94 KEN	Fixed misc. interface bugs
;R06	02/04/94 KEN	Support 32 device no.
;R05	02/03/94 KEN	Fixed bug at supporting multi-function cards
;R04	12/01/93 KEN	Support Configuration Mechanism #1
;R03	11/29/93 RCH	Fixed function 0AH read dword error
;R02	11/29/93 RCH	Fixed WINDOW/NT driver for NCR/SCSI 53C810 failure
;R01	10/13/93 RCH	Complete special cycle generation function

		PAGE	60,132
		TITLE	PCI32.ASM
.386P
.XLIST
		INCLUDE	BIOS.CFG
		INCLUDE	COMMON.EQU
		INCLUDE	COMMON.MAC
		include	CMOS.EQU

.LIST

ifdef	PCI_BUS
ifdef	CONFIG_MECHANISM_1

CONFIG_ADDRESS	EQU	0CF8H
CONFIG_DATA	EQU	0CFCH
ENABLE_PCI_CONFIG MACRO
		ENDM
DISABLE_PCI_CONFIG MACRO
		ENDM

MAX_PCI_BUS		EQU	8
BUS_ID		EQU	0		;Assume bus identification number = 0 ;???
INTR_LEVEL	EQU	0		;???

LAST_DEVICE_NO	EQU	31

;
SUCCESSFUL		EQU	00h
PCI_FUNCTION_ID		EQU	0B1H
PCI_SPACE_HI_ADDR	EQU	0C0H
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

;
endif	;CONFIG_MECHANISM_1
endif	;PCI_BUS

ifdef	VUMA
		extrn	VUMA_Procedure32:near
		extrn	VUMA_Code_Size:abs
endif	;VUMA

CALL32	MACRO	ADDRESS
		X	=	$
		CALL	ADDRESS
		IF2
		Y	=	ADDRESS
			IF (X GT Y)
				X=X+3
				ORG	X
				DW	0FFFFh
			ENDIF
		ENDIF
		ENDM

DGROUP		GROUP	FCODE

FCODE		SEGMENT PARA PUBLIC 'CODE'
		ASSUME	CS:DGROUP

ifdef	PCI_BUS
ifdef	CONFIG_MECHANISM_1

		Public	PCI_BIOS32_Directory
PCI_BIOS32_Directory:

		pushf

;R44 - start
ifdef SB_LINK_SUPPORT

		cmp	eax, "KLBS"			;4B4C4253h
		jne	short Not_Sblk_Function

		or	bl, bl
		jnz	short Invalid_Function

		mov	ebx, 0F0000h
		mov	edx, offset Sblk_Procedure32
		mov	ecx, Sblk_Code_Size+200H	;256 byte more

		jmp	short Service32_Exit
Not_Sblk_Function:
endif ;SB_LINK_SUPPORT
;R44 - end

ifdef	VUMA
		cmp	eax, "AMUV"
		jne	short Not_VUMA_Function

		or	bl, bl
		jnz	short Invalid_Function

		mov	ebx, 0F0000h
		mov	edx, offset VUMA_Procedure32
		mov	ecx, VUMA_Code_Size+100H	;256 byte more

		xor	al, al				;success
		popf
		retf

Not_VUMA_Function:
endif	;VUMA

		cmp	eax, "ICP$"
		jne	short Invalid_ID
		or	bl, bl
		jnz	short Invalid_Function

		mov	ebx,0F0000h
		mov	edx,offset PCI_Procedure32

		mov	ecx, offset DGROUP:PCI_Code_End

Service32_Exit:					;R44
		xor	al,al
		jmp	short @f
Invalid_ID:
		mov	al, 80h
		jmp	short @f
Invalid_Function:
		mov	al, 81h
@@:

		popf
		retf


;R44 - start
ifdef SB_LINK_SUPPORT

SB_LINK_ID		EQU	0E8CH		;SB LINK Identifier
UNSPECIFIED_ERROR	EQU	080H		;unspecified error
INVALID_PARA		EQU	081H		;Invalid parameter
BUFF_TO_SMALL		EQU	082H		;buffer too small
FUNC_NOT_SUPPORT	EQU	086H		;function not support
SB_BUFF_SIZE		EQU	08H		;need 8-2 bytes buffer
		EXTRN	SB_LINK_CMD_MAX:ABS

		ALIGN	16
		PUBLIC	Sblk_Procedure32
Sblk_Procedure32 proc	far

		mov	ah, FUNC_NOT_SUPPORT	;assume invalid function
		cmp	al,SB_LINK_CMD_MAX	;check command overflow?
		jae	short SBLink32_EXIT	;Yes,skip

		mov	ah, INVALID_PARA	;assume invalid parameter
		cmp	bx,SB_LINK_ID		;SB Link ID ?
		jne	short SBLink32_EXIT

		or	al,al			;function 0 ?
		jz	short SBLink32_Fun00	;Get SBLINK info.

		dec	al			
		jz	short SBLink32_Fun01	;save DMA channel

		dec	al
		jz	short SBLink32_Fun02	;set DMA channel

		dec	al
		jz	short SBLink32_Fun03 	;restore DMA channel

		dec	al
		jz	short SBLink32_Fun04 	;save serial IRQ info.

		dec	al
		jz	short SBLink32_Fun05 	;set serial IRQ

		jmp	short SBLink32_Fun06  	;restore serial IRQ
SBLink32_Succeed:
		xor	ah,ah			;return no error
		clc
		retf

SBLink32_EXIT:
		stc
		retf
Sblk_Procedure32 endp


;================================================================
;SBLink32_FUN00	(Get Information)
;   Description :
;	This function allows the caller determine the current interface
;     version of SB-LINK, and which are the DMA channels available and be
;     configured as SB-LINK DMA channel to operate in PC/PCI mode.It also
;     retrun a signature of SB-LINK which the caller can use to confirm the
;     present of SB-LINK functions.
;   Entry:
;	AH : 0AFH (SBLINK_FUNCTION_ID)
;	AL : 0h (SBLINK_GET_INFO)
;	BX : 0E8CH
;   Exit:
;	AH : Return code
;	     00h = SB-LINK interface is present if DX set to 0E8Ch
;	AL : Serialize IRQ operating polarity
;	BL : Interface minor version in BCD value
;	BH : Interface major version in BCD value
;	CL : Pair of REQ/GNT that used as SB-LINK
;	CH : DMA channels available for SB-LINK
;	DX : 0E8Ch
;	CF : set = error,cleared = success
;================================================================
SBLink32_FUN00:
		mov	dx,bx		;return DX with value 0E8CH
		xor	al,al		;indicates serialize IRQ is
					;negative active polarity
		mov	bx,100h		;interface version
		mov	cl,REQ_GNT_PAIR	;Pair # of REQ/GNT is used in SB-LINK
					;1 = Pair A , 2 = Pair B , 3 = Pair C
;		mov	ch,0ebh		;DMA channels available for SB-LINK	cs:[DMA_]

					;return available DMA channels
		call32	GetPciDmaChns
		mov	ch,ah

		jmp	short SBLink32_Succeed

;================================================================
;SBLink32_FUN01	(Save DMA Channel)
;   Description :
;	This function saves a DMA channel current information.This
;     information will be used to restore the PCI system controller
;     DMA channel settings prior to this call.
;   Entry:
;	AH : 0AFH (SBLINK_FUNCTION_ID)
;	AL : 1h (SBLINK_SAVE_DMA)
;	BX : 0E8CH
;	CL : DMA channel number to save
;	ES:DI : Segment:Offset of DataBuffer structure for real-mode
;	EDI : Offset of Data structure for 32-bit protected mode
;   Exit:
;	AH : Return code
;	     00h = success
;	     81h = Invalid parameter
;	     82h = Buffer too small
;	CF : set = error,cleared = success
;================================================================
SBLink32_FUN01:

		mov	ah, BUFF_TO_SMALL	;assume buffer too small
		cmp	word ptr es:[edi],SB_BUFF_SIZE	;smaller than minimum size ?
		jae	short Buff_Enough

		mov	word ptr es:[edi],SB_BUFF_SIZE	;set required buffer size
		jmp	short SBLink32_EXIT	;buffer is too small
Buff_Enough:
		call32	Ct32_Save_PCI_Dma  	;set PC/PCI DMA channel

		jmp	short SBLink32_Succeed

;================================================================
;SBLink32_FUN02	(Set DMA Channel)
;   Description :
;	This function sets a DMA channel to perate in SB-LINK mode.
;   Entry:
;	AH : 0AFH (SBLINK_FUNCTION_ID)
;	AL : 2h (SBLINK_SET_DMA)
;	BX : 0E8CH
;	CL : DMA channel number to set
;   Exit:
;	AH : Return code
;	     00h = success
;	     81h = Invalid parameter
;	CF : set = error,cleared = success
;================================================================
SBLink32_FUN02:
		mov	ah, INVALID_PARA	;assume bad parameter
;		cmp	cl,2			;DMA 2 ?
;		je	short SBLink32_EXIT
;		cmp	cl,4			;DMA 4 ?
;		je	short SBLink32_EXIT
		cmp	cl,8			;valid DMA channel ?
		jae	short SBLink32_EXIT

		push	ax
		mov	al,1 			;shift DMA channel into bit
		shl	al,cl			;map ( bit0 = DMA 0, ..etc)

		call32	GetPciDmaChns
		test	al,ah
						;check valid DMA channels

		pop	ax
		jz	short SBLink32_EXIT	;no, return error

;		extrn	Ct32_Set_PCI_Dma:near
		call32	Ct32_Set_PCI_Dma  	;set PC/PCI DMA channel
		jmp	short SBLink32_Succeed


;================================================================
;SBLink32_FUN03	(Restore DMA Channel)
;   Description :
;	This function restores the settings that has been changed by
;     the call of SBLINK_DMA.
;   Entry:
;	AH : 0AFH (SBLINK_FUNCTION_ID)
;	AL : 3h (SBLINK_RESTORE_DMA)
;	BX : 0E8CH
;	CL : DMA channel number to restore
;	ES:DI : Segment:Offset of DataBuffer structure for real-mode
;	EDI : Offset of Data structure for 32-bit protected mode
;   Exit:
;	AH : Return code
;	     00h = success
;	     81h = Invalid parameter
;	     82h = Buffer too small
;	CF : set = error,cleared = success
;================================================================
SBLink32_FUN03:

		call32	Ct32_Restore_PCI_Dma  	;restore PC/PCI DMA channel

		jmp	short SBLink32_Succeed

;================================================================
;SBLink32_FUN04	(Save Serialize IRQ Mode)
;   Description :
;	This function saves the current serialize IRQ operational mode.This
;     information will be used to restore the PCI system controller's
;     serialize IRQ settings prior to this call.
;   Entry:
;	AH : 0AFH (SBLINK_FUNCTION_ID)
;	AL : 4h (SBLINK_SAVE_SIRQ)
;	BX : 0E8CH
;	ES:DI : Segment:Offset of DataBuffer structure for real-mode
;	EDI : Offset of Data structure for 32-bit protected mode
;   Exit:
;	AH : Return code
;	     00h = success
;	     81h = Invalid parameter
;	     82h = Buffer too small
;	CF : set = error,cleared = success
;================================================================
SBLink32_FUN04:
		mov	ah, BUFF_TO_SMALL	;assume buffer too small
		cmp	word ptr es:[edi],SB_BUFF_SIZE	;smaller than minimum size ?
		jae	short SirqBuff_Enough

		mov	word ptr es:[edi],SB_BUFF_SIZE	;set required buffer size
		jmp	short SBLink32_EXIT		;buffer is too small
SirqBuff_Enough:

		call32	Ct32_Save_SIRQ  	;save reg. of SIRQ

		jmp	short SBLink32_Succeed

;================================================================
;SBLink32_FUN05	(Set Serialize IRQ Mode)
;   Description :
;	This function enables and sets the serialize IRQ operational mode
;     to the SB-LINK mode.
;   Entry:
;	AH : 0AFH (SBLINK_FUNCTION_ID)
;	AL : 5h (SBLINK_SET_SIRQ)
;	BX : 0E8CH
;   Exit:
;	AH : Return code
;	     00h = success
;	     81h = Invalid parameter
;	CF : set = error,cleared = success
;================================================================
SBLink32_FUN05:
;		extrn	Ct32_Set_SerialIRQ:near
		call32	Ct32_Set_SerialIRQ 	;enable serial IRQ mode
		jmp	short SBLink32_Succeed

;================================================================
;SBLink32_FUN06	(Restore Serialize IRQ Mode)
;   Description :
;	This function restores the settings that has been changed by
;     the call of SBLINK_SET_SIRQ.
;   Entry:
;	AH : 0AFH (SBLINK_FUNCTION_ID)
;	AL : 6h (SBLINK_RESTORE_SIRQ)
;	BX : 0E8CH
;	ES:DI : Segment:Offset of DataBuffer structure for real-mode
;	EDI : Offset of Data structure for 32-bit protected mode
;   Exit:
;	AH : Return code
;	     00h = success
;	     81h = Invalid parameter
;	     82h = Buffer too small
;	CF : set = error,cleared = success
;================================================================
SBLink32_FUN06:

		call32	Ct32_Restore_SIRQ  	;restore reg. of SIRQ

		jmp	short SBLink32_Succeed

;Function : Get current available DMA channels for PCI/DMA
;Input    : none
;Output   : AH - available DMA channels bit map
GetPciDmaChns	proc	near
		push	esi
		call32	Get_Next_IP
	@@:
		add	esi, offset PciDmaChns
		sub	esi, offset @B
		mov	ah, byte ptr cs:[esi]
		pop	esi
		ret
GetPciDmaChns	endp

		public	PciDmaChns
PciDmaChns	db	0ebh	;available DMA channels for PCI/DMA


ifdef	PIIX_ID				;only for Intel PIIX4 platform
Ct32_Save_PCI_Dma  	proc	near

		pushad
		mov	cx,(PIIX_ID SHL 8) + 90H;PCI DMA config. reg.
		xor	bh,bh			;bus 0
		call32	Get_CfgSpace_word	;read PCI word
		mov	word ptr es:[edi+2],ax	;save DMA registers
		popad
		ret
Ct32_Save_PCI_Dma  	endp

;Function : Program chipset to desired DMA channel for PC/PCI DMA mode
;Input    : CL - DMA channel number to set
;Output   : none
;Note     : The program need to enable REQ/GNT pair in this procedure
Ct32_Set_PCI_Dma  proc	near
		pushad

	;Set PC/PCI DMA channel
		mov	bl,cl		       	;save DMA channel
		mov	cx,(PIIX_ID SHL 8) + 90H;PCI DMA config. reg.
		xor	bh,bh			;bus 0
		call32	Get_CfgSpace_word	;read PCI word

		mov	dx,01b			;set PC/PCI DMA mode
		mov	cl,bl			;DMA channel number
		shl	cl,1			;each DMA need 2 bits
		shl	dx,cl
		or	ax,dx
		mov	cx,(PIIX_ID SHL 8) + 90H;PCI DMA config. reg.
		call32	Set_CfgSpace_word	;write PCI word

	;program REQ/GNT pair
		mov	cx,(PIIX_ID SHL 8) +0B1H;REQ/GNT pin select
		call32	Get_CfgSpace_Byte	;read PCI byte
		mov	dl,01h   		;register 0B1H
		mov	cl,REQ_GNT_PAIR-1	;get REQ/GNT pair
		shl	dl,cl
		or	al,dl
		mov	cx,(PIIX_ID SHL 8) +0B1H;REQ/GNT pin select
		call32	Set_CfgSpace_Byte	;read PCI byte

		popad
		ret
Ct32_Set_PCI_Dma  endp


Ct32_Restore_PCI_Dma	proc	near

		pushad
		mov	ax,word ptr es:[edi+2]	;restore DMA registers
		mov	cx,(PIIX_ID SHL 8) + 90H;PCI DMA config. reg.
		xor	bh,bh			;bus 0
		call32	Set_CfgSpace_word	;read PCI word
		popad
		ret
Ct32_Restore_PCI_Dma	endp

;Function : Program chipset to serial IRQ mode for SB-LINK operation
;Input    : none
;Output   : none
Ct32_Set_SerialIRQ	proc	near

		pushad

		xor	bh,bh			;bus 0
		mov	cx,(PIIX_ID SHL 8) +064H;serial IRQ control register
		mov	al,0d0h			;enable serial IRQ mode
		call32	Set_CfgSpace_Byte	;write PCI byte

		mov	cx,(PIIX_ID SHL 8) +0B2H;
		call32	Get_CfgSpace_Byte	;read PCI byte
		or	al,01h			;enable SERIRQ# pin
		mov	cx,(PIIX_ID SHL 8) +0B2H;
		call32	Set_CfgSpace_Byte	;write PCI byte

		popad
		ret
Ct32_Set_SerialIRQ	endp

Ct32_Save_SIRQ	proc	near

		pushad
		mov	cx,(PIIX_ID SHL 8) + 64H;serial IRQ reg.
		xor	bh,bh			;bus 0
		call32	Get_CfgSpace_Byte	;read PCI word
		mov	byte ptr es:[edi+2],al	;save SIRQ registers

		mov	cx,(PIIX_ID SHL 8) +0B2H;
		call32	Get_CfgSpace_Byte	;read PCI byte
		mov	byte ptr es:[edi+3],al	;save SIRQ registers

		popad

		ret
Ct32_Save_SIRQ	endp

Ct32_Restore_SIRQ	proc	near

		pushad
		mov	al,byte ptr es:[edi+2]	;save SIRQ registers
		mov	cx,(PIIX_ID SHL 8) + 64H;serial IRQ reg.
		xor	bh,bh			;bus 0
		call32	Set_CfgSpace_Byte	;read PCI word

		mov	al,byte ptr es:[edi+3]	;restore SIRQ registers
		mov	cx,(PIIX_ID SHL 8) +0B2H;
		call32	Set_CfgSpace_Byte	;write PCI byte

		popad

		ret
Ct32_Restore_SIRQ	endp
endif;	PIIX_ID				;only for Intel PIIX4 platform

		public	Sblk_Code_Size
Sblk_Code_Size	equ	$ - Sblk_Procedure32

endif; SB_LINK_SUPPORT
;R44 - end

		ALIGN	16
		PUBLIC	PCI_Procedure32
PCI_Procedure32	PROC	FAR

		pushf
		cli
		ENABLE_PCI_CONFIG
;========================== debug ==========================
	cmp	al,01h
	jne	short @F
	CALL32	PCI_BIOS_PRESENT
	jmp	PCI32_Func_exit1

@@:

	push	edx
	push	eax
	cmp	al,02h
	jne	short @F
	CALL32	FIND_PCI_DEVICE
	jmp	short PCI32_Func_exit
@@:
	cmp	al,03h
	jne	short @F
	CALL32	PCI_CLASS_CODE
	jmp	short PCI32_Func_exit
@@:
	cmp	al,06h
	jne	short @F
	CALL32	GENERATE_SPECIAL_CYCLE
	jmp	short PCI32_Func_exit
@@:
	cmp	al,08h
	jne	short @F
	CALL32	READ_CONFIG_BYTE
	jmp	short PCI32_Func_exit
@@:
	cmp	al,09h
	jne	short @F
	CALL32	READ_CONFIG_WORD
	jmp	short PCI32_Func_exit
@@:
	cmp	al,0Ah
	jne	short @F
	CALL32	READ_CONFIG_DWORD
	jmp	short PCI32_Func_exit
@@:
	cmp	al,0Bh
	jne	short @F
	CALL32	WRITE_CONFIG_BYTE
	jmp	short PCI32_Func_exit
@@:
	cmp	al,0Ch
	jne	short @F
	CALL32	WRITE_CONFIG_WORD
	jmp	short PCI32_Func_exit
@@:
	cmp	al,0Dh
	jne	short @F
	CALL32	WRITE_CONFIG_DWORD
	jmp	short PCI32_Func_exit
@@:

	cmp	al,0EH
	jne	short @F
	call32	Get_Irq_Routing_Options
	jmp	short PCI32_Func_exit
@@:
	cmp	al,0FH
	jne	short @F
	call32	Set_PCI_Irq
	jmp	short PCI32_Func_exit
@@:

	CALL32	INVALID_FUNC

;========================== debug ==========================

;========================= PCI Fucntion Finished ==========================
;		ALIGN	8
PCI32_Func_exit:
	mov	dx,ax
	pop	eax
	mov	ah,dh
	pop	edx
PCI32_Func_exit1:

		DISABLE_PCI_CONFIG

		jc	short Error_Return
		popf
		clc
		retf
Error_Return:
		popf
		stc

		retf

PCI_Procedure32	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.

		call32	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

		call32	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 from device 0
Search_loop:

		xor	cl,cl
		call32	Get_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:

		call32	GetNextDevFuncNo		;R45

;R45		test	ch,07h
;R45		jnz	short already_MF1
;R45		mov	cl,0eh
;R45		call32	Get_CfgSpace_Byte
;R45		test	al,80h
;R45
;R45		jnz	short Already_MF1
;R45		add	ch,7
;R45
;R45Already_MF1:
;R45		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
		cmp	ecx,00FFFFFFh			;R47
	       	je	short BadClassCode		;R47
		mov	edi,ecx

		xor	bh,bh			;start from bus 0
Search_Next_Bus0:

		xor	ch,ch			;start from device 0
Search_Class_Loop:

		mov	cl,08H			;class code index
		call32	Get_CfgSpace_Dword	;read class code

		shr	eax,8			;shift to lower 3 bytes
		cmp	eax,edi 		;class code match?
		jne	short Next_Slot_Class
;R45		push	cx
;R45		mov	cl,0
;R45		call32	Get_CfgSpace_Word
;R45		cmp	ax,0FFFFh
;R45		pop	cx
;R45		je	short Next_Slot_Class

		or	si,si			;check index matching?
		jz	short Class_found
		dec	si

Next_Slot_Class:

;R45		test	ch,07h
;R45		jnz	short already_MF
;R45		mov	cl,0eh
;R45		call32	Get_CfgSpace_Byte
;R45		test	al,80h
;R45
;R45		jnz	short Already_MF
;R45		add	ch,7
;R45Already_MF:
;R45		add	ch,1
		call32	GetNextDevFuncNo		;R45

		jnc	short Search_Class_Loop

		inc	bh
		call32	Qualify_PciBus
		jnc	short Search_Next_Bus0

BadClassCode:	 					;R47
		stc					;R47
		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

;R45 - start
;Function : get next device to check
;Input    : CH - device + function Number
;Output   : CH - next device+function number
;	    carry set - end of current PCI bus
;	    no carry  - not end of current PCI bus
GetNextDevFuncNo	proc	near

;R45D		xor	cl,cl
;R45D		call32	Get_CfgSpace_Word	;read vendor ID
;R45D
;R45D		cmp	ax, 0FFFFH		;invalid vendor ID ?
;R45D		je	short NextDevNo

		test	ch,111B			;in multi-func ?	;R45B
		jnz	short NextFuncNo				;R45B

		mov	cl,0eh
		call32	Get_CfgSpace_Byte

		cmp	al,0FFH			;empty device ?		;R45D
		je	short NextDevNO					;R45D

		test	al,80h			;multi-function device ?
		jnz	short NextFuncNo
		
NextDevNo:
		and	ch, NOT 111B		;mask function Number
		add	ch, 08H			;next device number
		jmp	short GoNextDev
NextFuncNo:
		add	ch, 1
GoNextDev:
		jc	short YesInBus0

		or	bh,bh			;in bus 0 ?
		clc
		jz	short YesInBus0

		cmp	ch, 16 SHL 3		;maximum dev. No. is 16
		clc				;still in current bus
;R45A		jb	short YesInBus0
		jne	short YesInBus0		;R45A
		stc				;end of bus scanning
YesInBus0:
		ret
GetNextDevFuncNo	endp
;R45 - end

;[]-------------------------------------------------------------------------[]
; GENERATE_SPECIAL_CYCLE:
;	This function allows for gereration of PCI special cycles.
;
; ENTRY :  AH = PCI_FUNCTION_ID 	 (B1h)
;	   AL = GENERATE SPECIAL_CYCLE	 (06h)
;		GENERATE SPECIAL_CYCLE32 (86h)
;	   BH = Bus Number (0...255)
;	  EDX = Special Cycle Data
;
; EXIT	: CF = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : FUNC_NOT_SUPPORTED	(81h)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
GENERATE_SPECIAL_CYCLE	PROC	NEAR

		CALL32	Qualify_PciBus
		jnc	short @F

		mov	ah,FUNC_NOT_SUPPORTED

		jmp	short GENERATE_SPECIAL_CYCLE_Exit
@@:
		push	edx
		push	eax

		push	edx			;special cycle data

;		mov	ah,bh
;		shl	eax,8
		xor	eax,eax
;		and	eax,00FF0000h		;bus number
		or	eax,8000FF00h		;device number all 1's
						;function number all 1's
						;register number with zero
		mov	dx,CONFIG_ADDRESS
		out	dx,eax

		pop	eax			;special cycle data

		mov	dx,CONFIG_DATA
		out	dx,eax

		pop	eax
		pop	edx

		mov	ah,SUCCESSFUL
		clc

GENERATE_SPECIAL_CYCLE_Exit:

		ret

GENERATE_SPECIAL_CYCLE	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

		call32	Validate_Args

		jc	short READ_CONFIG_BYTE_Exit

		push	cx

		mov	cx,di
		mov	ch,bl
ifndef	PatchMX					;R49
		call32	Get_CfgSpace_Word
else	;PatchMX				;R49
		call32	Get_CfgSpace_Byte	;R49
endif	;PatchMX				;R49
;R50 - starts
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R50A
;R50A		pushf
;R50A		call	DO_OR_DONT_PATCH32
;R50A		jnc	short label3
		mov	cx, 0300h	;read byte
		call	READ_PATCH_CONFIG_DATA32
;R50ALabel3:
;R50A		popf
endif;	Patch_PCIDIAG_For_VT586		;R50A
endif;	VT586
;R50 - end

		pop	cx

ifdef	PATCH_FOR_TRITON_IDE
		call32	Patch_Triton
endif;	PATCH_FOR_TRITON_IDE

		mov	cl,al

		mov	ah,SUCCESSFUL

READ_CONFIG_BYTE_Exit:

		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx

		or	ah,ah

		jz	short @F
		cmc				;error return
@@:
		ret

READ_CONFIG_BYTE	ENDP
;R50A;R50 - starts
;R50Aifdef	VT586
;R50AVIA_Byte_Index3:
;R50A	dw	07EH, 081H, 08CH, 03847H, 03849H, 03A44H, 03A47H
;R50A	dw      03B44H,03B47H,03B51H,03C51H,0FFFFH			 	
;R50AVIA_Byte_Value3:
;R50A	db	080H, 041H, 027H, 08H, 01H, 0C4H, 0C0H,04H, 0C0H
;R50A	db	0FFH, 0FFH
;R50A
;R50AVIA_Word_Index2:
;R50A	dw	07EH, 080H, 08CH, 03846H, 03848H, 03A44H, 03A46H
;R50A	dw      03B44H,03B46H,03B50H,03C50H,0FFFFH			 	
;R50AVIA_Word_Value2:
;R50A	dw	080H, 04100H, 027H, 0800H, 0100H, 0C4H, 0C000H
;R50A	dw	04H, 0C000H,0FFFFH, 0FFFFH
;R50A
;R50AVIA_Dword_Index1:
;R50A	dw	07CH, 080H, 08CH, 03844H, 03848H, 03A44H 
;R50A	dw      03B44H, 03B50H,03C50H,0FFFFH			 	
;R50AVIA_Dword_Value1:
;R50A	dd	0800000H, 04100H, 027H, 08000000H, 0100H, 0c00000c4h
;R50A	dd	0c0000004H, 0FFFFH, 0FFFFH
;R50Aendif;	VT586
;R50A;R50 - ends
;
;[]-------------------------------------------------------------------------[]
; 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

		call32	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

		call32	Get_CfgSpace_Word

;R50 - starts
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R50A
;R50A		pushf
;R50A		call	DO_OR_DONT_PATCH32
;R50A		jnc	short label2
		mov	cx, 0200h 	;read word
		call	READ_PATCH_CONFIG_DATA32
;R50ALabel2:
;R50A		popf		
endif;	Patch_PCIDIAG_For_VT586		;R50A
endif;	VT586
;R50 - ends

ifdef	PATCH_FOR_TRITON_IDE
		call32	Patch_Triton
endif;	PATCH_FOR_TRITON_IDE

		mov	cx,ax

		mov	ah,SUCCESSFUL

READ_CONFIG_WORD_Exit:

		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx

		or	ah,ah

		jz	short @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

		call32	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	READ_CONFIG_DWORD_Exit

Valid_reg_num_rd:
		mov	cx,di
		mov	ch,bl

		call32	Get_CfgSpace_Dword

;R50 - start
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R50A
;R50A		pushf
;R50A		call	DO_OR_DONT_PATCH32
;R50A		jnc	short label1
		mov	cx, 0100h 	;read dword
		call	READ_PATCH_CONFIG_DATA32
;R50ALabel1:
;R50A		popf
endif;	Patch_PCIDIAG_For_VT586		;R50A
endif;	VT586
;R50 - ends

ifdef	PATCH_FOR_TRITON_IDE
		call	Patch_Triton
endif;	PATCH_FOR_TRITON_IDE

		mov	ecx,eax

		mov	ah,SUCCESSFUL

READ_CONFIG_DWORD_Exit:

		mov	dl,ah
		pop	eax
		mov	ah,dl
		pop	edx

		or	ah,ah

		jz	short @F
		cmc				;error return
@@:
		ret

READ_CONFIG_DWORD	ENDP

;R50 - starts
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R50A
;R50A	Public	DO_OR_DONT_PATCH32
;R50ADO_OR_DONT_PATCH32 Proc	NEAR
;R50A		cmp	bh,0
;R50A		jne	short DONT_PATCH	;Not Bus0 => jmp!
;R50A
;R50A		cmp	bl,0
;R50A		jne	short Not_D0F0
;R50A		stc	
;R50A		ret
;R50ANot_D0F0:
;R50A		cmp	bl,38H
;R50A		jne	short Not_D7F0
;R50A		stc	
;R50A		ret
;R50ANot_D7F0:
;R50A		cmp	bl,3AH
;R50A		jne	short Not_D7F2
;R50A		stc	
;R50A		ret
;R50A
;R50ANot_D7F2:
;R50A		cmp	bl,3Bh
;R50A		jne	short Not_D7F3
;R50A		stc	
;R50A		ret
;R50ANot_D7F3:
;R50A		cmp	bl,3CH
;R50A		jne	short DONT_PATCH
;R50A		stc	
;R50A		ret
;R50ADONT_PATCH:
;R50A		clc
;R50A		ret
;R50ADO_OR_DONT_PATCH32 endp

	Public	READ_PATCH_CONFIG_DATA32
READ_PATCH_CONFIG_DATA32 Proc	NEAR
;R50A - starts
		push	bx

		cmp	bh,0
		jne	DONT_PATCH	;Not Bus0 => jmp!

	   	shl	bx, 8
		or	bx, di	;get input data

		cmp	cx, 0100h
		je	Patch_Dword    

		cmp	cx, 0200h
		je	Patch_Word    

		cmp	cx, 0300h
		jne	DONT_PATCH
						
;;;North bridge device 0 function 0
		cmp	bx, 007EH
		jne	short Not_D0F00B
		or	al, 80h		;Rx7e[7]
		jmp	DONT_PATCH
Not_D0F00B:
		cmp	bx, 0081H
		jne	short Not_D0F01B
		or	al, 41h		;Rx81[6,0]
		jmp	DONT_PATCH
Not_D0F01B:
		cmp	bx, 008cH
		jne	short Not_D0F02B
		or	al, 27h		;Rx8C[5,2,1,0]
		jmp	DONT_PATCH
Not_D0F02B:
;;;;south bridge device7 function0

		cmp	bx, 03847h
		jne	short Not_D7F00B
		or	al, 08h		;Rx47[3]
		jmp	DONT_PATCH
Not_D7F00B:
		cmp	bx, 03849h
		jne	short Not_D7F01B
		or	al, 01h		;Rx49[0]
		jmp	DONT_PATCH
Not_D7F01B:
;;;;device7 function2
 
		cmp	bx, 3a44h
		jne	short Not_D7F20B
		or	al, 0c4h	;Rx44[7,6,2]
		jmp	DONT_PATCH
Not_D7F20B:
		cmp	bx, 3a47h
		jne	short Not_D7F21B
		or	al, 0c0h	;Rx44[7,6]
		jmp	DONT_PATCH
Not_D7F21B:
;;;device7 function 3

		cmp	bx, 03b44h
		jne	short Not_D7F30B
		or	al, 04h		;Rx44[2]
		jmp	DONT_PATCH
Not_D7F30B:
		cmp	bx, 03b47h
		jne	short Not_D7F31B
		or	al, 0c0h   	;Rx47[2]
		jmp	DONT_PATCH
Not_D7F31B:
		cmp	bx, 03b51h
		jne	short Not_D7F32B
		or	al, 0ffh   	;Rx51
		jmp	DONT_PATCH
Not_D7F32B:
;;;device7 function 4
		cmp	bx, 03c51h
		jne	DONT_PATCH
		or	al, 0ffh   	;Rx51
		jmp	DONT_PATCH
Patch_Word:

;;;North bridge device 0 function 0
		cmp	bx, 007EH
		jne	short Not_D0F00W
		or	ax, 80h		;Rx7e[7]
		jmp	DONT_PATCH
Not_D0F00W:
		cmp	bx, 0080H
		jne	short Not_D0F01W
		or	ax, 4100h	;Rx81[6,0]
		jmp	DONT_PATCH
Not_D0F01W:
		cmp	bx, 008cH
		jne	short Not_D0F02W
		or	ax, 27h		;Rx8C[5,2,1,0]
		jmp	DONT_PATCH
Not_D0F02W:
;;;;south bridge device7 function0

		cmp	bx, 03846h
		jne	short Not_D7F00W
		or	ax, 0800h	;Rx47[3]
		jmp	DONT_PATCH
Not_D7F00W:
		cmp	bx, 03848h
		jne	short Not_D7F01W
		or	ax, 0100h	;Rx49[0]
		jmp	DONT_PATCH
Not_D7F01W:
;;;;device7 function2
 
		cmp	bx, 3a44h
		jne	short Not_D7F20W
		or	ax, 0c4h	;Rx44[7,6,2]
		jmp	DONT_PATCH
Not_D7F20W:
		cmp	bx, 3a46h
		jne	short Not_D7F21W
		or	ax, 0c000h	;Rx44[7,6]
		jmp	DONT_PATCH
Not_D7F21W:
;;;device7 function 3

		cmp	bx, 03b44h
		jne	short Not_D7F30W
		or	ax, 04h		;Rx44[2]
		jmp	DONT_PATCH
Not_D7F30W:
		cmp	bx, 03b46h
		jne	short Not_D7F31W
		or	ax, 0c000h	 ;Rx47[2]
		jmp	DONT_PATCH
Not_D7F31W:
		cmp	bx, 03b50h
		jne	short Not_D7F32W
		or	ax, 0ffffh	;Rx51
		jmp	DONT_PATCH
Not_D7F32W:
;;;device7 function 4
		cmp	bx, 03c50h
		jne	DONT_PATCH
		or	ax, 0ffffh	;Rx51
		jmp	DONT_PATCH
Patch_Dword:

;;;North bridge device 0 function 0
		cmp	bx, 007cH
		jne	short Not_D0F00DW
		or	eax,800000h 		;Rx7e[7]
		jmp	DONT_PATCH
Not_D0F00DW:
		cmp	bx, 0080H
		jne	short Not_D0F01DW
		or	eax, 4100h		;Rx81[6,0]
		jmp	DONT_PATCH
Not_D0F01DW:
		cmp	bx, 008cH
		jne	short Not_D0F02DW
		or	eax, 27h		;Rx8C[5,2,1,0]
		jmp	DONT_PATCH
Not_D0F02DW:
;;;;south bridge device7 function0

		cmp	bx, 03844h
		jne	short Not_D7F00DW
		or	eax, 08000000h		;Rx47[3]
		jmp	DONT_PATCH
Not_D7F00DW:
		cmp	bx, 03848h
		jne	short Not_D7F01DW
		or	eax, 100h		;Rx49[0]
		jmp	DONT_PATCH
Not_D7F01DW:
;;;;device7 function2
 
		cmp	bx, 3a44h
		jne	short Not_D7F20DW
		or	eax, 0c00000c4h		;Rx44[7,6,2]
		jmp	DONT_PATCH		;Rx44[7,6]
Not_D7F20DW:
;;;device7 function 3

		cmp	bx, 03b44h
		jne	short Not_D7F30DW
		or	eax, 0c0000004H		;Rx44[2]
		jmp	DONT_PATCH		;Rx47[2]
Not_D7F30DW:
		cmp	bx, 03b50h
		jne	short Not_D7F32DW
		or	eax, 0ffffh		;Rx51
		jmp	DONT_PATCH
Not_D7F32DW:
;;;device7 function 4
		cmp	bx, 03c50h
		jne	short DONT_PATCH
		or	eax, 0ffffh		;Rx51
DONT_PATCH:
		pop	bx
		ret
;R50A - ends

;R50A		push	esi
;R50A		push	bx
;R50A		push	di
;R50A
;R50A		shl	bx, 8
;R50A		or	bx, di	;get input data
;R50A		mov	di, cx
;R50A		xor	ecx, ecx
;R50A
;R50A		cmp	di, 0300h
;R50A		jne	short Loop_index2
;R50A		mov	esi, offset VIA_Byte_Index3 - 2
;R50A		jmp	short Loop_Index0
;R50ALoop_Index2:
;R50A		cmp	di, 0200h
;R50A		jne	short Loop_index1
;R50A		mov	esi, offset VIA_Word_Index2 - 2
;R50A		jmp	short Loop_Index0
;R50ALoop_Index1:
;R50A		cmp	di, 0100h
;R50A		jne	short Exit_Index0
;R50A		mov	esi, offset VIA_Dword_Index1 - 2
;R50ALoop_Index0:
;R50A		add	esi,2
;R50A		inc	ecx
;R50A		cmp	word ptr cs:[esi], 0FFFFH
;R50A		je	short Exit_Index0
;R50A
;R50A		cmp	bx, cs:[esi]
;R50A		jne	Loop_Index0
;R50A
;R50A		dec	ecx
;R50A
;R50A		cmp	di, 0300h
;R50A		jne	short Get_Word16
;R50A		mov	esi, offset VIA_Byte_Value3
;R50A		add	esi, ecx
;R50A		or	al, cs:[esi]	;byte read
;R50A		jmp	short Exit_Index0
;R50AGet_Word16:
;R50A		cmp	di, 0200h
;R50A		jne	short Get_Dword32
;R50A		mov	esi, offset VIA_Word_Value2
;R50A		shl	ecx, 1
;R50A		add	esi, ecx
;R50A		or	ax, cs:[esi]	;word read
;R50A		jmp	short Exit_Index0
;R50AGet_Dword32:
;R50A		mov	esi, offset VIA_Dword_Value1
;R50A		shl	ecx, 2
;R50A		add	esi, ecx
;R50A		or	eax, cs:[esi]	;dword read
;R50AExit_Index0:
;R50A		pop	di
;R50A		pop	bx
;R50A		pop	esi
;R50A		ret
;R50A
READ_PATCH_CONFIG_DATA32 endp
endif;	Patch_PCIDIAG_For_VT586		;R50A
endif;	VT586
;R50 -  ends

ifdef	PATCH_FOR_TRITON_IDE
;Input : bx - device & function no.
;	 di - register no.
;Output: eax - register value return

Patch_Triton	proc	near
;Always return value FFFFFFFFH for vendor & device ID if any one try to read
;Triton master IDE configuration information, this will fix error of PCI2.EXE
;and PCICHK.EXE
		pushf
		cmp	bx,0039H	       	;PIIX/IDE ?
		jne	short Pci_Not_Bus0
		or	di,di
		jnz	short Pci_Not_Bus0
		mov	eax,-1			;no vendor & device ID
Pci_Not_Bus0:
		popf
		ret
Patch_Triton	endp
endif;	PATCH_FOR_TRITON_IDE

;
;[]-------------------------------------------------------------------------[]
; 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

		call32	Validate_Args

		jc	short WRITE_CONFIG_BYTE_Exit

		mov	al,cl

		mov	cx,di
		mov	ch,bl

		call32	Set_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	short @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

		call32	Validate_Args

		jc	short 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

		call32	Set_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	short @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

		call32	Validate_Args

		jc	short 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

		call32	Set_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	short @F
		cmc				;error return
@@:
		ret

WRITE_CONFIG_DWORD	ENDP

;[]-------------------------------------------------------------------------[]
; Get_Irq_Routing_Options:
;	This function returns the PCI interrupt routing options available on
;   on the system motherboard and also the current state of what interrupts
;   are currently exclusively assigned to PCI
;
; ENTRY : AH  = PCI_FUNCTION_ID 	(B1h)
;	  AL  = Get_Irq_Routing_Options	(0Eh)
;	  BX  = Initiated to 0000H
;	  DS  = Segment or Selector for BIOS data
;	  ES  = Segment of Selector for RouteBuffer parameter
;	  DI  = Offset for RouteBuffer parameter
;
; EXIT	: CF = Completion Status, set = error, reset = success
;
;	  if CF clear --> AH = SUCCESSFUL	(00h)
;	  if CF set,
;	  AH = Error Code : BUFFER_TO_SMALL    	(89h)
;			    FUNC_NOT_SUPPORTED	(81h)
;[]-------------------------------------------------------------------------[]
;R41 - starts
		ALIGN	4
		extrn	IrqRouteTbl:Near
		extrn	PciIrqTbl_Size:near		;R42
		extrn	PCI_IRQ_RECORD:word		;R43
Get_Irq_Routing_Options	proc	near

 		pushad
;R42 		mov	ecx, IrqTbl_Size
;R42 - starts
		call	Get_Next_IP
	@@:
		add	esi, offset PciIrqTbl_Size
		sub	esi, offset @B

		xor	ecx,ecx			;clear highest word ;R42A

		mov	cx, word ptr cs:[esi]
;R42 - ends
 		cmp	cx, es:[edi]  	;compare input buffer size
 		mov	es:[edi], cx	;return buffer size
 		jbe	short Buffer_Enough
 		popad
 		mov	ah,BUFFER_TO_SMALL
 		stc
 		ret
Buffer_Enough:
		mov	edi, es:[edi+2]		;get data buffer address

		call	Get_Next_IP

	Start_Copy_Routing_Tbl:

		add	esi, offset IrqRouteTbl
		sub	esi, offset Start_Copy_Routing_Tbl

	Copy_Next_Tbl_Byte:

		mov	al, cs:[esi]
		mov	es:[edi], al
		inc	esi
		inc	edi
		loop	short Copy_Next_Tbl_Byte

		popad
;R43		mov	bx, 1
 		call	Get_PCI_IRQ_Record		;R43
		mov	ah, SUCCESSFUL
		clc
		ret

Get_Irq_Routing_Options	endp

Get_Next_IP	Proc	Near
		pop	esi
		push	esi
		ret
Get_Next_IP	Endp
;R41 - ends

;R41 	IrqTbl_Size	=	3*16		;minium two slots plus onboard IDE
;R41 IF	SLOT3_EXIST
;R41 	IrqTbl_Size	=	IrqTbl_Size+16
;R41 ENDIF	;SLOT3_EXIST
;R41 IF	SLOT4_EXIST
;R41 	IrqTbl_Size	=	IrqTbl_Size+16
;R41 ENDIF	;SLOT4_EXIST
;R41 IF	SLOT5_EXIST
;R41 	IrqTbl_Size	=	IrqTbl_Size+16
;R41 ENDIF	;SLOT5_EXIST
;R41 
;R41 IF	SCSI_ONBOARD
;R41 IrqTbl_Size	=	IrqTbl_Size+16	;scsi slots
;R41 ENDIF;	SCSI_ONBOARD
;R41 IF	VGA_ONBOARD
;R41 IrqTbl_Size	=	IrqTbl_Size+16	;scsi slots
;R41 ENDIF;	VGA_ONBOARD
;R41 
;R41 ifdef	BUILD_IN_IDE_IDSEL
;R41 	IrqTbl_Size	=	IrqTbl_Size+16
;R41 endif	;BUILD_IN_IDE_IDSEL
;R41 
;R41 		ALIGN	4
;R41 Get_Irq_Routing_Options	proc	near
;R41 
;R41 		pushad
;R41 
;R41 		mov	cx,IrqTbl_Size
;R41 		cmp	cx,es:[edi]  	;compare input buffer size
;R41 		mov	es:[edi],cx	;return buffer size
;R41 		jbe	short Buffer_Enough
;R41 
;R41 		popad
;R41 		mov	ah,BUFFER_TO_SMALL
;R41 		stc
;R41 		ret
;R41 
;R41 Buffer_Enough:
;R41 
;R41 		mov	edi,es:[edi+2]		;get data buffer address
;R41 
;R41 IF	SLOT1_EXIST
;R41 	;build IRQ routing table for slot 1
;R41 		mov	bl, 1			;slot number
;R41 		mov	bh, SLOT1_ID SHL 3
;R41 		mov	ax, (SLOT1_INTD shl 12)+(SLOT1_INTC shl 8)+\
;R41 			    (SLOT1_INTB shl 4)+SLOT1_INTA
;R41 		mov	dx, IRQ_PCI
;R41 		call32	Build_IrqTbl
;R41 ENDIF	;SLOT1_EXIST
;R41 
;R41 IF	SLOT2_EXIST
;R41 	;build IRQ routing table for slot 2
;R41 		inc	bl			;slot number
;R41 		mov	bh, SLOT2_ID SHL 3
;R41 		mov	ax, (SLOT2_INTD shl 12)+(SLOT2_INTC shl 8)+\
;R41 			    (SLOT2_INTB shl 4)+SLOT2_INTA
;R41 		mov	dx, IRQ_PCI
;R41 		call32	Build_IrqTbl
;R41 ENDIF	;SLOT2_EXIST
;R41 
;R41 IF	SLOT3_EXIST
;R41 	;build IRQ routing table for slot 3
;R41 		inc	bl			;slot number
;R41 		mov	bh, SLOT3_ID SHL 3
;R41 		mov	ax, (SLOT3_INTD shl 12)+(SLOT3_INTC shl 8)+\
;R41 			    (SLOT3_INTB shl 4)+SLOT3_INTA
;R41 		mov	dx, IRQ_PCI
;R41 		call32	Build_IrqTbl
;R41 ENDIF	;SLOT3_EXIST
;R41 
;R41 IF	SLOT4_EXIST
;R41 	;build IRQ routing table for slot 4
;R41 		inc	bl			;slot number
;R41 		mov	bh, SLOT4_ID SHL 3
;R41 		mov	ax, (SLOT4_INTD shl 12)+(SLOT4_INTC shl 8)+\
;R41 			    (SLOT4_INTB shl 4)+SLOT4_INTA
;R41 		mov	dx, IRQ_PCI
;R41 		call32	Build_IrqTbl
;R41 ENDIF	;SLOT4_EXIST
;R41 
;R41 IF	SLOT5_EXIST
;R41 	;build IRQ routing table for slot 5
;R41 		inc	bl			;slot number
;R41 		mov	bh, SLOT5_ID SHL 3
;R41 		mov	ax, (SLOT5_INTD shl 12)+(SLOT5_INTC shl 8)+\
;R41 			    (SLOT5_INTB shl 4)+SLOT5_INTA
;R41 		mov	dx, IRQ_PCI
;R41 		call32	Build_IrqTbl
;R41 ENDIF	;SLOT5_EXIST
;R41 
;R41 IF	SCSI_ONBOARD
;R41 	;build IRQ routing table for onboard SCSI
;R41 		inc	bl			;slot number
;R41 		mov	bh, byte ptr (SCSI_SLOT SHL 3)
;R41 		mov	ax, (SCSI_INTD shl 12)+(SCSI_INTC shl 8)+\
;R41 			    (SCSI_INTB shl 4)+SCSI_INTA
;R41 		mov	dx, IRQ_PCI
;R41 		call32	Build_IrqTbl
;R41 ENDIF	;SCSI_ONBOARD
;R41 
;R41 IF	VGA_ONBOARD
;R41 
;R41 	;build IRQ routing table for onboard IDE
;R41 
;R41 	ifdef	VGA_INTA
;R41 		inc	bl			;slot number
;R41 		mov	bh, byte ptr ((ONBOARD_PCI_VGA) shl 3)
;R41 		mov	ax, (VGA_INTD shl 12)+(VGA_INTC shl 8)+\
;R41 			    (VGA_INTB shl 4)+VGA_INTA
;R41 		mov	dx, IRQ_PCI
;R41 		call32	Build_IrqTbl
;R41 	else	;VGA_INTA
;R41 		xor	bl, bl			;slot number
;R41 		mov	bh, byte ptr ((ONBOARD_PCI_VGA) shl 3)
;R41 		xor	ax, ax
;R41 		xor	dx, dx			;no available IRQ
;R41 		call32	Build_IrqTbl
;R41 	endif	;VGA_INTA
;R41 
;R41 ENDIF	;VGA_ONBOARD
;R41 
;R41 ifdef	BUILD_IN_IDE_IDSEL
;R41 	;build IRQ routing table for onboard IDE
;R41 		xor	bl, bl			;slot number
;R41 		mov	bh, byte ptr (BUILD_IN_IDE_IDSEL)
;R41 		xor	ax, ax
;R41 		xor	dx, dx			;no available IRQ
;R41 		call32	Build_IrqTbl
;R41 endif	;BUILD_IN_IDE_IDSEL
;R41 
;R41 		popad
;R41 		call	Get_PCI_IRQ_Record
;R41 		mov	ah,SUCCESSFUL
;R41 		clc
;R41 		ret
;R41 Get_Irq_Routing_Options	endp
;R41 
;R41 ;[]======================================================[]
;R41 ;Function : build IRQ routing table slot by slot
;R41 ;Input    : es:[edi] - buffer to build
;R41 ;	    BL - slot number
;R41 ;	    BH - device number
;R41 ;	    AX - INTA (b3-0)   of the slot
;R41 ;		 INTB (b7-4)   of the slot
;R41 ;		 INTC (b11-8)  of the slot
;R41 ;		 INTD (b15-12) of the slot
;R41 ;	    DX - available IRQ bit maps
;R41 ;	    BH - device number
;R41 ;[]======================================================[]
;R41 
;R41 		Public	Build_IrqTbl
;R41 Build_IrqTbl	proc	near
;R41 
;R41 ;-------------------------------;-----------------------------------
;R41 ; Code for 32bit protected mode ;  Equivalent to 16 bit/real mode
;R41 ;-------------------------------;-----------------------------------
;R41 
;R41 	push	ecx		;	push	cx
;R41 	push	ebx		;	push	bx
;R41 
;R41 			;-------------
;R41 			;Bus number
;R41 			;-------------
;R41 
;R41 	push	eax		;	push	ax
;R41 	xor	al, al		;	xor	al, al
;R41 	stosb			;	stosb
;R41 
;R41 			;-------------
;R41 			;device number
;R41 			;-------------
;R41 
;R41 	mov	al, bh		;	mov	al, bh
;R41 	stosb			;	stosb
;R41 	pop	eax		;	pop	ax
;R41 
;R41 ;******************************************************************
;R41 ;	Loop to fill the LINK value of each INT
;R41 ;******************************************************************
;R41 
;R41 	xor	ecx, ecx	;	xor	cx, cx
;R41 	mov	cl, 4		;	mov	cl, 4
;R41 @@:				;@@:
;R41 	push	eax		;	push	ax
;R41 
;R41 		      ;-------------------
;R41 		      ; link value of INT#
;R41 		      ;-------------------
;R41 
;R41 	and	al, 0Fh		;	and	al, 0Fh
;R41 
;R41 ifdef	PIIX_ID
;R41 	jz	short NoIntPin	; for INTEL chipset ?
;R41 	dec	al		; use 60H,61H,62H & 63H
;R41 	or	al, 60h		; as IRQ router register
;R41 NoIntPin:			;
;R41 endif;	PIIX_ID
;R41 
;R41 	stosb			;	stosb
;R41 
;R41 		   ;--------------------------
;R41 		   ;available IRQs (low byte)
;R41 		   ;--------------------------
;R41 
;R41 	mov	al, dl		;	mov	al, dl
;R41 	stosb			;	stosb
;R41 
;R41 		   ;--------------------------
;R41 		   ;available IRQs (high byte)
;R41 		   ;--------------------------
;R41 
;R41 	mov	al, dh		;	mov	al, dh
;R41 	stosb			;	stosb
;R41 
;R41 	pop	eax		;	pop	ax
;R41 
;R41 	shr	eax, 4		;	shr	ax, 4
;R41 
;R41 	loop	@B		;	loop	@B
;R41 
;R41 ;******************************************************************
;R41 
;R41 		;--------------------------
;R41 		;slot number (low byte)
;R41 		;--------------------------
;R41 
;R41 	mov	al, bl		;	mov	al, bl
;R41 	stosb			;	stosb
;R41 
;R41 		;--------------------------
;R41 		;slot number (high byte)
;R41 		;--------------------------
;R41 
;R41 	xor	al, al		;	xor	al, al
;R41 	stosb			;	stosb
;R41 				;
;R41 
;R41 	pop	ebx		;	pop	bx
;R41 	pop	ecx		;	pop	cx
;R41 	ret			;	ret
;R41 
;R41 Build_IrqTbl	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  = Get_Irq_Routing_Options	(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)
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Set_PCI_Irq	proc	near
		cmp	ch,0FH			;maximum IRQ no. is 15
		ja	short Set_Fail

		cmp	cl,0aH			;valid value is 0AH..0DH

		jb	short Set_Fail
		cmp	cl,0dH			;valid value is 0AH..0DH
		ja	short Set_Fail

		pushad

		mov	ch,bl			;device+func no.
		mov	cl,3DH
		call32	Get_CfgSpace_Byte
		or	al,al			;need IRQ ?
		jnz	short Good_DevNum
		popad
		jmp	short Set_Fail
Good_DevNum:

		mov	al,ch			;IRQ number

		mov	cl,3CH			;register to set
		call32	Set_CfgSpace_Byte
		popad

		mov	ah,SUCCESSFUL
		clc
		ret
Set_Fail:
		mov	ah,SET_FAILED
		stc
		ret

Set_PCI_Irq	endp

;
;[]-------------------------------------------------------------------------[]
; 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	short @F
		cmc
@@:
		ret

Validate_Args	ENDP

Qualify_PciBus	Proc	Near
		push	ecx
		call32	Get_Max_PciBus
		cmp	bh, cl
		pop	ecx
		ja	short Bad_PciBus
		clc
		ret
Bad_PciBus:
		stc
		ret

Qualify_PciBus	endp

;[]-------------------------------------------------------------------------[]
; Set_CfgSpace_Byte:
;
; ENTRY : CX = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;
;	  AL = value write to CONFIG_DATA
;
; EXIT	: none
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Set_CfgSpace_Byte	PROC	NEAR
		push	edx
		push	esi

		mov	esi,eax

		mov	edx,0FFFFFF00h
		and	esi,000000FFh

		jmp	short Set_CfgSpace_Cont

Set_CfgSpace_Byte	ENDP

;[]-------------------------------------------------------------------------[]
; Set_CfgSpace_Word:
;
; ENTRY : CX = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;
;	  AX = value write to CONFIG_DATA
;
; EXIT	: none
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Set_CfgSpace_Word	PROC	NEAR
		push	edx
		push	esi

		mov	esi,eax

		mov	edx,0FFFF0000h
		and	esi,0000FFFFh

Set_CfgSpace_Cont	Label	Near

		push	cx

		and	cl,03
		shl	cl,3

		rol	edx,cl
		rol	esi,cl

		pop	cx

		call32	Get_CfgSpace_Dword

		and	eax,edx
		or	eax,esi

		call32	Set_CfgSpace_Dword

		pop	esi
		pop	edx
		ret
Set_CfgSpace_Word	ENDP

;[]-------------------------------------------------------------------------[]
; Set_CfgSpace_Dword:
;
; ENTRY : CX = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;
;	  EAX = value write to CONFIG_DATA
;
; EXIT	: none
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Set_CfgSpace_Dword	PROC	NEAR

		call32	Check_Valid_Slot_No
		jnc	short @F
		ret
	@@:

		push	dx
		push	eax

		mov	ax,8000H
ifndef	NO_MULTI_PCI_SUPPORT
		mov	al,bh
endif	;NO_MULTI_PCI_SUPPORT
		shl	eax,16

		mov	ax,cx
		and	al,0FCh			;must be dword read/write
		mov	dx,CONFIG_ADDRESS
		out	dx,eax
		pop	eax
		mov	dx,CONFIG_DATA
		out	dx,eax
		pop	dx
		ret
Set_CfgSpace_Dword	ENDP

;[]-------------------------------------------------------------------------[]
; Get_CfgSpace_Word:
;
; ENTRY : CX = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
; EXIT	: AX = value of CONFIG_DATA
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Get_CfgSpace_Word	PROC	NEAR
;R49 - Start
ifdef	PatchMX
		call32	Check_Valid_Slot_No

		jc	short Bad_Slot_Word1

  		call32	Qualify_PciBus
		jnc	short @F

Bad_Slot_Word1:
		mov	ax,-1				;invalid slot number
		ret
	@@:
ReadPCIWord:						;R46C
		push	dx
		call32	Get_PCI_Port
		in	ax,dx
		cmp	bh, 0
		jne	short Label2
		cmp	cx, 0eh
		jne	short Label2
		or	ax, 0080h
Label2:
		pop	dx
		ret
Get_CfgSpace_Word	ENDP
endif	;PatchMX
;R49 - End

Get_CfgSpace_Byte	Label	Near
ifndef	PatchMX					;R49
		call32	Get_CfgSpace_Dword

		and	cl,03			;byte in dword to get
		shl	cl,3			;*8 : 8 bits/byte for shifting

		shr	eax,cl

		ret
;R49 - Start
else	;PatchMX
		call32	Check_Valid_Slot_No
		jnc	short @F

  		call32	Qualify_PciBus
		jnc	short @F

		mov	al,-1				;invalid slot number
		ret
	@@:

ReadPCIByte:
		push	dx
		call32	Get_PCI_Port
		in	al,dx
		cmp	bh, 0
		jne	short Label3
		cmp	cx, 0eh
		jne	short Label3
		or	al, 80h
Label3:
		pop	dx
		ret

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
endif	;PatchMX
;R49 - End

ifndef	PatchMX			;R49
Get_CfgSpace_Word	ENDP
endif	;PatchMX		;R49
;
;[]-------------------------------------------------------------------------[]
; Get_CfgSpace_Dword:
;
; ENTRY : CX  = CONFIG_ADDRESS register value
;		CH = Device Number in upper 5 bits
;		     Function Number in lower 3 bits
;		CL = Register Number
;
; EXIT	: EAX = value of CONFIG_DATA
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
Get_CfgSpace_Dword	PROC	NEAR

		call32	Check_Valid_Slot_No

		jc	short Bad_Slot_Word

  		call32	Qualify_PciBus
		jnc	short @F

Bad_Slot_Word:
		mov	eax,-1
		ret
	@@:

	ifdef	PCI1A_87410_PATCH
		call32	Chk_Special_87410
		jnc	short @F
		xor	eax,eax
		ret
	@@:
	endif	;PCI1A_87410_PATCH

		push	dx

		mov	ax,8000H
ifndef	NO_MULTI_PCI_SUPPORT
		mov	al,bh
endif	;NO_MULTI_PCI_SUPPORT
		shl	eax,16

		mov	ax,cx
		and	al,0FCh			;must be dword read/write
		mov	dx,CONFIG_ADDRESS
		out	dx,eax
		mov	dx,CONFIG_DATA
		in	eax,dx
;R49 - Start
ifdef	PatchMX
		cmp	bh, 0
		jne	short Label1
		cmp	cx, 0ch
		jne	short Label1
		or	eax, 800000h
Label1:
endif	;PatchMX
;R49 - End
		pop	dx
		ret
Get_CfgSpace_Dword	ENDP

;-----------------------------------------------------------------------
;WARNING :	The below codes is shared with the PCI1A function
;		- DO NOT use WORD/DWORD/MEMORY access!
;		- DO NOT issue any subroutine CALL neither!
;-----------------------------------------------------------------------
		ALIGN	4
		Public	Check_Valid_Slot_No
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

		ALIGN	4
		Public	PCI_Code_Size
PCI_Code_Size	EQU	$ - Offset DGROUP:PCI_Procedure32
PCI_Code_End	label	near

endif	;CONFIG_MECHANISM_1

ifdef	PCI1A_87410_PATCH
		Public	Chk_Special_87410

	Chk_Special_87410:

		or	bh,bh
		jnz	short _tgc

		cmp	ch,(06 shl 3)
		jne	short _tgc

		cmp	cl,3Ch
		je	short _tgb
		cmp	cl,3Dh
		je	short _tgb

		cmp	cl,20h
		jb	short _tgc
		cmp	cl,27h
		ja	short _tgc
	_tgb:
		stc
		ret
	_tgc:
		clc
		ret
endif	;PCI1A_87410_PATCH

;[]----------------------------------------------------------------------[]
;Entry	:	None
;
;Exit	:	CL = the Maximum PCI Bus No. currently on the system
;
;Note	:	This instruction will be modified in POST by writing
;		the shadow RAM.
;
;		e.g. if the max. pci bus no. is 5, this routine should
;		     contain code "mov cl, 5" and the POST will place
;		     "B105h" which the machine code of "mov cl,5" into
;		     the shadow RAM
;
;[]----------------------------------------------------------------------[]
		Public	Get_Max_PciBus
Get_Max_PciBus	proc	near

ifdef	NO_MULTI_PCI_SUPPORT
		mov	cl, 0
else	;NO_MULTI_PCI_SUPPORT
		mov	cl, 128			;This instruction will
						;be modified in POST by
						;writing the shadow RAM
endif	;NO_MULTI_PCI_SUPPORT
		NOP
		NOP
		ret

Get_Max_PciBus	Endp



endif;	PCI_BUS

;R41 ;[]----------------------------------------------------------------------[]
;R41 ;Entry	:	None
;R41 ;
;R41 ;Exit	:	BX = the bit map of the IRQ assigned to PCI
;R41 ;
;R41 ;Note	:	This instruction will be modified in POST by writing
;R41 ;		the shadow RAM.
;R41 ;
;R41 ;		e.g. if the bit map is 1111111100000000b, this routine should
;R41 ;		     contain code "mov bl, 00000000b" and "mov bh, 11111111b"
;R41 ;		     The PCI POST will directly modify the machine code so that
;R41 ;		     this routine can reflect the bit map correctly.
;R41 ;[]----------------------------------------------------------------------[]
;R41 		ALIGN	4
;R41 		Public	Get_PCI_IRQ_Record
;R41 Get_PCI_IRQ_Record	Proc	Near
;R41 		Public	Get_PCI_IRQ_Record_Lo
;R41 Get_PCI_IRQ_Record_Lo	Label	Near
;R41 		mov	bl, 0
;R41 		Public	Get_PCI_IRQ_Record_Hi
;R41 Get_PCI_IRQ_Record_Hi	Label	Near
;R41 		mov	bh, 3
;R41 		ret
;R41 Get_PCI_IRQ_Record	Endp

;R43 - starts
;[]----------------------------------------------------------------------[]
;Entry	:	None
;
;Exit	:	BX = the bit map of the IRQ assigned to PCI
;
;Note	:	This instruction will be modified in POST by writing
;		the shadow RAM.
;
;		e.g. if the bit map is 1111111100000000b, this routine should
;		     contain code "mov bl, 00000000b" and "mov bh, 11111111b"
;		     The PCI POST will directly modify the machine code so that
;		     this routine can reflect the bit map correctly.
;[]----------------------------------------------------------------------[]
		ALIGN	4
		Public	Get_PCI_IRQ_Record
Get_PCI_IRQ_Record	Proc	Near
		Public	Get_PCI_IRQ_Record_Lo
Get_PCI_IRQ_Record_Lo	Label	Near
		mov	bl, 0
		Public	Get_PCI_IRQ_Record_Hi
Get_PCI_IRQ_Record_Hi	Label	Near
;R48		mov	bh, 3
		mov	bh, 0				;R48
		ret
Get_PCI_IRQ_Record	Endp
;R43 - ends

FCODE		ENDS
		END
