;	[]===========================================================[]
;
;	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
;----------------------------------------------------------------------------
;R49A	04/10/99 ADS	Add define "Patch_PCIDIAG_For_VT586" to Patch VIA
;			Chipset testing error for PCIDIAG.EXE.
;R49	04/08/99 ADS	Patch VIA Chipset testing error for PCIDIAG.EXE.
;R48	02/05/99 KGN	Patch IntelMX Ver1 Chipset Bug no report Multifunc
;			at Bus0,device0,func0
;R47	08/07/98 RCH	Fixed MediaGXm/5530 testing error for PCIDIAG.EXE
;R46D	07/30/98 RCH	Fixed device can be found if the device is a multi-
;			function and the devices are not continuous.
;R46C	07/22/98 RCH	Shorten the time taken by FIND_PCI_DEVICE routine
;R46B	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.
;R46A	07/20/98 RCH	Fixed some PCI/VGA or AGP card video driver installation
;			failure.
;R46	07/14/98 RCH	Fixed wrong device & function number scanning for
;			FIND_PCI_DEVICE & PCI_CLASS_CODE
;R45	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
;R44	11/18/97 RCH	Fixed Compaq's PCI testing program hang up while
;			running multi-tasking under WIN/NT.
;R43	08/06/97 RAY	Since the link value in the IRQ routing table might
;			not be 1,2,3 or 4, modify the code to translate
;			PIRQ0,1,2,3 to 1,2,3,4 in the Set PCI IRQ
;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.
;R38	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.
;
;R37A	06/16/97 RCH	Fixed compilation error for onboard CMD IDE controller
;R37	06/13/97 RCH	Fixed "IRQ routing table error" in Memphis for VIA
;			chipset with USB support
;R36	06/07/97 RCH	Fixed "IRQ steering" is disabled in Memphis if chipset
;			support USB controller.
;R35	03/15/97 RAY	No longer refer to PCI21.ASM for the PCI 2.1 routing
;			table. Instead, we build the routing table dynamically
;			such that the result is consistent with the 32 bit
;			protected mode interface.
;
;			Note: PCI32.ASM has been re-write not to use table
;			      in PCI21.ASM to solve the UNIXWare installation
;			      fail problem.
;
;R34	03/15/97 RAY	Support PCI 2.1 dynamic set PCI IRQ capability
;R33	03/10/97 RAY	The PCI_CONFIG_32BIT_IO definition only applys to 
;			a CONTAQ 486 chipset with part no. 2A4H2??? which is 
;			no longer exist in the market. Also we do not support
;			this chip in the compress BIOS. We delete the above
;			option for easy debugging
;R32	11/19/96 RAY	Support Multi-Level P2P bridge
;R31	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
;R30	06/18/96 RCH	Fixed PCIDIAG testing failure if ET4000 PCI/VGA 
;			plugged.
;R29	06/13/96 RCH	Modify function 06H to support PCI special cycle
;R28	05/27/96 RCH	Move some on run-time routine to file MISC.ASM to get
;			more space for F8000-FFFFF area
;R25A	11/08/95 RCH	Also patch for byte and word reading for TRITON, 
;			otherwise "PCIDIAG" failed
;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
;R25	08/24/95 RCH	Added patch code to fix error reporting of TRITON 
;			PIIX/IDE for PCI2.EXE of MS and PCICHK of Adaptec
;			Note : It is not a good idea , but customer need it.
;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
;R21A	05/23/95 RCH	"Find_P2p" become public routine
;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.
;R19	02/25/95 RCH	Let PCI_CLASS_CODE be public routine
;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/28/94 RCH	Let Aset_CfgSpace_Byte(Word & Dword) be public routine
;R15A	11/07/94 RCH	Added multiple PCI BUS support for function 02H & 03H
;R15	11/05/94 RCH	Support multiple PCI BUS and don't always use 32-bit
;			I/O transfer
;R14	10/18/94 RCH	The FOREX/613 PCI bridge can not access port address
;			0FFH , otherwise NCR DOSCAM driver hang
;R13B	09/16/94 DNL	Don't destroy FLAG register except Carry flag 
;R13A	09/15/94 RCH	Don't enable interrupt, because PCIDIAG fail
;R13	08/31/94 RCH	The setup program of MATROX PCI/VGA need BIOS to 
;			enable interrupt after calling INT 1A , otherwise
;			sytem hang
;R12	08/29/94 RAY	Add Special PCI slot range
;R11	07/28/94 RCH	Support multi-function support
;R10	06/23/94 RCH	Fixed SCO/UNIX double fault error for NCR/801 driver
;R08	06/21/94 DNL	Fixed WINDOW/NT driver for NCR/SCSI 53C810 failure
;R07	06/16/94 KEN	Fixed bug for Matrox PCI/VGA card
;R06	04/01/94 RCH	Replace NEWIODELAY with IODELAY,Because this cause
;			system hang on EFAR/PCI with adaptec/SCSI
;---	03/19/94 RAY	No more Mechanism 2 code in this file
;			Mechanism 2 codes will be placed in PCI1A_M2.ASM
;R05	02/15/94 KEN	Fixed misc. interface bugs
;R04	02/04/94 KEN	Support 32 device no.
;R03	02/03/94 KEN	Fixed bug at supporting multi-function cards
;R02	11/29/93 RCH	Added configuration space mechanism #1 support(INTEL
;			use mechanism #2 )
;R01	11/29/93 RCH	Fixed function 0AH read dword error


