;	[]===========================================================[]
;
;	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.
;
;	[]===========================================================[]
;

;************************************************************************
;*	This file will be included in PMUPOST.ASM, and compiled		*
;*	with 3 stages. All codes occupied at E000 segment, and		*
;*	some codes will be remove to SMI RAM for run-time execution.	*
;************************************************************************

;----------------------------------------------------------------------------
;Rev	Date	 Name	Description
;----------------------------------------------------------------------------
;R54	04/16/99 KEN	Fixed bug that the system is abnormal when the BIOS is
;			defined with "IOTRAP_SUPPORT" on VIA chipset.
;R53	03/22/99 KEN	Patch that the USB keyboard doesn't work after "restart
;			to MS-DOS mode" from Win98 on WHITNEY chipset.
;R52	03/05/99 KEN	Patch the Fujitsu keyboard hang-up while running its
;			testing utility.
;R51	02/10/99 RAY	SHADOW_NIT_64K Only
;			- Fixed coding mistake which caused the whole C000
;			  to be shadowed when ISA VGA is plugged. This shadow
;			  action will cause system hang up
;
;R50	01/18/99 KEN	Patch system hang up while the Japanese Keyobard DOS
;			driver is installed and the USB mouse legacy support
;			is on.
;R21A	01/14/99 RAY	R21 tried to set the rest of the shadow RAM (8k byte)
;			to 0FFh so that it passed the SCT memory test. However
;			there was a coding mistake to set 16K byte. It may 
;			corrupt some legacy devices which decodes their reg.
;			or memory on-card in that area.
;
;R49	01/05/99 KEN	Added SET_PROTOCOL request for some newest HID devices
;			need to set boot protocol. This is used to patch
;			USB keyboard failure with legacy support like
;			Microsoft new USB keyboard.
;R48	12/28/98 RAY	Support switch: SHADOW_UNIT_64K
;R47A	12/24/98 KEN	Fixed coding mistake.
;R47	12/22/98 KEN	Added declaration "ZERO_SET_IDLE" to patch that the
;			SET_IDLE rate of some USB keyboard isn't correct and
;			causes the BIOS simulated typematic rate is wrong.
;			If the BIOS is defined with the declaration, the
;			SET_IDLE value will be null that is the USB keyboard
;			just respond while keys pressing and de-pressing(not
;			periodic report), and the simulation of typematic rate
;			of USB keyboard will be done with a timer task of 16ms
;			interval. For the original method, the simulation is
;			done with the USB keyboard periodic response according
;			to the SET_IDLE rate.
;R46	12/11/98 KEN	Fixed bug that the mouse cursor is displayed abnormal
;			while using Microsoft IntelliMouse (socalled scroll
;			function or wheel control mouse) in Win98 safe mode,
;			when usb mouse support is enabled and no usb mouse
;			is installed.
;			Changed codes include:
;			1. No longer support switching activated mouse between
;			   USB and PS/2 when USB mouse plugged/unplugged.
;			   (USB mouse hot-plugged is still supported.)
;			2. Support Microsoft IntelliMouse setting extended mode
;			   sequence.
;R45	11/13/98 KEN	For USB_MOUSE_SUPPORT.
;			Fixed bug that if the setup item of USB mouse is
;			selected as disabled and no PS/2 mouse is plugged,
;			the BIOS still reports PS/2 mouse installed.
;R44	11/03/98 KEN	Fixed bug for USB_MOUSE_SUPPORT.
;			The system hang-up when shutdown from WinNT5.Beta2,
;			and both USB keyboard and mouse setup items are
;			disabled.
;R43	10/19/98 KEN	Fixed bug that the I/O 0CF8h of PCI configuration
;			space index is destroyed by SMI routine when execute
;			open/close PM_RAM, and cause that the APM kernal
;			cannot write PM_RAM correctly.
;R41D	10/14/98 KEN	Fixed bug that the system hang-up at Usb_Final_Init
;			when one device's setup item (USB keyboard or mouse)
;			is selected as disabled and another is enabled and
;			the corresponding device is installed.
;R41C	10/14/98 KEN	Fixed bug that the PS/2 keyboard should be inactive
;			when hold-down any key in POST stage and no USB
;			keyboard is plugged-in.
;R42	10/14/98 KEN	Added the declaration of "PATCH_AMIDIAG" to patch the
;			error of "BIOS ROM Test" of AMIDIAG.
;R41B	09/28/98 KEN	Added the disable/enable PS/2 mouse process when the
;			USB mouse is inserted/removed.
;R41A	09/28/98 KEN	Fixed coding mistake, and caused that USB mouse is also
;			disabled if USB keyboard is disabled.
;R41	09/21/98 KEN	Added USB_MOUSE_SUPPORT to support USB mouse to emulate
;			as PS/2 mouse for legacy OS(no USB supported).
;R40	09/21/98 KEN	Updated the bit manipulation of bUsbFlag with symbolic
;			variable.
;R39	09/17/98 KEN	Replace all I/O trapping code with the newest.
;R38	08/27/98 KEN	Turn on bus master and io/memory space decoding of USB
;			host controller, avoid that these two bits are not
;			turn-on by PCI kernel.
;R37	06/11/98 KEN	Set the default value of USB_STATUS to be USB disabled,
;			avoid abnormal action in SMI routine between the SMI
;			initialization and USB initialization.
;R36A	06/03/98 KEN	Fixed bug that the system hang-up when shut down from
;			Win98 after S4 suspend/resume process.
;R36    05/29/98 TNY	Fix system hang resume from S4 state if USB Legacy
;			support enabled.
;R35    02/25/98 JKY	Added usb ygroup support.  
;			code for (COMPILE_FOR_USBBIOS EQ 2) include in E-seg ,
;			code for (COMPILE_FOR_USBBIOS EQ 3) replace at YGROUP
;			and copy to smbase.
;R34	02/18/98 KEN	Added declaration of USB_PM_SUPPORT and codes to process
;			USB suspend and resume.
;R33	02/05/98 KEN	Patch that the system hang-up at Usb_Wait_Refresh of
;			Usb_Init while some combination of PCI card plugging
;			in Mitac M/B(2a69jm3c).
;R29A	12/16/97 KEN	Fixed coding mistake and cause some USB keyboard with
;			acceptable error at initialization stage can't work.
;			But it was working properbly with older BIOS.
;R32	12/16/97 KEN	Clear the bit-map flag of USB_RAM in LMEM_RESOURCE and
;			LMEM_RESERVED to release the UMB space when USB legacy
;			supporting is disabled. To correspond with the earlier
;			Usb_Final_Init before POST_82s.
;R31	12/16/97 KEN	Restore original method to allocate shadow RAM for
;			USB_RAM. That is, searching the available shadow RAM
;			upward from C800h to DC00h.
;			To fix that there are no sufficient UMB space for some
;			PCI devices that the size of option ROM is more than
;			48KB.
;R08A	12/15/97 KEN	Fixed bug for UHCI, the USB keyboard won't work after
;			seven times of hot-plugging. The causation is that
;			the flag of control buffer map is never cleared after
;			keyboard initailization.
;R30	11/28/97 JKY	When PMI_HANDLER move to XGROUP , need using F000_call
;R29	11/20/97 KEN	Added codes in Usb_Smi routine to process the error
;			recovery of USB host controller to patch some unstable
;			M/B.(e.g. GemLight 440LX+SMC672 M/B)
;R28	11/13/97 KEN	Fixed bug that there is incorrect handshaking when the
;			USB ownership is changed from the Windows98 to the
;			system BIOS.(e.g. select "Restart in MS-DOS mode" item
;			in Windows98 "Shut Down" menu)
;R27	11/11/97 KEN	Fixed bug that the SET_IDLE and SET_REPORT request
;			have no function with the newest USB keyboard(spec.
;			V1.0 final).
;R26	11/10/97 KEN	Added five keys' codes to support Japanese USB K/B.
;			Key codes translation:
;				USB Key Code	Translated Key Code
;				87h		73h
;				88h		70h
;				89h		7Dh
;				8Ah		79h
;				8Bh		7Bh
;R25	10/06/97 KEN	Get hub descriptor with the value 29h of descriptor
;			type byte to match the newest spec.
;R24	09/18/97 KEN	Get USB keyboard endpoint descriptor with more flexible
;			method to match the old and newest(V1.0 final) USB HID
;			specification.
;			To solve some new USB keyboards can't work with USB
;			BIOS legacy supporting.
;R23	08/28/97 KEN	Added codes to clear enabled status change of hub port
;			after device is disconnected and disabled, otherwise
;			the Intel Hub will always respond with hub port status
;			change.
;R22A	07/30/97 KEN	Modified I/O trapping codes to suit the current BIOS.
;			1. Added definition "IOTRAP_SUPPORT" to enable this
;			   module.
;			2. Got the device ID of host controller with wHostID
;			   that originally got with PIIX3_USB definition.
;			3. Call Ct_DisableUsbLegacySmi/Ct_EnableUsbLegacySmi
;			   to instead that direct setting registers according
;			   to PIIX_ID definition originally.
;			4. Four chipset hook routines added:
;				Ct_CheckUsbLegacySmi
;				Ct_ClearUsbLegacySmi
;				Ct_DisableUsbLegacySmi
;				Ct_EnableUsbLegacySmi
;R22	07/30/97 KEN	Added 60h/64h I/O trapping codes got from Award U.S.
;			Original files were backup and zipped as usb0730.zip
;			in oldfile directory.
;			Only one difference with original files in this
;			revision:
;			  Added pseudo code 'short' to some conditional or
;			  unconditional jumpping instructions.
;R21	06/25/97 RCH	Fixed SCT sometimes testing failure if "USB keyboard"
;			is enabled.
;R20	06/24/97 KEN	Fixed bugs:
;			 1. The system hang up while running the diagnostic
;			    program of Adaptec SCSI ROM.
;			 2. The system hang up when the boot-ROM of 3Com 3C900
;			    is executed.
;			The causation is that the USB kernal uses the base
;			memory at POST stage, and the base memory is conflicted
;			with these programs. To solve these problems, the USB
;			kernal will use the shadow RAM at whole time.
;R19A	06/16/97 KEN	Don't send any key code if over-run, otherwise the
;			system will hang-up when many keys are struke
;			simultaneously and the KEYB driver is installed.
;R19	06/16/97 KEN	Fixed bug for incorrect key code 00h of over-run, the
;			correct key code is 0FFh, and this will cause the KEYB
;			driver to translate key code 00h to 53h("S").
;R18	06/12/97 KEN	Added the definition "NO_UPDATE_USBKB_LED" to patch
;			that the SEJIN USB keyboard is inactive after updating
;			LED.
;R17	06/12/97 KEN	Added "GET_REPORT_DESCRIPTOR" to patch that the SEJIN
;			USB keyboard can't be activated.
;R16	06/11/97 KEN	Fixed bug for the CMD USB keyboard can't repeat and
;			abnormal keystroke. The causation seems to be that
;			the "SET_IDLE" request isn't set correctly.
;R15	06/10/97 KEN	Added 102-key supporting.
;			USB key number 32h, 64h are corresponding to AT key
;			number 42, 45.
;R14A	05/30/97 RCH	Fixed compiation error
;R14	05/27/97 KEN	Fixed bug that the testing program of CATC USB tester
;			report error at first time testing with 430VX M/B and
;			the SETUP item of "USB Keyboard Support" is disabled.
;R13	05/23/97 KEN	Fixed bug that the system hang-up at POST 31h in 430VX
;			system with CATC USB tester.
;R12	05/08/97 KEN	Fixed bug that the screen display abnormal in Win95
;			(no USB supporting) when press USB keyboard and move
;			PS/2 mouse at the same time.
;R11	04/28/97 KEN	Support USB always enabled at POST stage, and
;			initialize USB before memory testing.
;R10	04/16/97 KEN	Fixed bug that the system hang-up when cancel the
;			detection of PCI USB Controller at Win95(no USB
;			supporting). This condition occured when the USB Host
;			Controller shared IRQ with another PCI bus master card
;			and the BIOS USB legacy supporting is enabled.
;R09	04/09/97 KEN	Patched the abnormal keystroke of TATUNG USB keyboard.
;R08	04/09/97 KEN	Fixed bug for supporting multiple hub.
;R07	04/09/97 KEN	Saving all registers is done by Usb_Smi, it's done
;			by PMUPOST originally.
;R06	04/07/97 KEN	Changed the method of processing keystroke, to solve
;			the CMD keyboard problem.
;R05	04/01/97 KEN	Patch that some USB keyboards don't support the
;			SET_IDLE request.(e.g. BTC USB Keyboard)
;R04	03/26/97 KEN	Rename this file as UHCI.ASM, and is included by new
;			USBBIOS.ASM. Some host controller independent codes in
;			this file will be moved to new USBBIOS.ASM in future.
;R03	02/19/97 RCH	Fixed SCT 5.3 "unreport memory" error if USB legacy
;			support is enabled.
;R02	01/22/97 KEN	Updated the interval of system control task to 1024,
;			avoid to enter SMI frequently.
;R01	01/21/97 KEN	Fixed coding mistake.
;R00	01/16/97 KEN	New USBBIOS structure to support HUB and multiple
;			keyboard. The old files is backup as USB0116.zip.

;************************************************************************
;									*
; NOTES: If no special definition, DS and ES always point to USB_RAM	*
;									*
;************************************************************************

;R04IFDEF	USB_SUPPORT
IF	COMPILE_FOR_USBBIOS EQ 1

;****************************************************************
;*								*
;*	COMPILING STAGE 1					*
;*								*
;*	MISCELLANEOUS DEFINITION				*
;*								*
;****************************************************************

;R04	INCLUDE HCI.EQU
;R04	INCLUDE USB.EQU

	extrn	Get_Pci:near
	extrn	Set_Pci:near
	extrn	F000_Shadow_W:near
	extrn	F000_Shadow_R:near
	extrn	Ct_Shadow_RW:near
	extrn	C000_Shadow_RW:near		;R48
	extrn	Ct_Disable_Shadow:near		;R20
	extrn	USB_RAM_SEG:word
	extrn	LMEM_RESOURCE:abs
	extrn	LMEM_RESERVED:abs		;R20
	extrn	USB_STATUS:byte

;R04USB_RAM SEGMENT USE16	AT 0
;R04	INCLUDE HCDATA.INC
;R04USB_RAM ENDS

ENDIF	;COMPILE_FOR_USBBIOS EQ 1

IF	COMPILE_FOR_USBBIOS EQ 2

;R03 - start
ifdef	PNP_BIOS
	extrn	Build_UsbRamNode:near
endif;	PNP_BIOS
;R03 - start

;****************************************************************
;*								*
;*	COMPILING STAGE 2					*
;*								*
;*	POST INITIALIZATION CODES OCCUPIED AT E000 SEGMENT	*
;*								*
;****************************************************************

	assume	ds:USB_RAM

;************************************************************************
;*									*
;*	POST INTERFACE MODULE						*
;*									*
;************************************************************************

ifndef	SMIHANDLE_IN_YGROUP				;R35

;[]========================================================================[]
;Procedure:	Usb_Init
;Function:	USB initialization
;Input:		none
;Output:	none
;[]========================================================================[]

	public	Usb_Init
Usb_Init	proc	near
	push	ds
	push	es
	pushad

	call	Ct_USB_Init
;R37	jnc	short @f
;R37	call	Record_USB_Disabled
;R37	stc
;R37	jmp	short Usb_Init_Exit
;R37@@:
	jc	short Usb_Init_Exit		;R37
	call	Record_USB_Enabled		;R37

;R20	call	Allocate_Post_USBRAM
	call	Allocate_USBRAM			;R20
	call	Get_USBRAM
	mov	ds, ax
	mov	es, ax
;R45 - start
ifdef	USB_MOUSE_SUPPORT
	call	Ct_Check_USB_Disabled
	and	al, USBMSSUPPORT
	and	byte ptr bUsbFlag, not USBMSSUPPORT
	or	byte ptr bUsbFlag, al
endif	;USB_MOUSE_SUPPORT
;R45 - end

	call	Host_Init

	call	System_Control_Init

	call	Resume_Tasks

	call	Host_Run

	clc

Usb_Init_Exit:
	popad
	pop	es
	pop	ds
	ret
Usb_Init	endp

;[]========================================================================[]
;Procedure:	Usb_Final_Init
;Function:	Re-initialize USB for reallocating USB_RAM to shadow
;Input:		none
;Output:	none
;[]========================================================================[]

	public	Usb_Final_Init
Usb_Final_Init	proc	near
	push	ds
	push	es
	pushad

	call	Check_USB_Disabled
;R14A	jnz	short Usb_Final_Init_Exit
	jnz	Usb_Final_Init_Exit			;R14A

	call	Get_USBRAM
	mov	ds, ax
	mov	es, ax

;R20	call	Host_Stop

;R36 - start
ifdef	ACPI_SUPPORT
ifdef	S4_SUPPORT
	extrn	Check_S4_Resume:near
	F000_call	DGROUP:Check_S4_Resume
;R36A	jnz	short USB_KB_DISABLED
;R36A - start
	jz	short Usb_Final_Init_Cont
	call	Ct_Check_USB_Disabled
	jc	short USB_KB_DISABLED
ifdef	USB_MOUSE_SUPPORT			;R41
	push	ax				;R41
endif	;USB_MOUSE_SUPPORT			;R41
	call	Disable_Host
	jmp	short Usb_Final_Init_End
Usb_Final_Init_Cont:
;R36A - end
endif	;S4_SUPPORT
endif	;ACPI_SUPPORT
;R36 - end

;R11 - start
	call	Ct_Check_USB_Disabled
	jnc	short @f

USB_KB_DISABLED:				;R36

	call	Record_USB_Disabled
;R36A	call	Host_Stop			;R20
;R36A	call	Host_Reset			;R14host controller reset
;R36A	mov	cx, wHostID
;R36A	add	cx, LEGACY_LO
;R36A	F000_CALL	Get_Pci
;R36Aifdef	IOTRAP_SUPPORT				;R22A
;R36A	and	al, not (USBSMIEN+0Fh)		;R22A
;R36Aelse	;IOTRAP_SUPPORT				;R22A
;R36A	and	al, not USBSMIEN
;R36Aendif	;IOTRAP_SUPPORT				;R22A
;R36A	F000_CALL	Set_Pci
;R36A	mov	cx, wHostID
;R36A	add	cx, LEGACY_HI
;R36A	F000_CALL	Get_Pci
;R36A	or	al, USBPIRQDEN
;R36A	F000_CALL	Set_Pci
;R36A	mov	ax, 0FFFFh			;clear all pending status
;R36A	mov	dx, USBSTS
;R36A	call	Set_Host_Word
	call	Disable_Host			;R36A
	call	Close_USBRAM			;R20
	jmp	short Usb_Final_Init_Exit
@@:
ifdef	USB_MOUSE_SUPPORT			;R41
	push	ax				;R41
endif	;USB_MOUSE_SUPPORT			;R41
;R11 - end
Usb_Final_Init_End:				;R36A
;R41 - start
ifdef	USB_MOUSE_SUPPORT
	pop	ax
;R46	and	al, USBKBSUPPORT+USBMSSUPPORT
	and	al, USBKBSUPPORT		;R46
	or	al, REMOVEDEV			;R41D
;R46	and	byte ptr bUsbFlag, not (USBKBSUPPORT+USBMSSUPPORT)
	and	byte ptr bUsbFlag, not USBKBSUPPORT	;R46
	or	byte ptr bUsbFlag, al
;R41D	test	al, USBKBSUPPORT
;R41D	jnz	short Check_Ms_Support
;R41D	push	ax
;R41D	call	Remove_KbTask
;R41D	pop	ax
;R41DCheck_Ms_Support:
;R41D;R41A	test	al, USBKBSUPPORT
;R41D	test	al, USBMSSUPPORT		;R41A
;R41D	jnz	short Check_Support_Exit
;R41D	call	Remove_MsTask
;R41DCheck_Support_Exit:
else	;USB_MOUSE_SUPPORT
	or	byte ptr bUsbFlag, USBKBSUPPORT
endif	;USB_MOUSE_SUPPORT
;R41 - end

;R20	call	Allocate_USBRAM
;R20	call	Get_USBRAM
;R03 - start
ifdef	PNP_BIOS
	xor	edi,edi
;R20	mov	di,ax
	mov	di,ds				;R20
	shl	edi,4
ifndef	SMIHANDLE_IN_XGROUP			;R30
	call	Build_UsbRamNode	;build device node for USB RAM
else	;SMIHANDLE_IN_XGROUP			;R30
	POST_func_call	EGROUP:Build_UsbRamNode	;R30
endif	;SMIHANDLE_IN_XGROUP			;R30
endif;	PNP_BIOS
;R03 - start
;R20	mov	ds, ax
;R20	mov	es, ax
;R20
;R20	call	Host_Init
;R20
;R20	call	System_Control_Init
;R20
;R20	call	Resume_Tasks
;R20
;R20	call	Host_Run

Usb_Final_Init_Exit:
	popad
	pop	es
	pop	ds
	ret
Usb_Final_Init	endp

;R36A - start
;[]========================================================================[]
;Procedure:	Disable_Host
;Function:	Disable host controller for legacy supporting
;		No data is recorded in USBRAM
;Input:		none
;Output:	none
;[]========================================================================[]

Disable_Host	proc	near
	call	Host_Stop			;R20
	call	Host_Reset			;R14host controller reset
	mov	cx, wHostID
	add	cx, LEGACY_LO
	F000_CALL	Get_Pci
ifdef	IOTRAP_SUPPORT				;R22A
;R44	and	al, not (USBSMIEN+0Fh)		;R22A
	and	al, not (USBSMIEN+A20PASSEN+0Fh)	;R44
else	;IOTRAP_SUPPORT				;R22A
	and	al, not USBSMIEN
endif	;IOTRAP_SUPPORT				;R22A
	F000_CALL	Set_Pci
	mov	cx, wHostID
	add	cx, LEGACY_HI
	F000_CALL	Get_Pci
	or	al, USBPIRQDEN
	F000_CALL	Set_Pci
	mov	ax, 0FFFFh			;clear all pending status
	mov	dx, USBSTS
	call	Set_Host_Word
	ret
Disable_Host	endp
;R36A - end

;[]========================================================================[]
;Procedure:	Report_USB_Keyboard
;Function:	Report the status of the USB keyboard's existence.
;Input:		none
;Output:	CF = 0 USB keyboard presented
;		CF = 1 no USB keyboard presented
;[]========================================================================[]
	public	Report_USB_Keyboard
Report_USB_Keyboard	proc	near
	pushad
	push	ds

	call	Check_USB_Disabled		;host or legacy support disabled?
	jnz	short Report_USB_Fail

	call	Get_USBRAM
	mov	ds, ax

	test	word ptr ds:wKbdDevMap, 0FFFFh	;keyboard present?
	jz	short Report_USB_Fail

	clc					;keyboard present
	jmp	short Report_USB_Exit

Report_USB_Fail:
	stc					;keyboard absent

Report_USB_Exit:
	pop	ds
	popad
	ret
Report_USB_Keyboard	endp

;R46 - start
;[]========================================================================[]
;Procedure:	Determine_Mouse_Trap
;Function:	Determine if to trap PS/2 mouse command before "Ms_Instal".
;Input:		none
;Output:	none
;[]========================================================================[]
	public	Determine_Mouse_Trap
Determine_Mouse_Trap	proc	near
	pushad
	push	ds

	call	Check_USB_Disabled		;host or legacy support disabled?
	jnz	short Determine_Mouse_Trap_Exit

	call	Get_USBRAM
	mov	ds, ax

	call	Ct_Check_USB_Disabled

	and	byte ptr bUsbFlag, not USBMSSUPPORT

	and	al, USBMSSUPPORT		;usb mouse support enabled?
	jz	short Determine_Mouse_Trap_Exit

	test	word ptr ds:wMsDevMap, 0FFFFh	;mouse present?
	jz	short Determine_Mouse_Trap_Exit

	or	bUsbFlag, al			;trap command enabled

Determine_Mouse_Trap_Exit:

	pop	ds
	popad
	ret
Determine_Mouse_Trap	endp

;[]========================================================================[]
;Procedure:	Report_USB_Mouse_Support
;Function:	Report the status of the USB mouse's supporting.
;Input:		none
;Output:	CF = 0 USB mouse support
;		CF = 1 no USB mouse support
;[]========================================================================[]
	public	Report_USB_Mouse_Support
Report_USB_Mouse_Support	proc	near
	pushad
	push	ds

	call	Check_USB_Disabled		;host or legacy support disabled?
	jnz	short Report_USB_Mouse_Fail

	call	Get_USBRAM
	mov	ds, ax

	call	Ct_Check_USB_Disabled
	and	al, USBMSSUPPORT		;usb mouse support enabled
	and	byte ptr bUsbFlag, not USBMSSUPPORT
	or	byte ptr bUsbFlag, al
	test	al, USBMSSUPPORT
	jz	short Report_USB_Mouse_Fail

	clc					;mouse present
	jmp	short Report_USB_Mouse_Exit

Report_USB_Mouse_Fail:
	stc					;mouse absent

Report_USB_Mouse_Exit:
	pop	ds
	popad
	ret
Report_USB_Mouse_Support	endp
;R46 - end

;[]========================================================================[]
;Procedure:	Record_USB_Disabled
;Function:	Record USB legacy support disabled to USB_STATUS
;Input:		none
;Output:	none
;[]========================================================================[]

Record_USB_Disabled	proc	near
	push	ds
	push	ax

	F000_CALL	F000_Shadow_W
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	mov	al, 01
	or	ds:USB_STATUS, al
	F000_CALL	F000_Shadow_R

	pop	ax
	pop	ds
	assume	ds:USB_RAM
	ret
Record_USB_Disabled	endp

;R37 - start
;[]========================================================================[]
;Procedure:	Record_USB_Enabled
;Function:	Record USB legacy support enabled to USB_STATUS
;Input:		none
;Output:	none
;[]========================================================================[]

Record_USB_Enabled	proc	near
	push	ds
	push	ax

	F000_CALL	F000_Shadow_W
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	mov	al, 0FEh
	and	ds:USB_STATUS, al
	F000_CALL	F000_Shadow_R

	pop	ax
	pop	ds
	assume	ds:USB_RAM
	ret
Record_USB_Enabled	endp
;R37 - end

;[]========================================================================[]
;Procedure:	Allocate_Post_USBRAM
;Function:	Allocate USB_RAM for POST usage
;Input:		none
;Output:	none
;[]========================================================================[]

;R20Allocate_Post_USBRAM	proc	near
;R20	push	es
;R20	push	ds
;R20	pushad
;R20
;R20	mov	ax, 9000h
;R20
;R20	call	Record_USBRAM
;R20
;R20	mov	ds, ax
;R20	mov	es, ax
;R20	call	Init_USBRAM
;R20
;R20	popad
;R20	pop	ds
;R20	pop	es
;R20	ret
;R20Allocate_Post_USBRAM	endp

;[]========================================================================[]
;Procedure:	Allocate_USBRAM
;Function:	Allocate USB_RAM for run-time usage, may be shadow RAM or
;		base memory.
;Input:		none
;Output:	none
;[]========================================================================[]

Allocate_USBRAM	proc	near
	push	ds
	push	es
	pushad

	mov	eax, LMEM_RESOURCE[bp]
;R20	mov	dx, 0C800h
;R31	mov	dx, 0DC00h			;R20;start from DC00h
;R31	mov	edi, 00F00000h			;R20;mask value
	mov	dx, 0C800h			;R31;start from C800h
	mov	edi, 0000000Fh			;R31;mask value
	mov	cx, 6
@@:
;R20	test	al, 0Fh
	test	eax, edi			;R20
	jz	short Use_Shadow
;R20	shr	eax, 4
;R20	add	dx, 400h
;R31	shr	edi, 4				;R20
;R31	sub	dx, 400h			;R20;next backward 16KB
	shl	edi, 4				;R31
	add	dx, 400h			;R31;next upward 16KB
	loop	short @b

Use_Base_Mem:
	mov	ax, G_RAM
	mov	ds, ax
	assume	ds:G_RAM
	mov	ax, ds:SIZE_SYSRAM
	sub	ax, 8				;top 8K basemem as temp USBRAM
	and	ax, 0FFFCh			;4K boundary
	mov	ds:SIZE_SYSRAM, ax
	shl	ax, 6				;translate to segment address
	jmp	short Move_USB_RAM

Use_Shadow:
	or	LMEM_RESOURCE[bp], edi		;R20
	mov	LMEM_RESERVED[bp], edi		;R20
;R48 - starts
ifdef	SHADOW_UNIT_64K
	cmp	dh, 0D0h
;R51	ja	short USB_RAM_At_D
	jae	short USB_RAM_At_D		;R51
	push	dx
	F000_call C000_Shadow_RW
	pop	ax
	jmp	short Move_USB_RAM
USB_RAM_At_D:
endif	;SHADOW_UNIT_64K
;R48 - ends
	push	dx
	F000_CALL	Ct_Shadow_RW
	pop	ax

Move_USB_RAM:
	call	Record_USBRAM

	mov	ds, ax
	mov	es, ax
	call	Init_USBRAM

	popad
	pop	es
	pop	ds
	ret
Allocate_USBRAM	endp

;[]========================================================================[]
;Procedure:	Record_USBRAM
;Function:	Record USB_RAM segment address to USB_RAM_SEG at F000 segment.
;Input:		AX = segment address
;Output:	none
;[]========================================================================[]

Record_USBRAM	proc	near
	push	ds
	push	ax

	push	ax
	F000_CALL	F000_Shadow_W
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	pop	ax
	mov	ds:USB_RAM_SEG, ax
	F000_CALL	F000_Shadow_R

	pop	ax
	pop	ds
	assume	ds:USB_RAM
	ret
Record_USBRAM	endp

;R20 - start
;[]========================================================================[]
;Procedure:	Close_USBRAM
;Function:	Close USB_RAM if Shadow RAM
;Input:		DS = point to USB_RAM
;Output:	none
;[]========================================================================[]

Close_USBRAM:
	mov	dx, ds
	cmp	dx, 0A000h			;base memory?
	jb	short Close_USBRAM_Exit
;R32 - start
	mov	cl, dh
	sub	cl, 0C8h
	mov	edi, 0FFFFFFF0h
	rol	edi, cl
	and	LMEM_RESOURCE[bp], edi
	and	LMEM_RESERVED[bp], edi
;R32 - end
	F000_call	Ct_Disable_Shadow
Close_USBRAM_Exit:
	ret
;R20 - end

;************************************************************************
;*									*
;*	UHCI POST INTERFACE MODULE					*
;*									*
;************************************************************************

;[]========================================================================[]
;Procedure:	Init_USBRAM
;Function:	Initialize USB_RAM to default value
;Input:		DS,ES=USB_RAM
;Output:	none
;[]========================================================================[]

Init_USBRAM:
;R08	xor	ax, ax
;R08	mov	cx, 1000h
;R08	xor	di, di
;R08	rep	stosw
	mov	cx, 2000h			;R08
	xor	si, si				;R08
	call	Clear_Buffer			;R08

;R21 - start
;set the upper 8Kb content of shadow RAM to prevent SCT testing error
	push	es
	push	di
	mov	ax,ds
	mov	es,ax
	mov	ax,0ffffh		;pattern to fill
	mov	di,2000h		;start from 8Kb address
	mov	cx,2000h		;8Kb to fill
;R21A	rep	stosw
	rep	stosb			;R21A
	pop	di	
	pop	es
;R21 - end

ifndef	PATACH_AMIDIAG				;R42
	mov	word ptr ds:[0], 0AA55h
endif	;PATACH_AMIDIAG				;R42
	mov	word ptr ds:[2], 0CB10h
	mov	dword ptr ds:[4], 'BSU$'

	mov	ax, ds
	shl	eax, 4
	mov	ds:dUsbRamAddr, eax
	add	eax, offset FrameList
	mov	ds:dFrameListAddr, eax

	call	Init_FL

	mov	word ptr wTaskLink, 0FFFFh	;task terminated
	mov	word ptr DevAddrMap+2, 0080h	;root hub device

;R39 - start
	mov	byte ptr bDelayRate,  31	;default typematic delay
	mov	byte ptr bRepeatRate, 6		;default typematic repeat rate

	mov	bUsbFlag, USBKBSUPPORT+USBMSSUPPORT	;R41
	mov	bDevCtrl, MSDISABLE			;R41

ifdef	IOTRAP_SUPPORT
	mov	bMsStatus1, 0FAh		;dummy code
	mov	bMsDataPacket1, 0FAh		;dummy code

	mov	bMsStatus, 00h			;stream mode
						;disabled
						;scaling 1:1
						;no mouse button pressed
	mov	bResolution, 02h		;4 counts/mm resolution
	mov	bSampleRate, 64h		;100 times/s sample rate

	mov	bCipFlag, 0
	mov	bEmuCmdByte, 65h		;emulated commnad byte
	mov	bRealCmdByte, 65h		;physical command byte
	mov	bTrapEnabled, TRAPENABLE
	mov	wKcCmdProc, offset NullProc SMI_OFFSET
	mov	wKbCmdProc, offset NullProc SMI_OFFSET
	mov	wMsCmdProc, offset NullProc SMI_OFFSET
ENDIF	;IOTRAP_SUPPORT
;R39 - end

	ret

;[]========================================================================[]
;Procedure:	System_Control_Init
;Function:	Initialize system control task
;Input:		none
;Output:	none
;[]========================================================================[]

System_Control_Init:

	; Initialize Root Hub task

	xor	ax, ax
	mov	wPort1Status, ax
	mov	wPort2Status, ax
	mov	bLedStatus, al

	mov	si, offset SysCtrlQH
	call	Init_QH
	mov	si, offset SysCtrlTD
	call	Init_TD
	or	byte ptr [si].bTdControl, ISS_IOC

	mov	si, offset SysCtrlTask
	call	Init_Task
	mov	byte ptr [si].bTkDevStatus, TK_WFP
	mov	byte ptr [si].bTkDevAddr, 1
;R02	mov	word ptr [si].wTkInterval, 512
	mov	word ptr [si].wTkInterval, 1024			;R02
	mov	word ptr [si].wTkQueueHead, offset SysCtrlQH
	mov	word ptr [si].wTkTransDesp, offset SysCtrlTD
	mov	word ptr [si].wTkProc, offset System_Control SMI_OFFSET
	call	Link_Task

;R06 - start
	; Initialize Timer task, and no link at this stage until
	; the USB keyboard is attached.

	mov	si, offset TimerQH
	call	Init_QH
	mov	si, offset TimerTD
	call	Init_TD
;R47	or	byte ptr [si].bTdControl, ISS_IOC
	call	Init_TimerTD				;R47

	mov	si, offset TimerTask
	call	Init_Task
	mov	byte ptr [si].bTkDevStatus, TK_WFP
	mov	byte ptr [si].bTkDevAddr, 1
;R41	mov	word ptr [si].wTkInterval, 64
	mov	word ptr [si].wTkInterval, 16		;R41
	mov	word ptr [si].wTkQueueHead, offset TimerQH
	mov	word ptr [si].wTkTransDesp, offset TimerTD
	mov	word ptr [si].wTkProc, offset Proc_Timer SMI_OFFSET
;R06 - end