.386
;[]-----------------------------------[]
;
;   Award Software 386/486 BIOS
;	  Timer handling
;   Initial Revision 30-Apr-1990
;
;[]-----------------------------------[]

.XLIST
		INCLUDE BIOS.CFG
		INCLUDE COMMON.EQU

		INCLUDE 8259.EQU
		INCLUDE CMOS.EQU

		INCLUDE COMMON.MAC
.LIST

ifdef	PCI_BUS
ifdef	CONFIG_MECHANISM_1

MAX_PCI_BUS		EQU	8
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

		extrn	Check_Valid_Slot_No:near

ifndef	Special_PCI_Slot_Range
		MIN_PCI_SLOT	EQU	0
		MAX_PCI_SLOT	EQU	31
endif	;Special_PCI_Slot_Range

	ifdef	PCI1A_87410_PATCH
		extrn	Chk_Special_87410:near
	endif	;PCI1A_87410_PATCH

		extrn	Get_Max_PciBus:near

endif	;CONFIG_MECHANISM_1
endif	;PCI_BUS

ifdef	PNP_BIOS
		extrn	Ct_Shadow_Write:near
		extrn	Ct_Shadow_Read:near
endif	;PNP_BIOS

FCODE		SEGMENT USE16 PARA PUBLIC 'CODE'
		ASSUME	CS:FCODE

ifdef	PCI_BUS
ifdef	CONFIG_MECHANISM_1

;[]========================================================================[]
;[]========================================================================[]
	ALIGN	16
	extrn	PCI_BIOS32_Directory:near
	Public	Pci_Bios32_Signature
Pci_Bios32_Signature:
	db	'_32_'                          ;four bytes signature
	dw	offset PCI_BIOS32_Directory	;32 bit function physical address
	dw	000Fh
	db	0				;revision level
	db	01h				;data structure length, in terms of PARA
	db	0				;checksum location
	db	5 dup (0)			;5 bytes reserved (must be 0)

;[]========================================================================[]
;[]========================================================================[]

		ALIGN	16
		PUBLIC	PCI_Procedure
PCI_Procedure	PROC	NEAR

	cli				;R44


;		ENABLE_PCI_CONFIG
	cmp	al,01h
	jne	short @F
	CALL	PCI_BIOS_PRESENT
	jmp	short PCI_Func_exit1

@@:
	push	edx
	push	eax
	cmp	al,02h
	jne	short @F
	CALL	FIND_PCI_DEVICE
	jmp	short PCI_Func_exit
@@:
	cmp	al,03h
	jne	short @F
	CALL	PCI_CLASS_CODE
	jmp	short PCI_Func_exit
@@:
	cmp	al,06h
	jne	short @F
	CALL	GENERATE_SPECIAL_CYCLE
	jmp	short PCI_Func_exit
@@:
	cmp	al,08h
	jne	short @F
	CALL	READ_CONFIG_BYTE
	jmp	short PCI_Func_exit
@@:
	cmp	al,09h
	jne	short @F
	CALL	READ_CONFIG_WORD
	jmp	short PCI_Func_exit
@@:
	cmp	al,0Ah
	jne	short @F
	CALL	READ_CONFIG_DWORD
	jmp	short PCI_Func_exit
@@:
	cmp	al,0Bh
	jne	short @F
	CALL	WRITE_CONFIG_BYTE
	jmp	short PCI_Func_exit
@@:
	cmp	al,0Ch
	jne	short @F
	CALL	WRITE_CONFIG_WORD
	jmp	short PCI_Func_exit
@@:
	cmp	al,0Dh
	jne	short @F
	CALL	WRITE_CONFIG_DWORD
	jmp	short PCI_Func_exit
@@:

	cmp	al,0EH
	jne	short @F
	call	Get_Irq_Routing_Options
	jmp	short PCI_Func_exit
@@:
	cmp	al,0FH
	jne	short @F
	call	Set_PCI_Irq
	jmp	short PCI_Func_exit
@@:

	CALL	INVALID_FUNC

;========================= PCI Fucntion Finished ==========================
;		ALIGN	8
PCI_Func_exit:
	mov	dx,ax
	pop	eax
	mov	ah,dh
	pop	edx
PCI_Func_exit1:

;		DISABLE_PCI_CONFIG

		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

;R44		retf	2

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
;R46C		call	Aget_CfgSpace_Dword	;read vendor & device ID
		call	ReadPCIDword		;read vendor & device ID;R46C

		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:

;R46		test	ch,07h
;R46		jnz	short already_MF1
;R46		mov	cl,0eh
;R46		call	Aget_CfgSpace_Byte
;R46		test	al,80h
;R46		jnz	Already_MF1
;R46		add	ch,7
;R46
;R46Already_MF1:
;R46		add	ch,1
		call	GetNextDevFuncNo		;R46
		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


;R46 - 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

;R46D		xor	cl,cl
;R46D		call	ReadPCIword		;read vendor ID	;R46C
;R46D;R46C 	call	Aget_CfgSpace_Word	;read vendor ID
;R46D
;R46D		cmp	ax, 0FFFFH		;invalid vendor ID ?
;R46D		je	short NextDevNo

		test	ch,111B			;in multi-func ?	;R46B
		jnz	short NextFuncNo				;R46B

		mov	cl,0eh			;read header type
		call	ReadPCIByte		;read byte	;R46C
;R46C		call	Aget_CfgSpace_Byte

		cmp	al,0FFH			;empty device ?	;R46D
		je	short NextDevNO				;R46D

		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			;next function number
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
;R46A		jb	short YesInBus0
		jne	short YesInBus0		;R46A
		stc				;end of bus scanning
YesInBus0:

		ret
GetNextDevFuncNo	endp
;R46 - end
;[]-------------------------------------------------------------------------[]
;  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
		public	PCI_CLASS_CODE
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:

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
;R46		push	cx
;R46		mov	cl,0
;R46		call	Aget_CfgSpace_Word
;R46		cmp	ax,0FFFFh
;R46		pop	cx
;R46		je	short Next_Slot_Class

		or	si,si			;check index matching?
		jz	short Class_found
		dec	si

Next_Slot_Class:


;R46		test	ch,07h
;R46		jnz	short already_MF
;R46		mov	cl,0eh
;R46		call	Aget_CfgSpace_Byte
;R46		test	al,80h
;R46		jnz	Already_MF
;R46		add	ch,7
;R46
;R46Already_MF:
;R46		add	ch,1

		call	GetNextDevFuncNo		;R46

		jnc	short Search_Class_Loop

		inc	bh
		call	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

;[]-------------------------------------------------------------------------[]
; 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

		call	Qualify_PciBus
		jnc	short @F

		mov	ah,FUNC_NOT_SUPPORTED

		jmp	short GENERATE_SPECIAL_CYCLE_Exit
@@:
		call	Proc_Special_Cycle

		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

		call	Validate_Args
		jc	READ_CONFIG_BYTE_Exit

		push	cx

		mov	cx,di
		mov	ch,bl