;R50 - start
ifdef   IOTRAP_SUPPORT
        ; Initialize Response task, and no link at this stage until
        ; the keyboard command process need respond to system.

        mov     si, offset ResponseQH
        call    Init_QH
        mov     [si].wQhInterval, 4                     ;2ms interval
        call    Link_QH_to_FL
        mov     si, offset ResponseTD
        call    Init_TD
        call    Init_ResponseTD
        mov     di, offset ResponseQH
        mov     si, offset ResponseTD
        call    Link_TD_to_QH

        mov     si, offset ResponseTask
        call    Init_Task
        mov     byte ptr [si].bTkDevStatus, TK_WFP
        mov     byte ptr [si].bTkDevAddr, 1             ;dummy device address
        mov     word ptr [si].wTkInterval, 4            ;2ms interval
        mov     word ptr [si].wTkQueueHead, offset ResponseQH
        mov     word ptr [si].wTkTransDesp, offset ResponseTD
        mov     word ptr [si].wTkProc, offset Proc_Response SMI_OFFSET
endif   ;IOTRAP_SUPPORT
;R50 - end

	; Link Control Transfer Queue Head for future using
	; and no TD link

	mov	si, offset ControlQH
	call	Init_QH
	mov	word ptr [si].wQhInterval, 1
	call	Link_QH_to_FL

	ret

;[]========================================================================[]
;Procedure:	Host_Init
;Function:	Initialize host controller
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Init:

	call	Ct_USB_ID
	mov	wHostID, ax

;R38 - start
	; Turn on bus master and io space decoding,
	; avoid that these two bits are not turn-on
	; by PCI kernel.
	mov	cx, wHostID
	add	cx, 4				;command register
	F000_call	Get_PCI
	or	al, 00000111b			;bus master/io space
	F000_call	Set_PCI
;R38 - end

	mov	cx, wHostID
	add	cx, LEGACY_LO
	F000_call	Get_PCI
ifdef	IOTRAP_SUPPORT				;R22A
;R39	or	al, USBSMIEN+0Fh		;R22A;Enable Trap/SMI on USB IRQ
	or	al, USBSMIEN+A20PASSEN+TRAPENABLE	;R39;Enable SMI
else	;IOTRAP_SUPPORT				;R22A
	or	al, USBSMIEN			;Enable Trap/SMI on USB IRQ
endif	;IOTRAP_SUPPORT				;R22A
	F000_call	Set_PCI

	mov	cx, wHostID
	add	cx, (USBBASE+1)
	F000_call	Get_PCI
	push	ax
	mov	cx, wHostID
	add	cx, USBBASE
	F000_call	Get_PCI
	pop	dx
	mov	ah, dl
	and	al, 0FCh
	mov	ds:wHostIoBase, ax

	; Global Reset

	call	Global_Reset

	; Clear USB Status Register

	mov	ax, 0FFFFh			;write clear
	mov	dx, USBSTS
	call	Set_Host_Word

	; USB Interrupt Enable Register

	mov	ax, IOC				;interrupt on complete
	mov	dx, USBINTR
	call	Set_Host_Word

	; Frame Number Register

	mov	ax, 0				;Starting from frame 0
	mov	dx, FRNUM
	call	Set_Host_Word

	; Frame List Base Address Register

	mov	ax, ds
	shl	eax, 4
	add	eax, offset FrameList
	mov	dx, FRBASEADD
	call	Set_Host_Dword

	ret

;[]========================================================================[]
;Procedure:	Global_Reset
;Function:	Global host controller reset
;Input:		none
;Output:	none
;[]========================================================================[]

Global_Reset:
	pusha

	; Issue global reset and set maximum packet size to 64

	mov	al, GRESET+MAX_PACKET		;Global reset/max packet=64
	mov	dx, USBCMD
	call	Set_Host_Byte

	; Minimum delay time 10ms

	call	Delay_12ms

	; Clear reset signal

	mov	al, MAX_PACKET			;max packet=64
	mov	dx, USBCMD
	call	Set_Host_Byte

	popa
	ret

;R14 - start
;[]========================================================================[]
;Procedure:	Host_Reset
;Function:	Host controller reset
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Reset:
	pusha

	; Issue host controller reset

	mov	al, HCRESET			;Host controller reset
	mov	dx, USBCMD
	call	Set_Host_Byte

	popa
	ret
;R14 - end

;R35 - start
else	;SMIHANDLE_IN_YGROUP
;[]========================================================================[]
;Procedure:	Usb_Init
;Function:	USB initialization
;Input:		none
;Output:	none
;[]========================================================================[]

	public	Usb_Init
Usb_Init	proc	near
	push	ds
	push	es
	pushad

	call	Ct_USB_Init
;R37	jnc	short @f
;R37	call	Record_USB_Disabled
;R37	stc
;R37	jmp	short Usb_Init_Exit
;R37@@:
	jc	short Usb_Init_Exit		;R37
	call	Record_USB_Enabled		;R37

	call	Allocate_USBRAM			
	call	Ex_Get_USBRAM
	mov	ds, ax
	mov	es, ax

	call	Host_Init

	call	System_Control_Init

	call	Ex_Resume_Tasks	

	call	Ex_Host_Run			

	clc

Usb_Init_Exit:
	popad
	pop	es
	pop	ds
	ret
Usb_Init	endp

;[]========================================================================[]
;Procedure:	Usb_Final_Init
;Function:	Re-initialize USB for reallocating USB_RAM to shadow
;Input:		none
;Output:	none
;[]========================================================================[]

	public	Usb_Final_Init
Usb_Final_Init	proc	near
	push	ds
	push	es
	pushad

	call	Ex_Check_USB_Disabled		
	jnz	Usb_Final_Init_Exit

	call	Ex_Get_USBRAM			
	mov	ds, ax
	mov	es, ax

	call	Ct_Check_USB_Disabled
	jnc	short @f
	call	Record_USB_Disabled
	call	Ex_Host_Stop			
	call	Host_Reset			;host controller reset
	mov	cx, wHostID
	add	cx, LEGACY_LO
	F000_CALL	Get_Pci
ifdef	IOTRAP_SUPPORT				
	and	al, not (USBSMIEN+0Fh)		
else	;IOTRAP_SUPPORT				
	and	al, not USBSMIEN
endif	;IOTRAP_SUPPORT				
	F000_CALL	Set_Pci
	mov	cx, wHostID
	add	cx, LEGACY_HI
	F000_CALL	Get_Pci
	or	al, USBPIRQDEN
	F000_CALL	Set_Pci
	mov	ax, 0FFFFh			;clear all pending status
	mov	dx, USBSTS
	call	Ex_Set_Host_Word		
	call	Close_USBRAM			
	jmp	short Usb_Final_Init_Exit
@@:

ifdef	PNP_BIOS
	xor	edi,edi
	mov	di,ds
	shl	edi,4
ifndef	SMIHANDLE_IN_XGROUP
	call	Build_UsbRamNode	;build device node for USB RAM
else	;SMIHANDLE_IN_XGROUP		
	POST_func_call	Build_UsbRamNode
endif	;SMIHANDLE_IN_XGROUP		
endif;	PNP_BIOS

Usb_Final_Init_Exit:
	popad
	pop	es
	pop	ds
	ret
Usb_Final_Init	endp

;[]========================================================================[]
;Procedure:	Report_USB_Keyboard
;Function:	Report the status of the USB keyboard's existence.
;Input:		none
;Output:	CF = 0 USB keyboard presented
;		CF = 1 no USB keyboard presented
;[]========================================================================[]
	public	Report_USB_Keyboard
Report_USB_Keyboard	proc	near
	pushad
	push	ds

	call	Ex_Check_USB_Disabled		;host or legacy support disabled?
	jnz	short Report_USB_Fail

	call	Ex_Get_USBRAM			
	mov	ds, ax

	test	word ptr ds:wKbdDevMap, 0FFFFh	;keyboard present?
	jz	short Report_USB_Fail

	clc					;keyboard present
	jmp	short Report_USB_Exit

Report_USB_Fail:
	stc					;keyboard absent

Report_USB_Exit:
	pop	ds
	popad
	ret
Report_USB_Keyboard	endp

;[]========================================================================[]
;Procedure:	Record_USB_Disabled
;Function:	Record USB legacy support disabled to USB_STATUS
;Input:		none
;Output:	none
;[]========================================================================[]

Record_USB_Disabled	proc	near
	push	ds
	push	ax

	F000_CALL	F000_Shadow_W
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	mov	al, 01
	or	ds:USB_STATUS, al
	F000_CALL	F000_Shadow_R

	pop	ax
	pop	ds
	assume	ds:USB_RAM
	ret
Record_USB_Disabled	endp

;R37 - start
;[]========================================================================[]
;Procedure:	Record_USB_Enabled
;Function:	Record USB legacy support enabled to USB_STATUS
;Input:		none
;Output:	none
;[]========================================================================[]

Record_USB_Enabled	proc	near
	push	ds
	push	ax

	F000_CALL	F000_Shadow_W
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	mov	al, 0FEh
	and	ds:USB_STATUS, al
	F000_CALL	F000_Shadow_R

	pop	ax
	pop	ds
	assume	ds:USB_RAM
	ret
Record_USB_Enabled	endp
;R37 - end

;[]========================================================================[]
;Procedure:	Allocate_USBRAM
;Function:	Allocate USB_RAM for run-time usage, may be shadow RAM or
;		base memory.
;Input:		none
;Output:	none
;[]========================================================================[]

Allocate_USBRAM	proc	near
	push	ds
	push	es
	pushad

	mov	eax, LMEM_RESOURCE[bp]
	mov	dx, 0C800h			;start from C800h
	mov	edi, 0000000Fh			;mask value
	mov	cx, 6
@@:
	test	eax, edi
	jz	short Use_Shadow
	shl	edi, 4				
	add	dx, 400h			;next upward 16KB
	loop	short @b

Use_Base_Mem:
	mov	ax, G_RAM
	mov	ds, ax
	assume	ds:G_RAM
	mov	ax, ds:SIZE_SYSRAM
	sub	ax, 8				;top 8K basemem as temp USBRAM
	and	ax, 0FFFCh			;4K boundary
	mov	ds:SIZE_SYSRAM, ax
	shl	ax, 6				;translate to segment address
	jmp	short Move_USB_RAM

Use_Shadow:
	or	LMEM_RESOURCE[bp], edi		
	mov	LMEM_RESERVED[bp], edi		
	push	dx
	F000_CALL	Ct_Shadow_RW
	pop	ax

Move_USB_RAM:
	call	Record_USBRAM

	mov	ds, ax
	mov	es, ax
	call	Init_USBRAM

	popad
	pop	es
	pop	ds
	ret
Allocate_USBRAM	endp

;[]========================================================================[]
;Procedure:	Record_USBRAM
;Function:	Record USB_RAM segment address to USB_RAM_SEG at F000 segment.
;Input:		AX = segment address
;Output:	none
;[]========================================================================[]

Record_USBRAM	proc	near
	push	ds
	push	ax

	push	ax
	F000_CALL	F000_Shadow_W
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	pop	ax
	mov	ds:USB_RAM_SEG, ax
	F000_CALL	F000_Shadow_R

	pop	ax
	pop	ds
	assume	ds:USB_RAM
	ret
Record_USBRAM	endp

;[]========================================================================[]
;Procedure:	Close_USBRAM
;Function:	Close USB_RAM if Shadow RAM
;Input:		DS = point to USB_RAM
;Output:	none
;[]========================================================================[]

Close_USBRAM:
	mov	dx, ds
	cmp	dx, 0A000h			;base memory?
	jb	short Close_USBRAM_Exit
	mov	cl, dh
	sub	cl, 0C8h
	mov	edi, 0FFFFFFF0h
	rol	edi, cl
	and	LMEM_RESOURCE[bp], edi
	and	LMEM_RESERVED[bp], edi
	F000_call	Ct_Disable_Shadow
Close_USBRAM_Exit:
	ret

;************************************************************************
;*									*
;*	UHCI POST INTERFACE MODULE					*
;*									*
;************************************************************************

;[]========================================================================[]
;Procedure:	Init_USBRAM
;Function:	Initialize USB_RAM to default value
;Input:		DS,ES=USB_RAM
;Output:	none
;[]========================================================================[]

Init_USBRAM:
	mov	cx, 2000h			
	xor	si, si				
	call	Ex_Clear_Buffer			

;set the upper 8Kb content of shadow RAM to prevent SCT testing error
	push	es
	push	di
	mov	ax,ds
	mov	es,ax
	mov	ax,0ffffh		;pattern to fill
	mov	di,2000h		;start from 8Kb address
	mov	cx,2000h		;8Kb to fill
	rep	stosw
	pop	di	
	pop	es

	mov	word ptr ds:[0], 0AA55h
	mov	word ptr ds:[2], 0CB10h
	mov	dword ptr ds:[4], 'BSU$'

	mov	ax, ds
	shl	eax, 4
	mov	ds:dUsbRamAddr, eax
	add	eax, offset FrameList
	mov	ds:dFrameListAddr, eax

	call	Ex_Init_FL			

	mov	word ptr wTaskLink, 0FFFFh	;task terminated
	mov	word ptr DevAddrMap+2, 0080h	;root hub device

;R39 - start
	mov	byte ptr bDelayRate,  31	;default typematic delay
	mov	byte ptr bRepeatRate, 6		;default typematic repeat rate

	mov	bUsbFlag, USBKBSUPPORT+USBMSSUPPORT	;R41
	mov	bDevCtrl, MSDISABLE			;R41

ifdef	IOTRAP_SUPPORT
	mov	bMsStatus1, 0FAh		;dummy code
	mov	bMsDataPacket1, 0FAh		;dummy code

	mov	bMsStatus, 00h			;stream mode
						;disabled
						;scaling 1:1
						;no mouse button pressed
	mov	bResolution, 02h		;4 counts/mm resolution
	mov	bSampleRate, 64h		;100 times/s sample rate

	mov	bCipFlag, 0
	mov	bEmuCmdByte, 65h		;emulated commnad byte
	mov	bRealCmdByte, 65h		;physical command byte
	mov	bTrapEnabled, TRAPENABLE
	mov	wKcCmdProc, offset NullProc SMI_OFFSET
	mov	wKbCmdProc, offset NullProc SMI_OFFSET
	mov	wMsCmdProc, offset NullProc SMI_OFFSET
ENDIF	;IOTRAP_SUPPORT
;R39 - end

	ret

;[]========================================================================[]
;Procedure:	System_Control_Init
;Function:	Initialize system control task
;Input:		none
;Output:	none
;[]========================================================================[]

System_Control_Init:

	; Initialize Root Hub task

	xor	ax, ax
	mov	wPort1Status, ax
	mov	wPort2Status, ax
	mov	bLedStatus, al

	mov	si, offset SysCtrlQH
	call	Ex_Init_QH			
	mov	si, offset SysCtrlTD
	call	Ex_Init_TD			
	or	byte ptr [si].bTdControl, ISS_IOC

	mov	si, offset SysCtrlTask
	call	Ex_Init_Task			
	mov	byte ptr [si].bTkDevStatus, TK_WFP
	mov	byte ptr [si].bTkDevAddr, 1
	mov	word ptr [si].wTkInterval, 1024	
	mov	word ptr [si].wTkQueueHead, offset SysCtrlQH
	mov	word ptr [si].wTkTransDesp, offset SysCtrlTD
	mov	word ptr [si].wTkProc, offset System_Control SMI_OFFSET
	call	Ex_Link_Task			

	; Initialize Timer task, and no link at this stage until
	; the USB keyboard is attached.

	mov	si, offset TimerQH
	call	Ex_Init_QH			
	mov	si, offset TimerTD
	call	Ex_Init_TD			
	or	byte ptr [si].bTdControl, ISS_IOC

	mov	si, offset TimerTask
	call	Ex_Init_Task			
	mov	byte ptr [si].bTkDevStatus, TK_WFP
	mov	byte ptr [si].bTkDevAddr, 1
;R41	mov	word ptr [si].wTkInterval, 64
	mov	word ptr [si].wTkInterval, 16		;R41
	mov	word ptr [si].wTkQueueHead, offset TimerQH
	mov	word ptr [si].wTkTransDesp, offset TimerTD
	mov	word ptr [si].wTkProc, offset Proc_Timer SMI_OFFSET

	; Link Control Transfer Queue Head for future using
	; and no TD link

	mov	si, offset ControlQH
	call	Ex_Init_QH			
	mov	word ptr [si].wQhInterval, 1
	call	Ex_Link_QH_to_FL		

	ret

;[]========================================================================[]
;Procedure:	Host_Init
;Function:	Initialize host controller
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Init:

	call	Ct_USB_ID
	mov	wHostID, ax

	mov	cx, wHostID
	add	cx, LEGACY_LO
	F000_call	Get_PCI
ifdef	IOTRAP_SUPPORT				
;R39	or	al, USBSMIEN+0Fh		;Enable Trap/SMI on USB IRQ
	or	al, USBSMIEN+A20PASSEN+TRAPENABLE	;R39;Enable SMI
else	;IOTRAP_SUPPORT				
	or	al, USBSMIEN			;Enable Trap/SMI on USB IRQ
endif	;IOTRAP_SUPPORT				
	F000_call	Set_PCI

	mov	cx, wHostID
	add	cx, (USBBASE+1)
	F000_call	Get_PCI
	push	ax
	mov	cx, wHostID
	add	cx, USBBASE
	F000_call	Get_PCI
	pop	dx
	mov	ah, dl
	and	al, 0FCh
	mov	ds:wHostIoBase, ax

	; Global Reset

	call	Global_Reset

	; Clear USB Status Register

	mov	ax, 0FFFFh			;write clear
	mov	dx, USBSTS
	call	Ex_Set_Host_Word		

	; USB Interrupt Enable Register

	mov	ax, IOC				;interrupt on complete
	mov	dx, USBINTR
	call	Ex_Set_Host_Word		

	; Frame Number Register

	mov	ax, 0				;Starting from frame 0
	mov	dx, FRNUM
	call	Ex_Set_Host_Word		

	; Frame List Base Address Register

	mov	ax, ds
	shl	eax, 4
	add	eax, offset FrameList
	mov	dx, FRBASEADD
	call	Ex_Set_Host_Dword		

	ret

;[]========================================================================[]
;Procedure:	Global_Reset
;Function:	Global host controller reset
;Input:		none
;Output:	none
;[]========================================================================[]

Global_Reset:
	pusha

	; Issue global reset and set maximum packet size to 64

	mov	al, GRESET+MAX_PACKET		;Global reset/max packet=64
	mov	dx, USBCMD
	call	Ex_Set_Host_Byte		

	; Minimum delay time 10ms

	call	Ex_Delay_12ms			

	; Clear reset signal

	mov	al, MAX_PACKET			;max packet=64
	mov	dx, USBCMD
	call	Ex_Set_Host_Byte		

	popa
	ret

;[]========================================================================[]
;Procedure:	Host_Reset
;Function:	Host controller reset
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Reset:
	pusha

	; Issue host controller reset

	mov	al, HCRESET			;Host controller reset
	mov	dx, USBCMD
	call	Ex_Set_Host_Byte		

	popa
	ret

;[]========================================================================[]
;Procedure:	Ex_Init_FL
;Function:	Initialize Frame List
;Input:		none
;Output:	none
;[]========================================================================[]

Ex_Init_FL:
	pushad

	; Clear frame list

	mov	cx, 1024			;Number of entries
	xor	esi, esi
@@:
	mov	dword ptr FrameList[esi*4], T
        inc	esi
	loop	short @b

	popad
	ret

;[]========================================================================[]
;Procedure:	Ex_Init_QH
;Function:	Initialize Queue Head data block
;Input:		SI = point to queue head
;Output:	none
;[]========================================================================[]

Ex_Init_QH:
	pusha
	mov	cx, SIZE QH			
	call	Ex_Clear_Buffer			
	or	byte ptr [si].dQhLink, T
	or	byte ptr [si].dQhElement, T
	popa
	ret

;[]========================================================================[]
;Procedure:	Ex_Init_TD
;Function:	Initialize Transfer Descriptor data block
;Input:		SI = point to transfer descriptor
;Output:	none
;[]========================================================================[]

Ex_Init_TD:
	pusha
	mov	cx, SIZE TD			
	call	Ex_Clear_Buffer			
	or	byte ptr [si].dTdLink, T
	popa
	ret

;[]========================================================================[]
;Procedure:	Ex_Init_Task
;Function:	Initialize task data block
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Ex_Init_Task:
	pusha
	mov	cx, SIZE TASK			
	call	Ex_Clear_Buffer			
	popa
	ret

;[]========================================================================[]
;Procedure:	Ex_Link_Task
;Function:	Link (Append/Insert) one task to the Task Link
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Ex_Link_Task:
	pusha

;R40	or	byte ptr bUsbFlag, 04		;task link updated
	or	byte ptr bUsbFlag, TASKCHG	;R40;task link updated

	; Link Task to Task Chain

	mov	ax, [si].wTkInterval

	mov	cx, ax				;interval
	or	cx, cx				;avoid coding mistake
	jz	short Ex_Link_TK_Exit

	mov	di, offset wTaskLink		;task link point

Ex_Link_TK_Loop:
	cmp	word ptr [di].wTkLink, 0FFFFh
	je	short Ex_Link_TK_Append

	mov	bx, [di].wTkLink

	cmp	cx, [bx].wTkInterval
	jb	short Ex_Link_TK_Insert

	mov	di, bx
	jmp	short Ex_Link_TK_Loop

Ex_Link_TK_Insert:
	mov	ax, [di].wTkLink
	mov	[si].wTkLink, ax
	jmp	short Ex_Link_TK_Previous

Ex_Link_TK_Append:
	mov	word ptr [si].wTkLink, 0FFFFh	;terminate

Ex_Link_TK_Previous:
	mov	[di].wTkLink, si

	; Link Queue Head to Frame List

	mov	ax, [si].wTkInterval
	mov	di, [si].wTkTransDesp
	mov	si, [si].wTkQueueHead
	mov	[si].wQhInterval, ax
	call	Ex_Link_QH_to_FL

	test	word ptr wKbdDevMap, 0FFFFh
;R41	jz	short Ex_Link_TK_Exit
	jnz	short Ex_Link_Timer_Task	;R41
	test	word ptr wMsDevMap, 0FFFFh	;R41
	jz	short Ex_Link_TK_Exit		;R41
Ex_Link_Timer_Task:				;R41

;R40	test	bUsbFlag, 08
	test	bUsbFlag, TIMERINST		;R40;timer task installed?
	jnz	short Ex_Link_TK_Exit

;R40	or	bUsbFlag, 08
	or	bUsbFlag, TIMERINST		;R40;timer task installed
	mov	si, offset TimerTask
	call	Ex_Link_Task

Ex_Link_TK_Exit:
	popa
	ret

;[]========================================================================[]
;Procedure:	Ex_Link_QH_to_FL
;Function:	Link Queue Head to Fram List
;Input:		SI = point to QH
;Output:	none
;[]========================================================================[]

Ex_Link_QH_to_FL:
	pushad

	mov	ax, [si].wQhInterval

	mov	cx, ax				;interval
	or	cx, cx				;avoid coding mistake
	jz	short Ex_Link_QF_Exit
	xor	dx, dx				;frame point

Ex_Link_QF_Loop:
	push	dx

	mov	ax, 4
	mul	dx
	mov	di, offset FrameList
	add	di, ax

Ex_Link_QF_Check:
	mov	eax, [di].dQhLink		;link pointer

	test	al, T				;terminate
	jnz	short Ex_Link_QF_Append

	call	Ex_Physical_Offset			;get offset in USB_RAM
	mov	bx, ax

	cmp	si, bx
	je	short Ex_Link_QF_Next

	cmp	cx, [bx].wQhInterval
	jae	short Ex_Link_QF_Insert

	mov	di, bx				;next queue head address
	jmp	short Ex_Link_QF_Check

Ex_Link_QF_Insert:
	mov	eax, [di].dQhLink
	mov	[si].dQhLink, eax
	jmp	short Ex_Link_QF_Previous

Ex_Link_QF_Append:
	or	byte ptr [si].dQhLink, T	;terminate

Ex_Link_QF_Previous:
	mov	ax, si
	call	Ex_Physical_Linear
	or	al, Q				;queue head
	and	al, not T			;no terminate
	mov	[di].dQhLink, eax

Ex_Link_QF_Next:
	pop	dx

	add	dx, cx				;next interval
	cmp	dx, 1024			;maximum interval
	jb	short Ex_Link_QF_Loop

Ex_Link_QF_Exit:
	popad
	ret

;[]========================================================================[]
;Procedure:	Ex_Link_TD_to_QH
;Function:	Link Transfer Descriptor to Queue Head
;Input:		SI = point to TD
;		DI = point to QH
;Output:	none
;[]========================================================================[]

Ex_Link_TD_to_QH:
	push	eax
	mov	ax, si
	call	Ex_Physical_Linear
	mov	[di].dQhElement, eax
	pop	eax
	ret

;[]========================================================================[]
;Procedure:	Ex_Check_USB_Disabled
;Function:	Check USB legacy support disabled either by device disabled
;		or by setup disabled.
;Input:		none
;Output:	ZF = 0 enabled
;		ZF = 1 disabled
;[]========================================================================[]

Ex_Check_USB_Disabled	proc	near
	push	ds
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	test	byte ptr ds:USB_STATUS, 01
	pop	ds
	assume	ds:USB_RAM
	ret
Ex_Check_USB_Disabled	endp

;[]========================================================================[]
;Procedure:	Ex_Clear_Buffer
;Function:	Clear miscellaneous data buffer
;Input:		SI = point to data buffer
;		CX = length
;Output:	none
;[]========================================================================[]

Ex_Clear_Buffer:
	pusha
	xor	al, al
@@:
	mov	[si], al
	inc	si
	loop	short @b
	popa
	ret

;[]========================================================================[]
;Procedure:	Ex_Delay_12ms
;Function:	Delay for 12 ms
;Input:		none
;Output:	none
;[]========================================================================[]

Ex_Delay_12ms:
	push	bx
	push	cx

       	xor	bx, bx
	mov	cx, 400				;bx:cx=wait period
						; (400 -> 12 msec)
	call	Ex_Usb_Wait_Refresh

	pop	cx
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Ex_Usb_Wait_Refresh
;Function:	Delay time with system DRAM refresh period
;Input:		BX:CX = delay counter (*30us)
;Output:	none
;[]========================================================================[]

	align	4
Ex_Usb_Wait_Refresh:
	pusha

	align	4
Ex_Wait_Refresh_Loop:
@@:
	in	al, 61h
	test	al, 10h
	jz	short @b

	align	4
@@:
	in	al, 61h
	test	al, 10h
	jnz	short @b

	loop	short Ex_Wait_Refresh_Loop

	or	bx, bx
	jz	short @f
	dec	bx
	jnz	short Ex_Wait_Refresh_Loop

@@:
	popa
	ret

;[]========================================================================[]
;Procedure:	Ex_Resume_Tasks
;Function:	Resume all tasks after Control Transfer
;Input:		none
;Output:	none
;[]========================================================================[]

Ex_Resume_Tasks:
	pusha

	mov	bx, offset wTaskLink
Ex_Resume_TK_Loop:
	cmp	word ptr [bx].wTkLink, 0FFFFh
	je	short Ex_Resume_TK_Exit

	mov	bx, [bx].wTkLink
	mov	si, [bx].wTkTransDesp
	mov	di, [bx].wTkQueueHead
	call	Ex_Link_TD_to_QH
	jmp	short Ex_Resume_TK_Loop

Ex_Resume_TK_Exit:
	popa
	ret

;[]========================================================================[]
;Procedure:	Ex_Host_Stop
;Function:	Stop host controller working
;Input:		none
;Output:	none
;[]========================================================================[]

Ex_Host_Stop:
	push	dx
	mov	dx, USBCMD
	call	Ex_Get_Host_Word
	and	ax, not RS
	call	Ex_Set_Host_Word
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Ex_Host_Run
;Function:	Start host controller working
;Input:		none
;Output:	none
;[]========================================================================[]

Ex_Host_Run:
	push	dx
	mov	dx, USBCMD
	call	Ex_Get_Host_Word
	or	ax, RS
	call	Ex_Set_Host_Word
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Ex_Get_USBRAM
;Function:	Get USB_RAM segment address
;Input:		none
;Output:	AX = USB_RAM segment address
;[]========================================================================[]

Ex_Get_USBRAM	proc	near
	push	ds
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	mov	ax, ds:USB_RAM_SEG
	pop	ds
	assume	ds:USB_RAM
	ret
Ex_Get_USBRAM	endp

;[]========================================================================[]
;Procedure:	Ex_Get_Host_Byte
;Function:	Get host controller I/O register value with byte
;Input:		DX = Host I/O register offset
;Output:	AL = value
;[]========================================================================[]

Ex_Get_Host_Byte:
	push	dx
	add	dx, wHostIoBase
	in	al, dx
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Ex_Get_Host_Word
;Function:	Get host controller I/O register value with word
;Input:		DX = Host I/O register offset
;Output:	AX = value
;[]========================================================================[]

Ex_Get_Host_Word:
	push	dx
	add	dx, wHostIoBase
	in	ax, dx
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Ex_Get_Host_Dword
;Function:	Get host controller I/O register value with double word
;Input:		DX = Host I/O register offset
;Output:	EAX = value
;[]========================================================================[]

Ex_Get_Host_Dword:
	push	dx
	add	dx, wHostIoBase
	in	eax, dx
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Ex_Set_Host_Byte
;Function:	Set host controller I/O register value with byte
;Input:		DX = Host I/O register offset
;		AL = value
;Output:	none
;[]========================================================================[]

Ex_Set_Host_Byte:
	push	dx
	add	dx, wHostIoBase
	out	dx, al
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Ex_Set_Host_Word
;Function:	Set host controller I/O register value with word
;Input:		DX = Host I/O register offset
;		AX = value
;Output:	none
;[]========================================================================[]

Ex_Set_Host_Word:
	push	dx
	add	dx, wHostIoBase
	out	dx, ax
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Ex_Set_Host_Dword
;Function:	Set host controller I/O register value with double word
;Input:		DX = Host I/O register offset
;		EAX = value
;Output:	none
;[]========================================================================[]

Ex_Set_Host_Dword:
	push	dx
	add	dx, wHostIoBase
	out	dx, eax
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Ex_Physical_Linear
;Function:	Calculate FL, QH and TD physical 32-bit linear address
;Input:		AX = offset value in USB_RAM
;Output:	EAX = physical 32-bit linear address value
;[]========================================================================[]

Ex_Physical_Linear:
	push	edx
	xor	edx, edx
	mov	dx, ds
	shl	edx, 4
	and	eax, 0000FFFFh
	add	eax, edx
	pop	edx
	ret

;[]========================================================================[]
;Procedure:	Ex_Physical_Offset
;Function:	Calculate 32-bit linear address to offset of USB_RAM
;Input:		EAX = physical 32-bit linear address value
;Output:	EAX = offset value in USB_RAM
;[]========================================================================[]

Ex_Physical_Offset:
	push	edx
	xor	edx, edx
	mov	dx, ds
	shl	edx, 4
	sub	eax, edx
	and	al, 0F0h			;don't care bit
	pop	edx
	ret

endif	;SMIHANDLE_IN_YGROUP
;R35 - end

	assume	ds:nothing

ENDIF	;COMPILE_FOR_USBBIOS EQ 2

IF	COMPILE_FOR_USBBIOS EQ 3

;****************************************************************
;*								*
;*	COMPILING STAGE 3					*
;*								*
;*	RUN-TIME EXECUTION CODES RESIDENT AT SMI RAM		*
;*								*
;****************************************************************

	assume	ds:USB_RAM

;[]========================================================================[]
;Procedure:	Usb_Smi
;Function:	Process SMI generated by USB Host
;Input:		none
;Output:	CF = 0 USB SMI
;		CF = 1 not USB SMI
;[]========================================================================[]

	public	Usb_Smi
Usb_Smi proc	near
	pushad					;R07
	push	ds				;R07
	push	es				;R07
	mov	dx, 0CF8h			;R43
	in	eax, dx				;R43
	push	eax				;R43
	call	Check_USB_Disabled
	jnz	usb_smi_exit

	call	Get_USBRAM
	mov	ds, ax
	mov	es, ax
;R41D - start
	mov	al, ds:bUsbFlag
	test	al, REMOVEDEV			;stage to remove unsupported device
	jz	short Usb_Smi_Cont
	and	al, not REMOVEDEV		;clear removing flag
	mov	ds:bUsbFlag, al
	test	al, USBKBSUPPORT		;keyboard supporting enabled?
	jnz	short Check_Ms_Support
	push	ax
	call	Remove_KbTask			;remove usb keyboard task
	pop	ax
Check_Ms_Support:
	test	al, USBMSSUPPORT		;mouse supporting enabled?
	jnz	short Usb_Smi_Cont
	call	Remove_MsTask			;remove usb mouse task
Usb_Smi_Cont:
;R41D - end
;R40	test	byte ptr ds:bUsbFlag, 02
	test	byte ptr ds:bUsbFlag, OWNERCHG	;R40;ownership changed?
;R36A	jnz	usb_smi_exit
;R36A - start
	jz	short Check_IoBase
	mov	cx, wHostID
	add	cx, LEGACY_LO
	SMI_F0CALL	Get_Pci
	test	al, USBSMIEN
	jz	usb_smi_exit
;R40	and	byte ptr ds:bUsbFlag, not 02
	and	byte ptr ds:bUsbFlag, not OWNERCHG	;R40;BIOS own
Check_IoBase:
;R36A - end

	call	Check_IoBase_Disabled		;R10
;R39	jc	short Disable_Usb_Smi		;R10
	jc	Disable_Usb_Smi			;R39

;R22A - start
ifdef	IOTRAP_SUPPORT
;R39	call	Ct_CheckUsbLegacySmi
;R39	jc	short @f
;R39	mov	cx, wHostID
;R39	add	cx, LEGACY_HI
;R39	SMI_F0CALL	Get_Pci
;R39	test	al, 0Fh
;R39	jz	short @f
;R39	call	UsbLegSmi
;R39	call	Ct_ClearUsbLegacySmi
;R39	jmp	Usb_Smi_End
;R39@@:
;R39 - start
	call	Ct_CheckUsbLegacySmi
	jc	short Not_UsbLegacySmi
	call	Ct_ClearUsbLegacySmi
	call	GetTrapBy
	mov	al, bTrapEnabled
	and	TrapByStatus, al
	jz	short Not_UsbLegacySmi
	call	UsbLegSmi
;R54 - start
	mov	cx, wHostID
	add	cx, LEGACY_HI
	SMI_F0CALL	Get_Pci
	test	al, SMIBYUSB
	jz	Usb_Smi_End
;R54 - end
;R54	jmp	Usb_Smi_End
Not_UsbLegacySmi:
;R39 - end
endif	;IOTRAP_SUPPORT
;R22A - end

;R28 - start
	mov	cx, wHostID
	add	cx, LEGACY_LO
	SMI_F0CALL	Get_Pci
	test	al, USBSMIEN
	jz	usb_smi_exit
;R28 - end

	mov	cx, wHostID
	add	cx, LEGACY_HI
	SMI_F0CALL	Get_Pci

	test	al, SMIBYUSB
	jz	usb_smi_exit

	mov	dx, USBSTS
	call	Get_Host_Byte
	IODELAY
;R13	test	al, USBINT			;int caused by Host
;R29	test	al, USBINT+UEI			;R13
	test	al, 00111011b			;R29;all interrupt
;R08	jz	short usb_smi_exit
	jz	usb_smi_exit			;R08

	call	Ct_USB_SMI_Entry

	mov	dx, FRBASEADD
	call	Get_Host_Dword
	and	ax, 0F000h			;discard reserved bits
	cmp	eax, ds:dFrameListAddr
	je	short @f