;R47		call	Aget_CfgSpace_Word
		call	Aget_CfgSpace_Byte	;R47

;R49 - starts
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R49A
		pushf
		call	DO_OR_DONT_PATCH
		jnc	short label3
		mov	cx, 0300h 	;read byte
		call	READ_PATCH_CONFIG_DATA
Label3:
		popf
endif;	Patch_PCIDIAG_For_VT586		;R49A
endif;	VT586
;R49 - ends
		pop	cx

ifdef	PATCH_FOR_TRITON_IDE
		call	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	@f
		cmc				;error return
@@:
		ret

READ_CONFIG_BYTE	ENDP
;R49 - starts
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R49A
VIA_Byte_Index3:
	dw	07EH, 081H, 08CH, 03847H, 03849H, 03A44H, 03A47H
	dw      03B44H,03B47H,03B51H,03C51H,0FFFFH			 	
VIA_Byte_Value3:
	db	080H, 041H, 027H, 08H, 01H, 0C4H, 0C0H,04H, 0C0H
	db	0FFH, 0FFH

VIA_Word_Index2:
	dw	07EH, 080H, 08CH, 03846H, 03848H, 03A44H, 03A46H
	dw      03B44H,03B46H,03B50H,03C50H,0FFFFH
VIA_Word_Value2:
	dw	080H, 04100H, 027H, 0800H, 0100H, 0C4H,0C000H
	dw	04H, 0C000H,0FFFFH, 0FFFFH

VIA_Dword_Index1:
	dw	07CH, 080H, 08CH, 03844H, 03848H, 03A44H 
	dw      03B44H, 03B50H,03C50H,0FFFFH
VIA_Dword_Value1:
	dd	0800000H, 04100H, 027H, 08000000H, 0100H, 0c00000c4h
	dd	0c0000004H, 0FFFFH, 0FFFFH
endif;	Patch_PCIDIAG_For_VT586		;R49A
endif;	VT586
;R49 - 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

		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

;R49 - starts
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R49A
 		pushf
 		call	DO_OR_DONT_PATCH
 		jnc	short label2
 		mov	cx, 0200h 	;read word
 		call	READ_PATCH_CONFIG_DATA
 Label2:
 		popf
endif;	Patch_PCIDIAG_For_VT586		;R49A
endif;	VT586
;R49 - ends
ifdef	PATCH_FOR_TRITON_IDE
		call	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	@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
;R49 - starts
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R49A
 		pushf
 		call	DO_OR_DONT_PATCH
 		jnc	short label1
 		mov	cx, 0100h 	;read dword
 		call	READ_PATCH_CONFIG_DATA
 Label1:
 		popf		
endif;	Patch_PCIDIAG_For_VT586		;R49A
endif;	VT586
;R49 - 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	@f
		cmc				;error return
@@:
		ret

READ_CONFIG_DWORD	ENDP
;R49 - starts
ifdef	VT586
ifdef	Patch_PCIDIAG_For_VT586		;R49A
	Public	DO_OR_DONT_PATCH
DO_OR_DONT_PATCH Proc	NEAR
		cmp	bh,0
		jne	short DONT_PATCH	;Not Bus0 => jmp!

		cmp	bl,0
		jne	short Not_D0F0
		stc	
		ret
Not_D0F0:
		cmp	bl,38H
		jne	short Not_D7F0
		stc	
		ret
Not_D7F0:
		cmp	bl,3AH
		jne	short Not_D7F2
		stc	
		ret

Not_D7F2:
		cmp	bl,3Bh
		jne	short Not_D7F3
		stc	
		ret
Not_D7F3:
		cmp	bl,3CH
		jne	short DONT_PATCH
		stc	
		ret
DONT_PATCH:
		clc
		ret
DO_OR_DONT_PATCH endp

	Public	READ_PATCH_CONFIG_DATA
READ_PATCH_CONFIG_DATA Proc	NEAR

		push	si
		push	bx
		push	di
		shl	bx, 8
		or	bx, di	;get input data

		mov	di, cx
		xor	cx, cx

		cmp	di, 0300h
		jne	short Loop_index2
		mov	si, offset VIA_Byte_Index3 - 2
		jmp	short Loop_Index0
Loop_Index2:
		cmp	di, 0200h
		jne	short Loop_index1
		mov	si, offset VIA_Word_Index2 - 2
		jmp	short Loop_Index0
Loop_Index1:
		cmp	di, 0100h
		jne	short Exit_Index0
		mov	si, offset VIA_Dword_Index1 - 2
Loop_Index0:
		add	si,2
		inc	cx
		cmp	word ptr cs:[si], 0FFFFH
		je	short Exit_Index0

		cmp	bx, cs:[si]
		jne	Loop_Index0

		dec	cx

		cmp	di, 0300h
		jne	short Get_Word16
		mov	si, offset VIA_Byte_Value3
		add	si, cx
		or	al, cs:[si]	;byte read
		jmp	short Exit_Index0
Get_Word16:
		cmp	di, 0200h
		jne	short Get_Dword32
		mov	si, offset VIA_Word_Value2
		shl	cx, 1
		add	si, cx
		or	ax, cs:[si]	;word read
		jmp	short Exit_Index0
Get_Dword32:
		mov	si, offset VIA_Dword_Value1
		shl	cx, 2
		add	si, cx
		or	eax, cs:[si]	;dword read
Exit_Index0:
		pop	di
		pop	bx
		pop	si

		ret
READ_PATCH_CONFIG_DATA endp
endif;	Patch_PCIDIAG_For_VT586		;R49A
endif;	VT586
;R49 -  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

		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

;[]-------------------------------------------------------------------------[]
; 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		extrn	Build_IrqTbl:near
;R41		extrn	Get_PCI_IRQ_Record_Lo:Near
;R41		extrn	Get_PCI_IRQ_Record_Hi:Near
		extrn	Ct_Set_PciIrq:near
		extrn	IrqRouteTbl:Near			;R41
		extrn	IrqRouteTbl_END:near			;R41
		extrn	PciIrqTbl_Size:near			;R42

		extrn	Get_PCI_IRQ_Record:Near			;R45

		ALIGN	4
Get_Irq_Routing_Options	proc	near

		pusha
;R42		mov	cx, IrqTbl_Size
		mov	si, offset PciIrqTbl_Size			;R42
		mov	cx, cs:[si]					;R42
		cmp	cx, es:[di]  	;compare input buffer size
		mov	es:[di], cx	;return buffer size
		jbe	short Buffer_Enough

		popa
		mov	ah, BUFFER_TO_SMALL
		stc
		ret

Buffer_Enough:

;R41 - starts
		push	es
		les	di, es:[di+2]		;get data buffer address
 		mov	si, offset IrqRouteTbl
		cld
		rep	movsb
		pop	es
		popa
;R45		mov	bx, 1
 		call	Get_PCI_IRQ_Record		;R45
		mov	ah, SUCCESSFUL
		clc
		ret

Get_Irq_Routing_Options	Endp
;R41 - ends

;R41		push	es
;R41		les	di,es:[di+2]		;get data buffer address
;R41
;R41		mov	bl, 1	   		;start slot 1
;R41		mov	si, offset PCI1A_Routing_Tbl
;R41		cld
;R41
;R41	Build_Next_IrqRouteTbl:
;R41
;R41		push	bx
;R41		push	si
;R41		mov	bh, cs:[si]		;get slot device number
;R41		mov	dx, IRQ_PCI		;default available IRQs
;R41		mov	ax, cs:[si+1]		;get IRQ routing inform.
;R41
;R41		or	al,al			;both INTA & INTB no routing?
;R41		jnz	short Not_OnboardDev
;R41		xor	bl,bl			;mark onboard device for IDE
;R41Not_OnboardDev:
;R41
;R41		or	ax, ax			;no routing ?
;R41		jnz	short @F		;with rouging.
;R41		xor	bl, bl			;set slot No. to 0 for onboard dev.
;R41		xor	dx, dx			;set no available IRQ
;R41	@@:
;R41		call	Build_IrqTbl		;build IRQ table for current
;R41		pop	si			;slot
;R41		pop	bx
;R41
;R41		inc	bl			;increment slot number
;R41		add	si, 3			;next slot inform.
;R41		cmp	byte ptr cs:[si], 0FFh	;last slot to build ?
;R41		jne	short Build_Next_IrqRouteTbl
;R41		pop	es
;R41
;R41		popa
;R41		mov	ah, SUCCESSFUL
;R41 		mov	bx, cs:[PCI_IRQ_RECORD]
;R41		clc
;R41		ret
;R41
;R41Get_Irq_Routing_Options	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)
;[]-------------------------------------------------------------------------[]

		ALIGN	4