;R10	or	byte ptr ds:bUsbFlag, 02
;R10	mov	cx, wHostID
;R10	add	cx, LEGACY_LO
;R10	SMI_F0CALL	Get_Pci
;R10	and	al, not USBSMIEN
;R10	SMI_F0CALL	Set_Pci
	mov	cx, wHostID
	add	cx, LEGACY_HI
	SMI_F0CALL	Get_Pci
	or	al, USBPIRQDEN
	SMI_F0CALL	Set_Pci
Disable_Usb_Smi:				;R10
	mov	cx, wHostID			;R10
	add	cx, LEGACY_LO			;R10
	SMI_F0CALL	Get_Pci			;R10
ifdef	IOTRAP_SUPPORT				;R22A
	and	al, not (USBSMIEN+0Fh)		;R22A
else	;IOTRAP_SUPPORT				;R22A
	and	al, not USBSMIEN		;R10
endif	;IOTRAP_SUPPORT				;R22A
	SMI_F0CALL	Set_Pci			;R10
ifdef	IOTRAP_SUPPORT				;R22A
	call	Ct_DisableUsbLegacySmi		;R22A
endif	;IOTRAP_SUPPORT				;R22A
;R40	or	byte ptr ds:bUsbFlag, 02	;R10
	or	byte ptr ds:bUsbFlag, OWNERCHG	;R40;OS own
	jmp	short Toggle_SMI_Exit
@@:

	; clear INT

	mov	dx, USBSTS
	call	Get_Host_Word
	call	Set_Host_Word
;R29 - start
;R29A	test	al, 00111010b			;error interrupt
	test	al, 00111000b			;R29A;error interrupt
	jz	short Proc_UsbSmi
	mov	dx, PORTSC1
	call	Get_Host_Word
	test	al, CURR_CONN			;device connected
	jz	short @f
	call	Reset_RootPort
	mov	al, 1				;device 1
	mov	ah, 1				;port 1
	call	Release_ChildDev
@@:
	mov	dx, PORTSC2
	call	Get_Host_Word
	test	al, CURR_CONN			;device connected
	jz	short @f
	call	Reset_RootPort
	mov	al, 1				;device 1
	mov	ah, 2				;port 2
	call	Release_ChildDev
@@:
	call	Host_Run
Proc_UsbSmi:
;R29 - end

@@:						;R08
;R40	and	byte ptr bUsbFlag, NOT 04h	;R08
	and	byte ptr bUsbFlag, NOT TASKCHG	;R40;no task link changed
	mov	si, offset wTaskLink
Usb_Smi_Loop:
;R40	test	byte ptr bUsbFlag, 04		;R08
	test	byte ptr bUsbFlag, TASKCHG	;R40;task link changed?
	jnz	short @b			;R08

	cmp	word ptr [si].wTkLink, 0FFFFh
	je	short Toggle_SMI_Exit

	mov	si, [si].wTkLink
	test	byte ptr [si].bTkDevStatus, TK_WFP
	jz	short Usb_Smi_Next

	pushad
	call	word ptr [si].wTkProc
	popad

Usb_Smi_Next:
	jmp	short Usb_Smi_Loop

Toggle_SMI_Exit:

	CALL	Ct_USB_SMI_Exit

Usb_Smi_End:					;R22A
	pop	eax				;R43
	mov	dx, 0CF8h			;R43
	out	dx, eax				;R43
	pop	es				;R07
	pop	ds				;R07
	popad					;R07
	clc
	ret

usb_smi_exit:
	pop	eax				;R43
	mov	dx, 0CF8h			;R43
	out	dx, eax				;R43
	pop	es				;R07
	pop	ds				;R07
	popad					;R07
	stc
	ret
Usb_Smi endp

;R34 - start
ifdef	USB_PM_SUPPORT
;[]========================================================================[]
;Procedure:	Usb_Suspend
;Function:	Force all USB devices to enter suspend state.
;Input:		DS = PM_RAM
;Output:	none
;[]========================================================================[]

Usb_Suspend	proc	near
	pushad
	push	ds
	push	es

	call	Check_USB_Disabled		;legacy support disabled?
	jnz	short Usb_Suspend_Exit

	call	Get_USBRAM
	mov	ds, ax
	mov	es, ax
;R40	test	byte ptr ds:bUsbFlag, 02	;ownership change?
	test	byte ptr ds:bUsbFlag, OWNERCHG	;R40;ownership change?
	jnz	short Usb_Suspend_Exit

	call	Suspend_Tasks			;periodic list disabled

; SET_FEATURE with Feature Selector as DEVICE_REMOTE_WAKEUP

	call	Get_CtrlBuffer			;get control parameter buffer
	jc	short Usb_Host_Suspend

	mov	bx, si

	mov	si, offset RequestBuffer	;data buffer for SETUP token
	call	Init_ReqBuffer

	mov	byte ptr [si].bRequest, SET_FEATURE
	mov	byte ptr [si].wValue, 1			;DEVICE_REMOTE_WAKEUP

	mov	[bx].wReqBuffer, si

	mov	di, offset wTaskLink
Usb_Suspend_Loop:
	mov	di, [di].wTkLink
	cmp	di, 0FFFFh				;task link end?
	je	short Usb_Suspend_End

	and	byte ptr [bx].bCtrlByte, not CP_LS
	test	byte ptr [di].bTkDevStatus, TK_LS	;low speed device?
	jz	short @f
	or	byte ptr [bx].bCtrlByte, CP_LS
@@:

	mov	al, [di].bTkDevAddr			;device address
	mov	[bx].bDevAddr, al

	call	Control_Transfer			;don't care failure
	jmp	short Usb_Suspend_Loop

Usb_Suspend_End:
	mov	si, bx
	call	Release_CtrlBuffer

Usb_Host_Suspend:

	mov	dx, USBCMD
	call	Get_Host_Word
	and	ax, not RS			;host stop
	call	Set_Host_Word
	or	al, 00001000b			;global suspend
	call	Set_Host_Word
	mov	dx, USBINTR
	call	Get_Host_Word
	or	al, 00000010b			;resume detected interrupt
	call	Set_Host_Word

Usb_Suspend_Exit:
	pop	es
	pop	ds
	popad
	ret
Usb_Suspend	endp

;[]========================================================================[]
;Procedure:	Usb_Resume
;Function:	Wake-up all USB devices.
;Input:		DS = PM_RAM
;Output:	none
;[]========================================================================[]

Usb_Resume	proc	near
	pushad
	push	ds
	push	es

	call	Check_USB_Disabled		;legacy support disabled?
	jnz	short Usb_Resume_Exit

	call	Get_USBRAM
	mov	ds, ax
	mov	es, ax
;R40	test	byte ptr ds:bUsbFlag, 02	;ownership change?
	test	byte ptr ds:bUsbFlag, OWNERCHG	;R40;ownership change?
	jnz	short Usb_Resume_Exit

	; resume host controller

	mov	dx, USBCMD
	call	Get_Host_Word
	or	al, 00010000b			;global resume
	call	Set_Host_Word
	call	Resume_Delay			;wait device stable
	and	al, 11100111b			;normal state
	call	Set_Host_Word
	or	al, RS				;host run
	call	Set_Host_Word
	mov	dx, USBINTR
	call	Get_Host_Word
	and	al, 11111101b			;resume detected disabled
	call	Set_Host_Word
	mov	dx, USBSTS
	mov	ax, 04				;resume detected status
	call	Set_Host_Word

; CLEAR_FEATURE with Feature Selector as DEVICE_REMOTE_WAKEUP

	call	Get_CtrlBuffer			;get control parameter buffer
	jc	short Usb_Resume_Task

	mov	bx, si

	mov	si, offset RequestBuffer	;data buffer for SETUP token
	call	Init_ReqBuffer

	mov	byte ptr [si].bRequest, CLEAR_FEATURE
	mov	byte ptr [si].wValue, 1			;DEVICE_REMOTE_WAKEUP

	mov	[bx].wReqBuffer, si

	mov	di, offset wTaskLink
Usb_Resume_Loop:
	mov	di, [di].wTkLink
	cmp	di, 0FFFFh				;task link end?
	je	short Usb_Resume_End

	and	byte ptr [bx].bCtrlByte, not CP_LS
	test	byte ptr [di].bTkDevStatus, TK_LS	;low speed device?
	jz	short @f
	or	byte ptr [bx].bCtrlByte, CP_LS
@@:

	mov	al, [di].bTkDevAddr			;device address
	mov	[bx].bDevAddr, al

	call	Control_Transfer			;don't care failure
	jmp	short Usb_Resume_Loop

Usb_Resume_End:
	mov	si, bx
	call	Release_CtrlBuffer

Usb_Resume_Task:
	call	Resume_Tasks

Usb_Resume_Exit:
	pop	es
	pop	ds
	popad
	ret
Usb_Resume	endp

;[]========================================================================[]
;Procedure:	Resume_Delay
;Function:	Delay 20ms for all USB device to resume.
;Input:		none
;Output:	none
;[]========================================================================[]

Resume_Delay	proc	near
	push	bx
	push	cx

       	xor	bx, bx
	mov	cx, 700				;bx:cx=wait period
						; (700 -> 21 msec)
	call	Usb_Wait_Refresh

	pop	cx
	pop	bx
	ret
Resume_Delay	endp
endif	;USB_PM_SUPPORT
;R34 - end

;[]========================================================================[]
;Procedure:	Check_USB_Disabled
;Function:	Check USB legacy support disabled either by device disabled
;		or by setup disabled.
;Input:		none
;Output:	ZF = 0 enabled
;		ZF = 1 disabled
;[]========================================================================[]

Check_USB_Disabled	proc	near
	push	ds
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	test	byte ptr ds:USB_STATUS, 01
	pop	ds
	assume	ds:USB_RAM
	ret
Check_USB_Disabled	endp

;R10 - start
;[]========================================================================[]
;Procedure:	Check_IoBase_Disabled
;Function:	Check the I/O base address of USB Host Controller disabled.
;Input:		none
;Output:	CF = 0 no disabled
;		CF = 1 disabled
;[]========================================================================[]

Check_IoBase_Disabled	proc	near
	push	ax
	push	cx
	mov	cx, wHostID
	mov	cl, 04
	SMI_F0CALL	Get_Pci
	test	al, 01
	stc
	jz	short @f
	clc
@@:
	pop	cx
	pop	ax
	ret
Check_IoBase_Disabled	endp
;R10 - end

;[]========================================================================[]
;Procedure:	Get_USBRAM
;Function:	Get USB_RAM segment address
;Input:		none
;Output:	AX = USB_RAM segment address
;[]========================================================================[]

Get_USBRAM	proc	near
	push	ds
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	mov	ax, ds:USB_RAM_SEG
	pop	ds
	assume	ds:USB_RAM
	ret
Get_USBRAM	endp

;[]========================================================================[]
;Procedure:	Wait_Stable
;Function:	Delay for device to be stable
;Input:		none
;Output:	none
;Notes:		Delay timer refer to Cherry USB keyboard stable time after
;		attached.
;[]========================================================================[]

Wait_Stable:
	push	bx
	push	cx

	xor	bx, bx
	mov	cx, 6000			;180 ms
	call	Usb_Wait_Refresh

	pop	cx
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Delay_12ms
;Function:	Delay for 12 ms
;Input:		none
;Output:	none
;[]========================================================================[]

Delay_12ms:
	push	bx
	push	cx

       	xor	bx, bx
	mov	cx, 400				;bx:cx=wait period
						; (400 -> 12 msec)
	call	Usb_Wait_Refresh

	pop	cx
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Delay_1ms
;Function:	Delay for 1 ms
;Input:		none
;Output:	none
;[]========================================================================[]

Delay_1ms:
	push	bx
	push	cx

       	xor	bx, bx
	mov	cx, 40				;bx:cx=wait period
						; (40 -> 1.2 msec)
	call	Usb_Wait_Refresh

	pop	cx
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Usb_Wait_Refresh
;Function:	Delay time with system DRAM refresh period
;Input:		BX:CX = delay counter (*30us)
;Output:	none
;[]========================================================================[]

	align	4
Usb_Wait_Refresh:
	pusha

	NEWIODELAY				;R33
	align	4
Wait_Refresh_Loop:
@@:
	in	al, 61h
	test	al, 10h
	jz	short @b

	NEWIODELAY				;R33
	align	4
@@:
	in	al, 61h
	test	al, 10h
	jnz	short @b

	loop	short Wait_Refresh_Loop

	or	bx, bx
	jz	short @f
	dec	bx
	jnz	short Wait_Refresh_Loop

@@:
	popa
	ret

;[]========================================================================[]
;Procedure:	System_Control
;Function:	System control task process routine
;Input:		SI = point to SysCtrlTask
;Output:	none
;[]========================================================================[]

System_Control:

	; Check port 1 status changed

Check_Port1:
	mov	dx, PORTSC1
	call	Get_Host_Word

;R28	push	ax
;R28	xor	al, byte ptr wPort1Status
;R28	test	al, CURR_CONN
;R28	pop	ax
;R28	jz	short Check_Port2
;R28
;R28	mov	wPort1Status, ax
;R28 - start
	test	al, CONN_CHANGE
	jz	short Check_Port2
	call	Set_Host_Word
;R28 - end

	test	al, CURR_CONN
	jnz	short Enable_RootPort1

	; Port 1 disconnected

Disable_RootPort1:

	call	Disable_RootPort
	mov	al, 1				;device 1
	mov	ah, 1				;port 1
	call	Release_ChildDev

	jmp	short Check_Port2

	; Port 1 connected
	; DX = port address
	; AX = port value

Enable_RootPort1:
;R28 - start
	push	ax
	mov	al, 1				;device 1
	mov	ah, 1				;port 1
	call	Release_ChildDev
	pop	ax
;R28 - end

	call	Reset_RootPort
	call	Enable_RootPort

	call	Get_CtrlBuffer			;R08
	jc	short Disable_RootPort1		;R08

	call	Suspend_Tasks			;suspend all tasks
						;for bus enumeration

;R08	mov	si, offset ControlBuffer1
;R08	call	Init_CtrlBuffer

	test	ax, LOW_SPEED_DEV
	jz	short @f
	or	byte ptr [si].bCtrlByte, CP_LS
@@:
	mov	byte ptr [si].bParentAddr, 1	;device 1
	mov	byte ptr [si].bParentPort, 1	;port 1
	mov	byte ptr [si].bDevAddr, 0	;default address 0
	mov	byte ptr [si].bDevEndp, 0	;default endpoint 0

	mov	bx, si
	call	Init_Device
	jnc	short @f

	and	al, not PORT_ENABLE
	call	Set_Host_Word

	jmp	short Check_Port1_Exit

@@:
	call	Init_Config			;BX=point to control buffer

Check_Port1_Exit:

	call	Release_CtrlBuffer		;R08A

	call	Resume_Tasks			;resume all tasks
						;after bus enumeration

	; Check port 2 status changed

Check_Port2:
	mov	dx, PORTSC2
	call	Get_Host_Word

;R28	push	ax
;R28	xor	al, byte ptr wPort2Status
;R28	test	al, CURR_CONN
;R28	pop	ax
;R28	jz	short Check_Led			;System_Control_Exit
;R28
;R28	mov	wPort2Status, ax
;R28 - start
	test	al, CONN_CHANGE
	jz	short Check_Led
	call	Set_Host_Word
;R28 - end

	test	al, CURR_CONN
	jnz	short Enable_RootPort2

	; Port 2 disconnected

Disable_RootPort2:

	call	Disable_RootPort
	mov	al, 1				;device 1
	mov	ah, 2				;port 2
	call	Release_ChildDev

	jmp	short Check_Led			;System_Control_Exit

	; Port 2 connected
	; DX = port address
	; AX = port value

Enable_RootPort2:
;R28 - start
	push	ax
	mov	al, 1				;device 1
	mov	ah, 2				;port 2
	call	Release_ChildDev
	pop	ax
;R28 - end

	call	Reset_RootPort
	call	Enable_RootPort

	call	Get_CtrlBuffer			;R08
	jc	short Disable_RootPort2		;R08

	call	Suspend_Tasks			;suspend all tasks
						;for bus enumeration

;R08	mov	si, offset ControlBuffer1
;R08	call	Init_CtrlBuffer

	test	ax, LOW_SPEED_DEV
	jz	short @f
	or	byte ptr [si].bCtrlByte, CP_LS
@@:
	mov	byte ptr [si].bParentAddr, 1	;device 1
	mov	byte ptr [si].bParentPort, 2	;port 2
	mov	byte ptr [si].bDevAddr, 0	;default address 0
	mov	byte ptr [si].bDevEndp, 0	;default endpoint 0

	mov	bx, si
	call	Init_Device
	jnc	short @f

	and	al, not PORT_ENABLE
	call	Set_Host_Word

	jmp	short Check_Port2_Exit

@@:
	call	Init_Config			;BX=point to control buffer

Check_Port2_Exit:

	call	Release_CtrlBuffer		;R08A

	call	Resume_Tasks			;resume all tasks
						;after bus enumeration

	; Check keyboard LED status changed

Check_Led:
ifndef	IOTRAP_SUPPORT				;R22A
ifndef	NO_UPDATE_USBKB_LED			;R18
	test	word ptr wKbdDevMap, 0FFFFh
	jz	short System_Control_Exit

	push	ds
	mov	ax, 0040h
	mov	ds, ax
	mov	al, byte ptr ds:[0017h]		;BIOS key status flag
	pop	ds

	push	ax
	xor	al, bLedStatus
	test	al, 01110000b			;LED bits
	pop	ax
	jz	short System_Control_Exit

	mov	bLedStatus, al

	call	Suspend_Tasks			;suspend all tasks
						;for LED updated
	call	Update_Led			;update keyboard LED

	call	Resume_Tasks			;resume all tasks
						;after LED updated
endif	;NO_UPDATE_USBKB_LED			;R18
endif	;IOTRAP_SUPPORT				;R22A
System_Control_Exit:

	ret

;R47 - start
;[]========================================================================[]
;Procedure:	Init_TimerTD
;Function:	Initialize Timer TD
;Input:		none
;Output:	none
;[]========================================================================[]

Init_TimerTD:
	push	si
	mov	si, offset TimerTD
ifdef	ZERO_SET_IDLE
	mov	byte ptr [si].bTdControl, 09h		;one error count, IOC
;R47A	mov	dword ptr [si].dTdToken, 0FFE0169h	;null data, dev 1
	mov	dword ptr [si].dTdToken, 0FFE00169h	;R47A;null data, dev 1
							; PID_IN
;R47A	mov	byte ptr [di].bTdStatus, STS_ACTIVE
	mov	byte ptr [si].bTdStatus, STS_ACTIVE	;R47A
else	;ZERO_SET_IDLE
	or	byte ptr [si].bTdControl, ISS_IOC
endif	;ZERO_SET_IDLE
	pop	si
	ret
;R47 - end

;R06 - start
;[]========================================================================[]
;Procedure:	Proc_Timer
;Function:	Periodic timer task process routine
;Input:		SI = point to TimerTask
;Output:	none
;[]========================================================================[]

Proc_Timer:
ifdef	USB_MOUSE_SUPPORT			;R41
	cmp	bMsQueueCount, 0		;R41
	je	short @f			;R41
	call	Proc_MsBuffer			;R41
@@:						;R41
endif	;USB_MOUSE_SUPPORT			;R41
;R47 - start
ifdef	ZERO_SET_IDLE
	mov	bx, offset TimerTD
	test	byte ptr [bx].bTdStatus, STS_ACTIVE
	jnz	short Proc_Timer_Exit
endif	;ZERO_SET_IDLE
;R47 - end
	test	word ptr wKbdDevMap, 0FFFFh
;R47	jz	short Proc_Timer_Exit
	jz	short Proc_Keybuffer_End	;R47

	mov	di, offset wTaskLink
Proc_Keybuffer_Loop:
	cmp	word ptr [di].wTkLink, 0FFFFh
	je	short Proc_Keybuffer_End

	mov	di, [di].wTkLink
	test	byte ptr [di].bTkDevStatus, TK_KBD
	jz	short Proc_Keybuffer_Loop

	mov	si, [di].wTkCtrlBuffer

;R47 - start
ifdef	ZERO_SET_IDLE
	push	di
	call	Proc_KeyCode
	pop	di
endif	;ZERO_SET_IDLE
;R47 - end

	cmp	byte ptr [si].bKeyLength, 0
	je	short Proc_Keybuffer_Loop

	call	Proc_Key_Buffer

	jmp	short Proc_Keybuffer_Loop

Proc_Keybuffer_End:

;R47 - start
ifdef	ZERO_SET_IDLE
	call	Init_TimerTD
endif	;ZERO_SET_IDLE
;R47 - end

Proc_Timer_Exit:
	ret
;R06 - end

;R50 - start
ifdef   IOTRAP_SUPPORT

;[]========================================================================[]
;Procedure:     Init_ResponseTD
;Function:      Initialize Response Task's TD
;Input:         none
;Output:        none

;[]========================================================================[]

Init_ResponseTD:
        push    si
        mov     si, offset ResponseTD
        mov     byte ptr [si].bTdControl, 09h           ;one error count,IOC
        mov     dword ptr [si].dTdToken, 0FFE00169h     ;null data, dev 1
                                                        ; PID_IN
        mov     byte ptr [si].bTdStatus, STS_ACTIVE
        pop     si
        ret

;[]========================================================================[]
;Procedure:     Proc_Response
;Function:      Respond system command task
;Input:         SI = point to ResponseTask
;Output:        none

;[]========================================================================[]

Proc_Response:
        mov     bx, offset ResponseTD
        test    byte ptr [bx].bTdStatus, STS_ACTIVE
        jnz     short Proc_Response_Exit

        cmp     byte ptr bResponseLength, 0
        je      short Disable_Response_Task

        call    DisableUsbLegacySmi

        movzx   bx, byte ptr bResponsePoint
        lea     di, ResponseBuffer
        mov     al, [bx+di]
        call    Send_KeyCode
        jc      short Proc_Response_End

        inc     byte ptr bResponsePoint
        dec     byte ptr bResponseLength

Proc_Response_End:

        call    EnableUsbLegacySmi

        cmp     byte ptr bResponseLength, 0
        je      short Disable_Response_Task

        call    Init_ResponseTD

        jmp     short Proc_Response_Exit

Disable_Response_Task:
        mov     si, offset ResponseTask
        call    Remove_Task_Chain

Proc_Response_Exit:
        ret
endif   ;IOTRAP_SUPPORT
;R50 - end

ifndef	NO_UPDATE_USBKB_LED			;R18
;[]========================================================================[]
;Procedure:	Update_Led
;Function:	Update all USB keyboard LED
;Input:		bLedStatus = current BIOS flag(40:17)
;Output:	none
;[]========================================================================[]

Update_Led:

	movzx	bx, byte ptr bLedStatus
	shr	bx, 4
	and	bl, 00000111b
	add	bx, offset Led_Table SMI_OFFSET
	mov	al, byte ptr cs:[bx]
	mov	byte ptr MiscDataBuffer, al

;R08	mov	si, offset ControlBuffer1
;R08	call	Init_CtrlBuffer
	call	Get_CtrlBuffer			;R08
	jc	short Update_Led_Exit		;R08

	mov	byte ptr [si].wTotalSize, 1
	mov	byte ptr [si].wMaxSize, 1
	mov	word ptr [si].wDataBuffer, offset MiscDataBuffer

	mov	bx, si

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
;R27	mov	byte ptr [si].bmRequestType, 00100010b
	mov	byte ptr [si].bRequest, SET_REPORT
	mov	byte ptr [si+1].wValue, 2		;type output
	mov	byte ptr [si].wLength, 1

	mov	[bx].wReqBuffer, si

	mov	di, offset wTaskLink
Update_Led_Loop:
	cmp	word ptr [di].wTkLink, 0FFFFh
	je	short Update_Led_End

	mov	di, [di].wTkLink
	test	byte ptr [di].bTkDevStatus, TK_KBD
	jz	short Update_Led_Next

;R01	mov	al, [di].bDevEndp
;R27	mov	al, [di].bTkDevEndp			;R01
;R27	mov	byte ptr [si].wIndex, al
;R27 - start
	mov	byte ptr [si].bmRequestType, 00100010b
	mov	al, [di].bTkDevEndp
	test	byte ptr [di].bTkDevStatus, TK_NEWKBD
	jz	short @f
	mov	byte ptr [si].bmRequestType, 00100001b
	mov	al, [di].bTkDevInterface
@@:
	mov	byte ptr [si].wIndex, al
;R27 - end

	and	byte ptr [bx].bCtrlByte, not CP_LS
	test	byte ptr [di].bTkDevStatus, TK_LS
	jz	short @f
	or	byte ptr [bx].bCtrlByte, CP_LS
@@:

	mov	al, [di].bTkDevAddr
	mov	[bx].bDevAddr, al

	call	Control_Transfer

Update_Led_Next:
	jmp	short Update_Led_Loop


Update_Led_End:
	mov	si, bx				;R08
	call	Release_CtrlBuffer		;R08
Update_Led_Exit:				;R08
	ret

; LED translation table from USB keyboard format to AT keyboard format

Led_Table	label	byte
	db	000b, 100b, 001b, 101b, 010b, 110b, 011b, 111b
endif	;NO_UPDATE_USBKB_LED			;R18

;[]========================================================================[]
;Procedure:	Control_Transfer
;Function:	Control transfer
;Input:		BX = point to control parameter block
;Output:	CF = 0 successful
;		CF = 1 fail
;[]========================================================================[]

Control_Transfer:
	pushad

	mov	di, offset ControlQH

	mov	si, offset ControlTD
	call	Init_TD

	; SETUP stage

	mov	byte ptr [si].bTdControl, DEF_TDCTRL
	test	byte ptr [bx].bCtrlByte, CP_LS
	jz	short @f
	or	byte ptr [si].bTdControl, LS
@@:

	mov	edx, 00E00000h+PID_SETUP	;max length 8
	movzx	eax, byte ptr [bx].bDevAddr
	shl	eax, BIT_ADDR
	or	edx, eax
	movzx	eax, byte ptr [bx].bDevEndp
	shl	eax, BIT_EP
	or	edx, eax
	mov	[si].dTdToken, edx

	mov	ax, [bx].wReqBuffer
	call	Physical_Linear
	mov	[si].dTdPoint, eax

	mov	byte ptr [si].bTdStatus, STS_ACTIVE

	call	Delay_1ms			;wait device stable

	call	Link_TD_to_QH

	call	Wait_Ack
	jc	Control_Transfer_Fail

	; DATA stage

	cmp	word ptr [bx].wTotalSize, 0
	je	short Status_Stage

	mov	edx, [si].dTdToken
	mov	dl, PID_IN
	test	byte ptr [bx].bCtrlByte, CP_RD
	jnz	short @f
	mov	dl, PID_OUT
@@:
	and	edx, NOT MAX_LEN
	movzx	eax, word ptr [bx].wMaxSize
	dec	ax
	shl	eax, BIT_MAXL
	or	edx, eax
	mov	[si].dTdToken, edx

	xor	dx, dx
	mov	cx, [bx].wTotalSize

Data_Stage_Loop:
	xor	dword ptr [si].dTdToken, DATA_TOGGLE

	mov	ax, [bx].wDataBuffer
	add	ax, dx
	call	Physical_Linear
	mov	[si].dTdPoint, eax

	or	byte ptr [si].bTdControl, C_ERR		;error count 3
	mov	byte ptr [si].bTdStatus, STS_ACTIVE

	call	Delay_1ms			;wait device stable

	call	Link_TD_to_QH

	call	Wait_Ack
	jc	short Control_Transfer_Fail

	add	dx, [bx].wMaxSize
	cmp	dx, cx
	jb	short Data_Stage_Loop

	; STATUS stage

Status_Stage:
	mov	edx, [si].dTdToken
	mov	dl, PID_IN
	cmp	word ptr [bx].wTotalSize, 0
	je	short @f
	test	byte ptr [bx].bCtrlByte, CP_RD
	jz	short @f
	mov	dl, PID_OUT
@@:
	or	edx, DATA_TOGGLE			;terminated with DATA1
	or	edx, MAX_LEN				;null packet
	mov	[si].dTdToken, edx

	or	byte ptr [si].bTdControl, C_ERR		;error count 3
	mov	byte ptr [si].bTdStatus, STS_ACTIVE

	call	Delay_1ms			;wait device stable

	call	Link_TD_to_QH

	call	Wait_Ack
	jc	short Control_Transfer_Fail

	popad
	clc
	ret

Control_Transfer_Fail:

	call	Remove_TD_from_QH

	popad
	stc
	ret

;[]========================================================================[]
;Procedure:	Wait_Ack
;Function:	Wait transaction acknowledge
;Input:		SI = point to TD
;Output:	CF = 0 successful
;		CF = 1 fail (transaction error or time-out)
;[]========================================================================[]

Wait_Ack:
	push	cx

	mov	cx, WAIT_ACK_COUNT
@@:
	test	byte ptr [si].bTdStatus, STS_ACTIVE
	jz	short @f

	call	Delay_1ms

	loop	short @b

Wait_Ack_Fail:

	pop	cx
	stc
	ret

@@:
	test	byte ptr [si].bTdStatus, STS_ERROR
	jnz	short Wait_Ack_Fail

	pop	cx
	clc
	ret

;[]========================================================================[]
;Procedure:	Link_QH_to_FL
;Function:	Link Queue Head to Fram List
;Input:		SI = point to QH
;Output:	none
;[]========================================================================[]

Link_QH_to_FL:
	pushad

	mov	ax, [si].wQhInterval
;R08	call	Validate_Interval
;R08	mov	[si].wQhInterval, ax

	mov	cx, ax				;interval
	or	cx, cx				;avoid coding mistake
	jz	short Link_QF_Exit
	xor	dx, dx				;frame point

Link_QF_Loop:
	push	dx

	mov	ax, 4
	mul	dx
	mov	di, offset FrameList
	add	di, ax

Link_QF_Check:
	mov	eax, [di].dQhLink		;link pointer

	test	al, T				;terminate
	jnz	short Link_QF_Append

	call	Physical_Offset			;get offset in USB_RAM
	mov	bx, ax

	cmp	si, bx
	je	short Link_QF_Next

	cmp	cx, [bx].wQhInterval
	jae	short Link_QF_Insert

	mov	di, bx				;next queue head address
	jmp	short Link_QF_Check

Link_QF_Insert:
	mov	eax, [di].dQhLink
	mov	[si].dQhLink, eax
	jmp	short Link_QF_Previous

Link_QF_Append:
	or	byte ptr [si].dQhLink, T	;terminate

Link_QF_Previous:
	mov	ax, si
	call	Physical_Linear
	or	al, Q				;queue head
	and	al, not T			;no terminate
	mov	[di].dQhLink, eax

Link_QF_Next:
	pop	dx

	add	dx, cx				;next interval
	cmp	dx, 1024			;maximum interval
	jb	short Link_QF_Loop

Link_QF_Exit:
	popad
	ret

;[]========================================================================[]
;Procedure:	Link_TD_to_QH
;Function:	Link Transfer Descriptor to Queue Head
;Input:		SI = point to TD
;		DI = point to QH
;Output:	none
;[]========================================================================[]

Link_TD_to_QH:
	push	eax
	mov	ax, si
	call	Physical_Linear
	mov	[di].dQhElement, eax
	pop	eax
	ret

;[]========================================================================[]
;Procedure:	Remove_QH_from_FL
;Function:	Remove Queue Head from Fram List
;Input:		SI = point to QH
;Output:	none
;[]========================================================================[]

Remove_QH_from_FL:
	pushad

	mov	cx, [si].wQhInterval		;interval
	xor	dx, dx				;frame point

Remove_QF_Loop:
	push	dx

	mov	ax, 4
	mul	dx
	mov	di, offset FrameList
	add	di, ax

Remove_QF_Check:
	mov	eax, [di].dQhLink		;link pointer

	test	al, T
	jnz	short Remove_QF_Next

	call	Physical_Offset

	cmp	ax, si
	je	short Do_Remove_QF

	mov	di, ax
	jmp	short Remove_QF_Check

Do_Remove_QF:
	or	byte ptr [di].dQhLink, T	;terminate
	test	byte ptr [si].dQhlink, T	;terminate
	jnz	short Remove_QF_Next

	mov	eax, [si].dQhLink		;merge next task
	mov	[di].dQhLink, eax

Remove_QF_Next:
	pop	dx

	add	dx, cx				;next interval
	cmp	dx, 1024			;maximum interval
	jb	short Remove_QF_Loop

	popad
	ret

;[]========================================================================[]
;Procedure:	Remove_TD_from_QH
;Function:	Remove Transfer Descriptor from Queue Head
;Input:		SI = point to TD
;		DI = point to QH
;Output:	none
;[]========================================================================[]

Remove_TD_from_QH:
	or	byte ptr [di].dQhElement, T
	ret

;[]========================================================================[]
;Procedure:	Init_FL
;Function:	Initialize Frame List
;Input:		none
;Output:	none
;[]========================================================================[]

Init_FL:
	pushad

	; Clear frame list

	mov	cx, 1024			;Number of entries
	xor	esi, esi
@@:
	mov	dword ptr FrameList[esi*4], T
        inc	esi
	loop	short @b

	popad
	ret

;[]========================================================================[]
;Procedure:	Init_QH
;Function:	Initialize Queue Head data block
;Input:		SI = point to queue head
;Output:	none
;[]========================================================================[]

Init_QH:
	pusha
;R08	push	si
;R08	xor	al, al
;R08	mov	cx, SIZE QH
;R08@@:
;R08	mov	[si], al
;R08	inc	si
;R08	loop	short @b
;R08	pop	si
	mov	cx, SIZE QH			;R08
	call	Clear_Buffer			;R08
	or	byte ptr [si].dQhLink, T
	or	byte ptr [si].dQhElement, T
	popa
	ret

;[]========================================================================[]
;Procedure:	Init_TD
;Function:	Initialize Transfer Descriptor data block
;Input:		SI = point to transfer descriptor
;Output:	none
;[]========================================================================[]

Init_TD:
	pusha
;R08	push	si
;R08	xor	al, al
;R08	mov	cx, SIZE TD
;R08@@:
;R08	mov	[si], al
;R08	inc	si
;R08	loop	short @b
;R08	pop	si
	mov	cx, SIZE TD			;R08
	call	Clear_Buffer			;R08
	or	byte ptr [si].dTdLink, T
	popa
	ret

;[]========================================================================[]
;Procedure:	Host_Stop
;Function:	Stop host controller working
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Stop:
	push	dx
	mov	dx, USBCMD
	call	Get_Host_Word
	and	ax, not RS
	call	Set_Host_Word
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Host_Run
;Function:	Start host controller working
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Run:
	push	dx
	mov	dx, USBCMD
	call	Get_Host_Word
	or	ax, RS
	call	Set_Host_Word
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Reset_RootPort
;Function:	Reset root port
;Input:		DX = Port address to reset
;Output:	none
;[]========================================================================[]

Reset_RootPort:
	push	ax

	; Issue port reset

	call	Get_Host_Word			;ax=status of root port 1 or 2
	or	ax, PORT_RESET			;Issue RESET for about 10 ms
	call	Set_Host_Word

	; Delay for USB reset signaling is active

	call	Delay_12ms

	; Inactivate reset signal

;R53       	and	ax, not PORT_RESET
       	and	ax, not (PORT_RESET+SUSPEND)	;R53
	call	Set_Host_Word

	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Enable_RootPort
;Function:	Enable root port
;Input:		DX = Port address to enable
;Output:	none
;[]========================================================================[]

Enable_RootPort:
	push	ax

	call	Get_Host_Word			;ax=status of root port 1 or 2
	or	ax, PORT_ENABLE
	call	Set_Host_Word

	; Unknown reason must be set twice

	NEWIODELAY
	NEWIODELAY
	NEWIODELAY
	NEWIODELAY

	call	Set_Host_Word

	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Disable_RootPort
;Function:	Disable root port
;Input:		DX = Port address to disable
;Output:	none
;[]========================================================================[]

Disable_RootPort:
	push	ax

	call	Get_Host_Word			;ax=status of root port 1 or 2
	and	ax, not PORT_ENABLE
	call	Set_Host_Word

	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Get_Host_Byte
;Function:	Get host controller I/O register value with byte
;Input:		DX = Host I/O register offset
;Output:	AL = value
;[]========================================================================[]

Get_Host_Byte:
	push	dx
	add	dx, wHostIoBase
	in	al, dx
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Get_Host_Word
;Function:	Get host controller I/O register value with word
;Input:		DX = Host I/O register offset
;Output:	AX = value
;[]========================================================================[]

Get_Host_Word:
	push	dx
	add	dx, wHostIoBase
	in	ax, dx
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Get_Host_Dword
;Function:	Get host controller I/O register value with double word
;Input:		DX = Host I/O register offset
;Output:	EAX = value
;[]========================================================================[]

Get_Host_Dword:
	push	dx
	add	dx, wHostIoBase
	in	eax, dx
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Set_Host_Byte
;Function:	Set host controller I/O register value with byte
;Input:		DX = Host I/O register offset
;		AL = value
;Output:	none
;[]========================================================================[]

Set_Host_Byte:
	push	dx
	add	dx, wHostIoBase
	out	dx, al
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Set_Host_Word
;Function:	Set host controller I/O register value with word
;Input:		DX = Host I/O register offset
;		AX = value
;Output:	none
;[]========================================================================[]

Set_Host_Word:
	push	dx
	add	dx, wHostIoBase
	out	dx, ax
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Set_Host_Dword
;Function:	Set host controller I/O register value with double word
;Input:		DX = Host I/O register offset
;		EAX = value
;Output:	none
;[]========================================================================[]

Set_Host_Dword:
	push	dx
	add	dx, wHostIoBase
	out	dx, eax
	pop	dx
	ret


;************************************************************************
;*									*
;*	GENERAL DEVICE MANAGEMENT					*
;*									*
;************************************************************************

;[]========================================================================[]
;Procedure:	Init_Device
;Function:	Get device descriptor and set address for attached device
;Input:		BX = point to control parameter block
;			bCtrlByte contained low speed device information
;			bParentAddr conatined upstream device address
;			bParentPort contained upstream device port number
;Output:	CF = 0 successful
;			bDevAddr contained device address
;			DevDespBuffer contained device descriptor
;		CF = 1 fail
;[]========================================================================[]

Init_Device:
	pushad

	call	Wait_Stable			;wait device stable

	; First time to get device descriptor (8 bytes)

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	byte ptr [si].bmRequestType, 10000000b
	mov	byte ptr [si].bRequest, GET_DESCRIPTOR
	mov	byte ptr [si+1].wValue, DEVICE_DESCRIPTOR
	mov	word ptr [si].wLength, 8

	mov	word ptr [bx].wReqBuffer, si
	or	byte ptr [bx].bCtrlByte, CP_RD
	mov	word ptr [bx].wDataBuffer, offset DevDespBuffer
	mov	word ptr [bx].wTotalSize, 8
	mov	word ptr [bx].wMaxSize, 8
	call	Control_Transfer
	jc	short Init_Device_Fail

	; Set device address

	call	Query_Addr			;query available device address
	jc	short Init_Device_Fail

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	byte ptr [si].bmRequestType, 0
	mov	byte ptr [si].bRequest, SET_ADDRESS
	mov	byte ptr [si].wValue, al	;device address

	mov	[bx].wReqBuffer, si
	mov	word ptr [bx].wTotalSize, 0	;null data control transfer
	call	Control_Transfer
	jc	short Init_Device_Fail

	mov	byte ptr [bx].bDevAddr, al	;device address
	mov	dl, [bx].bParentAddr		;upstream device address
	mov	dh, [bx].bParentPort		;upstream device port
	call	Record_Addr			;record device address

	; Second time to get device descriptor (total bytes)

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	byte ptr [si].bmRequestType, 10000000b
	mov	byte ptr [si].bRequest, GET_DESCRIPTOR
	mov	byte ptr [si+1].wValue, DEVICE_DESCRIPTOR
	movzx	ax, byte ptr DevDespBuffer.DDbLength		;total length
	mov	word ptr [si].wLength, ax

	mov	word ptr [bx].wReqBuffer, si
	or	byte ptr [bx].bCtrlByte, CP_RD
	mov	word ptr [bx].wDataBuffer, offset DevDespBuffer
	mov	word ptr [bx].wTotalSize, ax
	movzx	ax, byte ptr DevDespBuffer.DDbMaxPackSize	;packet size
	mov	word ptr [bx].wMaxSize, ax
	call	Control_Transfer
	jc	short Init_Device_Fail

	popad
	clc
	ret

Init_Device_Fail:
	popad
	stc
	ret

;[]========================================================================[]
;Procedure:	Init_Config
;Function:	Get configuration descriptor and set configuration for BIOS
;		supported device
;Input:		BX = point to control parameter block
;			bCtrlByte contained low speed device information
;			bParentAddr conatined upstream device address
;			bParentPort contained upstream device port number
;			bDevAddr contained device address
;		DevDespBuffer contained device descriptor
;Output:	CF = 0 successful
;		CF = 1 fail
;[]========================================================================[]

Init_Config:
	pushad

	xor	cl, cl					;index

Init_Config_Loop:

	; First time to get configuration descriptor (8 bytes)

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	byte ptr [si].bmRequestType, 10000000b
	mov	byte ptr [si].bRequest, GET_DESCRIPTOR
	mov	byte ptr [si].wValue, cl
	mov	byte ptr [si+1].wValue, CONFIG_DESCRIPTOR
	mov	word ptr [si].wLength, 8

	mov	word ptr [bx].wReqBuffer, si
	or	byte ptr [bx].bCtrlByte, CP_RD
	mov	word ptr [bx].wDataBuffer, offset CfgDespBuffer
	mov	word ptr [bx].wTotalSize, 8
	mov	word ptr [bx].wMaxSize, 8
	call	Control_Transfer
	jc	Init_Config_Fail

	; Second time to get configuration descriptor (total bytes)

	mov	ax, word ptr CfgDespBuffer.CDwTotalLen		;total length
	cmp	ax, MAX_DESP_LEN
	jbe	short @f
	mov	ax, MAX_DESP_LEN
@@:
	mov	word ptr [si].wLength, ax

	mov	word ptr [bx].wTotalSize, ax
	movzx	ax, byte ptr DevDespBuffer.DDbMaxPackSize	;packet size
	mov	word ptr [bx].wMaxSize, ax
	call	Control_Transfer
	jc	short Init_Config_Fail

;R41 - start
	; Check BIOS supported device for this configuration

	call	Check_BIOS_Device
	jc	short Init_Config_Next
;R41 - end
;R41	push	cx
;R41
;R41	mov	cx, BIOS_Device_Num
;R41	mov	dx, offset Init_Proc SMI_OFFSET
;R41	mov	di, offset BIOS_Device SMI_OFFSET
;R41	mov	si, offset CfgDespBuffer.StdIDsp	;interface descriptor
;R41
;R41Init_BIOS_Device_Loop:
;R41
;R41	mov	al, cs:[di]
;R41	cmp	al, [si].IDbClass
;R41	jne	short Next_BIOS_Device
;R41	mov	al, cs:[di+1]
;R41	cmp	al, 0FFh			;R08
;R41	je	short BIOS_Device_Found		;R08
;R41	cmp	al, [si].IDbSubClass
;R41	jne	short Next_BIOS_Device
;R41	mov	al, cs:[di+2]
;R41	cmp	al, 0FFh			;R08
;R41	je	short BIOS_Device_Found		;R08
;R41	cmp	al, [si].IDbProtocol
;R41	jne	short Next_BIOS_Device
;R41
;R41BIOS_Device_Found:				;R08
;R41
;R41	pop	cx
;R41
;R41	mov	di, dx

	; Set configuration

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	byte ptr [si].bmRequestType, 0
	mov	byte ptr [si].bRequest, SET_CONFIGURATION
	mov	al, CfgDespBuffer.CDbCfgValue
	mov	byte ptr [si].wValue, al

	mov	[bx].wReqBuffer, si
	mov	word ptr [bx].wTotalSize, 0	;null data control transfer
	call	Control_Transfer
	jc	short Init_Config_Exit

;R41 - start
	; Initialize the BIOS supported devices' interfaces

	push	cx

	movzx	cx, byte ptr CfgDespBuffer.CDbNumInt	;numbers of interface

Init_Interface_Loop:
	push	cx

	mov	al, cl
	call	Verify_BIOS_Device
	jc	short Init_Interface_Next

	; wIntDspPoint = point to interface descriptor
	; wInitProcPoint = point to initialization procedure

	call	wInitProcPoint

Init_Interface_Next:
	pop	cx
	loop	short Init_Interface_Loop

	pop	cx
;R41 - end
;R41	; Call corresponding procedure to initialize BIOS devices
;R41
;R41	pushad
;R41	call	word ptr cs:[di]
;R41	popad
;R41	jmp	short Init_Config_Exit
;R41
;R41Next_BIOS_Device:
;R41	add	di, 3
;R41	add	dx, 2
;R41	loop	short Init_BIOS_Device_Loop
;R41
;R41	pop	cx

Init_Config_Next:
	inc	cl				;next configuration
	cmp	cl, DevDespBuffer.DDbNumConfig	;number of config
	jb	Init_Config_Loop

Init_Config_Exit:
	popad
	clc
	ret

Init_Config_Fail:
	popad
	stc
	ret

BIOS_Device	label	byte
;		Class, SubClass, Protocol
;R08	db	09, 01, 00			;Hub
	db	09, 0FFh, 0FFh			;R08;Hub
	db	03, 01, 01			;Keyboard
ifdef	USB_MOUSE_SUPPORT			;R41
	db	03, 01, 02			;R41;mouse
endif	;USB_MOUSE_SUPPORT			;R41
BIOS_Device_Num	equ	($ - BIOS_Device)/3

Init_Proc	label	word
	dw	offset Init_Hub SMI_OFFSET
	dw	offset Init_Keyboard SMI_OFFSET
ifdef	USB_MOUSE_SUPPORT			;R41
	dw	offset Init_Mouse SMI_OFFSET	;R41
endif	;USB_MOUSE_SUPPORT			;R41

;R41 - start
;[]========================================================================[]
;Procedure:	Check_BIOS_Device
;Function:	Check the interface of BIOS supported device for current
;		configuration
;Input:		CfgDespBuffer = current configuration descriptor
;Output:	CF = 1 no BIOS supported device interface
;		CF = 0 BIOS supported device interface found
;[]========================================================================[]

Check_BIOS_Device:
	push	ax
	push	cx
	movzx	cx, byte ptr CfgDespBuffer.CDbNumInt	;numbers of interface
Check_BIOS_Device_Loop:
	mov	al, cl
	call	Verify_BIOS_Device
	jnc	short Check_BIOS_Device_Exit
	loop	short Check_BIOS_Device_Loop
Check_BIOS_Device_Exit:
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Verify_BIOS_Device
;Function:	Verify BIOS supported device interface
;Input:		AL = interface number
;		CfgDespBuffer = current configuration descriptor
;Output:	CF = 1 not BIOS supported device interface
;		CF = 0 BIOS supported device interface
;			wIntDspPoint = point to interface descriptor
;			wInitProcPoint = point to initialization procedure
;[]========================================================================[]

Verify_BIOS_Device:
	pusha
	mov	di, offset CfgDespBuffer
	call	Find_IntDesp
	jc	short Verify_BIOS_Device_Exit

	mov	cx, BIOS_Device_Num
	mov	bx, offset Init_Proc SMI_OFFSET
	mov	si, offset BIOS_Device SMI_OFFSET

Verify_BIOS_Device_Loop:

	mov	al, cs:[si]
	cmp	al, [di].IDbClass
	jne	short Next_BIOS_Device
	mov	al, cs:[si+1]
	cmp	al, 0FFh
	je	short BIOS_Device_Found
	cmp	al, [di].IDbSubClass
	jne	short Next_BIOS_Device
	mov	al, cs:[si+2]
	cmp	al, 0FFh
	je	short BIOS_Device_Found
	cmp	al, [di].IDbProtocol
	je	short BIOS_Device_Found

Next_BIOS_Device:
	add	si, 3
	add	bx, 2
	loop	short Verify_BIOS_Device_Loop
	stc
	jmp	short Verify_BIOS_Device_Exit

BIOS_Device_Found:
	mov	wIntDspPoint, di
	mov	ax, cs:[bx]
	mov	wInitProcPoint, ax
	clc

Verify_BIOS_Device_Exit:
	popa
	ret

;[]========================================================================[]
;Procedure:	Find_IntDesp
;Function:	Find interface descriptor in CfgDespBuffer according to
;		the interface number
;Input:		AL = interface number (one based)
;		DI = point to configuration descriptor
;Output:	CF = 1 interface descriptor not found
;		CF = 0 interface descriptor found
;			DI = point to interface descriptor
;[]========================================================================[]

Find_IntDesp:
	push	ax
	push	cx
	push	dx
	mov	cx, [di].CDwTotalLen
Find_IntDesp_Loop:
	cmp	byte ptr [di+1], 04		;descriptor type byte
	jne	short Find_IntDesp_Next
	dec	al
	jnz	short Find_IntDesp_Next
	clc
	jmp	short Find_IntDesp_Exit
Find_IntDesp_Next:
	movzx	dx, byte ptr [di+0]		;descriptor length
	add	di, dx				;next descriptor
	sub	cx, dx
	jnb	short Find_IntDesp_Loop
	stc
Find_IntDesp_Exit:
	pop	dx
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Remove_KbTask
;Function:	Remove all keyboard task from task link
;Input:		none
;Output:	none
;[]========================================================================[]

Remove_KbTask:
	mov	al, TK_KBD
	call	Remove_BiosDevTask
	ret

;[]========================================================================[]
;Procedure:	Remove_MsTask
;Function:	Remove all mouse task from task link
;Input:		none
;Output:	none
;[]========================================================================[]

Remove_MsTask:
	mov	al, TK_MS
	call	Remove_BiosDevTask
	ret

;[]========================================================================[]
;Procedure:	Remove_BiosDevTask
;Function:	Remove BIOS supported device(kb, ms) task from task link
;Input:		AL = devive identifier in Task Data Structure
;Output:	none
;[]========================================================================[]

Remove_BiosDevTask:
	push	si
	push	di

	mov	di, offset wTaskLink

Remove_BiosDevTask_Loop:
	cmp	word ptr [di].wTkLink, 0FFFFh
	je	short Remove_BiosDevTask_Exit

	mov	di, [di].wTkLink
	test	byte ptr [di].bTkDevStatus, al
	jz	short Remove_BiosDevTask_Loop

	mov	si, di
	call	Remove_Task
	jmp	Remove_BiosDevTask_Loop

Remove_BiosDevTask_Exit:
	pop	di
	pop	si
	ret
;R41 - end

;[]========================================================================[]
;Procedure:	Release_ChildDev
;Function:	Release downstream device address and remove device task
;		if existed in Task Link
;Input:		AL = device number
;		AH = port number (0=all ports)
;Output:	none
;[]========================================================================[]

Release_ChildDev:
	pusha

	mov	cx, 127
	xor	dl, dl				;device address count
	mov	si, offset DevAddrMap+2

Release_ChildDev_Loop:

	inc	dl				;next device address

	push	ax
	xor	al, [si]
	cmp	al, 80h				;address occupied and
	jne	short Release_ChildDev_Next	;matched?

	or	ah, ah				;all ports?
	jz	short @f			;yes

	xor	ah, [si+1]			;port match?
	jnz	short Release_ChildDev_Next	;no

@@:
	and	byte ptr [si], 7Fh		;clear occupied bit

	mov	al, dl
	call	Remove_DevTask			;AL=dev addr

	call	Release_ChildDev		;AL=dev addr, AH=0:all ports

Release_ChildDev_Next:

	pop	ax

	inc	si				;next DevAddrMap
	inc	si
	loop	short Release_ChildDev_Loop

	popa
	ret

;[]========================================================================[]
;Procedure:	Link_Task
;Function:	Link (Append/Insert) one task to the Task Link
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Link_Task:
	pusha

;R40	or	byte ptr bUsbFlag, 04		;R08;task link updated
	or	byte ptr bUsbFlag, TASKCHG	;R40;task link updated

	; Link Task to Task Chain

        call    Link_Task_Chain                 ;R50

;R50	mov	ax, [si].wTkInterval
;R50;R08	call	Validate_Interval
;R50;R08	mov	[si].wTkInterval, ax
;R50
;R50	mov	cx, ax				;interval
;R50	or	cx, cx				;avoid coding mistake
;R50	jz	short Link_TK_Exit
;R50
;R50	mov	di, offset wTaskLink		;task link point
;R50;R47 - start
;R50	cmp	si, offset SysCtrlTask		;always link system control task
;R50	je	short Link_TK_Insert		;to the head of task link
;R50	mov	di, [di].wTkLink		;skip system control task
;R50;R47 - end
;R50
;R50Link_TK_Loop:
;R50	cmp	word ptr [di].wTkLink, 0FFFFh
;R50	je	short Link_TK_Append
;R50
;R50	mov	bx, [di].wTkLink
;R50;R47 - start
;R50	cmp	bx, offset TimerTask		;always link other tasks prior
;R50	je	short Link_TK_Insert		;to the timer task
;R50	cmp	si, offset TimerTask		;always link the timer task
;R50	je	short Link_TK_Next		;to the tail of task link
;R50;R47 - end
;R50
;R50	cmp	cx, [bx].wTkInterval
;R50	jb	short Link_TK_Insert
;R50
;R50Link_TK_Next:					;R47
;R50	mov	di, bx
;R50	jmp	short Link_TK_Loop
;R50
;R50Link_TK_Insert:
;R50	mov	ax, [di].wTkLink
;R50	mov	[si].wTkLink, ax
;R50	jmp	short Link_TK_Previous
;R50
;R50Link_TK_Append:
;R50	mov	word ptr [si].wTkLink, 0FFFFh	;terminate
;R50
;R50Link_TK_Previous:
;R50	mov	[di].wTkLink, si

	; Link Queue Head to Frame List

	mov	ax, [si].wTkInterval
	mov	di, [si].wTkTransDesp
	mov	si, [si].wTkQueueHead
	mov	[si].wQhInterval, ax
	call	Link_QH_to_FL

;R06 - start
	test	word ptr wKbdDevMap, 0FFFFh
;R41	jz	short Link_TK_Exit
	jnz	short Link_Timer_Task		;R41
	test	word ptr wMsDevMap, 0FFFFh	;R41
	jz	short Link_TK_Exit		;R41
Link_Timer_Task:				;R41

;R40	test	bUsbFlag, 08
	test	bUsbFlag, TIMERINST		;R40;timer task installed?
	jnz	short Link_TK_Exit

;R40	or	bUsbFlag, 08
	or	bUsbFlag, TIMERINST		;R40;timer task installed
	call	Init_TimerTD			;R47;initialize timer TD
	mov	si, offset TimerTask
	call	Link_Task
;R06 - end

Link_TK_Exit:
	popa
	ret

;R50 - start

;[]========================================================================[]
;Procedure:     Link_Task_Chain
;Function:      Link (Append/Insert) one task control block to the Task Link
;Input:         SI = point to task
;Output:        none

;[]========================================================================[]

Link_Task_Chain:
        pusha

        mov     ax, [si].wTkInterval

        mov     cx, ax                          ;interval
        or      cx, cx                          ;avoid coding mistake
        jz      short Link_TKC_Exit

        mov     di, offset wTaskLink            ;task link point

        cmp     si, offset SysCtrlTask          ;always link system control task
        je      short Link_TK_Insert            ;to the head of task link
        mov     di, [di].wTkLink                ;skip system control task

Link_TK_Loop:
        cmp     word ptr [di].wTkLink, 0FFFFh
        je      short Link_TK_Append

        mov     bx, [di].wTkLink

        cmp     bx, offset TimerTask            ;always link other tasks prior
        je      short Link_TK_Insert            ;to the timer task
        cmp     si, offset TimerTask            ;always link the timer task
        je      short Link_TK_Next              ;to the tail of task link

        cmp     cx, [bx].wTkInterval
        jb      short Link_TK_Insert

Link_TK_Next:
        mov     di, bx
        jmp     short Link_TK_Loop

Link_TK_Insert:
        mov     ax, [di].wTkLink
        mov     [si].wTkLink, ax
        jmp     short Link_TK_Previous

Link_TK_Append:
        mov     word ptr [si].wTkLink, 0FFFFh   ;terminate

Link_TK_Previous:
        mov     [di].wTkLink, si

Link_TKC_Exit:
        popa
        ret

;[]========================================================================[]
;Procedure:     Remove_Task_Chain
;Function:      Remove one task control block from the Task Link
;Input:         SI = point to task
;Output:        none

;[]========================================================================[]

Remove_Task_Chain:
        pusha

        ; Remove Task from Task Chain

        mov     di, offset wTaskLink

Remove_TKC_Loop:
        cmp     word ptr [di].wTkLink, 0FFFFh
        je      short Remove_TKC_Exit

        cmp     si, [di].wTkLink
        je      short Go_Remove_TKC

        mov     di, [di].wTkLink
        jmp     short Remove_TKC_Loop

Go_Remove_TKC:
        mov     ax, [si].wTkLink
        mov     [di].wTkLink, ax

Remove_TKC_Exit:
        popa
        ret
;R50 - end

;[]========================================================================[]
;Procedure:	Remove_Task
;Function:	Remove one task from the Task Link
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Remove_Task:
	pusha

	; Remove Task from Task Chain

	mov	di, offset wTaskLink

Remove_TK_Loop:
	cmp	word ptr [di].wTkLink, 0FFFFh
	je	short Remove_TK_Exit

	cmp	si, [di].wTkLink
	je	short Go_Remove_TK

	mov	di, [di].wTkLink
	jmp	short Remove_TK_Loop

Go_Remove_TK:
	mov	ax, [si].wTkLink
	mov	[di].wTkLink, ax

	call	Do_Remove_Task

Remove_TK_Exit:
	popa
	ret

;[]========================================================================[]
;Procedure:	Remove_DevTask
;Function:	Remove one task from the Task Link according to device address
;Input:		AL = device address
;Output:	none
;[]========================================================================[]

Remove_DevTask:
	pusha

	; Remove Task from Task Chain

	mov	di, offset wTaskLink

Remove_DTK_Loop:
	cmp	word ptr [di].wTkLink, 0FFFFh
	je	short Remove_DTK_Exit

	mov	si, [di].wTkLink

	cmp	al, [si].bTkDevAddr
	je	short Go_Remove_DTK

	mov	di, si
	jmp	short Remove_DTK_Loop

Go_Remove_DTK:
	push	ax				;R47
	mov	ax, [si].wTkLink
	mov	[di].wTkLink, ax

	call	Do_Remove_Task
	pop	ax				;R47
	jmp	short Remove_DTK_Loop		;R47

Remove_DTK_Exit:
	popa
	ret

;[]========================================================================[]
;Procedure:	Do_Remove_Task
;Function:	Remove TD and QH, release BIOS supported device map
;Input:		SI = point to task be removed
;Output:	none
;[]========================================================================[]

Do_Remove_Task:
	pushad					;R47

;R40	or	byte ptr bUsbFlag, 04		;R08;task link updated
	or	byte ptr bUsbFlag, TASKCHG	;R40;task link updated

	; Remove Transfer Descriptor from Queue Head

	push	si

	mov	di, [si].wTkQueueHead
	mov	si, [si].wTkTransDesp
	call	Remove_TD_from_QH

	; Remove Queue Head from Frame List

	mov	si, di
	call	Remove_QH_from_FL

	pop	si

	; Release index number of BIOS supported devices

	mov	ah, byte ptr [si].bTkDevStatus
	test	ah, (TK_HUB+TK_KBD+TK_MS)
	jz	short Do_Remove_Exit

	mov	al, [si].bTkDevIndex
	mov	bx, offset Release_Hub_Index SMI_OFFSET
	test	ah, TK_HUB
	jnz	short @f
	mov	bx, offset Release_Kbd_Index SMI_OFFSET
	test	ah, TK_KBD
	jnz	short @f
	mov	bx, offset Release_Ms_Index SMI_OFFSET
@@:
	call	bx
;R41B - start
;R46ifdef	USB_MOUSE_SUPPORT
;R46	test	byte ptr [si].bTkDevStatus, TK_MS	;mouse task?
;R46	jz	short Do_Remove_Exit
;R46	test	wMsDevMap, 0FFFFh		;any USB mouse installed?
;R46	jnz	short Do_Remove_Exit
;R46	test	bEmuCmdByte, MSIFDIS		;emulated command byte of kc
;R46	jnz	short Do_Remove_Exit
;R46	and	bRealCmdByte, not MSIFDIS	;real command byte of kc
;R46	call	DisableUsbLegacySmi
;R46	mov	al, 0A8h			;enable PS2 mouse interface
;R46	out	64h, al				;write to kc
;R46	call	EnableUsbLegacySmi
;R46endif	;USB_MOUSE_SUPPORT
;R41B - end

Do_Remove_Exit:

;R06 - start
	test	word ptr wKbdDevMap, 0FFFFh
	jnz	short @f
	test	word ptr wMsDevMap, 0FFFFh	;R41
	jnz	short @f			;R41

;R40	test	bUsbFlag, 08
	test	bUsbFlag, TIMERINST		;R40;timer task installed?
	jz	short @f

;R40	and	bUsbFlag, 0F7h
	and	bUsbFlag, NOT TIMERINST		;R40;no timer task installed
	mov	si, offset TimerTask
	call	Remove_Task
@@:
;R06 - end

	popad					;R47
	ret

;[]========================================================================[]
;Procedure:	Init_Task
;Function:	Initialize task data block
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Init_Task:
	pusha
;R08	xor	al, al
;R08	mov	cx, SIZE TASK
;R08@@:
;R08	mov	[si], al
;R08	inc	si
;R08	loop	short @b
	mov	cx, SIZE TASK			;R08
	call	Clear_Buffer			;R08
	popa
	ret

;[]========================================================================[]
;Procedure:	Suspend_Tasks
;Function:	Suspend all tasks for Control Transfer
;Input:		none
;Output:	none
;[]========================================================================[]

Suspend_Tasks:
	pusha

	mov	bx, offset wTaskLink
Suspend_TK_Loop:
	cmp	word ptr [bx].wTkLink, 0FFFFh
	je	short Suspend_TK_Exit

	mov	bx, [bx].wTkLink
	mov	si, [bx].wTkTransDesp
	mov	di, [bx].wTkQueueHead
	call	Remove_TD_from_QH
	jmp	short Suspend_TK_Loop

Suspend_TK_Exit:
	popa
	ret

;[]========================================================================[]
;Procedure:	Resume_Tasks
;Function:	Resume all tasks after Control Transfer
;Input:		none
;Output:	none
;[]========================================================================[]

Resume_Tasks:
	pusha

	mov	bx, offset wTaskLink
Resume_TK_Loop:
	cmp	word ptr [bx].wTkLink, 0FFFFh
	je	short Resume_TK_Exit

	mov	bx, [bx].wTkLink
	mov	si, [bx].wTkTransDesp
	mov	di, [bx].wTkQueueHead
	call	Link_TD_to_QH
	jmp	short Resume_TK_Loop

Resume_TK_Exit:
	popa
	ret

;[]========================================================================[]
;Procedure:	Validate_Interval
;Function:	Validate the interval value
;		Allowed interval value in Award BIOS is the dimension of 2
;		e.g.1,2,4,8,16,32,64,128,256,512,1024
;Input:		AX = interval value reported by device
;Output:	AX = allowed interval value
;[]========================================================================[]

Validate_Interval:
	push	bx
	push	cx
	push	dx
	mov	bx, ax
	mov	ax, 1
	mov	cx, 10
@@:
	cmp	bx, ax
	jbe	short @f
	mov	dx, 2
	mul	dx
	loop	short @b
@@:
	pop	dx
	pop	cx
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Physical_Linear
;Function:	Calculate FL, QH and TD physical 32-bit linear address
;Input:		AX = offset value in USB_RAM
;Output:	EAX = physical 32-bit linear address value
;[]========================================================================[]

Physical_Linear:
	push	edx
	xor	edx, edx
	mov	dx, ds
	shl	edx, 4
	and	eax, 0000FFFFh
	add	eax, edx
	pop	edx
	ret

;[]========================================================================[]
;Procedure:	Physical_Offset
;Function:	Calculate 32-bit linear address to offset of USB_RAM
;Input:		EAX = physical 32-bit linear address value
;Output:	EAX = offset value in USB_RAM
;[]========================================================================[]

Physical_Offset:
	push	edx
	xor	edx, edx
	mov	dx, ds
	shl	edx, 4
	sub	eax, edx
	and	al, 0F0h			;don't care bit
	pop	edx
	ret

;[]========================================================================[]
;Procedure:	Query_Addr
;Function:	Query availible device address
;Input:		none
;Output:	CF = 1 no device address availible
;		CF = 0 availible device address found
;			AL = availible device address
;[]========================================================================[]

Query_Addr:
	push	cx
	push	si

	mov	cx, 127
	xor	ah, ah
	mov	si, offset DevAddrMap+2
Query_Addr_Loop:
	inc	ah
	lodsb
	test	al, 80h
	jz	short Query_Addr_Success
	inc	si
	loop	short Query_Addr_Loop
	stc
	jmp	short Query_Addr_Exit

Query_Addr_Success:
	mov	al, ah
	clc
Query_Addr_Exit:
	pop	si
	pop	cx
	ret

;[]========================================================================[]
;Procedure:	Record_Addr
;Function:	Record device address
;Input:		AL = device address to record
;		DL = parent device address
;		DH = parent device port
;Output:	none
;[]========================================================================[]

Record_Addr:
	push	bx
	push	dx
	movzx	bx, al
	shl	bx, 1
	or	dl, 80h
	mov	word ptr DevAddrMap[bx], dx
	pop	dx
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Release_Addr
;Function:	Release device address
;Input:		AL = device address to release
;Output:	none
;[]========================================================================[]

Release_Addr:
	push	bx
	movzx	bx, al
	shl	bx, 1
	and	byte ptr DevAddrMap[bx], 7Fh
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Query_Index
;Function:	Query availible hub/keyboard/mouse index number
;Input:		none
;Output:	CF = 1 no index number availible
;		CF = 0 availible index number found
;			AL = availible index number
;[]========================================================================[]

Query_Hub_Index:
	push	cx
	push	dx
	mov	cx, MAX_HUB
	mov	dx, wHubDevMap
	jmp	short Query_Index

Query_Kbd_Index:
	push	cx
	push	dx
	mov	cx, MAX_KBD
	mov	dx, wKbdDevMap
	jmp	short Query_Index

Query_Ms_Index:
	push	cx
	push	dx
	mov	cx, MAX_MS
	mov	dx, wMsDevMap

Query_Index:
	xor	al, al
@@:
	shr	dx, 1
	jnc	short @f
	inc	al
	loop	short @b

	pop	dx
	pop	cx
	stc
	ret
@@:
	pop	dx
	pop	cx
	clc
	ret

;[]========================================================================[]
;Procedure:	Record_Index
;Function:	Record hub/keyboard/mouse index number
;Input:		AL = index number
;Output:	none
;[]========================================================================[]

Record_Hub_Index:
	push	bx
	mov	bx, offset wHubDevMap
	jmp	short Record_Index

Record_Kbd_Index:
	push	bx
	mov	bx, offset wKbdDevMap
	jmp	short Record_Index

Record_Ms_Index:
	push	bx
	mov	bx, offset wMsDevMap

Record_Index:
	push	ax
	push	cx
	mov	cl, al
	mov	ax, 1
	rol	ax, cl
	or	[bx], ax
	pop	cx
	pop	ax
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Release_Index
;Function:	Release hub/keyboard/mouse index number
;Input:		AL = index number
;Output:	none
;[]========================================================================[]

Release_Hub_Index:
	push	bx
	mov	bx, offset wHubDevMap
	jmp	short Release_Index

Release_Kbd_Index:
	push	bx
	mov	bx, offset wKbdDevMap
	jmp	short Release_Index

Release_Ms_Index:
	push	bx
	mov	bx, offset wMsDevMap

Release_Index:
	push	ax
	push	cx
	mov	cl, al
	mov	ax, 0FFFEh
	rol	ax, cl
	and	[bx], ax
	pop	cx
	pop	ax
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Init_ReqBuffer
;Function:	Initialize device request data buffer
;Input:		SI = point to device request data buffer
;Output:	none
;[]========================================================================[]

Init_ReqBuffer:
	pusha
;R08	xor	al, al
;R08	mov	cx, SIZE DEVREQ
;R08@@:
;R08	mov	[si], al
;R08	inc	si
;R08	loop	short @b
	mov	cx, SIZE DEVREQ			;R08
	call	Clear_Buffer			;R08
	popa
	ret

;R08 - start
;[]========================================================================[]
;Procedure:	Get_CtrlBuffer
;Function:	Get availible control parameter block
;Input:		none
;Output:	CF = 1 no availible control buffer
;		CF = 0 found availible control buffer
;			SI = point to control parameter block
;[]========================================================================[]

Get_CtrlBuffer:
	push	ax
	push	cx
	push	dx

	mov	cx, MAX_CTLBUFF
	mov	dx, 1
	xor	ax, ax
@@:
	test	wCtrlBuffMap, dx
	jz	short @f
	shl	dx, 1
	inc	ax
	loop	short @b
	jmp	short Get_CtrlBuff_Fail

@@:
	or	wCtrlBuffMap, dx

	mov	si, SIZE CTLPARA
	mul	si
	mov	si, ax
	add	si, offset ControlBuffer
	call	Init_CtrlBuffer

	clc
	jmp	short Get_CtrlBuff_Exit

Get_CtrlBuff_Fail:
	stc

Get_CtrlBuff_Exit:
	pop	dx
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Release_CtrlBuffer
;Function:	Release control parameter block
;Input:		SI = point to control parameter block
;Output:	none
;[]========================================================================[]

Release_CtrlBuffer:
	pusha
	cmp	si, (offset ControlBuffer+((SIZE CTLPARA)*MAX_CTLBUFF))
	jae	short @f
	mov	ax, si
	sub	ax, offset ControlBuffer
	mov	cx, SIZE CTLPARA
	xor	dx, dx
	div	cx
	or	dx, dx
	jnz	short @f
	mov	cl, al
	mov	ax, 0FFFEh
	rol	ax, cl
	and	wCtrlBuffMap, ax
@@:
	popa
	ret
;R08 - end

;[]========================================================================[]
;Procedure:	Init_CtrlBuffer
;Function:	Initialize control parameter block
;Input:		SI = point to control parameter block
;Output:	none
;[]========================================================================[]

Init_CtrlBuffer:
	pusha
;R08	xor	al, al
;R08	mov	cx, SIZE CTLPARA
;R08@@:
;R08	mov	[si], al
;R08	inc	si
;R08	loop	short @b
	mov	cx, SIZE CTLPARA		;R08
	call	Clear_Buffer			;R08
	popa
	ret