Set_PCI_Irq	proc	near

ifdef	PNP_BIOS
		pushf
		cli

		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
		call	AGet_CfgSpace_Byte
		or	al, al			;need IRQ ?
		popad
		jz	short Set_Fail

		pushad
		push	cx
		mov	ch, bl
		mov	cl, 3CH
		call	Aget_CfgSpace_Byte
		mov	cl, al
		mov	ax, not 01h
		shl	ax, cl
		pop	cx
		popad						;R41

;R41		mov	cl, ch
;R41		mov	bx, 1
;R41		shl	bx, cl
;R41
;R41		pusha
;R41		call	Ct_Shadow_Write
;R41		popa
;R41
;R41		mov	si, offset PCI_IRQ_RECORD
;R41		and	word ptr cs:[si], ax
;R41		or	word ptr cs:[si], bx
;R41
;R41		mov	ax, cs:[si]
;R41		mov	si, offset Get_PCI_IRQ_Record_Lo
;R41		mov	byte ptr cs:[si+1], al
;R41		mov	si, offset Get_PCI_IRQ_Record_Hi
;R41		mov	byte ptr cs:[si+1], ah
;R41
;R41		call	Ct_Shadow_Read
;R41		popad

		pushad
		mov	al, ch			;IRQ number
		mov	ch, bl
		mov	cl, 3CH			;register to set
		call	Aset_CfgSpace_Byte
		popad

		call	Set_Ct_PIRQ_Pins
		jc	short Set_Fail
		popf
		mov	ah, SUCCESSFUL
		clc
		ret
Set_Fail:
		popf

endif	;PNP_BIOS

		mov	ah, SET_FAILED
		stc
		ret

Set_PCI_Irq	endp

ifdef	PnP_BIOS
;R41 Set_Ct_PIRQ_Pins	Proc	Near
;R41 
;R41 		pushad
;R41 
;R41 		and	bl, not 03h
;R41 		mov	si, offset PCI1A_Routing_Tbl
;R41 
;R41 	Cmp_Next_Slot:
;R41 
;R41 		cmp	bl, byte ptr cs:[si]
;R41 		jne	short @F
;R41 		mov	ax, word ptr cs:[si+1]
;R41 		or	ax, ax
;R41 		jz	short @F
;R41 		mov	dh, ch
;R41 		mov	dl, 1
;R41 
;R41 		sub	cl, 0Ah
;R41 		shl	cl, 2
;R41 		shr	ax, cl
;R41 		and	al, 0Fh
;R41 		mov	ah, dh
;R41 		mov	ch, 0FFh
;R41 		extrn	Ct_Set_PciIrq:near
;R41 		call	Ct_Set_PciIrq
;R41 
;R41 		clc
;R41 		jmp	short Set_PIRQ_Success
;R41 	@@:
;R41 		add	si, 3
;R41 		cmp	byte ptr cs:[si], 0FFh
;R41 		jne	short Cmp_Next_Slot
;R41 		stc
;R41 
;R41 Set_PIRQ_Success:
;R41 Set_PIRQ_Exit:
;R41 
;R41 		popad
;R41 		ret
;R41 
;R41 Set_Ct_PIRQ_Pins	Endp

;R41 - starts 
Set_Ct_PIRQ_Pins	Proc	Near

		pushad

		xchg	bh, bl

	;----------------------------------------------
		mov	dx, 2
		cmp	cl, 0Ah
		je	short @F
		add	dx, 3
		cmp	cl, 0Bh
		je	short @F
		add	dx, 3
		cmp	cl, 0Ch
		je	short @F
		add	dx, 3
		cmp	cl, 0Dh
		jne	short Set_PIRQ_Fail
	@@:
	;----------------------------------------------

		mov	si, offset IrqRouteTbl

	Cmp_Next_Slot:

		cmp	bx, word ptr cs:[si]
		jne	short Try_Next_Entry

		mov	bx, dx