;R08 - start
;[]========================================================================[]
;Procedure:	Clear_Buffer
;Function:	Clear miscellaneous data buffer
;Input:		SI = point to data buffer
;		CX = length
;Output:	none
;[]========================================================================[]

Clear_Buffer:
	pusha
	xor	al, al
@@:
	mov	[si], al
	inc	si
	loop	short @b
	popa
	ret
;R08 - end

;R24 - start
;[]========================================================================[]
;Procedure:	Find_EndpDesp
;Function:	Find endpoint descriptor
;R41;Input:		DI = point to configuration descriptor
;Input:		DI = point to interface descriptor			;R41
;Output:	CF = 0 descriptor found
;			DI = point to endpoint descriptor
;		CF = 1 descriptor not found
;[]========================================================================[]

Find_EndpDesp:
;R41 - start
	push	ax
	push	cx
	mov	cx, 3				;3 descriptor for HID
Find_EndpDesp_Loop:
	cmp	byte ptr [di+1], 05		;descriptor type byte
	clc
	je	short Find_EndpDesp_Exit
	movzx	ax, byte ptr [di+0]		;descriptor length
	add	di, ax				;next descriptor
	loop	short Find_EndpDesp_Loop
	stc
Find_EndpDesp_Exit:
	pop	cx
	pop	ax
	ret
;R41 - end
;R41	push	ax
;R41	push	cx
;R41	mov	cx, [di].CDwTotalLen
;R41Find_EndpDesp_Loop:
;R41	cmp	byte ptr [di+1], 05		;descriptor type byte
;R41	jne	short Find_EndpDesp_Next
;R41	pop	cx
;R41	pop	ax
;R41	clc
;R41	ret
;R41Find_EndpDesp_Next:
;R41	movzx	ax, byte ptr [di+0]		;descriptor length
;R41	add	di, ax				;next descriptor
;R41	sub	cx, ax
;R41	jnb	short Find_EndpDesp_Loop
;R41	pop	cx
;R41	pop	ax
;R41	stc
;R41	ret
;R24 - end


;************************************************************************
;*									*
;*	HUB MANAGEMENT							*
;*									*
;************************************************************************

;[]========================================================================[]
;Procedure:	Init_Hub
;Function:	Initialize HUB
;Input:		BX = point to control parameter block
;Output:	none
;[]========================================================================[]

Init_Hub:

	; First time to get hub descriptor (8 bytes)

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	byte ptr [si].bmRequestType, 10100000b
	mov	byte ptr [si].bRequest, GET_DESCRIPTOR
	mov	byte ptr [si+1].wValue, HUB_DESCRIPTOR	;R25
	mov	word ptr [si].wLength, 8

	mov	word ptr [bx].wReqBuffer, si
	or	byte ptr [bx].bCtrlByte, CP_RD
	mov	word ptr [bx].wDataBuffer, offset ClassDespBuffer
	mov	word ptr [bx].wTotalSize, 8
	mov	word ptr [bx].wMaxSize, 8
	call	Control_Transfer
	jc	Init_Hub_Exit

	; Second time to get hub descriptor (total bytes)

	movzx	ax, byte ptr ClassDespBuffer.UDbLength		;total length
	cmp	ax, MAX_DESP_LEN
	jbe	short @f
	mov	ax, MAX_DESP_LEN
@@:
	mov	word ptr [si].wLength, ax

	mov	word ptr [bx].wTotalSize, ax
	movzx	ax, byte ptr DevDespBuffer.DDbMaxPackSize	;packet size
	mov	word ptr [bx].wMaxSize, ax
	call	Control_Transfer
	jc	Init_Hub_Exit

	call	Query_Hub_Index
	jc	Init_Hub_Exit

	call	Record_Hub_Index

	mov	dl, al					;hub index number

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	byte ptr [si].bmRequestType, 00100011b
	mov	byte ptr [si].bRequest, SET_FEATURE	;set port feature
	mov	word ptr [si].wValue, S_PORT_POWER	;set port power
	mov	word ptr [bx].wTotalSize, 0
	xor	ax, ax
	movzx	cx, byte ptr ClassDespBuffer.UDbNumPort
@@:
	inc	ax
	mov	[si].wIndex, ax
	call	Control_Transfer
	loop	short @b

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	byte ptr [si].bmRequestType, 10100011b
	mov	byte ptr [si].bRequest, GET_STATUS	;get port status
	mov	word ptr [si].wLength, 4

	or	byte ptr [bx].bCtrlByte, CP_RD
	mov	word ptr [bx].wDataBuffer, offset MiscDataBuffer
	mov	word ptr [bx].wTotalSize, 4
	mov	word ptr [bx].wMaxSize, 4
;R08	xor	ax, ax
;R08	xor	dl, dl
;R08	mov	dh, 02
	movzx	cx, byte ptr ClassDespBuffer.UDbNumPort

	push	cx
	push	dx				;R08;hub index number
	xor	ax, ax				;R08
	xor	dl, dl				;R08
	mov	dh, 02				;R08;start with port 1

Get_HubPort_Loop:
	inc	ax
	mov	[si].wIndex, ax
	call	Control_Transfer
	jc	short Get_HubPort_Next
	test	byte ptr MiscDataBuffer.HPSbStatus1, HPS_CONNECT
	jz	short Get_HubPort_Next
	or	dl, dh
Get_HubPort_Next:
	shl	dh, 1
	loop	short Get_HubPort_Loop

	pop	ax				;R08;hub index number
	push	dx
	mov	dx, ax				;R08;hub index number

	; Configure HUB interrupt transaction task
	; DL = hub index number

	mov	al, SIZE TASK
	mul	dl
	add	ax, offset HubIntTask
	mov	si, ax
	call	Init_Task

	mov	[si].bTkDevStatus, TK_WFP+TK_HUB

	mov	byte ptr [si].bTkDevIndex, dl

	mov	word ptr [si].wTkProc, offset Proc_Hub SMI_OFFSET

	mov	al, [bx].bDevAddr
	mov	[si].bTkDevAddr, al

	mov	al, [bx].bParentAddr
	mov	[si].bTkParentAddr, al

	mov	al, [bx].bParentPort
	mov	[si].bTkParentPort, al

	mov	di, offset CfgDespBuffer.StdEDsp

	movzx	ax, byte ptr [di].EDbInterval
	call	Validate_Interval		;R08
	mov	[si].wTkInterval, ax

	mov	ax, [di].EDwMaxPackSize
	mov	[si].wTkPacketSize, ax

	mov	al, byte ptr [di].EDbEndpAddr
	and	al, 7Fh
	mov	[si].bTkDevEndp, al

	push	si				;R08
	mov	al, 8
	movzx	cx, al
	mul	dl
	add	ax, offset HubDataBuffer
;R08	mov	di, ax
;R08	xor	al, al
;R08	rep	stosb
;R08	mov	[si].wTkDataBuffer, di
	mov	si, ax				;R08
	call	Clear_Buffer			;R08
	pop	si				;R08
	mov	[si].wTkDataBuffer, ax		;R08

	push	si				;R08
	mov	al, SIZE HUBCTRL
	movzx	cx, al
	mul	dl
	add	ax, offset HubCtrlBuffer
;R08	mov	di, ax
;R08	xor	al, al
;R08	rep	stosb
;R08
;R08	mov	al, ClassDespBuffer.UDbNumPort
;R08	mov	[di].bHcNumPort, al
;R08
;R08	mov	[si].wTkCtrlBuffer, di
	mov	si, ax				;R08
	call	Clear_Buffer			;R08
	mov	cl, ClassDespBuffer.UDbNumPort	;R08
	mov	[si].bHcNumPort, cl		;R08
	pop	si				;R08
	mov	[si].wTkCtrlBuffer, ax		;R08

	push	si
	mov	al, 16
	mul	dl
	add	ax, offset HubIntQH
	mov	si, ax
	call	Init_QH
	pop	si
	mov	[si].wTkQueueHead, ax

	push	si
	mov	al, SIZE TD
	mul	dl
	add	ax, offset HubIntTD
	mov	si, ax
	call	Init_TD
;R08	mov	di, si
	pop	si
;R08	mov	[si].wTkTransDesp, di
	mov	[si].wTkTransDesp, ax		;R08
	mov	di, ax				;R08

	mov	al, DEF_TDCTRL+ISS_IOC		;hub always high speed
	mov	[di].bTdControl, al

	mov	edx, PID_IN
	movzx	eax, word ptr [si].wTkPacketSize
	dec	eax
	shl	eax, BIT_MAXL
	or	edx, eax
	movzx	eax, byte ptr [si].bTkDevAddr
	shl	eax, BIT_ADDR
	or	edx, eax
	movzx	eax, byte ptr [si].bTkDevEndp
	shl	eax, BIT_EP
	or	edx, eax
	mov	[di].dTdToken, edx

	mov	ax, [si].wTkDataBuffer
	call	Physical_Linear
	mov	[di].dTdPoint, eax

	mov	byte ptr [di].bTdStatus, STS_ACTIVE

	call	Link_Task

	pop	ax
	pop	cx

	or	al, al
	jz	short Init_Hub_Exit

	; SI = point to hub task
	; AL = hub port status

	xor	ah, ah

Init_HubPort_Loop:
	inc	ah
	ror	al, 1
	test	al, 1
	jz	short Init_HubPort_Next

	call	Check_HubPort

Init_HubPort_Next:
	loop	short Init_HubPort_Loop

Init_Hub_Exit:
	ret

;[]========================================================================[]
;Procedure:	Proc_Hub
;Function:	HUB interrupt transaction process routine
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Proc_Hub:
	mov	bx, [si].wTkTransDesp
	test	byte ptr [bx].bTdStatus, STS_ACTIVE
	jnz	short Proc_Hub_Exit

	test	byte ptr [bx].bTdStatus, STS_ERROR
	jnz	short Proc_Hub_End

	mov	bx, [si].wTkCtrlBuffer
	movzx	cx, byte ptr [bx].bHcNumPort

	mov	bx, [si].wTkDataBuffer
	mov	al, [bx]
	or	al, al
	jz	short Proc_Hub_End
	xor	ah, ah
Proc_HubPort_Loop:
	inc	ah
	ror	al, 1
	test	al, 1
	jz	short Proc_HubPort_Next

	call	Suspend_Tasks

	call	Check_HubPort

	call	Resume_Tasks

Proc_HubPort_Next:
	loop	short Proc_HubPort_Loop

Proc_Hub_End:
	mov	bx, [si].wTkTransDesp
	or	byte ptr [bx].bTdControl, DEF_TDCTRL
	xor	dword ptr [bx].dTdToken, DATA_TOGGLE
	mov	byte ptr [bx].bTdStatus, STS_ACTIVE

	mov	di, [si].wTkQueueHead
	mov	si, [si].wTkTransDesp
	call	Link_TD_to_QH

Proc_Hub_Exit:
	ret

;[]========================================================================[]
;Procedure:	Check_HubPort
;Function:	Check and configure hub port device attached
;Input:		SI = point to hub task
;		AH = hub port number to enumerate
;Output:	none
;[]========================================================================[]

Check_HubPort:
	pusha

	mov	di, si

	; Get Hub port status

;R08	mov	si, offset ControlBuffer1
;R08	call	Init_CtrlBuffer
	call	Get_CtrlBuffer				;R08
	jc	Check_HubPort_End			;R08

	mov	bx, si

	mov	al, [di].bTkDevAddr
	mov	[bx].bDevAddr, al
	mov	byte ptr [bx].bCtrlByte, CP_RD		;hub always high speed
	mov	word ptr [bx].wDataBuffer, offset MiscDataBuffer
	mov	byte ptr [bx].wTotalSize, 4
	mov	byte ptr [bx].wMaxSize, 4

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
	mov	[bx].wReqBuffer, si

	mov	byte ptr [si].bmRequestType, 10100011b
	mov	byte ptr [si].bRequest, GET_STATUS	;get port status
	mov	byte ptr [si].wLength, 4
	mov	byte ptr [si].wIndex, ah

	call	Control_Transfer
	jc	Check_HubPort_Exit

	; Clear connection change status of hub port

	mov	word ptr [bx].wTotalSize, 0

	mov	byte ptr [si].bmRequestType, 00100011b
	mov	byte ptr [si].bRequest, CLEAR_FEATURE
	mov	byte ptr [si].wValue, C_PORT_CONNECTION
	mov	byte ptr [si].wLength, 0

	call	Control_Transfer
	jc	Check_HubPort_Exit

	; Check hub port connection status

	test	byte ptr MiscDataBuffer.HPSbStatus1, HPS_CONNECT
	jnz	short Enable_HubPort

	; Disable hub port

Disable_HubPort:

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer

	mov	byte ptr [si].bmRequestType, 00100011b
	mov	byte ptr [si].bRequest, CLEAR_FEATURE
	mov	byte ptr [si].wValue, S_PORT_ENABLE
	mov	byte ptr [si].wIndex, ah	;R01

	mov	word ptr [bx].wTotalSize, 0

	call	Control_Transfer
;R23	jc	Check_HubPort_Exit

;R23 - start
	mov	byte ptr [si].wValue, C_PORT_ENABLE
	call	Control_Transfer
;R23 - end

	mov	al, [di].bTkDevAddr		;device address
						;AH = port number
	call	Release_ChildDev
;R08	jmp	short Check_HubPort_Exit
	jmp	Check_HubPort_Exit		;R08

Enable_HubPort:

	; Reset port

	mov	byte ptr [si].bmRequestType, 00100011b
	mov	byte ptr [si].bRequest, SET_FEATURE
	mov	byte ptr [si].wValue, S_PORT_RESET

	call	Control_Transfer
;R08	jc	short Check_HubPort_Exit
	jc	Check_HubPort_Exit		;R08

	; Wait reset completed

	mov	byte ptr [bx].wTotalSize, 4

	mov	byte ptr [si].bmRequestType, 10100011b
	mov	byte ptr [si].bRequest, GET_STATUS	;get port status
	mov	byte ptr [si].wValue, 0			;selector field
	mov	byte ptr [si].wLength, 4

	call	Delay_12ms			;wait reset process

Wait_HubPort_Reset:
	call	Control_Transfer
	jc	short Check_HubPort_Exit

	test	byte ptr MiscDataBuffer.HPSbStatus1, HPS_RESET
	jnz	short Wait_HubPort_Reset

	mov	word ptr [bx].wTotalSize, 0

	mov	byte ptr [si].bmRequestType, 00100011b
	mov	byte ptr [si].bRequest, CLEAR_FEATURE
	mov	byte ptr [si].wValue, C_PORT_RESET
	mov	byte ptr [si].wLength, 0

	call	Control_Transfer
	jc	short Check_HubPort_Exit

	mov	byte ptr [si].bmRequestType, 00100011b	;R08
	mov	byte ptr [si].bRequest, CLEAR_FEATURE	;R08
	mov	byte ptr [si].wValue, C_PORT_ENABLE	;R08
	mov	byte ptr [si].wLength, 0		;R08
	call	Control_Transfer			;R08
	jc	short Check_HubPort_Exit		;R08

	; Enumerate device attached

	call	Get_CtrlBuffer				;R08
	jc	Disable_HubPort				;R08

	push	bx

;R08	mov	si, offset ControlBuffer2
;R08	call	Init_CtrlBuffer
	mov	bx, si

	test	byte ptr MiscDataBuffer.HPSbStatus2, HPS_LS
	jz	short @f
	or	byte ptr [bx].bCtrlByte, CP_LS
@@:
	mov	al, [di].bTkDevAddr
	mov	byte ptr [bx].bParentAddr, al	;upstream device address
	mov	byte ptr [bx].bParentPort, ah	;upstream port number
	mov	byte ptr [bx].bDevAddr, 0	;default address 0
	mov	byte ptr [bx].bDevEndp, 0	;default endpoint 0

	call	Init_Device
	jnc	short @f

	mov	si, bx				;R08
	call	Release_CtrlBuffer		;R08
	pop	bx

	jmp	Disable_HubPort

@@:
	call	Init_Config			;BX=point to control buffer

	mov	si, bx				;R08
	call	Release_CtrlBuffer		;R08
	pop	bx

Check_HubPort_Exit:
	mov	si, bx				;R08
	call	Release_CtrlBuffer		;R08
Check_HubPort_End:				;R08
	popa
	ret

;************************************************************************
;*									*
;*	KEYBOARD MANAGEMENT						*
;*									*
;************************************************************************

;[]========================================================================[]
;Procedure:	Init_Keyboard
;Function:	Initialize USB keyboard
;Input:		BX = point to control parameter block
;Output:	none
;[]========================================================================[]

Init_Keyboard:
	test	bUsbFlag, USBKBSUPPORT		;R41;USB kb supported?
	jz	Init_Kbd_Exit			;R41

	; Query/record available keyboard index number

	call	Query_Kbd_Index
	jc	Init_Kbd_Exit

	call	Record_Kbd_Index

;R27	mov	dl, al				;keyboard index number

;R24 - start
;R41	mov	di, offset CfgDespBuffer
	mov	di, wIntDspPoint		;R41;interface descriptor point
	call	Find_EndpDesp
;R24 - end

	call	Init_Keyboard_Task		;R27

;R49 - start
	; DI = task buffer pointer
	; Set boot protocol

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer

	; wValue = 0 : Boot protocol

	mov	byte ptr [si].bRequest, SET_PROTOCOL
	mov	byte ptr [si].bmRequestType, 00100010b
	mov	al, [di].bTkDevEndp			;endpoint
	test	byte ptr [di].bTkDevStatus, TK_NEWKBD
	jz	short @f
	mov	byte ptr [si].bmRequestType, 00100001b
	mov	al, [di].bTkDevInterface		;interface
@@:
	mov	byte ptr [si].wIndex, al	;interface or endpoint

	mov	word ptr [bx].wReqBuffer, si
	mov	word ptr [bx].wTotalSize, 0

	call	Control_Transfer
;R49 - end

	; Set idle rate

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
;R27	mov	byte ptr [si].bmRequestType, 00100010b
	mov	byte ptr [si].bRequest, SET_IDLE
;R16	mov	word ptr [si].wValue, 0201h
ifndef	ZERO_SET_IDLE					;R47
	mov	word ptr [si].wValue, 0400h		;R16
endif	;ZERO_SET_IDLE					;R47
;R24	mov	al, CfgDespBuffer.HidEDsp.EDbEndpAddr
;R27	mov	al, [di].EDbEndpAddr			;R24
;R27	and	al, 07Fh				;mask direction bit
;R27 - start
	mov	byte ptr [si].bmRequestType, 00100010b
	mov	al, [di].bTkDevEndp
	test	byte ptr [di].bTkDevStatus, TK_NEWKBD
	jz	short @f
	mov	byte ptr [si].bmRequestType, 00100001b
	mov	al, [di].bTkDevInterface
@@:
;R27 - end
	mov	byte ptr [si].wIndex, al

	mov	word ptr [bx].wReqBuffer, si
	mov	word ptr [bx].wTotalSize, 0

	call	Control_Transfer
;R05	jc	Init_Kbd_Exit
;R17 - start
	; Get report descriptor

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
;R41	mov	byte ptr [si].bmRequestType, 10000010b
	mov	byte ptr [si].bRequest, GET_DESCRIPTOR
	mov	byte ptr [si+1].wValue, 22h		;report descriptor
;R24	mov	al, CfgDespBuffer.HidEDsp.EDbEndpAddr
;R27	mov	al, [di].EDbEndpAddr			;R24
;R27	and	al, 07Fh				;mask direction bit
;R41	mov	al, [di].bTkDevEndp			;R27
;R41	mov	byte ptr [si].wIndex, al
	mov	word ptr [si].wLength, 003Fh		;descriptor length
;R41 - start
	mov	byte ptr [si].bmRequestType, 10000010b
	mov	al, [di].bTkDevEndp
	test	byte ptr [di].bTkDevStatus, TK_NEWKBD
	jz	short @f
	mov	byte ptr [si].bmRequestType, 10000001b
	mov	al, [di].bTkDevInterface
@@:
	mov	byte ptr [si].wIndex, al
;R41 - end

	mov	word ptr [bx].wReqBuffer, si
	or	byte ptr [bx].bCtrlByte, CP_RD		;read from device
	mov	word ptr [bx].wDataBuffer, offset MiscDataBuffer
	mov	word ptr [bx].wTotalSize, 3Fh			;total length
	movzx	ax, byte ptr DevDespBuffer.DDbMaxPackSize	;packet size
	mov	word ptr [bx].wMaxSize, ax
	call	Control_Transfer
;R17 - end

;R27	; Configure Keyboard interrupt transaction task
;R27	; DL = keyboard index number
;R27
;R27	mov	al, SIZE TASK
;R27	mul	dl
;R27	add	ax, offset KbdIntTask
;R27	mov	si, ax
;R27	call	Init_Task
;R27
;R27;R01	mov	[si].bTkDevStatus, TK_WFP+TK_KBD
;R27	mov	al, TK_WFP+TK_KBD			;R01
;R27	test	byte ptr [bx].bCtrlByte, CP_LS		;R01
;R27	jz	short @f				;R01
;R27	or	al, TK_LS				;R01
;R27@@:							;R01
;R27	mov	[si].bTkDevStatus, al			;R01
;R27
;R27	mov	byte ptr [si].bTkDevIndex, dl
;R27
;R27	mov	word ptr [si].wTkProc, offset Proc_Keyboard SMI_OFFSET
;R27
;R27	mov	al, [bx].bDevAddr
;R27	mov	[si].bTkDevAddr, al
;R27
;R27	mov	al, [bx].bParentAddr
;R27	mov	[si].bTkParentAddr, al
;R27
;R27	mov	al, [bx].bParentPort
;R27	mov	[si].bTkParentPort, al
;R27
;R27;R24	mov	di, offset CfgDespBuffer.HidEDsp
;R27
;R27	movzx	ax, byte ptr [di].EDbInterval
;R27	call	Validate_Interval		;R08
;R27	mov	[si].wTkInterval, ax
;R27
;R27	mov	ax, [di].EDwMaxPackSize
;R27	mov	[si].wTkPacketSize, ax
;R27
;R27	mov	al, byte ptr [di].EDbEndpAddr
;R27	and	al, 7Fh				;mask direction bit
;R27	mov	[si].bTkDevEndp, al
;R27
;R27	push	si				;R08
;R27	mov	al, 8
;R27	movzx	cx, al
;R27	mul	dl
;R27	add	ax, offset KbdDataBuffer
;R27;R08	mov	di, ax
;R27;R08	xor	al, al
;R27;R08	rep	stosb
;R27;R08	mov	[si].wTkDataBuffer, di
;R27	mov	si, ax				;R08
;R27	call	Clear_Buffer			;R08
;R27	pop	si				;R08
;R27	mov	[si].wTkDataBuffer, ax		;R08
;R27
;R27	push	si				;R08
;R27	mov	al, SIZE KBDCTRL
;R27	movzx	cx, al
;R27	mul	dl
;R27	add	ax, offset KbdCtrlBuffer
;R27;R08	mov	di, ax
;R27;R08	xor	al, al
;R27;R08	rep	stosb
;R27;R08	mov	byte ptr [di].bDelayRate,  12
;R27;R08	mov	byte ptr [di].bRepeatRate, 4
;R27;R08
;R27;R08	mov	[si].wTkCtrlBuffer, di
;R27	mov	si, ax				;R08
;R27	call	Clear_Buffer			;R08
;R27	mov	byte ptr [si].bDelayRate,  12	;R08
;R27	mov	byte ptr [si].bRepeatRate, 4	;R08
;R27	pop	si				;R08
;R27	mov	[si].wTkCtrlBuffer, ax		;R08
;R27
;R27	push	si
;R27	mov	al, 16
;R27	mul	dl
;R27	add	ax, offset KbdIntQH
;R27	mov	si, ax
;R27	call	Init_QH
;R27	pop	si
;R27	mov	[si].wTkQueueHead, ax
;R27
;R27	push	si
;R27	mov	al, SIZE TD
;R27	mul	dl
;R27	add	ax, offset KbdIntTD
;R27	mov	si, ax
;R27	call	Init_TD
;R27;R08	mov	di, si
;R27	pop	si
;R27;R08	mov	[si].wTkTransDesp, di
;R27	mov	[si].wTkTransDesp, ax		;R08
;R27	mov	di, ax				;R08
	mov	si, di				;R27;task control pointer
	mov	di, [si].wTkTransDesp		;R27;TransDescriptor pointer

	mov	al, DEF_TDCTRL+ISS_IOC
	test	byte ptr [bx].bCtrlByte, CP_LS
	jz	short @f
	or	al, LS
@@:
	mov	[di].bTdControl, al

	mov	edx, PID_IN
	movzx	eax, word ptr [si].wTkPacketSize
	dec	eax
	shl	eax, BIT_MAXL
	or	edx, eax
	movzx	eax, byte ptr [si].bTkDevAddr
	shl	eax, BIT_ADDR
	or	edx, eax
	movzx	eax, byte ptr [si].bTkDevEndp
	shl	eax, BIT_EP
	or	edx, eax
	mov	[di].dTdToken, edx

	mov	ax, [si].wTkDataBuffer
	call	Physical_Linear
	mov	[di].dTdPoint, eax

	mov	byte ptr [di].bTdStatus, STS_ACTIVE

	call	Link_Task

ifndef	NO_UPDATE_USBKB_LED			;R18
	call	Update_Led			;update all keyboards' LED
endif	;NO_UPDATE_USBKB_LED			;R18

Init_Kbd_Exit:
	ret

;R27 - start
;[]========================================================================[]
;Procedure:	Init_Keyboard_Task
;Function:	Initialize keyboard task data structure
;Input:		BX = point to control parameter block
;		DI = point to endpoint descriptor
;		AL = keyboard index number
;		wIntDspPoint = point to interface descriptor		;R41
;Output:	DI = point to task
;[]========================================================================[]

Init_Keyboard_Task:

	mov	dl, al

	; DL = keyboard index number			;R41

	mov	al, SIZE TASK
	mul	dl
	add	ax, offset KbdIntTask
	mov	si, ax
	call	Init_Task

	; SI = task buffer pointer			;R41

	mov	al, TK_WFP+TK_KBD
;R41 - start
	mov	cx, di
	sub	cx, wIntDspPoint
	cmp	cx, 9				;Old kb: Interface-Endpoint-HID
						;length: 9	   7	    9
	je	short @f
;R41 - end
;R41	cmp	di, offset CfgDespBuffer.HidEDsp
;R41	je	short @f
	or	al, TK_NEWKBD
@@:
	test	byte ptr [bx].bCtrlByte, CP_LS
	jz	short @f
	or	al, TK_LS
@@:
	mov	[si].bTkDevStatus, al

	mov	byte ptr [si].bTkDevIndex, dl

	mov	word ptr [si].wTkProc, offset Proc_Keyboard SMI_OFFSET

	mov	al, [bx].bDevAddr
	mov	[si].bTkDevAddr, al

	mov	al, [bx].bParentAddr
	mov	[si].bTkParentAddr, al

	mov	al, [bx].bParentPort
	mov	[si].bTkParentPort, al

	movzx	ax, byte ptr [di].EDbInterval
	call	Validate_Interval
	mov	[si].wTkInterval, ax

	mov	ax, [di].EDwMaxPackSize
	mov	[si].wTkPacketSize, ax

	mov	al, byte ptr [di].EDbEndpAddr
	and	al, 7Fh				;mask direction bit
	mov	[si].bTkDevEndp, al

;R41	mov	al, CfgDespBuffer.StdIDsp.IDbAltSet
;R41 - start
	push	di
	mov	di, wIntDspPoint
	mov	al, [di].IDbIntNum
	pop	di
;R41 - end
	mov	[si].bTkDevInterface, al

	push	si				;task control pointer
	mov	al, 8
	movzx	cx, al
	mul	dl
	add	ax, offset KbdDataBuffer
	mov	si, ax
	call	Clear_Buffer
	pop	si				;task control pointer
	mov	[si].wTkDataBuffer, ax

	push	si				;task control pointer
	mov	al, SIZE KBDCTRL
	movzx	cx, al
	mul	dl
	add	ax, offset KbdCtrlBuffer
	mov	si, ax
	call	Clear_Buffer
;R39	mov	byte ptr [si].bDelayRate,  12
;R39	mov	byte ptr [si].bRepeatRate, 4
	pop	si				;task control pointer
	mov	[si].wTkCtrlBuffer, ax

	push	si				;task control pointer
	mov	al, 16
	mul	dl
	add	ax, offset KbdIntQH
	mov	si, ax
	call	Init_QH
	pop	si				;task control pointer
	mov	[si].wTkQueueHead, ax

	push	si				;task control pointer
	mov	al, SIZE TD
	mul	dl
	add	ax, offset KbdIntTD
	mov	si, ax
	call	Init_TD
	pop	si				;task control pointer
	mov	[si].wTkTransDesp, ax

	mov	di, si

	ret
;R27 - end

;[]========================================================================[]
;Procedure:	Proc_Keyboard
;Function:	Keyboard interrupt transaction process routine
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Proc_Keyboard:
;R06	mov	bx, [si].wTkTransDesp
;R06	test	byte ptr [bx].bTdStatus, STS_ACTIVE
;R06	jnz	short Proc_Kbd_Exit
;R06
;R06	mov	bx, [si].wTkCtrlBuffer
;R06
;R06	cmp	byte ptr [bx].bKeyLength, 0
;R06	je	short Check_Kbd_Data
;R06
;R06	push	si
;R06
;R06	mov	si, bx
;R06	call	Proc_Key_Buffer
;R06
;R06	pop	si
;R06
;R06	jmp	short Proc_Kbd_End
;R06
;R06Check_Kbd_Data:
	mov	bx, [si].wTkTransDesp
	test	byte ptr [bx].bTdStatus, STS_ACTIVE	;R06
	jnz	short Proc_Kbd_Exit			;R06
;R47	test	byte ptr [bx].bTdStatus, STS_ERROR
;R47	jnz	short Proc_Kbd_End
;R47 - start
	test	byte ptr [bx].bTdStatus, STS_NAK
	jnz	short Proc_Kbd_End
	test	byte ptr [bx].bTdStatus, STS_ERROR	;all errors
	jz	short Proc_Kbd_Cont
	lea	di, [si].CurrentBuffer
	mov	cx, 32
	xor	al, al
	rep	stosb
	jmp	short Proc_Kbd_End
Proc_Kbd_Cont:
;R47 - end

	mov	ax, [bx].wTdActLen
	and	ax, 07FFh
	cmp	ax, 07FFh
	je	short Proc_Kbd_End

	push	si

	mov	di, [si].wTkDataBuffer
	mov	si, [si].wTkCtrlBuffer
	call	Proc_Kbd_Data

;R06 - start
ifndef	ZERO_SET_IDLE				;R47
	cmp	byte ptr [si].bKeyLength, 0
	je	short @f

	call	Proc_Key_Buffer
@@:
endif	;ZERO_SET_IDLE				;R47
;R06 - end
	pop	si

Proc_Kbd_End:
	mov	bx, [si].wTkTransDesp
	or	byte ptr [bx].bTdControl, DEF_TDCTRL
	xor	dword ptr [bx].dTdToken, DATA_TOGGLE
	mov	byte ptr [bx].bTdStatus, STS_ACTIVE

	mov	di, [si].wTkQueueHead
	mov	si, [si].wTkTransDesp
	call	Link_TD_to_QH

Proc_Kbd_Exit:
	ret

;[]========================================================================[]
;Input:		SI = point to control buffer
;		DI = point to data buffer
;[]========================================================================[]

; Key map process algorithm
; Current Map	Last Map
; 0		0		no key press
; 1		0		make key
; 1		1		repeat key
; 0		1		break key

Proc_Kbd_Data:
	call	Check_RollOver			;R09
	jz	Roll_Over_Exit			;R09

	call	Clear_Current_Buffer		;clear current key map

;R09	call	Check_RollOver
;R09	jz	Roll_Over_Exit

	call	Check_Modifier			;check empty modifier bytes
	jz	short Proc_MainKey		;skip if empty

Proc_Modifier:
	mov	al, [di]			;modifier

	mov	cx, 8				;8 bits
	mov	bx, offset Modifier_Table SMI_OFFSET
Proc_Modifier_Loop:
	test	al, 1
	jz	short Proc_Modifier_Next
	push	cx
	push	bx
	push	ax
	mov	al, cs:[bx]
	call	Mark_Current_Buffer		;mark current key map
	pop	ax
	pop	bx
	pop	cx
Proc_Modifier_Next:
	inc	bx
	shr	al, 1
	loop	short Proc_Modifier_Loop

Proc_MainKey:
	call	Check_MainKey			;check empty main key buffer?
	jz	short Proc_KeyCode		;skip if empty

	mov	cx, 6				;6 bytes
	lea	bx, [di+2]			;main key start offset
Proc_MainKey_Loop:
	mov	al, [bx]
	push	cx
	push	bx
	or	al, al
	jz	short Proc_MainKey_Next
	call	Mark_Current_Buffer		;mark current key map
Proc_MainKey_Next:
	pop	bx
	pop	cx
	inc	bx
	loop	short Proc_MainKey_Loop
;R47 - start
ifdef	ZERO_SET_IDLE
	ret
endif	;;ZERO_SET_IDLE

;[]========================================================================[]
;Input:		SI = point to control buffer
;[]========================================================================[]
;R47 - end

Proc_KeyCode:
	call	Check_Current_Buffer		;check current key map empty?
	jnz	short @f			;jmp if not empty
	call	Check_Last_Buffer		;check last key map empty?
	jz	short Proc_Kbd_Buff_Exit	;jmp if also empty
@@:
ifdef	IOTRAP_SUPPORT				;R39
	mov	al, bLedStatus			;R39
	and	al, 70h				;R39;LED status
	and	byte ptr [si].bBiosFlag, 8Fh	;R39
	or	byte ptr [si].bBiosFlag, al	;R39
else	;IOTRAP_SUPPORT				;R39
	push	ds
	mov	ax, 0040h
	mov	ds, ax
	mov	al, byte ptr ds:[0017h]		;BIOS key status flag
	pop	ds
	mov	[si].bBiosFlag, al		;save for status reference
endif	;IOTRAP_SUPPORT				;R39

	xor	dx, dx
	lea	bx, [si].CurrentBuffer
	lea	di, [si].LastBuffer
	mov	cx, 32

Proc_Byte_Loop:
	push	cx
	push	bx
	push	di

	mov	al, ds:[bx]
	mov	ah, ds:[di]
	mov	cx, 8
Proc_Bit_Loop:
	push	ax
	push	dx
	push	cx

	mov	[si].bCurrentIndex, dl

	test	al, 1
	jz	short Check_Break		;current=0 (no make)
	test	ah, 1
	jnz	short Check_Repeat		;current/last=1 (repeat)

	mov	[si].bLastIndex, dl

;R39	mov	al, [si].bDelayRate		;typematic delay rate
	mov	al, bDelayRate			;R39;typematic delay rate
	mov	[si].bDelayCount, al

	call	Proc_MakeKey			;translate make codes

	jmp	short Proc_Next_Bit

Check_Repeat:
	cmp	dl, [si].bLastIndex		;just repeat with last key
	jne	short Proc_Next_Bit

	dec	byte ptr [si].bDelayCount
	jnz	short Proc_Next_Bit

;R39	mov	al, [si].bRepeatRate		;typematic repeat rate
	mov	al, bRepeatRate			;R39;typematic repeat rate
	mov	[si].bDelayCount, al

	call	Proc_RepeatKey			;translate repeat codes

	jmp	short Proc_Next_Bit

Check_Break:
	test	ah, 1
	jz	short Proc_Next_Bit		;current/last=0 (no key)

	;current=0, last=1 (break key)

	call	Proc_BreakKey			;translate break codes

Proc_Next_Bit:
	pop	cx
	pop	dx
	pop	ax
	inc	dx
	shr	al, 1
	shr	ah, 1
	loop	short Proc_Bit_Loop

	pop	di
	pop	bx
	pop	cx
	inc	bx
	inc	di
	loop	short Proc_Byte_Loop

Proc_Kbd_Buff_Exit:
	call	Update_Last_Buffer		;update last map to current map
Roll_Over_Exit:
	ret

;[]========================================================================[]
; Modifier translation table from modifier bit map to USB key number(-70h)
;[]========================================================================[]

Modifier_Table:
;		0E0h, 0E1h, 0E2h, 0E3h, 0E4h, 0E5h, 0E6h, 0E7h
	db	070h, 071h, 072h, 073h, 074h, 075h, 076h, 077h

;[]========================================================================[]
; Key codes translation table from USB key number to AT key code
;[]========================================================================[]

Xlat_Code_Table:
; Scan code set 1 (USB key number mapping)
;   0	 1    2    3	4    5	  6    7    8	 9    A    B	C    D	  E    F
 db 000h,000h,000h,000h,01Eh,030h,02Eh,020h,012h,021h,022h,023h,017h,024h,025h,026h ;0
 db 032h,031h,018h,019h,010h,013h,01Fh,014h,016h,02Fh,011h,02Dh,015h,02Ch,002h,003h ;1
 db 004h,005h,006h,007h,008h,009h,00Ah,00Bh,01Ch,001h,00Eh,00Fh,039h,00Ch,00Dh,01Ah ;2
;R15 db 01Bh,02Bh,000h,027h,028h,029h,033h,034h,035h,03Ah,03Bh,03Ch,03Dh,03Eh,03Fh,040h ;3
 db 01Bh,02Bh,02Bh,027h,028h,029h,033h,034h,035h,03Ah,03Bh,03Ch,03Dh,03Eh,03Fh,040h ;3;R15
 db 041h,042h,043h,044h,057h,058h,037h,046h,000h,052h,047h,049h,053h,04Fh,051h,04Dh ;4
 db 04Bh,050h,048h,045h,035h,037h,04Ah,04Eh,01Ch,04Fh,050h,051h,04Bh,04Ch,04Dh,047h ;5
;R15 db 048h,049h,052h,053h,000h,05Dh,000h,000h,054h,000h,000h,000h,000h,000h,000h,000h ;6
 db 048h,049h,052h,053h,056h,05Dh,000h,000h,054h,000h,000h,000h,000h,000h,000h,000h ;6;R15
 db 01Dh,02Ah,038h,05Bh,01Dh,036h,038h,05Ch,000h,000h,000h,000h,000h,000h,000h,000h ;7
 db 000h,000h,000h,000h,000h,000h,000h,073h,070h,07Dh,079h,07Bh,000h,000h,000h,000h ;8;R26

;[]========================================================================[]
; Convenient flag codes translation table
;[]========================================================================[]

Xlat_Flag_Table:
; Flag code for process conveniently (USB key number mapping)
; bit7=0 status key
; bit6=0 send extended E0
; 0000.0100 - 04 : RtCtrl
; 0000.1000 - 08 : RtAlt
; 0100.0001 - 41 : RtShft
; 0100.0010 - 42 : LtShft
; 0100.0100 - 44 : LtCtrl
; 0100.1000 - 48 : LtAlt
; 1000.0000 - 80 : RtEnter
; 1000.1000 - 88 : /
; 1001.0000 - 90 : PrntScrn
; 1010.0000 - A0 : Ins, Del, Home, End, PgUp, PgDn, UpA, DnA, LtA, RtA
; 1100.0000 - C0 : NSK (No Special Keys)
; 1100.0100 - C4 : Pause
; 1100.0111 - C7 : CapsLock
; 1100.1011 - CB : NumLock
; 1100.1101 - CD : ScrollLock
;   0	 1    2    3	4    5	  6    7    8	 9    A    B	C    D	  E    F
 db 0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h ;0
 db 0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h ;1
 db 0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h ;2
 db 0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C7h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h ;3
 db 0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,090h,0CDh,0C4h,0A0h,0A0h,0A0h,0A0h,0A0h,0A0h,0A0h ;4
 db 0A0h,0A0h,0A0h,0CBh,088h,0C0h,0C0h,0C0h,080h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h ;5
 db 0C0h,0C0h,0C0h,0C0h,0C0h,0A0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h ;6
 db 044h,042h,048h,0A0h,004h,041h,008h,0A0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h ;7
 db 0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h,0C0h ;8;R26

;[]========================================================================[]
;Procedure:	Proc_MakeKey
;Function:	Translate make codes
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Proc_MakeKey:
	call	Reloc_PrnScrn			;relocate <PrnScrn> key number

	mov	al, [si].bCurrentIndex
	call	Get_Key_Num

	call	Proc_Shift			;process enhance <Shift> code

	call	Send_Ext_Shift

	mov	al, [si].bCurrentKey
	call	Get_Flag_Code

	cmp	al, 0C4h
	je	short Proc_Pause

	test	al, 80h
	jnz	short Not_Make_FKP

; Setting RtShft, LtShft, RtCtrl, LtCtrl, AltGr, LtAlt flag

	and	al, 0Fh
	or	[si].bBiosFlag, al

Not_Make_FKP:
	call	Send_Ext_E0

	movzx	bx, byte ptr [si].bCurrentKey
	add	bx, offset Xlat_Code_Table SMI_OFFSET
	mov	al, cs:[bx]
	call	Store_Code

Proc_MakeKey_Exit:
	ret

; <Pause> process

Proc_Pause:
	mov	bx, offset Pause_Code SMI_OFFSET
	mov	cx, 6
	test	byte ptr [si].bBiosFlag, 04	;check <Ctrl> status
	jz	short @f			;jump if no <Ctrl> depress
	add	bx, 6
	mov	cl, 4
@@:
	mov	al, cs:[bx]
	call	Store_Code
	inc	bx
	loop	short @b
	jmp	short Proc_MakeKey_Exit

Pause_Code:
; Normal <Pause> code
	DB	0E1H, 01DH, 045H, 0E1H, 09DH, 0C5H

; <Ctrl+Pause> code
	DB	0E0h, 046h, 0E0h, 0C6h

;[]========================================================================[]
;Procedure:	Proc_RepeatKey
;Function:	Translate repeat codes
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Proc_RepeatKey:
	mov	al, [si].bCurrentIndex
	call	Get_Key_Num

	call	Send_Ext_Shift			;send extended <Shift> code
						;if necessary
	call	Send_Ext_E0

	movzx	bx, byte ptr [si].bCurrentKey
	add	bx, offset Xlat_Code_Table SMI_OFFSET
	mov	al, cs:[bx]
	call	Store_Code

	ret

;[]========================================================================[]
;Procedure:	Proc_BreakKey
;Function:	Translate break codes
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Proc_BreakKey:
	mov	al, [si].bCurrentIndex
	call	Get_Key_Num

	call	Get_Flag_Code			;get flag code
	cmp	al, 0C4h			;check <Pause> break
	je	short Proc_BreakKey_Exit

	test	al, 80h 			;check FKP break
	jnz	short Normal_Break

; RtCtrl, AltGr, RtShft, LtShft, LtCtrl, LtAlt

	and	al, 0Fh
	xor	[si].bBiosFlag, al		;toggle status flag

	not	al
	or	al, 0FCh			;reserved <Shift> status
	and	[si].bStatusFlag, al

Normal_Break:
	call	Send_Ext_E0

	movzx	bx, byte ptr [si].bCurrentKey
	add	bx, offset Xlat_Code_Table SMI_OFFSET
	mov	al, cs:[bx]
	or	al, 80h
	call	Store_Code

	mov	al, [si].bCurrentIndex
	cmp	al, [si].bLastIndex
	jne	short Proc_BreakKey_Exit

	call	Proc_Shift

Proc_BreakKey_Exit:
	ret

;[]========================================================================[]
;Procedure:	Get_Key_Num
;Function:	Get AT key codes and relocate PrnScrn code if necessary
;Input:		SI = point to control buffer
;		AL = Current_Index
;Output:	AL = Current_Key
;[]========================================================================[]

Get_Key_Num:
	cmp	al, 46h 			;check <PrnScrn> key number
	jne	short @f
	mov	al, [si].bRelocKey		;get <PrnScrn> relocate in make
@@:
	mov	[si].bCurrentKey, al
	ret

;[]========================================================================[]
;Procedure:	Reloc_PrnScrn
;Function:	Relocate PrnScrn code if ALT pressed
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Reloc_PrnScrn:
	mov	byte ptr [si].bRelocKey, 46h 	;normal <PrnScrn> key number

	test	byte ptr [si].bBiosFlag, ALT 	;<Alt> status
	jz	short @f

	mov	byte ptr [si].bRelocKey, 68h 	;code 54H key number
@@:
	ret

;[]========================================================================[]
;Procedure:	Proc_Shift
;Function:	Process virtual shift codes
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Proc_Shift:
	test	byte ptr [si].bStatusFlag, VLTSHFT
	jz	short Chk_RtShft		;skip if virtual <LtShft> off

	test	byte ptr [si].bBiosFlag, LTSHFT
	jnz	short Proc_LtShft		;jump if <LtShft> on

; Send Enhance <LtShft> break code (VLTSHFT-on, LTSHFT-off)

	call	LtShft_Break
	jmp	short Chk_RtShft

; Send Enhance <LtShft> make code (VLTSHFT-on, LTSHFT-on)

Proc_LtShft:
	call	LtShft_Make

Chk_RtShft:
	test	byte ptr [si].bStatusFlag, VRTSHFT
	jz	short Proc_Shift_Ret		;skip if virtual <RtShft> off

	test	byte ptr [si].bBiosFlag, RTSHFT
	jnz	short Proc_RtShft		;jump if <RtShft> on

; Send Enhance <RtShft> break code (VRTSHFT-on, RTSHFT-off)

	call	RtShft_Break
	jmp	short Proc_Shift_Ret

; Send Enhance <RtShft> make code (VRTSHFT-on, RTSHFT-on)

Proc_RtShft:
	call	RtShft_Make

Proc_Shift_Ret:
	and	byte ptr [si].bStatusFlag, 0FCh	;clear virtual shift flag
	ret

; Send Enhance <RtShft> make code

RtShft_Make:
	mov	al, 0E0h			;Code E0h
	call	Store_Code
	mov	al, 036h			;Code <RtShft>
	call	Store_Code
	ret

; Send Enhance <RtShft> break code

RtShft_Break:
	mov	al, 0E0h			;Code E0h
	call	Store_Code
	mov	al, 0B6h			;Code <RtShft> break
	call	Store_Code
	ret

; Send Enhance <LtShft> make code

LtShft_Make:
	mov	al, 0E0h			;Code E0h
	call	Store_Code
	mov	al, 02Ah			;Code <LtShft>
	call	Store_Code
	ret

; Send Enhance <LtShft> break code

LtShft_Break:
	mov	al, 0E0h			;Code E0h
	call	Store_Code
	mov	al, 0AAh			;Code <LtShft> break
	call	Store_Code
	ret

;[]========================================================================[]
;Procedure:	Send_Ext_Shift
;Function:	Translate extended shift code for special keys
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Send_Ext_Shift:
	mov	al, [si].bCurrentKey
	call	Get_Flag_Code			;get flag code
	test	al, 10000000b
	jz	short SES_Ret
	test	al, 00000001b
	jnz	short SES_Ret
	test	al, 00100000b
	jnz	short Chk_NumLock		;jump if FKP
	test	al, 00010000b
	jnz	short SES_PrnScrn		;jump if <PrnScrn>
	test	al, 00001000b
	jnz	short FKP_NumLock_Off		;jump if "/"

SES_Ret:
	ret

; FKP : Function Keys Pad : Ins,Del,Home,End,PgUp,PgDn,UpA,DnA,LtA,RtA

Chk_NumLock:
	test	byte ptr [si].bBiosFlag, NUMLOCK
	jnz	short FKP_NumLock_On		;jump if <NumLock> On

; Key < / >
; FKP and <NumLock> off

FKP_NumLock_Off:
	mov	al, [si].bBiosFlag
	xor	al, [si].bStatusFlag 		;toggle virtual shift state
	and	al, 03
	jz	short SES_Ret

	and	byte ptr [si].bStatusFlag, 0FCh
	or	byte ptr [si].bStatusFlag, al

	test	byte ptr [si].bStatusFlag, VLTSHFT
	jz	short Chk_VRTSHFT		;skip if virtual <LtShft> off

	call	LtShft_Break			;send enhance LtShft break code

Chk_VRTSHFT:
	test	byte ptr [si].bStatusFlag, VRTSHFT
	jz	short SES_Ret			;skip if virtual <RtShft> off

	call	RtShft_Break			;send enhance RtShft break code
	jmp	short SES_Ret

; FKP and <NumLock> on

FKP_NumLock_On:
	mov	al, [si].bBiosflag
	or	al, [si].bStatusFlag
	and	al, 03
	jnz	short SES_Ret			;skip if <Shift> on

	and	byte ptr [si].bStatusFlag, 0FCh
	or	byte ptr [si].bStatusFlag, VLTSHFT	;set <LtShft> flag
	call	LtShft_Make			;send enhance LtShft make code
	jmp	short SES_Ret

; <PrnScrn>

SES_PrnScrn:
	mov	al, [si].bStatusFlag
	and	al, 03
	or	al, [si].bBiosFlag

	and	al, 07h
	jnz	short SES_Ret			;skip if <Ctrl> or <Shift> on

	and	byte ptr [si].bStatusFlag, 0FCh
	or	byte ptr [si].bStatusFlag, VLTSHFT	;set <LtShft> flag
	call	LtShft_Make
	jmp	short SES_Ret

;[]========================================================================[]
;Procedure:	Send_Ext_E0
;Function:	Translate extended E0 code for special keys
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Send_Ext_E0:
	mov	al, [si].bCurrentKey
	call	Get_Flag_Code			;get flag code

	test	al, 01000000b
	jnz	short @f

; Send E0H : RtCtrl, RtAlt, RtEnter, /, PrnScrn, FKP, LtGUI, RtGUI, APP

	mov	al, 0E0h
	call	Store_Code
@@:
	ret

;[]========================================================================[]
;Procedure:	Get_Flag_Code
;Function:	Get key convenient flag code
;Input:		AL = USB key number
;Output:	AL = flag code
;[]========================================================================[]

Get_Flag_Code:
	movzx	bx, al
	add	bx, offset Xlat_Flag_Table SMI_OFFSET
	mov	al, cs:[bx]
	ret

;[]========================================================================[]
;Procedure:	Proc_Key_Buffer
;Function:	Process key codes buffer and output to keyboard controller
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Proc_Key_Buffer:
	push	bx
	push	di
;R39 - start
ifdef	IOTRAP_SUPPORT
	call	DisableUsbLegacySmi
	test	bCipFlag, WFPMASK		;check command in process
	jnz	short Proc_Key_Buffer_Exit
	test	byte ptr bEmuCmdByte, KBIFDIS	;keyboard interface disabled
	jnz	short Proc_Key_Buffer_Exit
;R41	test	byte ptr bKbCtrl, KBDISABLE	;keyboard disabled
	test	byte ptr bDevCtrl, KBDISABLE	;R41;keyboard disabled
	jnz	short Proc_Key_Buffer_Exit
endif	;IOTRAP_SUPPORT
;R39 - end

	mov	al, 0Bh 			;read ISR
	out	20h, al
	NEWIODELAY
	in	al, 20h
	test	al, 02				;IRQ1 in service
	jnz	short Proc_Key_Buffer_Exit

	mov	al, 0Bh 			;R12;read ISR
	out	0A0h, al			;R12
	NEWIODELAY				;R12
	in	al, 0A0h			;R12
	test	al, 10h				;R12;IRQ12 in service
	jnz	short Proc_Key_Buffer_Exit	;R12

	movzx	bx, byte ptr [si].bKeyPoint
	lea	di, [si].KeyBuffer
	mov	al, [bx+di]
	call	Send_KeyCode
	jc	short Proc_Key_Buffer_Exit

;R19A	cmp	byte ptr [si].bKeyLength, 17
;R19A	jne	short @f
;R19A	movzx	bx, byte ptr [si].bKeyPoint
;R19A	lea	di, [si].KeyBuffer
;R19A;R19	mov	byte ptr [bx+di], 0		;roll over key
;R19A	mov	byte ptr [bx+di], 0FFh		;R19;roll over key
;R19A@@:
	inc	byte ptr [si].bKeyPoint
	and	byte ptr [si].bKeyPoint, 0Fh
	dec	byte ptr [si].bKeyLength

Proc_Key_Buffer_Exit:
;R39 - start
ifdef	IOTRAP_SUPPORT
        call    EnableUsbLegacySmi
endif	;IOTRAP_SUPPORT
;R39 - end
	pop	di
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Store_Code
;Function:	Store key codes to bKeyBuffer
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Store_Code:
	push	bx
	push	di
	cmp	byte ptr [si].bKeyLength, 16
	jae	short Store_Code_Exit		;R19A
;R19A	ja	short Store_Code_Exit
;R19A	jb	short @f
;R19A	inc	byte ptr [si].bKeyLength	;length=17:roll over
;R19A	jmp	short Store_Code_Exit
;R19A@@:
	movzx	bx, byte ptr [si].bKeyPoint
	movzx	di, byte ptr [si].bKeyLength
	add	bx, di
	and	bx, 0Fh
	lea	di, [si].KeyBuffer
	mov	[bx+di], al
	inc	byte ptr [si].bKeyLength
Store_Code_Exit:
	pop	di
	pop	bx
	ret

;[]========================================================================[]
;Procedure:	Check_Modifier
;Function:	check modifier empty
;Input:		DI = point to data buffer
;Output:	ZF = 1 empty
;		ZF = 0 not empty
;[]========================================================================[]

Check_Modifier:
	test	byte ptr [di], 11111111b	;modifier
	ret

;[]========================================================================[]
;Procedure:	Check_MainKey
;Function:	check mainkey buffer empty
;Input:		DI = point to data buffer
;Output:	ZF = 1 empty
;		ZF = 0 not empty
;[]========================================================================[]

Check_MainKey:
	push	ax
	push	cx
	push	di
	xor	al, al
	mov	cx, 6
	add	di, 2
	repe	scasb
	pop	di
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Check_RollOver
;Function:	check keyboard roll-over error
;Input:		DI = point to data buffer
;Output:	ZF = 1 roll-over error
;		ZF = 0 no error
;[]========================================================================[]

Check_RollOver:
	push	ax
	push	cx
	push	di
	mov	al, 01
;R09	mov	cx, 8
;R09	repe	scasb
	mov	cx, 6				;R09
	add	di, 2				;R09
	repe	scasb				;R09
	pop	di
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Mark_Current_Buffer
;Function:	Mark current key bit map with key code
;Input:		SI = point to control buffer
;		AL = USB key code
;Output:	none
;[]========================================================================[]

Mark_Current_Buffer:
	push	ax
	push	bx
	push	cx
	cmp	al, 90h				;R26
	jae	short @f			;R26
	movzx	bx, al
	shr	bx, 3				;byte position
	lea	cx, [si].CurrentBuffer
	add	bx, cx
	mov	cl, al
	and	cl, 07				;bit position
	mov	al, 01
	shl	al, cl
	or	[bx], al
@@:						;R26
	pop	cx
	pop	bx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Check_Current_Buffer
;Function:	check current key bit map empty
;Input:		SI = point to control buffer
;Output:	ZF = 1 empty
;		ZF = 0 not empty
;[]========================================================================[]

Check_Current_Buffer:
	push	ax
	push	cx
	push	di
	xor	al, al
	mov	cx, 32
	lea	di, [si].CurrentBuffer
	repe	scasb
	pop	di
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Check_Last_Buffer
;Function:	check last key bit map empty
;Input:		SI = point to control buffer
;Output:	ZF = 1 empty
;		ZF = 0 not empty
;[]========================================================================[]

Check_Last_Buffer:
	push	ax
	push	cx
	push	di
	xor	al, al
	mov	cx, 32
	lea	di, [si].LastBuffer
	repe	scasb
	pop	di
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Clear_Current_Buffer
;Function:	clear current key bit map
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Clear_Current_Buffer:
	push	ax
	push	cx
	push	di
	mov	cx, 32
	xor	al, al
	lea	di, [si].CurrentBuffer
	rep	stosb
	pop	di
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Clear_Last_Buffer
;Function:	clear last key bit map
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Clear_Last_Buffer:
	push	ax
	push	cx
	push	di
	mov	cx, 32
	xor	al, al
	lea	di, [si].LastBuffer
	rep	stosb
	pop	di
	pop	cx
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Update_Last_Buffer
;Function:	update last key map with current key map
;Input:		SI = point to control buffer
;Output:	none
;[]========================================================================[]

Update_Last_Buffer:
	push	cx
	push	si
	push	di
	mov	cx, 32
	lea	di, [si].LastBuffer
	lea	si, [si].CurrentBuffer
	rep	movsb
	pop	di
	pop	si
	pop	cx
	ret

;[]========================================================================[]
;Procedure:	Send_KeyCode
;Function:	Send key code to keyboard controller with D2 command
;Input:		AL = key code
;Output:	CF = 0 successful
;		CF = 1 fail
;[]========================================================================[]

Send_KeyCode:
	push	cx
	push	ax
;R39ifdef	IOTRAP_SUPPORT				;R22A
;R39        call    DisableUsbLegacySmi             ;R22A
;R39endif	;IOTRAP_SUPPORT				;R22A
	in	al, 64h
	test	al, 03				;IBF/OBF
	jz	short @f
kc_write_fail:
	pop	ax
	stc
	jmp	short kc_write_exit
@@:
	mov	al, 0D2h			;write output buffer command
	out	64h, al
	NEWIODELAY
	xor	cx, cx
@@:
	in	al, 64h
	NEWIODELAY
	test	al, 01				;R12
	jnz	short kc_write_fail		;R12
	test	al, 02				;IBF
	jz	short @f
	loop	short @b
	jmp	short kc_write_fail
@@:
	pop	ax
	out	60h, al
	mov	bLastCode, al			;R39
	clc
kc_write_exit:
;R22A - start
;R39ifdef	IOTRAP_SUPPORT
;R39	pushf
;R39        mov     al, 0fh
;R39	mov	cx, wHostID
;R39	add	cx, LEGACY_HI
;R39	SMI_F0CALL	Set_Pci
;R39        call    EnableUsbLegacySmi
;R39	popf
;R39endif	;IOTRAP_SUPPORT
;R22A - end
	pop	cx
	ret

;R41 - start
ifdef	USB_MOUSE_SUPPORT
;************************************************************************
;*									*
;*	MOUSE MANAGEMENT						*
;*									*
;************************************************************************

;[]========================================================================[]
;Procedure:	Init_Mouse
;Function:	Initialize USB mouse
;Input:		BX = point to control parameter block
;Output:	none
;[]========================================================================[]

Init_Mouse:
	test	bUsbFlag, USBMSSUPPORT		;USB ms supported?
	jz	Init_Ms_Exit
;R41B - start
;R46	test	wMsDevMap, 0FFFFh		;any USB mouse installed?
;R46	jnz	short Usb_Mouse_Installed
;R46	test	bRealCmdByte, MSIFDIS		;real command byte for kc
;R46	jnz	short Usb_Mouse_Installed
;R46	or	bRealCmdByte, MSIFDIS		;PS2 mouse interface disabled
;R46	call	DisableUsbLegacySmi
;R46	mov	al, 0A7h			;disable PS2 mouse interface
;R46	out	64h, al				;write to kc
;R46	call	EnableUsbLegacySmi
;R46Usb_Mouse_Installed:
;R41B - end

	; Query/record available mouse index number

	call	Query_Ms_Index
	jc	Init_Ms_Exit

	call	Record_Ms_Index

	mov	di, wIntDspPoint		;interface descriptor point
	call	Find_EndpDesp

	; DI = endpoint descriptor pointer

	call	Init_Mouse_Task

	; DI = task buffer pointer

;R49 - start
	; Set boot protocol

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer

	; wValue = 0 : boot protocol

	mov	byte ptr [si].bRequest, SET_PROTOCOL
	mov	byte ptr [si].bmRequestType, 00100010b
	mov	al, [di].bTkDevEndp			;endpoint
	test	byte ptr [di].bTkDevStatus, TK_NEWHID
	jz	short @f
	mov	byte ptr [si].bmRequestType, 00100001b
	mov	al, [di].bTkDevInterface		;interface
@@:
	mov	byte ptr [si].wIndex, al		;interface or endpoint

	mov	word ptr [bx].wReqBuffer, si
	mov	word ptr [bx].wTotalSize, 0

	call	Control_Transfer
;R49 - end

	; Set idle rate

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer

	mov	byte ptr [si].bRequest, SET_IDLE
	mov	byte ptr [si].bmRequestType, 00100010b
	mov	al, [di].bTkDevEndp
	test	byte ptr [di].bTkDevStatus, TK_NEWHID
	jz	short @f
	mov	byte ptr [si].bmRequestType, 00100001b
	mov	al, [di].bTkDevInterface
@@:
	mov	byte ptr [si].wIndex, al

	mov	word ptr [bx].wReqBuffer, si
	mov	word ptr [bx].wTotalSize, 0

	call	Control_Transfer

	; Get report descriptor

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer

	mov	byte ptr [si].bRequest, GET_DESCRIPTOR
	mov	byte ptr [si+1].wValue, 22h		;report descriptor
	mov	word ptr [si].wLength, 003Fh		;descriptor length
	mov	byte ptr [si].bmRequestType, 10000010b
	mov	al, [di].bTkDevEndp
	test	byte ptr [di].bTkDevStatus, TK_NEWHID
	jz	short @f
	mov	byte ptr [si].bmRequestType, 10000001b
	mov	al, [di].bTkDevInterface
@@:
	mov	byte ptr [si].wIndex, al

	mov	word ptr [bx].wReqBuffer, si
	or	byte ptr [bx].bCtrlByte, CP_RD		;read from device
	mov	word ptr [bx].wDataBuffer, offset MiscDataBuffer
	mov	word ptr [bx].wTotalSize, 3Fh			;total length
	movzx	ax, byte ptr DevDespBuffer.DDbMaxPackSize	;packet size
	mov	word ptr [bx].wMaxSize, ax
	call	Control_Transfer

	mov	si, di				;task control pointer
	mov	di, [si].wTkTransDesp		;TransDescriptor pointer

	mov	al, DEF_TDCTRL+ISS_IOC
	test	byte ptr [bx].bCtrlByte, CP_LS
	jz	short @f
	or	al, LS
@@:
	mov	[di].bTdControl, al

	mov	edx, PID_IN
	movzx	eax, word ptr [si].wTkPacketSize
	dec	eax
	shl	eax, BIT_MAXL
	or	edx, eax
	movzx	eax, byte ptr [si].bTkDevAddr
	shl	eax, BIT_ADDR
	or	edx, eax
	movzx	eax, byte ptr [si].bTkDevEndp
	shl	eax, BIT_EP
	or	edx, eax
	mov	[di].dTdToken, edx

	mov	ax, [si].wTkDataBuffer
	call	Physical_Linear
	mov	[di].dTdPoint, eax

	mov	byte ptr [di].bTdStatus, STS_ACTIVE

	call	Link_Task

	mov	byte ptr bMsQueueCount, 0

Init_Ms_Exit:
	ret

;[]========================================================================[]
;Procedure:	Init_Mouse_Task
;Function:	Initialize mouse task data structure
;Input:		BX = point to control parameter block
;		DI = point to endpoint descriptor
;		AL = mouse index number
;		wIntDspPoint = point to interface descriptor
;Output:	DI = point to task
;[]========================================================================[]

Init_Mouse_Task:

	mov	dl, al

	; DL = mouse index number

	mov	al, SIZE TASK
	mul	dl
	add	ax, offset MsIntTask
	mov	si, ax
	call	Init_Task

	; SI = task buffer pointer

	mov	al, TK_WFP+TK_MS
	mov	cx, di
	sub	cx, wIntDspPoint
	cmp	cx, 9				;Old HID:Interface-Endpoint-HID
						;length: 9	   7	    9
	je	short @f
	or	al, TK_NEWHID
@@:
	test	byte ptr [bx].bCtrlByte, CP_LS
	jz	short @f
	or	al, TK_LS
@@:
	mov	[si].bTkDevStatus, al

	mov	byte ptr [si].bTkDevIndex, dl

	mov	word ptr [si].wTkProc, offset Proc_Mouse SMI_OFFSET

	mov	al, [bx].bDevAddr
	mov	[si].bTkDevAddr, al

	mov	al, [bx].bParentAddr
	mov	[si].bTkParentAddr, al

	mov	al, [bx].bParentPort
	mov	[si].bTkParentPort, al

	movzx	ax, byte ptr [di].EDbInterval
	call	Validate_Interval
	mov	[si].wTkInterval, ax

	mov	ax, [di].EDwMaxPackSize
	mov	[si].wTkPacketSize, ax

	mov	al, byte ptr [di].EDbEndpAddr
	and	al, 7Fh				;mask direction bit
	mov	[si].bTkDevEndp, al

	push	di
	mov	di, wIntDspPoint
	mov	al, [di].IDbIntNum
	pop	di
	mov	[si].bTkDevInterface, al

	push	si				;task control pointer
	mov	al, 8
	movzx	cx, al
	mul	dl
	add	ax, offset MsDataBuffer
	mov	si, ax
	call	Clear_Buffer
	pop	si				;task control pointer
	mov	[si].wTkDataBuffer, ax

	push	si				;task control pointer
	mov	al, SIZE MSCTRL
	movzx	cx, al
	mul	dl
	add	ax, offset MsCtrlBuffer
	mov	si, ax
	call	Clear_Buffer
	pop	si				;task control pointer
	mov	[si].wTkCtrlBuffer, ax

	push	si				;task control pointer
	mov	al, 16
	mul	dl
	add	ax, offset MsIntQH
	mov	si, ax
	call	Init_QH
	pop	si				;task control pointer
	mov	[si].wTkQueueHead, ax

	push	si				;task control pointer
	mov	al, SIZE TD
	mul	dl
	add	ax, offset MsIntTD
	mov	si, ax
	call	Init_TD
	pop	si				;task control pointer
	mov	[si].wTkTransDesp, ax

	mov	di, si

	ret

;[]========================================================================[]
;Procedure:	Proc_Mouse
;Function:	Mouse interrupt transaction process routine
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Proc_Mouse:
	mov	bx, [si].wTkTransDesp			;TD point of task
	test	byte ptr [bx].bTdStatus, STS_ACTIVE	;TD done?
	jnz	short Proc_Mouse_Exit			;not yet done

	cmp	byte ptr bMsQueueCount, 0	;mouse data wait for process
	jne	short Proc_Mouse_End

	test	byte ptr [bx].bTdStatus, STS_ERROR	;any error?
	jnz	short Proc_Mouse_End

	mov	ax, [bx].wTdActLen		;actual length of received data
	and	ax, 07FFh
	cmp	ax, 07FFh			;null data
	je	short Proc_Mouse_End

	mov	bx, [si].wTkDataBuffer		;data buffer point of task
	call	Proc_MsData			;convert received data
	call	Proc_MsBuffer			;process mouse data buffer

Proc_Mouse_End:
	mov	bx, [si].wTkTransDesp
	or	byte ptr [bx].bTdControl, DEF_TDCTRL
	xor	dword ptr [bx].dTdToken, DATA_TOGGLE
	mov	byte ptr [bx].bTdStatus, STS_ACTIVE

	mov	di, [si].wTkQueueHead
	mov	si, [si].wTkTransDesp
	call	Link_TD_to_QH

Proc_Mouse_Exit:
	ret

;[]========================================================================[]
;Procedure:	Proc_MsData
;Function:	Translate USB mouse data to PS/2 mouse data
;Input:		BX = point to data buffer
;Output:	bMsDataPacket = mouse data packet
;		bMsQueueCount = mouse data packet length
;		wMsQueueIndex = point to bMsDataPacket
;[]========================================================================[]

Proc_MsData:
;R46 - start
	;clear 4th byte temporarily,
	;until scroll funcion USB mouse supporting
	mov	byte ptr bMsDataPacket+3, 0
;R46 - end
	mov	al, [bx+1]			;X axis displacement
	mov	bMsDataPacket+1, al
	mov	al, [bx+2]			;Y axis displacement
	neg	al
	mov	bMsDataPacket+2, al
	mov	al, [bx]			;pressed buttons status
	and	al, 07				;3 buttons
	or	al, 08				;reserved bit of PS2 mouse data
	test	byte ptr bMsDataPacket+1, 80h	;X data sign
	jz	short @f
	or	al, 10h				;negative X data sign
@@:
	test	byte ptr bMsDataPacket+2, 80h	;Y data sign
	jz	short @f
	or	al, 20h				;negative Y data sign
@@:
	mov	bMsDataPacket, al		;pressed buttons status

	mov	word ptr wMsQueueIndex, offset bMsDataPacket
;R46	mov	byte ptr bMsQueueCount, 3
;R46 - start
	mov	al, 3
	cmp	bMsID, 3
	jne	short @f
	inc	al
@@:
	mov	bMsQueueCount, al
;R46 - end
	ret

;[]========================================================================[]
;Procedure:	Proc_MsBuffer
;Function:	Process mouse codes buffer and output to keyboard controller
;Input:		none
;Output:	none
;[]========================================================================[]

Proc_MsBuffer:
	call	DisableUsbLegacySmi
	test	bCipFlag, WFPMASK		;check command in process
	jnz	short Proc_MsBuffer_Exit
	test	byte ptr bEmuCmdByte, MSIFDIS	;mouse interface disabled
	jnz	short Proc_MsBuffer_Exit
	test	byte ptr bDevCtrl, MSDISABLE	;mouse disabled
	jnz	short Proc_MsBuffer_Exit

	mov	al, 0Bh 			;read ISR
	out	20h, al
	NEWIODELAY
	in	al, 20h
	test	al, 02				;IRQ1 in service
	jnz	short Proc_MsBuffer_Exit

	cmp	byte ptr bMsQueueCount, 0	;length of mouse data queue
	je	short Proc_MsBuffer_Exit

	mov	bx, wMsQueueIndex		;index of mouse data queue
	mov	al, [bx]
	call	Send_MsCode			;send mouse code to KC
	jc	short Proc_MsBuffer_Exit

	dec	byte ptr bMsQueueCount		;decrement mouse data length
	inc	word ptr wMsQueueIndex		;increment mouse data index

Proc_MsBuffer_Exit:
        call    EnableUsbLegacySmi
	ret
endif	;USB_MOUSE_SUPPORT
;R41 - end

;R39 - start
;[]========================================================================[]
;Procedure:	Send_MsCode
;Function:	Send mouse code to keyboard controller with D3 command
;Input:		AL = mouse code
;Output:	CF = 0 successful
;		CF = 1 fail
;[]========================================================================[]

Send_MsCode:
	push	cx
	push	ax
	in	al, 64h
	test	al, 03				;IBF/OBF
	jz	short Send_MsCode_Cont
Send_MsCode_Fail:
	pop	ax
	stc
	jmp	short Send_MsCode_Exit