;R43		mov	al, cs:[si+bx]
;R43		and	al, 0Fh
;R43		or	al, al
;R43		jz	short Set_PIRQ_Fail
;R43 - starts
		mov	ah, cs:[si+bx]
		or	ah, ah
		jz	short Set_PIRQ_Fail

		mov	al, 1
		cmp	ah, PIRQ0_VAL
		je	short @F
		inc	al
		cmp	ah, PIRQ1_VAL
		je	short @F
		inc	al
		cmp	ah, PIRQ2_VAL
		je	short @F
		inc	al
		cmp	ah, PIRQ3_VAL
		je	short @F
		mov	al, ah
	@@:
;R43 - ends
		mov	ah, ch

		mov	ch, 0FFh
		call	Ct_Set_PciIrq

		clc
		jmp	short Set_PIRQ_Success

	Try_Next_Entry:

		add	si, 16				
		cmp	si, offset IrqRouteTbl_END
		jb	short Cmp_Next_Slot
Set_PIRQ_Fail:

		stc
Set_PIRQ_Success:
Set_PIRQ_Exit:
		popad
		ret

Set_Ct_PIRQ_Pins	Endp
;R41 - ends
endif	;PnP_BIOS

;R41 PCI1A_Routing_Tbl:
;R41 
;R41 	IF	SLOT1_EXIST
;R41 		db	(SLOT1_ID SHL 3)
;R41 		dw	(SLOT1_INTD shl 12)+(SLOT1_INTC shl 8)+\
;R41 			(SLOT1_INTB shl 4)+SLOT1_INTA
;R41 	ENDIF	;SLOT1_EXIST
;R41 
;R41 	IF	SLOT2_EXIST
;R41 		db	(SLOT2_ID SHL 3)
;R41 		dw	(SLOT2_INTD shl 12)+(SLOT2_INTC shl 8)+\
;R41    			(SLOT2_INTB shl 4)+SLOT2_INTA
;R41 	ENDIF	;SLOT2_EXIST
;R41 
;R41 	IF	SLOT3_EXIST
;R41    		db	(SLOT3_ID SHL 3)
;R41    		dw	(SLOT3_INTD shl 12)+(SLOT3_INTC shl 8)+\
;R41 			(SLOT3_INTB shl 4)+SLOT3_INTA
;R41 	ENDIF	;SLOT3_EXIST
;R41 
;R41 	IF	SLOT4_EXIST
;R41    		db	(SLOT4_ID SHL 3)
;R41    		dw	(SLOT4_INTD shl 12)+(SLOT4_INTC shl 8)+\
;R41 			(SLOT4_INTB shl 4)+SLOT4_INTA
;R41 	ENDIF	;SLOT4_EXIST
;R41 
;R41 	IF	SLOT5_EXIST
;R41    		db	(SLOT5_ID SHL 3)
;R41    		dw	(SLOT5_INTD shl 12)+(SLOT5_INTC shl 8)+\
;R41 			(SLOT5_INTB shl 4)+SLOT5_INTA
;R41 	ENDIF	;SLOT5_EXIST
;R41 
;R41 	IF	SCSI_ONBOARD
;R41 		db	(SCSI_SLOT SHL 3)
;R41 		dw	(SCSI_INTD shl 12)+(SCSI_INTC shl 8)+\
;R41 			(SCSI_INTB shl 4)+SCSI_INTA
;R41 	ENDIF	;SCSI_ONBOARD
;R41 
;R41 	IF	VGA_ONBOARD
;R41 	ifdef	VGA_INTA
;R41 		db	(ONBOARD_PCI_VGA shl 3)
;R41 		dw	(VGA_INTD shl 12)+(VGA_INTC shl 8)+\
;R41 			(VGA_INTB shl 4)+VGA_INTA
;R41 	endif	;VGA_INTA
;R41 	ENDIF	;VGA_ONBOARD
;R41 
;R41 ifdef	BUILD_IN_IDE_IDSEL
;R41  ROUT_VAL	=	0
;R41  IDE_IDSEL	=	(BUILD_IN_IDE_IDSEL SHL 3)
;R41 
;R41   ifdef	ONBOARD_CMD_IDSEL
;R41    IDE_IDSEL	=	BUILD_IN_IDE_IDSEL
;R41   endif	;ONBOARD_CMD_IDSEL
;R41   ifdef	Onboard_PCI_IDE
;R41    ifndef BUILD_IN_IDE_IDSEL
;R41     IDE_IDSEL	=	BUILD_IN_IDE_IDSEL
;R41    endif  ;BUILD_IN_IDE_IDSEL
;R41   endif	;Onboard_PCI_IDE
;R41 
;R41  ifdef	PIIX_ID
;R41  ROUT_VAL	=	4 shl 12		;use INTD# and shared
;R41  IDE_IDSEL	=	PIIX_ID
;R41  endif;	PIIX_ID
;R41 
;R41  ifdef	VT586_USB
;R41  ROUT_VAL	=	5 shl 12		;use INTD# but no share
;R41  endif;	VT586_USB
;R41 
;R41 		db	IDE_IDSEL
;R41 		dw	ROUT_VAL
;R41 endif;	BUILD_IN_IDE_IDSEL
;R41 
;R41 		db	0FFh
;R41 
;R41 		EVEN
;R41 		Public	PCI_IRQ_RECORD
;R41 PCI_IRQ_RECORD	Label	word
;R41 		dw	0