Send_MsCode_Cont:
	mov	al, 0D3h			;write mouse output buffer
	out	64h, al
	NEWIODELAY
	xor	cx, cx
Send_MsCode_Loop:
	in	al, 64h
	NEWIODELAY
	test	al, 01
	jnz	short Send_MsCode_Fail
	test	al, 02
	jz	short Send_MsCode_Success
	loop	short Send_MsCode_Loop
	jmp	short Send_MsCode_Fail
Send_MsCode_Success:
	pop	ax
	out	60h, al
	clc
Send_MsCode_Exit:
	pop	cx
	ret

ifdef	IOTRAP_SUPPORT
;************************************************************************
;*									*
;*	60h/64h I/O TRAPPING MODULE					*
;*									*
;************************************************************************
;[]========================================================================[]
;Procedure:	UsbLegSmi
;Function:	Port 60/64h I/O trapping main routine. UsbLegSmi is called
;		by Usb_smi to perform kc/kb/ms commands emulation before
;		USB key code handling.
;Input:
;	DS and ES = segments address of USB_RAM
;	bCipFlag = command in process flag
;		   KCWFP : keyboard controller command wait for process
;		   RKBWFP,WKBWFP : keyboard command wait for process
;		   RMSWFP,WMSWFP : mouse command wait for process
;	wKcCmdProc = pointer to kc command handler if KCWFP in bCipFlag is set
;	wKbCmdProc = pointer to kb command handler if RKBWFP or WKBWFP in
;		     bCipFlag is set
;	wMsCmdProc = pointer to ms command handler if RMSWFP or WMSWFP in
;		     bCipFlag is set
;Output:
;	CF = 0 if SMI is not caused by port 60/64h I/O
;	CF = 1 if SMI is caused by port 60/64h I/O
;Note:
;	All chipset dependent routines are marked with the string "[CDR]".
;	Abbreviation:
;		KC : keyboard controller
;		KB : keyboard
;		MS : mouse
;[]========================================================================[]
	public	UsbLegSmi
UsbLegSmi       proc	near

	call	DisableUsbLegacySmi
	call	GetTrapData			;IoTrapData = contents of AL
						; register when port 60/64h I/O
						; is trapped
	mov	al, TrapByStatus
	test	al, TRAPBY64W
	jnz	short Do64W
	test	al, TRAPBY60W
	jnz	short Do60W
	test	al, TRAPBY60R
	jnz	short Do60R
	test	al, TRAPBY64R
	jnz	short Do64R
	call	ClearTrapBy
	call	EnableUsbLegacySmi
	clc
	ret

;Port 64h write handler

Do64W:
	call	Proc_KcCmd
	jmp	short UsbLegSmi_Exit

;Port 60h write handler

Do60W:
	test	bCipFlag, KCWFP			;kc command wait for process
	jz	short Do60W_Cont
	call	wKcCmdProc
	jmp	short UsbLegSmi_Exit

Do60W_Cont:
	test	bCipFlag, WKBWFP		;kb command wait for process
	jz	short First_60W
	call	wKbCmdProc
	jmp	short UsbLegSmi_Exit

First_60W:
	call	Proc_KbCmd			;process kb command
	jmp	short UsbLegSmi_Exit

;Port 60h Read handler

Do60R:
;R41C - start
	test	bCipFlag, KCWFP			;kc command wait for process
	jz	short Check_Kb_60R
	call	wKcCmdProc
	jmp	short UsbLegSmi_Exit
Check_Kb_60R:
;R41C - end
	test	bCipFlag, RKBWFP		;kb command wait for process
	jz	short Check_Mouse_60R
	in	al, 64h				;R41
	test	al, 20h				;R41;mouse obf?
	jnz	short Do60R_Cont		;R41
	call	wKbCmdProc
	jmp	short UsbLegSmi_Exit

Check_Mouse_60R:
	test	bCipFlag, RMSWFP		;ms command wait for process
	jz	short Do60R_Cont
	in	al, 64h				;R41
	test	al, 20h				;R41;mouse obf?
	jz	short Do60R_Cont		;R41
	call	wMsCmdProc
	jmp	short UsbLegSmi_Exit

Do60R_Cont:
	call	SmiIn60				;no trapping on 60R
	call	SetTrapData
	jmp	short UsbLegSmi_Exit

;Port 64h Read handler

Do64R:
	call	SmiIn64				;no trapping on 64R anyway
	call	SetTrapData
	jmp	short UsbLegSmi_Exit

UsbLegSmi_Exit:
	call	ClearTrapBy
	call	EnableUsbLegacySmi
	stc
	ret
UsbLegSmi	endp

;[]========================================================================[]
;Procedure:	SmiOut60
;Function:      Output data (in IoTrapData) to port 60h in USB Legacy SMM
;Input:		IoTrapData
;Output:        None
;[]========================================================================[]
SmiOut60	proc	near
	push	ax
	mov	al, IoTrapData
	out	60h, al
	pop	ax
	ret
SmiOut60	endp

;[]========================================================================[]
;Procedure:	SmiOut64
;Function:      Output data (in IoTrapData) to port 64h in USB Legacy SMM
;Input:		IoTrapData
;Output:        None
;[]========================================================================[]
SmiOut64	proc	near
	push	ax
	mov	al, IotrapData
	out	64h, al
	pop	ax
	ret
SmiOut64	endp

;[]========================================================================[]
;Procedure:	SmiIn60
;Function:      Input data from port 60h in USB Legacy SMM
;Input:		None
;Output:        IoTrapData = Data read from port 60h
;[]========================================================================[]
SmiIn60	proc	near
	push	ax
	in	al, 60h
	mov	IoTrapData, al
	pop	ax
	ret
SmiIn60	endp

;[]========================================================================[]
;Procedure:	SmiIn64
;Function:      Input data from port 64h in USB Legacy SMM
;Input:		None
;Output:        IoTrapData = Data read from port 64h
;[]========================================================================[]
SmiIn64	proc	near
	push	ax
        in      al, 64h
	mov	IoTrapData, al
	pop	ax
	ret
SmiIn64	endp

;[]========================================================================[]
;Procedure:	GetTrapBy [CDR]
;Function:      Get information about which I/O is trapped from host
;		contrller. This is a chipset dependent routine.
;Input:
;	wHostID = Host controller PCI bus address
;Output:
;	TrapByStatus:
;	Bit 0:	Trapped by port 60h read
;	Bit 1:	Trapped by port 60h write
;	Bit 2:	Trapped by port 64h read
;	Bit 3:	Trapped by port 64h write
;	Bit 4 to 6: Reserved
;[]========================================================================[]
GetTrapBy	proc	near
	mov	cx, wHostID
	add	cx, LEGACY_HI			;For host controller in PIIX4
	SMI_F0CALL	Get_Pci
	and	al, 0Fh
	mov	TrapByStatus, al
	ret
GetTrapBy	endp

;[]========================================================================[]
;Procedure:	ClearTrapBy [CDR]
;Function:      Clear trap-by status bits in host controller.
;		This is a chipset dependent routine.
;Input:
;	wHostID = Host controller PCI bus address
;Output:
;	None
;[]========================================================================[]
ClearTrapBy	proc	near
;R54 - start
	mov	cx, wHostID
	add	cx, LEGACY_HI			;For host controller in PIIX4
	SMI_F0CALL	Get_Pci
	or	al, 0Fh
;R54 - end
;R54	mov     al, 0Fh
;R54	mov	cx, wHostID
;R54	add	cx, LEGACY_HI			;For host controller in PIIX4
	SMI_F0CALL	Set_Pci
	ret
ClearTrapBy	endp

;[]========================================================================[]
;Procedure:	GetTrapData
;Function:      Retrieve the contents of AL register from the SMM storage
;               area.
;Input:
;	None
;Output:
;	IoTrapData = Contents of AL register when SMI is triggered.
;[]========================================================================[]
GetTrapData    proc     near
        push    ax
        push    si
        mov     si, 7fd0h			;AL register in SMM
        mov     al, cs:[si]
        mov     IoTrapData, al
        pop     si
        pop     ax
        ret
GetTrapData   endp

;[]========================================================================[]
;Procedure:	SetTrapData
;Function:      move data (in IoTrapData) to SMM storage area for
;               AL register
;Input:
;	IoTrapData
;Output:
;	None
;[]========================================================================[]
SetTrapData    proc     near
        push    ax
        push    si
	mov	al, IoTrapData
        mov     si, 7fd0h			;AL register in SMM
        mov     cs:[si], al
        pop     si
        pop     ax
        ret
SetTrapData   endp

;[]========================================================================[]
;Procedure:	GetTrapEanbled [CDR]
;Function:	Get information on which I/O trapping is enabled from
;		host controller. This routine is chipset dependent.
;Input:
;	wHostID = host controller PCI bus address
;Output:
;	In AL register:
;	Bit 0 = 1 if port 60h read trapping is enabled
;	Bit 1 = 1 if port 60h write trapping is enabled
;	Bit 2 = 1 if port 64h read trapping is enabled
;	Bit 3 = 1 if port 64h write trapping is enabled
;	Bit 4 to 7 = Reserved
;[]========================================================================[]
GetTrapEnabled	proc	near
	;For Intel PIIX4
	push	cx
	mov	cx, wHostID			;Load PCI bus address of
						; host controller
	add	cx, LEGACY_LO
	SMI_F0CALL	Get_Pci
	and	al, 0Fh
	pop	cx
	ret
GetTrapEnabled	endp

;[]========================================================================[]
;Procedure:	DisableUsbLegacySmi [CDR]
;Function:	Disable the host controller's ability to generate SMI for
;		port 60/64h I/O. This is a chipset dependent routine.
;Input:
;	wHostID = Host controller PCI bus address
;Output:
;	None
;[]========================================================================[]
DisableUsbLegacySmi	proc	near
	push	ax
	push	cx
	mov	cx, wHostID
	add	cx, LEGACY_LO
	SMI_F0CALL	Get_Pci

        ;Clear the following bits:
	;   PORT64REN, PORT60REN, PORT64WEN and PORT60WEN

	and	al, 0F0h			;disable trap/smi
	SMI_F0CALL	Set_Pci
	call	Ct_DisableUsbLegacySmi		;Disable SMI from PIIX4
	pop	cx
	pop	ax
	ret
DisableUsbLegacySmi	endp

;[]========================================================================[]
;Procedure:	EnableUsbLegacySmi [CDR]
;Function:	Enable the host controller's ability to generate SMI for
;		port 60/64h I/O. This is a chipset dependent routine.
;Input:
;	wHostID = Host controller PCI bus address
;Output:
;	None
;[]========================================================================[]
EnableUsbLegacySmi	proc	near
	push	ax
	push	cx
	mov	cx, wHostID
	add	cx, LEGACY_LO
	SMI_F0CALL	Get_Pci
	or	al, bTrapEnabled
	SMI_F0CALL	Set_Pci
	call	Ct_EnableUsbLegacySmi
	pop	cx
	pop	ax
	ret
EnableUsbLegacySmi	endp

;[]========================================================================[]
;Procedure:	Enable_PORT60REN
;Function:	Enable trap on port 60h reading, normally the reading port 60h
;		trapping is disabled
;Input:		none
;Output:	bTrapEnabled affected
;[]========================================================================[]
Enable_PORT60REN	proc	near
	or	byte ptr bTrapEnabled, PORT60REN
	ret
Enable_PORT60REN	endp

;[]========================================================================[]
;Procedure:	Disable_PORT60REN
;Function:	Disable trap on port 60h reading, normally the reading port 60h
;		trapping is disabled
;Input:		none
;Output:	bTrapEnabled affected
;[]========================================================================[]
Disable_PORT60REN	proc	near
	and	byte ptr bTrapEnabled, not PORT60REN
	ret
Disable_PORT60REN	endp

;[]========================================================================[]
;Procedure:	NullProc
;Function:	This routine is used to clear a keyboard handler
;Input:		None
;Output:	CF = 1
;[]========================================================================[]
NullProc	proc	near
	stc
	ret
NullProc	endp

;************************************************************************
;*									*
;*	PROCESS USB KB/MS MODULE FOR I/O TRAPPING			*
;*									*
;************************************************************************

;[]========================================================================[]
;Procedure:	UsbKb_Reset
;Function:	Reset the data related USB kb when the system issue keyboard
;		reset command(0FFh)
;Input:		none
;Output:	none
;[]========================================================================[]
UsbKb_Reset	proc	near
	call	UsbKb_Default
	call	UsbKb_Enable
	ret
UsbKb_Reset	endp

;[]========================================================================[]
;Procedure:	UsbKb_Default
;Function:	Reset the data related USB kb when the system issue keyboard
;		set default command(0F6h)
;Input:		none
;Output:	none
;[]========================================================================[]
UsbKb_Default	proc	near
	mov	byte ptr bDelayRate,  31	;default typematic delay
	mov	byte ptr bRepeatRate, 6		;default typematic repeat rate
	ret
UsbKb_Default	endp

;[]========================================================================[]
;Procedure:	UsbKb_Disable
;Function:	Disable USB kb when the system issue keyboard disable command
;		(0F5h)
;Input:		none
;Output:	none
;[]========================================================================[]
UsbKb_Disable	proc	near
	call	UsbKb_Default
;R41	or	byte ptr bKbCtrl, KBDISABLE
	or	byte ptr bDevCtrl, KBDISABLE	;R41
	ret
UsbKb_Disable	endp

;[]========================================================================[]
;Procedure:	UsbKb_Enable
;Function:	Enable USB kb when the system issue keyboard enable command
;		(0F4h)
;Input:		none
;Output:	none
;[]========================================================================[]
UsbKb_Enable	proc	near
;R41	and	byte ptr bKbCtrl, not KBDISABLE
	and	byte ptr bDevCtrl, not KBDISABLE	;R41
	ret
UsbKb_Enable	endp

;[]========================================================================[]
;Procedure:	UsbKb_Typematic
;Function:	Translate typematic rate/delay data for USB kb usage
;Input:		AL = typematic rate data
;Output:	bTypematic = AL
;		bDelayRate = count for USB kb delay emulation
;		bRepeatRate = count for USB kb repeat emulation
;[]========================================================================[]
UsbKb_Typematic	proc	near
	push	ax
	push	si
	and	al, 7Fh				;bit7 don't care
	mov	bTypematic, al
	mov	ah, al
	and	al, 1Fh				;bit4-0
	movzx	si, al
	add	si, offset Repeat_Table SMI_OFFSET
	mov	al, cs:[si]			;get tranlated value
	mov	bRepeatRate, al			;typematic rate
	mov	al, ah
	shr	al, 5				;bit6,5
	and	al, 03
	movzx	si, al
	add	si, offset Delay_Table SMI_OFFSET
	mov	al, cs:[si]			;get translated value
	mov	bDelayRate, al			;typematic delay
	pop	si
	pop	ax
	ret
UsbKb_Typematic	endp

;[]========================================================================[]
; Bit definition of typematic rate and delay parameter
; Refer to PC/AT technical manual
; +20%, -20% represent allowed error
; A=Bit2-0	B=Bit4,3	C=Bit6-5
;
; Typematic delay = (C+1)*250 ms
; Bit6,5	Delay(ms)	+20%	-20%		USB Emulated
;-------------------------------------------------------------------
; 00		250		300	200		256=16*16
; 01		500		600	400		496=16*31 (default)
; 10		750		900	600		752=16*47
; 11		1000		1200	800		992=16*62
;
; Typematic period = (8+A)*2^B*41.7 ms
; Bit4-0	period(ms)	+20%	-20%		USB Emulated
;-------------------------------------------------------------------
; 00000		33.36		40.032	26.688		32=16*2
; 00001		37.53		45.036	30.024		32=16*2
; 00010		41.7		50.04	33.36		48=16*3
; 00011		45.87		55.044	36.696		48=16*3
; 00100		50.04		60.048	40.032		48=16*3
; 00101		54.21		65.052	43.368		48=16*3
; 00110		58.38		70.056	46.704		64=16*4
; 00111		62.55		75.06	50.04		64=16*4
; 01000		66.72		80.064	53.376		64=16*4
; 01001		75.06		90.072	60.048		80=16*5
; 01010		83.4		100.08	66.72		80=16*5
; 01011		91.74		110.088	73.392		96=16*6
; 01100		100.08		120.096	80.064		96=16*6 (default)
; 01101		108.42		130.104	86.736		112=16*7
; 01110		116.76		140.112	93.408		112=16*7
; 01111		125.1		150.12	100.08		128=16*8
; 10000		133.44		160.128	106.752		128=16*8
; 10001		150.12		180.144	120.096		144=16*9
; 10010		166.8		200.16	133.44		160=16*10
; 10011		183.48		220.176	146.784		176=16*11
; 10100		200.16		240.192	160.128		208=16*13
; 10101		216.84		260.208	173.472		224=16*14
; 10110		233.52		280.224	186.816		240=16*15
; 10111		250.2		300.24	200.16		256=16*16
; 11000		266.88		320.256	213.504		272=16*17
; 11001		300.24		360.288	240.192		304=16*19
; 11010		333.6		400.32	266.88		336=16*21
; 11011		366.96		440.352	293.568		368=16*23
; 11100		400.32		480.384	320.256		400=16*25
; 11101		433.68		520.416	346.944		432=16*27
; 11110		467.04		560.448	373.632		464=16*29
; 11111		500.4		600.48	400.32		496=16*31
;[]========================================================================[]
Delay_Table	label	byte			; Bit6,5
	db	16				; 00
	db	31				; 01 (default)
	db	47				; 10
	db	62				; 11

Repeat_Table	label	byte			; Bit4-0
	db	2				; 00000
	db	2				; 00001
	db	3				; 00010
	db	3				; 00011
	db	3				; 00100
	db	3				; 00101
	db	4				; 00110
	db	4				; 00111
	db	4				; 01000
	db	5				; 01001
	db	5				; 01010
	db	6				; 01011
	db	6				; 01100 (default)
	db	7				; 01101
	db	7				; 01110
	db	8				; 01111
	db	8				; 10000
	db	9				; 10001
	db	10				; 10010
	db	11				; 10011
	db	13				; 10100
	db	14				; 10101
	db	15				; 10110
	db	16				; 10111
	db	17				; 11000
	db	19				; 11001
	db	21				; 11010
	db	23				; 11011
	db	25				; 11100
	db	27				; 11101
	db	29				; 11110
	db	31				; 11111

;[]========================================================================[]
;Procedure:	UsbMs_Default
;Function:	Reset the data related USB mouse to default state
;Input:		none
;Output:	none
;[]========================================================================[]
UsbMs_Default	proc	near
;R41	and	bMsCtrl, not MSWRAPMODE		;mouse control
	and	bDevCtrl, not MSWRAPMODE	;R41;not in wrap mode
	or	bDevCtrl, MSDISABLE		;R41;mouse disabled
	mov	bMsStatus, 00h			;stream mode
						;disabled
						;scaling 1:1
						;no mouse button pressed
	mov	bResolution, 02h		;4 counts/mm resolution
	mov	bSampleRate, 64h		;100 times/s sample rate
	ret
UsbMs_Default	endp

;************************************************************************
;*									*
;*	KEYBOARD CONTROLLER COMMAND PROCESS MODULE			*
;*									*
;************************************************************************

;[]========================================================================[]
; Index table of keyboard controller command
; Sorted with the frequency of command issued
;
; **** Note ****
; We have no support some special set input port/output port commands.
; Since these commands are meaningless at the newest PC platform and these
; commands are different from various chip vendors.
;[]========================================================================[]
KcCmdTbl  label   byte
	db	0ADh				;disable keyboard interface
	dw	offset KcCmd_Disable_Kb SMI_OFFSET
	db	0AEh				;enable keyboard interface
	dw	offset KcCmd_Enable_Kb SMI_OFFSET
	db	020h				;read KC command byte
	dw	offset KcCmd_Read_Cmd SMI_OFFSET
	db	060h				;write KC command byte
	dw	offset KcCmd_Write_Cmd SMI_OFFSET
	db	0A7h				;disable mouse interface
	dw	offset KcCmd_Disable_Ms SMI_OFFSET
	db	0A8h				;enable mouse interface
	dw	offset KcCmd_Enable_Ms SMI_OFFSET
	db	0D0h				;read output port
	dw	offset KcCmd_Pass_1Cmd SMI_OFFSET
	db	0D1h				;write output port
	dw	offset KcCmd_Pass_2Cmd SMI_OFFSET
	db	0D2h				;write keyboard output buffer
	dw	offset KcCmd_Pass_2Cmd SMI_OFFSET
	db	0D3h				;write mouse output buffer
	dw	offset KcCmd_Pass_2Cmd SMI_OFFSET
	db	0D4h				;write to mouse
	dw	offset KcCmd_Write_Ms SMI_OFFSET
	db	0AAh				;self test
	dw	offset KcCmd_Self_Test SMI_OFFSET
	db	0A9h				;mouse interface test
	dw	offset KcCmd_Interface_Test SMI_OFFSET
	db	0ABh				;keyboard interface test
	dw	offset KcCmd_Interface_Test SMI_OFFSET
	db	0C0h				;read input port
	dw	offset KcCmd_Pass_1Cmd SMI_OFFSET
	db	0C1h				;poll input port low
	dw	offset KcCmd_Pass_1Cmd SMI_OFFSET
	db	0C2h				;poll input port high
	dw	offset KcCmd_Pass_1Cmd SMI_OFFSET
KC_CMD_CNT    EQU    ($-KcCmdTbl)/3

PulseOutputCmd	dw	offset KcCmd_Pass_1Cmd SMI_OFFSET
ReadRamCmd	dw	offset KcCmd_Pass_1Cmd SMI_OFFSET
WriteRamCmd	dw	offset KcCmd_Pass_2Cmd SMI_OFFSET

;[]========================================================================[]
;Procedure:	Proc_KcCmd
;Function:	Process keyboard controller command
;Input:		IoTrapData = keyboard controller command
;Output:	individual command's related data affected
;[]========================================================================[]

Proc_KcCmd	proc	near

	and	bCipFlag, not KCWFP		;clear previous pending cmd

	push	es
	push	cs
	pop	es

	mov	di, offset KcCmdTbl SMI_OFFSET
	mov	al, IoTrapData
	mov	cx, KC_CMD_CNT
Find_KcCmd_Loop:
	scasb
	je	short Found_KcCmd
	inc	di
	inc	di
	loop	short Find_KcCmd_Loop

	; Check F0h-FFh command: Pulse output port

	mov	di, offset PulseOutputCmd SMI_OFFSET
	cmp	al, 0F0h
	jae	short Found_KcCmd

	; Check 21h-3Fh command: Read the keyboard controller RAM

	mov	di, offset ReadRamCmd SMI_OFFSET
	cmp	al, 21h
	jb	short Unknown_KcCmd
	cmp	al, 3Fh
	jbe	short Found_KcCmd

	; Check 61h-7Fh command: Write the keyboard controller RAM

	mov	di, offset WriteRamCmd SMI_OFFSET
	cmp	al, 7Fh
	ja	short Unknown_KcCmd
	cmp	al, 61h
	jae	short Found_KcCmd

Unknown_KcCmd:

	; Ignore unknown command

	pop	es
	ret

Found_KcCmd:

	pop	es

	call	word ptr cs:[di]

Proc_KcCmd_Exit:

	ret
Proc_KcCmd	endp

;[]========================================================================[]
;Procedure:	Write_KcCmd
;Function:	Write keyboard controller command to port 64h
;Input:		AL = command
;Output:	CF = 0 : success
;		CF = 1 : fail
;[]========================================================================[]
Write_KcCmd	proc	near
	call	Wait_Ibf_Clear
	jc	short Write_KcCmd_Exit
	out	64h, al				;write to command port
Write_KcCmd_Exit:
	ret
Write_KcCmd	endp

;[]========================================================================[]
;Procedure:	Wait_Ibf_Clear
;Function:	Wait the keyboard controller's IBF(Input Buffer Full) flag to
;		clear
;Input:		none
;Output:	CF = 0 : success
;		CF = 1 : fail
;[]========================================================================[]
Wait_Ibf_Clear	proc	near
	push	cx
	push	ax
	mov	cx, 4				;4ms wait IBF clear
Wait_Ibf_Clear_Loop:
	in	al, 64h				;read from status port
	test	al, 02				;input buffer full
	clc
	jz	short Wait_Ibf_Clear_Success
	call	Delay_1ms
	loop	short Wait_Ibf_Clear_Loop
	stc
Wait_Ibf_Clear_Success:
	pop	ax
	pop	cx
	ret
Wait_Ibf_Clear	endp

;[]========================================================================[]
;Procedure:	Wait_Obf_Set
;Function:	Wait the keyboard controller's OBF(Output Buffer Full) flag to
;		set
;Input:		none
;Output:	CF = 0 : success
;		CF = 1 : fail
;[]========================================================================[]
Wait_Obf_Set	proc	near
	push	cx
	push	ax
Wait_Obf_Set_Loop:
	in	al, 64h				;read from status port
	test	al, 01				;output buffer full
	clc
	jnz	short Wait_Obf_Set_Success
	call	Delay_1ms
	loop	short Wait_Obf_Set_Loop
	stc
Wait_Obf_Set_Success:
	pop	ax
	pop	cx
	ret
Wait_Obf_Set	endp

;[]========================================================================[]
;Procedure:	Wait_MsObf_Clear
;Function:	Wait the keyboard controller's mouse OBF to set
;Input:		none
;Output:	CF = 0 : success
;		CF = 1 : fail
;[]========================================================================[]
Wait_MsObf_Set	proc	near
	push	cx
	push	ax
Wait_MsObf_Set_Loop:
	in	al, 64h				;read from status port
	test	al, 01				;output buffer full
	clc
	jnz	short Wait_MsObf_Set_Cont
	call	Delay_1ms
	loop	short Wait_MsObf_Set_Loop
	stc
	jmp	short Wait_MsObf_Set_Exit
Wait_MsObf_Set_Cont:
	test	al, 20h				;mouse obf
	clc
	jnz	short Wait_MsObf_Set_Exit
	stc
Wait_MsObf_Set_Exit:
	pop	ax
	pop	cx
	ret
Wait_MsObf_Set	endp

;[]========================================================================[]
;Procedure:	KcCmd_Pass_1Cmd
;Function:	Pass 1 keyboard controller command
;Input:		IoTrapData = command
;Output:	none
;[]========================================================================[]
KcCmd_Pass_1Cmd	proc	near
	call	SmiOut64
	ret
KcCmd_Pass_1Cmd	endp

;[]========================================================================[]
;Procedure:	KcCmd_Pass_2Cmd
;Function:	Pass 2 keyboard controller command
;Input:		IoTrapData = command
;Output:	wKcCmdProc, bCipFlag affected
;[]========================================================================[]
KcCmd_Pass_2Cmd	proc	near
	call	SmiOut64
	mov	wKcCmdProc, offset KcCmd_Pass_2Cmd2 SMI_OFFSET
	or	bCipFlag, KCWFP
	ret

	; Second trapping: second data from port 60h

KcCmd_Pass_2Cmd2:
	call	SmiOut60
	and	bCipFlag, not KCWFP
	ret
KcCmd_Pass_2Cmd	endp

;[]========================================================================[]
;Procedure:	KcCmd_Disable_Kb
;Function:	Keyboard controller command ADh handler
;		Disable keyboard interface
;Input:		IoTrapData = command ADh
;Output:	bEmuCmdByte, bRealCmdByte affected
;[]========================================================================[]
KcCmd_Disable_Kb	proc	near
	call	SmiOut64			;notify keyboard controller
	or	bEmuCmdByte, KBIFDIS		;keyboard interface disabled
	or	bRealCmdByte, KBIFDIS
	ret
KcCmd_Disable_Kb	endp

;[]========================================================================[]
;Procedure:	KcCmd_Enable_Kb
;Function:	Keyboard controller command AEh handler
;		Enable keyboard interface
;Input:		IoTrapData = command AEh
;Output:	bEmuCmdByte, bRealCmdByte affected
;[]========================================================================[]
KcCmd_Enable_Kb	proc	near
	call	SmiOut64			;notify keyboard controller
	and	bEmuCmdByte, not KBIFDIS	;keyboard interface Enabled
	and	bRealCmdByte, not KBIFDIS
	ret
KcCmd_Enable_Kb	endp

;[]========================================================================[]
;Procedure:	KcCmd_Read_Cmd
;Function:	Keyboard controller command 20h handler
;		Read keyboard controller command byte
;		Emulated reply from USB legacy smi handler, no command pass
;		to keyboard controller
;		Reply bEmuCmdByte(emulated command byte) to system
;Input:		bEmuCmdByte = emulated command byte
;Output:	none
;[]========================================================================[]
KcCmd_Read_Cmd	proc	near
;R41C - start
	call	Enable_PORT60REN		;enable 60R trap
	mov	wKcCmdProc, offset KcCmd_Read_Cmd2 SMI_OFFSET
	or	bCipFlag, KCWFP
;R41C - end
	mov	al, bEmuCmdByte
	call	Send_KeyCode			;reply to system
	ret

;R41C - start
	; Second trapping: system wish to get command byte

KcCmd_Read_Cmd2:
	in	al, 60h				;clear pervious code
	mov	al, bEmuCmdByte			;emulated command byte
	mov	IoTrapData, al
	call	SetTrapData
	and	bCipFlag, not KCWFP
	call	Disable_PORT60REN		;disable 60R trap
	ret
;R41C - end
KcCmd_Read_Cmd	endp

;[]========================================================================[]
;Procedure:	KcCmd_Write_Cmd
;Function:	Keyboard controller command 60h handler
;		Write keyboard controller command byte
;Input:		IoTrapData = command 60h
;Output:	wKcCmdProc, bCipFlag affected
;		bEmuCmdByte, bRealCmdByte affected
;[]========================================================================[]
KcCmd_Write_Cmd	proc	near
	call	SmiOut64			;notify keyboard controller
	mov	wKcCmdProc, offset KcCmd_Write_Cmd2 SMI_OFFSET
	or	bCipFlag, KCWFP
	ret

	; Second trapping: command byte data from port 60

KcCmd_Write_Cmd2:
	mov	al, IoTrapData
	mov	bEmuCmdByte, al
	mov	bRealCmdByte, al
;R40	test	bMsCtrl, USBMSSUPPORT		;check usb mice support
	test	bUsbFlag, USBMSSUPPORT		;R40;check usb mice support
	jz	short KcCmd_Write_Cmd2_Cont
;R46	test	wMsDevMap, 0FFFFh		;check usb mice installed
;R46	jz	short KcCmd_Write_Cmd2_Cont
	or	bRealCmdByte, MSIFDIS		;PS2 mice disabled if USB mice
						; installed
KcCmd_Write_Cmd2_Cont:
	mov	al, bRealCmdByte
	out	60h, al
	and	bCipFlag, not KCWFP		;clear WFP flag
	ret
KcCmd_Write_Cmd	endp

;[]========================================================================[]
;Procedure:	KcCmd_Disable_Ms
;Function:	Keyboard controller command A7h handler
;		Disable mouse interface
;Input:		IoTrapData = command A7h
;Output:	bEmuCmdByte, bRealCmdByte affected
;[]========================================================================[]
KcCmd_Disable_Ms	proc	near
	call	SmiOut64			;notify keyboard controller
	or	bEmuCmdByte, MSIFDIS		;mouse interface disabled
	or	bRealCmdByte, MSIFDIS
	ret
KcCmd_Disable_Ms	endp

;[]========================================================================[]
;Procedure:	KcCmd_Enable_Ms
;Function:	Keyboard controller command A8h handler
;		Enable mouse interface
;Input:		IoTrapData = command A8h
;Output:	bEmuCmdByte, bRealCmdByte affected
;[]========================================================================[]
KcCmd_Enable_Ms	proc	near
	and	bEmuCmdByte, not MSIFDIS	;mice interface Enabled
	and	bRealCmdByte, not MSIFDIS
;R40	test	bMsCtrl, USBMSSUPPORT		;check usb mice support
	test	bUsbFlag, USBMSSUPPORT		;R40;check usb mice support
	jz	short KcCmd_Enable_Ms_Cont
;R46	test	wMsDevMap, 0FFFFh		;check usb mice installed
;R46	jz	short KcCmd_Enable_Ms_Cont
	or	bRealCmdByte, MSIFDIS
	mov	byte ptr IoTrapData, 0A7h	;disable mouse interface
KcCmd_Enable_Ms_Cont:
	call	SmiOut64			;notify keyboard controller
	ret
KcCmd_Enable_Ms	endp

;[]========================================================================[]
;Procedure:	KcCmd_Write_Ms
;Function:	Keyboard controller command D4h handler
;		Write to mouse
;Input:		none
;Output:	wKcCmdProc, bCipFlag affected
;[]========================================================================[]
KcCmd_Write_Ms proc near
;R45 - start
	test	byte ptr bUsbFlag, USBMSSUPPORT
	jz	KcCmd_Pass_2Cmd
;R45 - end
	mov	wKcCmdProc, offset Proc_MsCmd SMI_OFFSET
	or	bCipFlag, KCWFP
	ret
KcCmd_Write_Ms endp

;[]========================================================================[]
;Procedure:	KcCmd_Self_Test
;Function:	Keyboard controller command AAh handler
;		Self test
;		Emulated reply from USB legacy smi handler, no command pass
;		to keyboard controller
;		Always reply 055h as self test successful
;Input:		none
;Output:	none
;[]========================================================================[]
KcCmd_Self_Test	proc	near
;R52 - start
	mov	al, 30h				;default command byte
	mov	bEmuCmdByte, al
	mov	bRealCmdByte, al
;R52 - end
	mov	al, 055h			;no error
	call	Send_KeyCode			;reply to system
	ret
KcCmd_Self_Test	endp

;[]========================================================================[]
;Procedure:	KcCmd_Interface_Test
;Function:	Keyboard controller command A9h/ABh handler
;		mouse/keyboard interface test
;		Emulated reply from USB legacy smi handler, no command pass
;		to keyboard controller
;		Always reply 00 as no error detected
;Input:		none
;Output:	none
;[]========================================================================[]
KcCmd_Interface_Test	proc	near
	xor	al, al				;00: no error detected
	call	Send_KeyCode			;reply to system
	ret
KcCmd_Interface_Test	endp

;************************************************************************
;*									*
;*	KEYBOARD COMMAND PROCESS MODULE					*
;*									*
;************************************************************************

;[]========================================================================[]
; Index table of keyboard command
; Sorted with the frequency of command issued
;[]========================================================================[]
KbCmdTbl	label	byte
	db	0EDh				;set/reset LED
	dw	offset KbCmd_Set_Led SMI_OFFSET
	db	0FFh				;reset
	dw	offset KbCmd_Reset SMI_OFFSET
	db	0F4h				;enable
	dw	offset KbCmd_Enable SMI_OFFSET
	db	0F5h				;default disable
	dw	offset KbCmd_Disable SMI_OFFSET
	db	0FEh				;resend
	dw	offset KbCmd_Resend SMI_OFFSET
	db	0F3h				;set typematic/delay
	dw	offset KbCmd_Typematic SMI_OFFSET
	db	0F2h				;read keyboard ID bytes
	dw	offset KbCmd_Read_ID SMI_OFFSET
	db	0F0h				;choose scan code set
	dw	offset KbCmd_Code_Set SMI_OFFSET
	db	0EEh				;echo
	dw	offset KbCmd_Echo SMI_OFFSET
	db	0F6h				;set default
	dw	offset KbCmd_Default SMI_OFFSET
KB_CMD_CNT    EQU    ($-KbCmdTbl)/3