;[]-------------------------------------------------------------------------[]
; 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

		public	ASet_CfgSpace_Byte
		public	ASet_CfgSpace_Word
		public	ASet_CfgSpace_Dword
		public	AGet_CfgSpace_Byte
		public	AGet_CfgSpace_Word
		public	AGet_CfgSpace_Dword

;[]-------------------------------------------------------------------------[]
; 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
	@@:
	ifdef	PCI1A_87410_PATCH
		call	Chk_Special_87410
		jnc	short @F
		xor	eax,eax
		ret
	@@:
	endif	;PCI1A_87410_PATCH

ReadPCIDword:						;R46C
		push	dx
		call	Get_PCI_Port
		in	eax,dx
;R48 - Start
ifdef	PatchMX
		cmp	bh, 0
		jne	short Label1
		cmp	cx, 0ch
		jne	short Label1
		or	eax, 800000h
Label1:
endif	;PatchMX
;R48 - End
		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
	@@:
ReadPCIWord:						;R46C
		push	dx
		call	Get_PCI_Port
		in	ax,dx
;R48 - Start
ifdef	PatchMX
		cmp	bh, 0
		jne	short Label2
		cmp	cx, 0eh
		jne	short Label2
		or	ax, 0080h
Label2:
endif	;PatchMX
;R48 - End
		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

ReadPCIByte:						;R46C
		push	dx
		call	Get_PCI_Port
		in	al,dx
;R48 - Start
ifdef	PatchMX
		cmp	bh, 0
		jne	short Label3
		cmp	cx, 0eh
		jne	short Label3
		or	al, 80h
Label3:
endif	;PatchMX
;R48 - End
		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
; ifdef	MULTI_PCI_BUS_SUPPORT
		mov	al,bh
; endif;	MULTI_PCI_BUS_SUPPORT
		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

;[]-------------------------------------------------------------------------[]
; Proc_Special_Cycle:
;
; ENTRY : EDX  = Special cycle data
; EXIT	: none
;
;[]-------------------------------------------------------------------------[]
		ALIGN	4
		public	Proc_Special_Cycle
Proc_Special_Cycle	PROC	NEAR

		push	edx
		push	eax

		push	edx			;special cycle data

		xor	eax,eax
		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

		ret
Proc_Special_Cycle	ENDP

		Public	fProc_Qualify_PciBus
fProc_Qualify_PciBus	Proc	Far
		call	Qualify_PciBus
		retf
fProc_Qualify_PciBus	Endp

endif	;CONFIG_MECHANISM_1
endif	;PCI_BUS

FCODE		ENDS
		END