;[]========================================================================[]
;Procedure:	Proc_KbCmd
;Function:	Process keyboard command
;Input:		IoTrapData = keyboard command
;Output:	individual command's related data affected
;[]========================================================================[]

Proc_KbCmd	proc	near

	and	bCipFlag, not (WKBWFP+RKBWFP)	;clear previous pending cmd

	push	es
	push	cs
	pop	es

	mov	di, offset KbCmdTbl SMI_OFFSET
	mov	al, IoTrapData
	mov	cx, KB_CMD_CNT
Find_KbCmd_Loop:
	scasb
	je	short Found_KbCmd
	inc	di
	inc	di
	loop	short Find_KbCmd_Loop

	; Ignore unknown command

	pop	es
	ret

Found_KbCmd:

	pop	es

	call	word ptr cs:[di]

Proc_KbCmd_Exit:

	ret
Proc_KbCmd	endp

;[]========================================================================[]
;Procedure:	Write_Kb
;Function:	Write command/data to keyboard
;Input:		AL = command/data to write
;Output:	CF = 0 : success
;		CF = 1 : fail
;[]========================================================================[]
Write_Kb	proc	near
	call	Wait_Ibf_Clear
	jc	short Write_Kb_Exit
	out	60h, al
Write_Kb_Exit:
	ret
Write_Kb	endp

;[]========================================================================[]
;Procedure:	Wait_Kb_Ack
;Function:	Wait keyboard to reply 0FAh when any command/data is send
;Input:		none
;Output:	CF = 0 : success
;		CF = 1 : fail
;[]========================================================================[]
Wait_Kb_Ack	proc	near
	push	ax
	call	Wait_Ibf_Clear
	jc	short Wait_Kb_Ack_Exit
	mov	cx, 200				;200 ms wait ACK
	call	Wait_Obf_Set
	jc	short Wait_Kb_Ack_Exit
	in	al, 60h
	cmp	al, 0FAh
	stc
	jne	short Wait_Kb_Ack_Exit
	clc
Wait_Kb_Ack_Exit:
	pop	ax
	ret
Wait_Kb_Ack	endp

;[]========================================================================[]
;Procedure:	KbCmd_Set_Led
;Function:	Keyboard command 0EDh handler
;		Set/Reset LED
;Input:		none
;Output:	wKbCmdProc, bCipFlag affected
;		bLedStatus affected
;[]========================================================================[]
KbCmd_Set_Led	proc	near
	mov	al, 0EDh			;set LED command
	call	Write_Kb			;write to PS2 keyboard with
						; Set/Reset LED command
	jc	short KbCmd_Set_Led_Cont1
	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge
KbCmd_Set_Led_Cont1:
	mov	al, 0FAh			;keyboard acknowledge
	call	Send_KeyCode			;reply to system
	mov	wKbCmdProc, offset KbCmd_Set_Led2 SMI_OFFSET
	or	bCipFlag, WKBWFP
	ret

	; 2nd trapping: system issue LED value

KbCmd_Set_Led2:
	mov	al, IoTrapData
	call	Write_Kb			;write to PS2 keyboard with
						; LED value
	jc	short KbCmd_Set_Led_Cont2
	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge

KbCmd_Set_Led_Cont2:
	mov	al, 0FAh			;keyboard acknowledge
	call	Send_KeyCode			;reply to system

	; Update USB keyboard LED

ifndef	NO_UPDATE_USBKB_LED
	mov	al, IoTrapData
	and	al, 07h				;LED status
	shl	al, 4
	mov	bLedStatus, al
	call	Suspend_Tasks			;suspend all tasks
						; for LED updated
	call	Update_Led			;update keyboard LED
	call	Resume_Tasks			;resume all tasks
						; after LED updated
endif	;NO_UPDATE_USBKB_LED

	and	bCipFlag, not WKBWFP
	ret
KbCmd_Set_Led	endp

;[]========================================================================[]
;Procedure:	KbCmd_Reset
;Function:	Keyboard command 0FFh handler
;		Reset
;Input:		none
;Output:	wKbCmdProc, bCipFlag affected
;		All USB keyboard data reset to default
;[]========================================================================[]
KbCmd_Reset	proc	near
;R52 - start
        mov     si, offset ResponseBuffer
        mov     byte ptr [si], 0FAh
        mov     byte ptr [si+1], 0FCh		;assume kb fail
	mov	al, 0FFh			;reset command
	call	Write_Kb			;write to PS2 keyboard
	jc	short Ps2_Reset_Fail
	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge
	jc	short Ps2_Reset_Fail
	mov	cx, 900				;900 ms
						; according to AT spec.
						; KB BAT consume 600-900 ms
	call	Wait_Obf_Set
	jc	short Ps2_Reset_Fail
	in	al, 60h
	cmp	al, 0AAh			;KB BAT completion code
	jne	short Ps2_Reset_Fail
        mov     byte ptr [si+1], 0AAh		;kb reset success
	jmp	short Ps2_Reset_Exit
Ps2_Reset_Fail:
	test	word ptr wKbdDevMap, 0FFFFh	;USB KB exist?
	jz	short Ps2_Reset_Exit
        mov     byte ptr [si+1], 0AAh		;kb reset success
Ps2_Reset_Exit:
        mov     byte ptr bResponsePoint, 0
        mov     byte ptr bResponseLength, 2
        call    Init_ResponseTD
        mov     si, offset ResponseTask
        call    Link_Task_Chain
        ret
;R52 - end
;R52	call	Enable_PORT60REN		;enable 60R trapping
;R52	mov	wKbCmdProc, offset KbCmd_Reset2 SMI_OFFSET
;R52	or	bCipFlag, RKBWFP
;R52	mov	al, 0FAh			;dummy code to cause 60R trap
;R52	call	Send_KeyCode
;R52	ret
;R52
;R52	; 2nd trapping: system expect to get ACK code 0FAh
;R52
;R52KbCmd_Reset2:
;R52	in	al, 60h				;clear previous dummy code
;R52	mov	IoTrapData, 0FAh		;acknowledge code
;R52	call	SetTrapData
;R52	mov	wKbCmdProc, offset KbCmd_Reset3 SMI_OFFSET
;R52	mov	al, 0FAh			;dummy code to cause 60R trap
;R52	call	Send_KeyCode
;R52	ret
;R52
;R52	; 3rd trapping: system expect to get reset completion code 0AAh
;R52
;R52KbCmd_Reset3:
;R52	in	al, 60h				;clear previous dummy code
;R52	and	bCipFlag, not RKBWFP
;R52	call	Disable_PORT60REN		;disable 60R trapping
;R52	call	UsbKb_Reset			;reset data for USB kb
;R52	mov	al, 0FFh			;reset command
;R52	call	Write_Kb			;write to PS2 keyboard
;R52	jc	short KbCmd_Reset_Cont
;R52	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge
;R52	jc	short KbCmd_Reset_Cont
;R52	mov	cx, 900				;900 ms
;R52						; according to AT spec.
;R52						; KB BAT consume 600-900 ms
;R52	call	Wait_Obf_Set
;R52	jc	short KbCmd_Reset_Cont
;R52	in	al, 60h
;R52	cmp	al, 0AAh			;KB BAT completion code
;R52	je	short KbCmd_Reset_Cont1
;R52
;R52	; Check USB KB if PS2 KB fail
;R52
;R52KbCmd_Reset_Cont:
;R52	mov	al, 0AAh			;emulate reset completion
;R52	test	word ptr wKbdDevMap, 0FFFFh
;R52	jnz	short KbCmd_Reset_Cont1
;R52	mov	al, 0FCh			;emulate failure code
;R52KbCmd_Reset_Cont1:
;R52	mov	IoTrapData, al
;R52	call	SetTrapData
;R52	ret
KbCmd_Reset	endp

;[]========================================================================[]
;Procedure:	KbCmd_Read_ID
;Function:	Keyboard command 0F2h handler
;		Read keyboard ID byte
;		Emulated reply from USB legacy smi handler, no command pass
;		to keyboard
;		Replied codes : 0FAh, 0ABh, 041h
;Input:		none
;Output:	wKbCmdProc, bCipFlag affected
;[]========================================================================[]
KbCmd_Read_ID	proc	near
;R50 - start
        mov     si, offset ResponseBuffer
        mov     byte ptr [si], 0FAh
        mov     byte ptr [si+1], 0ABh
        mov     byte ptr [si+2], 041h
        mov     byte ptr bResponsePoint, 0
        mov     byte ptr bResponseLength, 3
        call    Init_ResponseTD
        mov     si, offset ResponseTask
        call    Link_Task_Chain
        ret
;R50 - end
;R50	call	Enable_PORT60REN		;enable 60R trapping
;R50	mov	wKbCmdProc, offset KbCmd_Read_ID2 SMI_OFFSET
;R50	or	bCipFlag, RKBWFP
;R50	mov	al, 0FAh			;dummy code to cause 60R trap
;R50	call	Send_KeyCode
;R50	ret
;R50
;R50	; 2nd trapping: system expect to get 0FAh from port 60h
;R50
;R50KbCmd_Read_ID2:
;R50	in	al, 60h				;clear kb buffer
;R50	mov	IoTrapData, 0FAh		;acknowledge code
;R50	call	SetTrapData
;R50	mov	wKbCmdProc, offset KbCmd_Read_ID3 SMI_OFFSET
;R50	mov	al, 0FAh			;dummy code to cause 60R trap
;R50	call	Send_KeyCode
;R50	ret
;R50
;R50	; 3rd trapping: system expect to get firt ID code 0ABh
;R50
;R50KbCmd_Read_ID3:
;R50	in	al, 60h				;clear kb buffer
;R50	mov	IoTrapData, 0ABh		;first ID code
;R50	call	SetTrapData
;R50	mov	wKbCmdProc, offset KbCmd_Read_ID4 SMI_OFFSET
;R50	mov	al, 0FAh			;dummy code to cause 60R trap
;R50	call	Send_KeyCode
;R50	ret
;R50
;R50	; 4th trapping: system expect to get second ID code 041h
;R50
;R50KbCmd_Read_ID4:
;R50	in	al, 60h				;clear kb buffer
;R50	mov	IoTrapData, 041h		;second ID code
;R50	call	SetTrapData
;R50	and	bCipFlag, not RKBWFP
;R50	call	Disable_PORT60REN		;disable 60R trapping
;R50	ret
KbCmd_Read_ID	endp

;[]========================================================================[]
;Procedure:	KbCmd_Enable
;Function:	Keyboard command 0F4h handler
;		Enable
;Input:		none
;Output:	none
;[]========================================================================[]
KbCmd_Enable	proc	near
	mov	al, 0F4h			;enable command
	call	Write_Kb			;write to PS2 keyboard
	jc	short KbCmd_Enable_Cont
	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge
KbCmd_Enable_Cont:
	mov	al, 0FAh			;keyboard acknowledge
	call	Send_KeyCode			;reply to system
	call	UsbKb_Enable
	ret
KbCmd_Enable	endp

;[]========================================================================[]
;Procedure:	KbCmd_Disable
;Function:	Keyboard command 0F5h handler
;		Disable
;Input:		none
;Output:	none
;[]========================================================================[]
KbCmd_Disable	proc	near
	mov	al, 0F5h			;disable command
	call	Write_Kb			;write to PS2 keyboard
	jc	short KbCmd_Disable_Cont
	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge
KbCmd_Disable_Cont:
	mov	al, 0FAh			;keyboard acknowledge
	call	Send_KeyCode			;reply to system
	call	UsbKb_Default
	call	UsbKb_Disable
	ret
KbCmd_Disable	endp

;[]========================================================================[]
;Procedure:	KbCmd_Resend
;Function:	Keyboard command 0FEh handler
;		Resend
;Input:		bLastCode = last code send to system from keyboard
;Output:	none
;[]========================================================================[]
KbCmd_Resend proc	near
	mov	al, bLastCode			;last code from keyboard
	call	Send_KeyCode			;reply to system
	ret
KbCmd_Resend endp

;[]========================================================================[]
;Procedure:	KbCmd_Typematic
;Function:	Keyboard command 0F3h handler
;		Set typematic repeat rate and delay period
;Input:		none
;Output:	wKbCmdProc, bCipFlag affected
;		bTypematic, bDelayRate, bRepeatRate affected
;[]========================================================================[]
KbCmd_Typematic	proc	near
	mov	al, 0F3h			;set typematic rate/delay
	call	Write_Kb			;write to PS2 keyboard
	jc	short KbCmd_Typematic_Cont1
	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge
KbCmd_Typematic_Cont1:
	mov	al, 0FAh			;keyboard acknowledge
	call	Send_KeyCode			;reply to system
	mov	wKbCmdProc, offset KbCmd_Typematic2 SMI_OFFSET
	or	bCipFlag, WKBWFP
	ret

	; 2nd trapping: system issue typematic rate/delay value

KbCmd_Typematic2:
	mov	al, IoTrapData
	call	Write_Kb			;write to PS2 keyboard
	jc	short KbCmd_Typematic_Cont2
	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge

KbCmd_Typematic_Cont2:
	mov	al, 0FAh			;keyboard acknowledge
	call	Send_KeyCode			;reply to system

	; Update USB keyboard typematic rate/delay

	mov	al, IoTrapData
	call	UsbKb_Typematic

	and	bCipFlag, not WKBWFP
	ret
KbCmd_Typematic	endp

;[]========================================================================[]
;Procedure:	KbCmd_Code_Set
;Function:	Keyboard command 0F0h handler
;		Choose alternate scan code set
;		Emulated reply with 0FAh(acknowledge), since we just support
;		scan code set 2 only.
;Input:		none
;Output:	none
;[]========================================================================[]
KbCmd_Code_Set	proc	near
	mov	al, 0FAh			;keyboard acknowledge
	call	Send_KeyCode			;reply to system
	ret
KbCmd_Code_Set	endp

;[]========================================================================[]
;Procedure:	KbCmd_Echo
;Function:	Keyboard command 0EEh handler
;		Choose alternate scan code set
;		Emulated reply with 0EEh(echo), no command pass to keyboard.
;Input:		none
;Output:	none
;[]========================================================================[]
KbCmd_Echo	proc	near
	mov	al, 0EEh			;echo reply
	call	Send_KeyCode			;reply to system
	ret
KbCmd_Echo	endp

;[]========================================================================[]
;Procedure:	KbCmd_Default
;Function:	Keyboard command 0F6h handler
;		Set default
;Input:		none
;Output:	all USB keyboard data reset to default state
;[]========================================================================[]
KbCmd_Default	proc	near
	mov	al, 0F6h			;set default command
	call	Write_Kb			;write to PS2 keyboard
	jc	short KbCmd_Default_Cont
	call	Wait_Kb_Ack			;wait PS2 keyboard acknowledge
KbCmd_Default_Cont:
	mov	al, 0FAh			;keyboard acknowledge
	call	Send_KeyCode			;reply to system
	call	UsbKb_Default
	ret
KbCmd_Default	endp

;************************************************************************
;*									*
;*	MOUSE COMMAND PROCESS MODULE					*
;*									*
;************************************************************************

;[]========================================================================[]
; Index table of mouse command
; Sorted with the frequency of command issued
;[]========================================================================[]
MsCmdTbl	label	byte
	db	0FFh				;reset
	dw	offset MsCmd_Reset SMI_OFFSET
	db	0F4h				;enable
	dw	offset MsCmd_Enable SMI_OFFSET
	db	0F5h				;disable
	dw	offset MsCmd_Disable SMI_OFFSET
	db	0E6h				;reset scaling 1:1
	dw	offset MsCmd_Scaling1 SMI_OFFSET
	db	0E7h				;set scaling 2:1
	dw	offset MsCmd_Scaling2 SMI_OFFSET
	db	0E8h				;set resolution
	dw	offset MsCmd_Resolution SMI_OFFSET
	db	0F3h				;set sampling rate
	dw	offset MsCmd_Sample_Rate SMI_OFFSET
	db	0F6h				;set default
	dw	offset MsCmd_Default SMI_OFFSET
	db	0E9h				;status request
	dw	offset MsCmd_Status SMI_OFFSET
	db	0F2h				;read device type
	dw	offset MsCmd_Read_ID SMI_OFFSET
	db	0FEh				;resend
	dw	offset MsCmd_Resend SMI_OFFSET
	db	0EBh				;read data
	dw	offset MsCmd_Read_Data SMI_OFFSET
	db	0EAh				;set stream mode
	dw	offset MsCmd_Stream_Mode SMI_OFFSET
	db	0F0h				;set remote mode
	dw	offset MsCmd_Remote_Mode SMI_OFFSET
	db	0ECh				;reset wrap mode
	dw	offset MsCmd_Reset_Wrap SMI_OFFSET
	db	0EEh				;set wrap mode
	dw	offset MsCmd_Set_Wrap SMI_OFFSET
MS_CMD_CNT	EQU	($-MsCmdTbl)/3

;[]========================================================================[]
;Procedure:	Proc_MsCmd
;Function:	Process mouse command
;Input:		IoTrapData = mouse command
;Output:	individual command's related data affected
;[]========================================================================[]
Proc_MsCmd	proc	near
	and	bCipFlag, not KCWFP

	; Check in wrap mode

;R41	test	bMsCtrl, MSWRAPMODE
	test	bDevCtrl, MSWRAPMODE		;R41;mouse in wrap mode?
	jz	short Not_In_Wrap_Mode

	; Exit wrap mode if command 0ECh(reset wrap mode), 0FFh(reset)

	mov	al, IoTrapData
	cmp	al, 0ECh			;reset wrap mode
	je	short Not_In_Wrap_Mode
	cmp	al, 0FFh			;reset
	je	short Not_In_Wrap_Mode
	call	Send_MsCode			;echo all command/data
	ret

Not_In_Wrap_Mode:
;R41	and	bMsCtrl, not MSWRAPMODE		;clear wrap mode flag
	and	bDevCtrl, not MSWRAPMODE	;R41;clear wrap mode flag
	test	bCipFlag, WMSWFP
	jz	short First_MsCmd
	call	wMsCmdProc
	jmp	short Proc_MsCmd_Exit

First_MsCmd:
;R46 - start
	cmp	byte ptr IoTrapData, 0F3h	;set sample rate
	je	short Is_Set_Sample_Rate
	mov	byte ptr bMsChangeMode, 0	;clear change mode sequence
Is_Set_Sample_Rate:
;R46 - end
	and	bCipFlag, not (WMSWFP+RMSWFP)	;clear previous pending cmd

	push	es
	push	cs
	pop	es

	mov	di, offset MsCmdTbl SMI_OFFSET
	mov	al, IoTrapData
	mov	cx, MS_CMD_CNT
Find_MsCmd_Loop:
	scasb
	je	short Found_MsCmd
	inc	di
	inc	di
	loop	short Find_MsCmd_Loop

	; Ignore unknown command

	pop	es
	ret

Found_MsCmd:

	pop	es

	call	word ptr cs:[di]

Proc_MsCmd_Exit:

	ret
Proc_MsCmd	endp

;R46 - start
;[]========================================================================[]
;Procedure:	Reply_System
;Function:	Emulate mouse reply to system with 0FAh
;Input:		none
;Output:	none
;[]========================================================================[]

Reply_System	proc	near
	mov	al, 0FAh			;acknowledge to system
	call	Send_MsCode
	ret
Reply_System	endp
;R46 - end
;R46;[]========================================================================[]
;R46;Procedure:	Write_Ms
;R46;Function:	Write command/data to PS/2 mouse with keyboard controller
;R46;		command 0D4h
;R46;Input:		AL = command/data to write
;R46;Output:	CF = 0 : success
;R46;		CF = 1 : fail
;R46;[]========================================================================[]
;R46Write_Ms	proc	near
;R46	push	ax
;R46	mov	al, 0D4h
;R46	call	Write_KcCmd
;R46	pop	ax
;R46	jc	short Write_Ms_Exit
;R46	call	Wait_Ibf_Clear
;R46	jc	short Write_Ms_Exit
;R46	out	60h, al
;R46Write_Ms_Exit:
;R46	ret
;R46Write_Ms	endp
;R46
;R46;[]========================================================================[]
;R46;Procedure:	Wait_Ms_Ack
;R46;Function:	Wait mouse to reply 0FAh when any command/data is send
;R46;Input:		none
;R46;Output:	CF = 0 : success
;R46;		CF = 1 : fail
;R46;[]========================================================================[]
;R46Wait_Ms_Ack	proc	near
;R46	call	Wait_Kb_Ack
;R46	ret
;R46Wait_Ms_Ack	endp
;R46
;R46;[]========================================================================[]
;R46;Procedure:	Ms_Write_Reply
;R46;Function:	Write command/data to mouse and wait mouse to reply 0FAh
;R46;Input:		AL = command to mouse
;R46;Output:	CF = 0 : success
;R46;		CF = 1 : fail
;R46;[]========================================================================[]
;R46Ms_Write_Reply	proc	near
;R46;R40	test	bMsCtrl, USBMSSUPPORT		;check usb mice support
;R46	test	bUsbFlag, USBMSSUPPORT		;R40;check usb mice support
;R46	jz	short Ms_Write_Reply_Cont
;R46	test	wMsDevMap, 0FFFFh		;check usb mice installed
;R46	jz	short Ms_Write_Reply_Cont
;R46	clc
;R46	ret
;R46Ms_Write_Reply_Cont:
;R46	call	Write_Ms
;R46	jc	short Ms_Write_Reply_Exit
;R46	call	Wait_Ms_Ack
;R46Ms_Write_Reply_Exit:
;R46	ret
;R46Ms_Write_Reply	endp
;R46
;R46;[]========================================================================[]
;R46;Procedure:	Write_Ms_Reply_System
;R46;Function:	Write command/data to mouse and emulated reply to system
;R46;		with 0FAh
;R46;Input:		AL = command to mouse
;R46;Output:	none
;R46;[]========================================================================[]
;R46
;R46Write_Ms_Reply_System	proc	near
;R46	call	Ms_Write_Reply
;R46	mov	al, 0FAh			;acknowledge to system
;R46	call	Send_MsCode
;R46	ret
;R46Write_Ms_Reply_System	endp

;[]========================================================================[]
;Procedure:	Setup_Ms_Queue
;Function:	Setup the process for a serial data expected to be read by
;		system
;Input:		wMsQueuePoint = point to the serial data
;		bMsQueueLen = length of the serial data
;Output:	wMsCmdProc, bCipFlag affected
;		wMsQueueIndex, bMsQueueCount affected
;[]========================================================================[]
Setup_Ms_Queue	proc	near
	call	Enable_PORT60REN		;enable 60R trapping
	mov	wMsCmdProc, offset Proc_Ms_Queue SMI_OFFSET
	mov	al, byte ptr bMsQueueLen
	mov	byte ptr bMsQueueCount, al
	mov	ax, word ptr wMsQueuePoint
	mov	word ptr wMsQueueIndex, ax
	or	bCipFlag, RMSWFP
	mov	al, 0FAh			;cause next 60R trap
	call	Send_MsCode
	ret
Setup_Ms_Queue	endp

;[]========================================================================[]
;Procedure:	Proc_Ms_Queue
;Function:	Process a serial data expected to be read by system and is
;		setup by previous Setup_Ms_Queue
;Input:		wMsQueueIndex = point to the current byte to send
;		bMsQueueCount = byte remained
;Output:	wMsQueueIndex, bMsQueueCount modified
;		bCipFlag affected
;[]========================================================================[]
Proc_Ms_Queue	proc	near
	in	al, 60h				;clear previous dummy code
	mov	si, wMsQueueIndex
	mov	al, [si]
	mov	IoTrapData, al
	call	SetTrapData
	inc	word ptr wMsQueueIndex
	dec	byte ptr bMsQueueCount
	jz	short Proc_Ms_Queue_End
	mov	al, 0FAh			;dummy code to cause 60R trap
	call	Send_MsCode
	ret
Proc_Ms_Queue_End:
	and	bCipFlag, not RMSWFP
	call	Disable_PORT60REN		;disable 60R trapping
	ret
Proc_Ms_Queue	endp

;[]========================================================================[]
;Procedure:	MsCmd_Reset
;Function:	Mouse command 0FFh handler
;		Reset
;		Write PS/2 mouse with 0F6h(set default) and emulated reply
;		to system with successful completion code
;Input:		none
;Output:	Data related to routines "Setup_Ms_Queue" and "Proc_Ms_Queue"
;		affected
;		All USB mouse data reset to default state
;[]========================================================================[]
MsCmd_Reset	proc	near
	call	UsbMs_Default			;reset data to default
	mov	byte ptr bMsID, 0		;R46;normal mode
;R46	mov	al, 0F6h			;set default
;R46	call	Ms_Write_Reply
	mov	wMsQueuePoint, offset bMsQueue
	mov	bMsQueueLen, 3
	mov	bMsQueue[0], 0FAh		;ACK
	mov	bMsQueue[1], 0AAh		;reset completion
	mov	bMsQueue[2], 000h		;mouse ID
	call	Setup_Ms_Queue
	ret
MsCmd_Reset	endp

;[]========================================================================[]
;Procedure:	MsCmd_Enable
;Function:	Mouse command 0F4h handler
;		Enable
;Input:		none
;Output:	bMsStatus affected
;		Data related to routine "Write_Ms_Reply_System" affected
;[]========================================================================[]
MsCmd_Enable	proc	near
	or	bMsStatus, MSENABLE		;mouse enabled
	and	bDevCtrl, not MSDISABLE		;R41;mouse enabled
;R46	mov	al, 0F4h			;enable
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret
MsCmd_Enable	endp

;[]========================================================================[]
;Procedure:	MsCmd_Disable
;Function:	Mouse command 0F5h handler
;		Disable
;Input:		none
;Output:	bMsStatus affected
;		Data related to routine "Write_Ms_Reply_System" affected
;[]========================================================================[]
MsCmd_Disable	proc	near
	and	bMsStatus, not MSENABLE		;mouse disabled
	or	bDevCtrl, MSDISABLE		;R41;mouse disabled
;R46	mov	al, 0F5h			;disable
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret
MsCmd_Disable	endp

;[]========================================================================[]
;Procedure:	MsCmd_Scaling1
;Function:	Mouse command 0E6h handler
;		Reset scaling to 1:1
;Input:		none
;Output:	bMsStatus affected
;		Data related to routine "Write_Ms_Reply_System" affected
;[]========================================================================[]
MsCmd_Scaling1	proc	near
	and	bMsStatus, not MSSCALE2		;scanling 1:1
;R46	mov	al, 0E6h			;reset scaling
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret
MsCmd_Scaling1	endp

;[]========================================================================[]
;Procedure:	MsCmd_Scaling2
;Function:	Mouse command 0E7h handler
;		Set scaling to 2:1
;Input:		none
;Output:	bMsStatus affected
;		Data related to routine "Write_Ms_Reply_System" affected
;[]========================================================================[]
MsCmd_Scaling2	proc	near
	or	bMsStatus, MSSCALE2		;scanling 2:1
;R46	mov	al, 0E7h			;set scaling
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret
MsCmd_Scaling2	endp

;[]========================================================================[]
;Procedure:	MsCmd_Resolution
;Function:	Mouse command 0E8h handler
;		Set resolution
;Input:		IoTrapData
;Output:	bResolution affected
;		Data related to routine "Write_Ms_Reply_System" affected
;[]========================================================================[]
MsCmd_Resolution	proc	near
	mov	wMsCmdProc, offset MsCmd_Resolution2 SMI_OFFSET
	or	bCipFlag, WMSWFP
;R46	mov	al, 0E8h			;set resolution
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret

	; 2nd trapping: system issue resolution rate value

MsCmd_Resolution2:
	and	bCipFlag, not WMSWFP
	mov	al, IoTrapData			;resolution value
	mov	bResolution, al
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret
MsCmd_Resolution	endp

;[]========================================================================[]
;Procedure:	MsCmd_Sample_Rate
;Function:	Mouse command 0F3h handler
;		Set sample rate
;Input:		IoTrapData
;Output:	bSampleRate affected
;		Data related to routine "Write_Ms_Reply_System" affected
;[]========================================================================[]
MsCmd_Sample_Rate	proc	near
	mov	wMsCmdProc, offset MsCmd_Sample_Rate2 SMI_OFFSET
	or	bCipFlag, WMSWFP
;R46	mov	al, 0F3h			;set sample rate
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret

	; 2nd trapping: system issue sample rate value

MsCmd_Sample_Rate2:
	and	bCipFlag, not WMSWFP
	mov	al, IoTrapData			;sample rate value
	mov	bSampleRate, al
;R46	call	Write_Ms_Reply_System
;R46 - start
	call	Reply_System
	cmp	byte ptr bMsID, 3		;extended mode mouse ID
	je	short MsCmd_Sample_Rate_Exit
	mov	si, offset CHANGE_MODE_SEQUENCE SMI_OFFSET
	movzx	dx, byte ptr bMsChangeMode
	add	si, dx
	cmp	al, cs:[si]
	jne	short Clear_ChangeMode_Flag
	inc	dx
	mov	bMsChangeMode, dl
	cmp	dl, 3
	jne	short MsCmd_Sample_Rate_Exit
	mov	byte ptr bMsID, 3		;extended mode mouse ID
Clear_ChangeMode_Flag:
	mov	byte ptr bMsChangeMode, 0	;normal mode mouse ID
MsCmd_Sample_Rate_Exit:
;R46 - end
	ret
MsCmd_Sample_Rate	endp

CHANGE_MODE_SEQUENCE	db	0C8h, 064h, 050h	;R46

;[]========================================================================[]
;Procedure:	MsCmd_Default
;Function:	Mouse command 0F6h handler
;		Set default
;Input:		none
;Output:	Data related to routine "Write_Ms_Reply_System" affected
;		All USB mouse data reset to default state
;[]========================================================================[]
MsCmd_Default	proc	near
	call	UsbMs_Default			;reset data to default
;R46	mov	al, 0F6h			;set default
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret
MsCmd_Default	endp

;[]========================================================================[]
;Procedure:	MsCmd_Status
;Function:	Mouse command 0E9h handler
;		Status request
;		Emulated reply to system with bMsStatus, no command pass to
;		mouse
;Input:		none
;Output:	Data related to routines "Setup_Ms_Queue" and "Proc_Ms_Queue"
;		affected
;[]========================================================================[]
MsCmd_Status	proc	near
	mov	wMsQueuePoint, offset bMsStatus1
	mov	bMsQueueLen, 4
	call	Setup_Ms_Queue
	ret
MsCmd_Status	endp

;[]========================================================================[]
;Procedure:	MsCmd_Read_ID
;Function:	Mouse command 0F2h handler
;		Read device type
;		Emulated reply to system with 0FAh and 00h, no command pass to
;		mouse
;Input:		none
;Output:	Data related to routines "Setup_Ms_Queue" and "Proc_Ms_Queue"
;		affected
;[]========================================================================[]
MsCmd_Read_ID	proc	near
	mov	wMsQueuePoint, offset bMsQueue
	mov	bMsQueueLen, 2
	mov	bMsQueue[0], 0FAh		;ACK
;R46	mov	bMsQueue[1], 000h		;mouse ID
	mov	al, bMsID			;R46;mouse ID
	mov	bMsQueue[1], al			;R46
	call	Setup_Ms_Queue
	ret
MsCmd_Read_ID	endp

;[]========================================================================[]
;Procedure:	MsCmd_Resend
;Function:	Mouse command 0FEh handler
;		Resend
;		Emulated reply to system with 0FEh(resend)
;Input:		none
;Output:	none
;[]========================================================================[]
MsCmd_Resend	proc	near
	mov	al, 0FEh
	call	Send_MsCode
	ret
MsCmd_Resend	endp

;[]========================================================================[]
;Procedure:	MsCmd_Read_Data
;Function:	Mouse command 0EBh handler
;		Read data
;		If USB mouse present then emulated reply to system with
;		bMsDataPacket, otherwise pass command to mouse
;Input:		none
;Output:	Data related to routines "Setup_Ms_Queue" and "Proc_Ms_Queue"
;		affected
;[]========================================================================[]
MsCmd_Read_Data	proc	near
;R40	test	bMsCtrl, USBMSSUPPORT		;check usb mice support
;R46	test	bUsbFlag, USBMSSUPPORT		;R40;check usb mice support
;R46	jz	short MsCmd_Read_Data_Cont
;R46	test	wMsDevMap, 0FFFFh		;check usb mice installed
;R46	jz	short MsCmd_Read_Data_Cont
	mov	wMsQueuePoint, offset bMsDataPacket1
;R46	mov	bMsQueueLen, 4
;R46 - start
	mov	al, 4
	cmp	bMsID, 3
	jne	short @f
	inc	al
@@:
	mov	bMsQueueLen, al
;R46 - end
	call	Setup_Ms_Queue
	ret
;R46MsCmd_Read_Data_Cont:
;R46	mov	al, 0EBh
;R46	call	Write_Ms
;R46	ret
MsCmd_Read_Data	endp

;[]========================================================================[]
;Procedure:	MsCmd_Stream_Mode
;Function:	Mouse command 0EAh handler
;		Set stream mode
;Input:		none
;Output:	bMsStatus affected
;		Data related to routine "Write_Ms_Reply_System" affected
;[]========================================================================[]
MsCmd_Stream_Mode	proc	near
	and	bMsStatus, not MSREMOTEMODE	;stream mode
;R46	mov	al, 0EAh			;set stream mode
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret
MsCmd_Stream_Mode	endp

;[]========================================================================[]
;Procedure:	MsCmd_Remote_Mode
;Function:	Mouse command 0F0h handler
;		Set remote mode
;Input:		none
;Output:	bMsStatus affected
;		Data related to routine "Write_Ms_Reply_System" affected
;[]========================================================================[]
MsCmd_Remote_Mode	proc	near
	or	bMsStatus, not MSREMOTEMODE	;stream mode
;R46	mov	al, 0F0h			;set remote mode
;R46	call	Write_Ms_Reply_System
	call	Reply_System			;R46
	ret
MsCmd_Remote_Mode	endp

;[]========================================================================[]
;Procedure:	MsCmd_Reset_Wrap
;Function:	Mouse command 0ECh handler
;		Reset wrap mode
;Input:		none
;R41;Output:	bMsCtrl affected
;Output:	bDevCtrl affected		;R41
;[]========================================================================[]
MsCmd_Reset_Wrap	proc	near
;R41	and	bMsCtrl, not MSWRAPMODE		;normal mode
	and	bDevCtrl, not MSWRAPMODE	;R41;normal mode
;R46	mov	al, 0FAh			;mouse acknowledge
;R46	call	Send_MsCode
	call	Reply_System			;R46
	ret
MsCmd_Reset_Wrap	endp

;[]========================================================================[]
;Procedure:	MsCmd_Set_Wrap
;Function:	Mouse command 0EEh handler
;		Set wrap mode
;Input:		none
;R41;Output:	bMsCtrl affected
;Output:	bDevCtrl affected		;R41
;[]========================================================================[]
MsCmd_Set_Wrap	proc	near
;R41	or	bMsCtrl, MSWRAPMODE		;normal mode
	or	bDevCtrl, MSWRAPMODE		;R41;normal mode
;R46	mov	al, 0FAh			;mouse acknowledge
;R46	call	Send_MsCode
	call	Reply_System			;R46
	ret
MsCmd_Set_Wrap	endp

endif	;IOTRAP_SUPPORT
;R39 - end

	assume	ds:nothing

ENDIF	;COMPILE_FOR_USBBIOS EQ 3
;R04ENDIF	;USB_SUPPORT
