;	[]===========================================================[]
;
;	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
;----------------------------------------------------------------------------
;R44	04/29/99 KEN	Added definition "FAST_CHANGE_A20M" and call "Ct_A20"
;			to change A20M state to solve that the system is very
;			slow when HIMEM is testing memory.
;R43	04/14/99 KEN	Patch that the SET_IDLE rate of some USB keyboard
;			isn't correct and causes the BIOS simulated typematic
;			rate is wrong.
;			With the newest codes, 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.
;R42	04/13/99 KEN	Add keyboard controller emulation code and USB mouse
;			support.
;R41	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
;
;R40  	01/18/99 JSN	Add Xgroup_Segment defination for dynamic change.
;R15A	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.
;
;R39	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.
;R38	12/28/98 RAY	Support switch: SHADOW_UNIT_64K
;R37	12/15/98 KEN	Added Usb_Check_Legacy routine to let other modules
;			to check if USB legacy supporting active.
;R36	11/03/98 KEN	Fixed bug that the memory address of host controller
;			is modified by Win98, and caused that the system
;			hang-up during the ownership changed from Win98 to
;			BIOS.
;R35	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.
;R34	10/14/98 KEN	Added the declaration of "PATCH_AMIDIAG" to patch the
;			error of "BIOS ROM Test" of AMIDIAG.
;R31B	09/25/98 RCH	More fix for R31A. The USB legacy won't work if
;			NO_EARLY_MASTER_ENABLE is used.
;R31A	09/25/98 LAW	fixed USB_Legacy_SUPPORT when exit windows 98 call USB
;			host_init error
;R33	09/21/98 KEN	Updated the bit manipulation of bUsbFlag with symbolic
;			variable.
;R32	09/18/98 KEN	Remove bRepeatRate and bDelayRate from individual
;			keyboard variable to global variable for OHCI.
;R31	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.
;R29B	07/30/98 KEN	Fixed bug that the USB ownership isn't transferred
;			successfully from Win98 to BIOS with "Restart in MS-DOS
;			mode" in the "Shut Down" menu of Win98.
;R30	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.
;R29A	05/21/98 KEN	Fixed bug for SiS chipset that the system sometimes
;			hang-up at POST_49s caused by the modification of R29.
;R29	05/13/98 KEN	Added the process of ownership changed from Win98 to
;			system BIOS while selecting "Shut Down" or "Restart in
;			MS-DOS mode" in the "Shut Down" menu of Win98.
;R28	05/12/98 KEN	Fixed bug that the USB keyboard can't work when the
;			system frequency is 66MHz and the USB keyboard is
;			attached at port 1 and the USB mouse is attached at
;			port 2. Swapping the devices to another port it will
;			be fine.
;			(The bug was found in both ALi and SiS chipsets.)
;R27	02/19/98 KEN	Fixed bug that the system hang up after hot plugging of
;			USB keyboard.
;R26	02/17/98 KEN	Added declaration of USB_PM_SUPPORT and codes to process
;			USB suspend and resume.
;R25	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.
;R24	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.
;R23	12/05/97 JSN	Add SMIHANDLE_IN_XGROUP define.(note: when use this 
;			define,USB & PMU codes need to replace at XGROUP).
;R22	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).
;R21	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
;R20	10/06/97 KEN	Get hub descriptor with the value 29h of descriptor
;			type byte to match the newest spec.
;R19	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.
;R18	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.
;R17	07/25/97 KEN	Fixed bug that the system hang at POST_49s when USB
;			legacy supportting is enabled and the Intel EtherExpess
;			PRO/100 PCI LAN card is installed.
;			The causation is that the memory space of OHCI will
;			be assigned to be A20 decoding address at this state.
;			To solve this bug, the USB kernal should turn on A20
;			at POST stage.
;R16	07/08/97 KEN	Clear OwnerShipChange status bit for ALi chipset to
;			fix that the system hang-up when BIOS legacy supporting
;			transfer to Memphis USB driver supporting.
;R15	06/25/97 RCH	Fixed SCT sometimes testing failure if "USB keyboard"
;			is enabled.
;R14	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.
;R13A	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.
;R13	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").
;R12	06/12/97 KEN	Added the definition "NO_UPDATE_USBKB_LED" to patch
;			that the SEJIN USB keyboard is inactive after updating
;			LED.
;R11	06/12/97 KEN	Added "GET_REPORT_DESCRIPTOR" to patch that the SEJIN
;			USB keyboard can't be activated.
;R10	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.
;R09	06/10/97 KEN	Added 102-key supporting.
;			USB key number 32h, 64h are corresponding to AT key
;			number 42, 45.
;R08	05/14/97 KEN	Fixed bug that the LED of USB keyboard isn't updated
;			with system LED status.
;R07	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.
;R06	04/28/97 KEN	Support USB always enabled at POST stage, and
;			initialize USB before memory testing.
;R05	04/09/97 KEN	Saving all registers is done by Usb_Smi, it's done
;			by PMUPOST originally.
;R04	04/03/97 KEN	Patch the ALi/M1523B doesn't support Per-Port power
;			switching mode.
;R03	04/01/97 KEN	Fixed bug, that system hang-up when transfer from BIOS
;			legacy support to Win95 with USB support.
;R02	04/01/97 KEN	Patch that some USB keyboards don't support the
;			SET_IDLE request.(e.g. BTC USB Keyboard)
;R01	03/31/97 KEN	Fixed coding mistake, device enumeration failed when
;			plug full-speed device after low-speed device removed.
;R00	03/26/97 KEN	This file is included by USBBIOS.ASM to support
;			OpenHCI. Some host controller independent codes
;			will be moved to USBBIOS.ASM in future.

;************************************************************************
;									*
; NOTES: If no special definition, DS and ES always point to USB_RAM	*
;									*
;************************************************************************

IF	COMPILE_FOR_USBBIOS EQ 1

;****************************************************************
;*								*
;*	COMPILING STAGE 1					*
;*								*
;*	MISCELLANEOUS DEFINITION				*
;*								*
;****************************************************************

;R44 - start
ifdef	FAST_CHANGE_A20M
	extrn	Ct_A20:near
endif	;FAST_CHANGE_A20M
;R44 - end
	extrn	Read_A20_Status:near		;R17
	extrn	A20_On:near			;R17
	extrn	A20_Off:near			;R17
	extrn	Get_Pci:near
	extrn	Set_Pci:near
	extrn	F000_Shadow_W:near
	extrn	F000_Shadow_R:near
	extrn	C000_Shadow_RW:near		;R38
	extrn	Ct_Shadow_RW:near
	extrn	Ct_Disable_Shadow:near		;R14
	extrn	USB_RAM_SEG:word
	extrn	LMEM_RESOURCE:abs
	extrn	LMEM_RESERVED:abs		;R14
	extrn	USB_STATUS:byte

ifdef	PNP_BIOS
	extrn	Build_UsbRamNode:near
endif;	PNP_BIOS

ENDIF	;COMPILE_FOR_USBBIOS EQ 1

IF	COMPILE_FOR_USBBIOS EQ 2

;****************************************************************
;*								*
;*	COMPILING STAGE 2					*
;*								*
;*	POST INITIALIZATION CODES OCCUPIED AT E000 SEGMENT	*
;*								*
;****************************************************************

	assume	ds:USB_RAM

;************************************************************************
;*									*
;*	POST INTERFACE MODULE						*
;*									*
;************************************************************************

;[]========================================================================[]
;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
;R30	jnc	short @f
;R30	call	Record_USB_Disabled
;R30	stc
;R30	jmp	short Usb_Init_Exit
;R30@@:
;R42	jc	short Usb_Init_Exit		;R30
	jc	Usb_Init_Exit			;R42
	call	Record_USB_Enabled		;R30

	call	Ct_USBRAM_Info
	or	al, al
	jz	short Use_Shadow_RAM
	call	Allocate_Base_Memory
	jmp	short @f
Use_Shadow_RAM:
;R14	call	Allocate_Post_USBRAM
	call	Allocate_USBRAM			;R14
@@:
	F000_call	Read_A20_Status		;R17
	pushf					;R17
	jnc	short @f			;R17
	F000_call	A20_On			;R17
@@:						;R17
	call	Get_USBRAM
	mov	ds, ax
	call	Get_HostMemBase
	mov	dHostMemBase, eax
	call	Linear_Segment

;R31B - start
	; Turn on bus master and memory 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/memory space
	F000_call	Set_PCI
;R31B - end
;R42 - start
ifdef	IOTRAP_SUPPORT
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
	call	Ct_A20M_Reverse			;reverse A20M control
endif	;IOTRAP_SUPPORT
;R42 - end

	call	Host_Init

	call	System_Control_Init

	call	Resume_Tasks

	call	Host_Run

	popf					;R17
	jnc	short @f			;R17
	F000_call	A20_Off			;R17
@@:						;R17
	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

	F000_call	Read_A20_Status		;R17
	pushf					;R17
	jnc	short @f			;R17
	F000_call	A20_On			;R17
@@:						;R17

	call	Check_USB_Disabled
	jnz	short Usb_Final_Init_Exit

;R14	call	Ct_USBRAM_Info
;R14	or	al, al
;R14	jnz	short Usb_Final_Init_Exit

	call	Get_USBRAM
	mov	ds, ax
	call	Linear_Segment

;R14	call	Host_Stop

;R06 - start
	call	Ct_Check_USB_Disabled
	jnc	short @f
	call	Record_USB_Disabled
	call	Host_Stop			;R14
	call	Global_Reset
;R42 - start
ifdef	IOTRAP_SUPPORT
	call	Ct_UsbMouse_NotSupport
	call	Ct_A20M_Normal			;normal A20M control
	call	Get_HceControl
	and	al, not (EXTIRQEN+CHARPENDING+EMEN)
	call	Set_HceControl
endif	;IOTRAP_SUPPORT
;R42 - end
	call	Close_USBRAM			;R14
	jmp	short Usb_Final_Init_Exit
@@:
;R06 - end
;R42 - start
ifdef	USB_MOUSE_SUPPORT
	and	al, USBKBSUPPORT
	or	al, REMOVEDEV
	and	byte ptr bUsbFlag, not USBKBSUPPORT
	or	byte ptr bUsbFlag, al
else	;USB_MOUSE_SUPPORT
	or	byte ptr bUsbFlag, USBKBSUPPORT
endif	;USB_MOUSE_SUPPORT
;R42 - end

;R14	call	Allocate_USBRAM
;R14	call	Get_USBRAM

ifdef	PNP_BIOS
	xor	edi,edi
;R14	mov	di,ax
	mov	di,ds				;R14
	shl	edi,4
ifndef	SMIHANDLE_IN_XGROUP		;R23
	call	Build_UsbRamNode	;build device node for USB RAM
else	;SMIHANDLE_IN_XGROUP		;R23
	POST_func_call	Build_UsbRamNode;R23
endif	;SMIHANDLE_IN_XGROUP		;R23
endif;	PNP_BIOS

;R14	mov	ds, ax
;R14	call	Get_HostMemBase
;R14	mov	dHostMemBase, eax
;R14	call	Linear_Segment
;R14
;R14	call	Host_Init
;R14
;R14	call	System_Control_Init
;R14
;R14	call	Resume_Tasks
;R14
;R14	call	Host_Run

Usb_Final_Init_Exit:
	popf					;R17
	jnc	short @f			;R17
	F000_call	A20_Off			;R17
@@:						;R17
	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	Check_USB_Disabled		;host or legacy support disabled?
	jnz	short Report_USB_Fail

	call	Get_USBRAM
	mov	ds, ax

ifdef	PATCH_SIS5571_KC
	call	Record_No_At_Keyboard
endif	;PATCH_SIS5571_KC

	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

;R42 - start
ifdef	USB_MOUSE_SUPPORT
;[]========================================================================[]
;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
endif	;USB_MOUSE_SUPPORT
;R42 - end

ifdef	PATCH_SIS5571_KC
;[]========================================================================[]
;Procedure:	Record_No_At_Keyboard
;Function:	Record no AT keyboard present
;Input:		none
;Output:	none
;[]========================================================================[]

Record_No_At_Keyboard	proc	near
	push	ds
	push	ax

	F000_CALL	F000_Shadow_W
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	mov	al, 02
	or	ds:USB_STATUS, al
	F000_CALL	F000_Shadow_R

	pop	ax
	pop	ds
	assume	ds:USB_RAM
	ret
Record_No_At_Keyboard	endp
endif	;PATCH_SIS5571_KC

;[]========================================================================[]
;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

;R30 - 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
;R30 - end

;[]========================================================================[]
;Procedure:	Allocate_Post_USBRAM
;Function:	Allocate USB_RAM for POST usage
;Input:		none
;Output:	none
;[]========================================================================[]

;R14Allocate_Post_USBRAM	proc	near
;R14	push	ds
;R14	pushad
;R14
;R14	mov	ax, 9000h
;R14
;R14	call	Record_USBRAM
;R14
;R14	mov	ds, ax
;R14	call	Init_USBRAM
;R14
;R14	popad
;R14	pop	ds
;R14	ret
;R14Allocate_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
	pushad

	mov	eax, LMEM_RESOURCE[bp]
;R14	mov	dx, 0C800h
;R24	mov	dx, 0DC00h			;R14;start from DC00h
;R24	mov	edi, 00F00000h			;R14;mask value
	mov	dx, 0C800h			;R24;start from C800h
	mov	edi, 0000000Fh			;R24;mask value
	mov	cx, 6
@@:
;R14	test	al, 0Fh
	test	eax, edi			;R14
	jz	short Use_Shadow
;R14	shr	eax, 4
;R14	add	dx, 400h
;R24	shr	edi, 4				;R14
;R24	sub	dx, 400h			;R14;next backward 16KB
	shl	edi, 4				;R24
	add	dx, 400h			;R24;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		;R14
	mov	LMEM_RESERVED[bp], edi		;R14
;R38 - starts
ifdef	SHADOW_UNIT_64K
	cmp	dh, 0D0h
;R41	ja	short USB_RAM_At_D
	jae	short USB_RAM_At_D		;R41
	push	dx
	F000_call C000_Shadow_RW
	pop	ax
	jmp	short Move_USB_RAM
USB_RAM_At_D:
endif	;SHADOW_UNIT_64K
;R38 - ends
	push	dx
	F000_CALL	Ct_Shadow_RW
	pop	ax

Move_USB_RAM:
	call	Record_USBRAM

	mov	ds, ax
	call	Init_USBRAM

	popad
	pop	ds
	ret
Allocate_USBRAM	endp

Allocate_Base_Memory:
	push	ds
	pushad
	jmp	short Use_Base_Mem

;[]========================================================================[]
;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

;R14 - 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
;R25 - start
	mov	cl, dh
	sub	cl, 0C8h
	mov	edi, 0FFFFFFF0h
	rol	edi, cl
	and	LMEM_RESOURCE[bp], edi
	and	LMEM_RESERVED[bp], edi
;R25 - end
	F000_call	Ct_Disable_Shadow
Close_USBRAM_Exit:
	ret
;R14 - end

;[]========================================================================[]
;Procedure:	Linear_Segment
;Function:	Enter protected mode and set ES to segment 0 then leave
;		protected mode
;Input:		none
;Output:	ES = selector
;[]========================================================================[]

Linear_Segment:
	push	ds

	lgdt    fword ptr cs:GDTR1

	mov	eax, cr0
	or	al, 1				; protect mode enable
	mov	cr0, eax

	mov	ax, DATA1_INDEX
	mov	es, ax				; es = 0 (4GB)

	mov     eax, cr0
	and     al, NOT 1
	mov     cr0, eax

	pop	ds
	ret

		ALIGN	4
GDTR1:						; global descriptor table register
		dw	8*2			; LIMIT
ifndef	SMIHANDLE_IN_XGROUP	      		;R23
		dw	offset EGROUP:GDT1
		dw	0Eh			; in 0F000h segment
else	;SMIHANDLE_IN_XGROUP			;R23
	 	dw	offset XGROUP:GDT1	;R23
;R40		dw	06h			;R23
		dw	(Xgroup_Segment shr 12)	;R40
endif	;SMIHANDLE_IN_XGROUP			;R23

GDT1:						; null descriptor
		dw	0			; limit
		dw	0			; base
		db	0			; hibase
		db	0			; access
		db	0			; hilimit
		db	0			; msbase

DATA1_DT:					; ds - first 64k segment
DATA1_INDEX	=	((OFFSET DATA1_DT - OFFSET GDT1)/8) SHL 3
		dw	0FFFFh			; limit
		dw	0			; base data segment points to
		db	0			; hibase	; 00000000
		db	93h			; access
		db	08Fh			; hilimit (4GB)
		db	0			; msbase

;R29 - start
	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
;R29 - end

;************************************************************************
;*									*
;*	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	Clear_Buffer

;R15 - 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
;R15A	rep	stosw
	rep	stosb			;R15A
	pop	di	
	pop	es
;R15 - end

ifndef	PATACH_AMIDIAG				;R34
	mov	word ptr ds:[0], 0AA55h
endif	;PATACH_AMIDIAG				;R34
	mov	word ptr ds:[2], 0CB10h
	mov	dword ptr ds:[4], 'BSU$'

	call	Init_FL

	mov	word ptr wTaskLink, 0FFFFh	;task terminated
	mov	word ptr DevAddrMap+2, 0080h	;root hub device

;R32 - start
	mov	byte ptr bDelayRate,  31	;default typematic delay
	mov	byte ptr bRepeatRate, 6		;default typematic repeat rate
;R32 - end

;R42 - start
ifdef	USB_MOUSE_SUPPORT
	mov	bUsbFlag, USBKBSUPPORT+USBMSSUPPORT
	mov	bDevCtrl, MSDISABLE
else	;USB_MOUSE_SUPPORT
	mov	bUsbFlag, USBKBSUPPORT
endif	;USB_MOUSE_SUPPORT

ifdef	IOTRAP_SUPPORT
	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	wKcCmdProc, offset NullProc SMI_OFFSET
	mov	wKbCmdProc, offset NullProc SMI_OFFSET
	mov	wMsCmdProc, offset NullProc SMI_OFFSET
endif	;IOTRAP_SUPPORT
;R42 - end

	ret

;[]========================================================================[]
;Procedure:	System_Control_Init
;Function:	Initialize system control task
;Input:		none
;Output:	none
;[]========================================================================[]

System_Control_Init:

;R43 - start
	; Initialize Timer task, and skip at this stage until
	; the USB keyboard is attached.

	mov	si, offset TimerQH
	call	Init_QH
	mov	[si].wEdControl, 4001h		;dev1, endp0, SKIP
	mov	[si].wEdMps, 1800h		;interval 4ms
	mov	si, offset TimerTD
	call	Init_TD
	mov	[si].wTdTask, offset TimerTask
	mov	[si].wTdControl, 0FA14H		;Buffer rounding=1
						;PID = 10b (PID_IN)
						;zero delay interrupt
						;use TD's data toggle
						;Error Count=2
						;Condition Code=NOTACCESSED
	mov	di, offset TimerQH
	call	Link_TD_to_QH

	mov	si, offset TimerTask
	call	Init_Task
	mov	byte ptr [si].bTkDevStatus, TK_WFP
	mov	byte ptr [si].bTkDevAddr, 1
	mov	word ptr [si].wTkInterval, 4		;interval 4ms
	mov	word ptr [si].wTkQueueHead, offset TimerQH
	mov	word ptr [si].wTkTransDesp, offset TimerTD
	mov	word ptr [si].wTkProc, offset Proc_Timer SMI_OFFSET
	call	Link_Task
;R43 - end

;R03	mov	eax, MIE+RHSC			;root hub status change int.
	mov	eax, MIE+RHSC+OC		;R03
	call	Set_HcInterruptEnable

	ret

;R43 - start
;[]========================================================================[]
;Procedure:	Init_TimerTD
;Function:	Initialize Timer TD
;Input:		none
;Output:	none
;[]========================================================================[]

Init_TimerTD:
	push	si
	mov	si, offset TimerTD
	mov	[si].wTdControl, 0FA14H		;Buffer rounding=1
						;PID = 10b (PID_IN)
						;zero delay interrupt
						;use TD's data toggle
						;Error Count=2
						;Condition Code=NOTACCESSED
	mov	si, offset TimerQH
	and	[si].wEdControl, not SKIP
	pop	si
	ret

;[]========================================================================[]
;Procedure:	Proc_Timer
;Function:	Periodic timer task process routine (period=4ms)
;Input:		SI = point to TimerTask
;Output:	none
;[]========================================================================[]

Proc_Timer:
	mov	al, bTimerCount			;general purpose timer counter
	inc	al
	mov	bTimerCount, al

Proc_Keybuffer:
	push	es
	push	ds
	pop	es

	mov	al, bTimerCount
	test	al, 03				;*4=16ms period
	jnz	short Proc_KeyBuffer_End

	test	word ptr wKbdDevMap, 0FFFFh	;any USB keyboard present
	jz	short Proc_Keybuffer_End

	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	;keyboard task?
	jz	short Proc_Keybuffer_Loop

	mov	si, [di].wTkCtrlBuffer		;SI point to control buffer

	push	di
	call	Proc_KeyCode			;generate key code
	pop	di

	cmp	byte ptr [si].bKeyLength, 0	;any key code present?
	je	short Proc_Keybuffer_Loop

	call	Proc_Key_Buffer			;send code to system

ifdef	IOTRAP_SUPPORT
	push	si
	push	di
	call	Proc_CharPending		;process character pending
	pop	di
	pop	si
endif	;IOTRAP_SUPPORT

	jmp	short Proc_Keybuffer_Loop

Proc_Keybuffer_End:
	pop	es

Proc_Timer_Exit:
	ret
;R43 - end

;[]========================================================================[]
;Procedure:	Host_Init
;Function:	Initialize host controller
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Init:

;R31A;R31 - start
;R31A	; Turn on bus master and memory space decoding,
;R31A	; avoid that these two bits are not turn-on
;R31A	; by PCI kernel.
;R31A	mov	cx, wHostID
;R31A	add	cx, 4				;command register
;R31A	F000_call	Get_PCI
;R31A	or	al, 00000111b			;bus master/memory space
;R31A	F000_call	Set_PCI
;R31A;R31 - end

	; Global Reset

	call	Global_Reset

;R06	call	Get_HcControl
;R06	and	eax, not HCFS
;R06	call	Set_HcControl
;R06	call	Delay_12ms

	; Set host controller function state to USBOPERATIONAL

	call	Get_HcControl
	and	eax, not HCFS
	or	eax, USBOPERATIONAL+USBSMI
	call	Set_HcControl

	; Turn on global power

	call	Get_HcRhDescriptorA		;R04
	or	eax, PSM			;R04
	call	Set_HcRhDescriptorA		;R04
	xor	eax, eax			;R04
	call	Set_HcRhDescriptorB		;R04

	call	Get_HcRhStatus
	or	eax, 00010000h
	call	Set_HcRhStatus

	; Delay after global power on

	call	Wait_Stable

	xor	eax, eax
	mov	ax, ds
	shl	eax, 4
	lea	edi, FrameList
	add	eax, edi
	call	Set_HcHCCA

	mov	eax, 27782EDFh
	call	Set_HcFmInterval

	mov	eax, 00002A27h
	call	Set_HcPeriodicStart

;R04	mov	eax, 0C000007FH			;Clear status bit
;R04	call	Set_HcInterruptStatus

	mov	eax, 0C000007FH			;Disable all USB int.
	call	Set_HcInterruptDisable

;R04	call	Get_HcRhDescriptorA
;R04	or	eax, PSM			;Per-port power switching
;R04	call	Set_HcRhDescriptorA
;R42 - start
ifdef	IOTRAP_SUPPORT
	xor	eax, eax
	in	al, 64h				;current kc status port
	call	Set_HceStatus
	in	al, 60h				;current kc output port
	call	Set_HceOutput
	mov	eax, (A20STATE+EXTIRQEN+IRQEN+EMEN)
	call	Set_HceControl
endif	;IOTRAP_SUPPORT
;R42 - end

	ret

;[]========================================================================[]
;Procedure:	Global_Reset
;Function:	Global host controller reset
;Input:		none
;Output:	none
;[]========================================================================[]

Global_Reset:
	call	Get_HcCommandStatus
	or	al, HCR
	call	Set_HcCommandStatus
@@:
	call	Get_HcCommandStatus
	test	al, HCR
	jnz	short @b
	call	Get_HcControl			;R06
	and	eax, not HCFS			;R06
	call	Set_HcControl			;R06
	call	Delay_12ms			;R06
	ret

;[]========================================================================[]
;Procedure:	Get_HostMemBase
;Function:	Get host controller memory base address
;		also call Ct_USB_ID and set wHostID
;Input:		none
;Output:	EAX = linear address
;[]========================================================================[]

Get_HostMemBase:
	call	Ct_USB_ID
	mov	wHostID, ax

	mov	cx, ax
	mov	cl, 13h
	F000_call	Get_PCI
	mov	bl, al
	shl	ebx, 8
	dec	cl
	F000_call	Get_PCI
	mov	bl, al
	shl	ebx, 8
	dec	cl
	F000_call	Get_PCI
	mov	bl, al
	shl	ebx, 8
	dec	cl
	F000_call	Get_PCI
	mov	bl, al
	and	bl, 0F0h
	mov	eax, ebx

	ret

;R29	assume	ds:nothing
;R29
;R29ENDIF	;COMPILE_FOR_USBBIOS EQ 2
;R29
;R29IF	COMPILE_FOR_USBBIOS EQ 3
;R29
;R29;****************************************************************
;R29;*								*
;R29;*	COMPILING STAGE 3					*
;R29;*								*
;R29;*	RUN-TIME EXECUTION CODES RESIDENT AT SMI RAM		*
;R29;*								*
;R29;****************************************************************
;R29
;R29	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					;R05
	push	ds				;R05
	push	es				;R05
	mov	dx, 0CF8h			;R35
	in	eax, dx				;R35
	push	eax				;R35
	call	Check_USB_Disabled
	jnz	usb_smi_exit

	call	Get_USBRAM
	mov	ds, ax
	xor	ax, ax
	mov	es, ax
;R42 - start
ifdef	USB_MOUSE_SUPPORT
	mov	al, ds:bUsbFlag
	test	al, REMOVEDEV			;stage to remove unsupported device
	jz	short Not_Remove_Task
	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
Not_Remove_Task:
endif	;USB_MOUSE_SUPPORT
;R42 - end
;R33	test	byte ptr ds:bUsbFlag, 02
	test	byte ptr ds:bUsbFlag, OWNERCHG	;R33;ownership changed?
;R29	jnz	usb_smi_exit
;R29 - start
	jz	short Usb_Bios_Active

	call	Ct_USB_SMI_Check		;R29A
	jc	usb_smi_exit			;R29A

	call	Ct_USB_SMI_Entry		;R29A
	call	Smi_Get_HostMemBase		;R36
	mov	dword ptr ds:dHostMemBase, eax	;R36

	call	Get_HcInterruptStatus
	test	eax, OC
;R29A	jz	usb_smi_exit
;R42	jz	short Toggle_SMI_Exit		;R29A
	jz	Toggle_SMI_Exit			;R42

	push	dword ptr ds:dHostMemBase
	call	Init_USBRAM
	pop	dword ptr ds:dHostMemBase

;R42 - start
ifdef	USB_MOUSE_SUPPORT
	call	SMI_Ct_UsbMouse_Support
endif	;USB_MOUSE_SUPPORT

ifdef	IOTRAP_SUPPORT
	call	SMI_Ct_A20M_Reverse		;reverse A20M control
endif	;IOTRAP_SUPPORT
;R42 - end

	call	Host_Init
	call	System_Control_Init
	call	Resume_Tasks
	call	Host_Run
	jmp	short Usb_Smi_Cont		;R29A

Usb_Bios_Active:
;R29 - end

	call	Ct_USB_SMI_Check
;R42	jc	short Usb_Smi_Exit
	jc	Usb_Smi_Exit			;R42

Usb_Smi_Cont:					;R29A
	call	Ct_USB_SMI_Entry

;R03	call	Get_HcControl
;R03	test	ax, USBSMI
;R03	jnz	short @f
	call	Get_HcInterruptStatus		;R03
	test	eax, OC				;R03
	jz	short @f			;R03
	call	Set_HcInterruptStatus		;R16

;R33	or	byte ptr ds:bUsbFlag, 02
	or	byte ptr ds:bUsbFlag, OWNERCHG	;R33;OS own

;R42 - start
ifdef	USB_MOUSE_SUPPORT
	call	SMI_Ct_UsbMouse_NotSupport
endif	;USB_MOUSE_SUPPORT

ifdef	IOTRAP_SUPPORT
	call	SMI_Ct_A20M_Normal		;normal A20M control
endif	;IOTRAP_SUPPORT
;R42 - end

	call	Get_HcControl			;R03
	and	ax, not IR			;R03
	call	Set_HcControl			;R03
;R42 - start
ifdef	IOTRAP_SUPPORT
	call	Get_HceControl
	and	al, not (EXTIRQEN+CHARPENDING+EMEN)
	call	Set_HceControl
endif	;IOTRAP_SUPPORT
;R42 - end

;R29B	call	Ct_USB_SMI_Disable
	jmp	short Toggle_SMI_Exit
@@:
;R42 - start
ifdef	IOTRAP_SUPPORT
	call	Get_HceControl
	test	al, EMINT
	jz	short Not_UsbLegSmi
	call	UsbLegSmi
Not_UsbLegSmi:
endif	;IOTRAP_SUPPORT
;R42 - end

Int_Service_Start:

;R33	and	byte ptr bUsbFlag, not 04	;task link updated
	and	byte ptr bUsbFlag, not TASKCHG	;R33;task link updated

	mov	bx, offset Interrupt_Table SMI_OFFSET
	mov	cx, 7
	mov	dh, 01

Int_Service_Loop:

	call	Get_HcInterruptEnable
	mov	dl, al
	call	Get_HcInterruptStatus
	and	al, dl

	test	al, dh
	jz	short Int_Service_Next

	pushad
	call	word ptr cs:[bx]
	popad

	movzx	eax, dh
	call	Set_HcInterruptStatus

;R33	test	byte ptr bUsbFlag, 04		;task link updated
	test	byte ptr bUsbFlag, TASKCHG	;R33;task link updated
	jnz	short Int_Service_Start

Int_Service_Next:
	add	bx, 2
	shl	dh, 1
	loop	short Int_Service_Loop

;R42 - start
ifdef	IOTRAP_SUPPORT
	call	Get_HceControl
	test	al, EMINT
	jz	short Not_UsbLegSmi1
	call	UsbLegSmi
Not_UsbLegSmi1:
endif	;IOTRAP_SUPPORT
;R42 - end

ifndef	IOTRAP_SUPPORT				;R42
ifndef	NO_UPDATE_USBKB_LED			;R12
	call	Check_Led			;R08
endif	;NO_UPDATE_USBKB_LED			;R12
endif	;IOTRAP_SUPPORT				;R42

Toggle_SMI_Exit:

	CALL	Ct_USB_SMI_Exit
	pop	eax				;R35
	mov	dx, 0CF8h			;R35
	out	dx, eax				;R35
	pop	es				;R05
	pop	ds				;R05
	popad					;R05
	clc
	ret

Usb_Smi_Exit:
	pop	eax				;R35
	mov	dx, 0CF8h			;R35
	out	dx, eax				;R35
	pop	es				;R05
	pop	ds				;R05
	popad					;R05
	stc
	ret
Usb_Smi endp

Interrupt_Table	label	word
	dw	offset Proc_SO SMI_OFFSET	;SchedulingOverrun
	dw	offset Proc_WDH SMI_OFFSET	;WriteBackDoneHead
	dw	offset Proc_SF SMI_OFFSET	;StartofFrame
	dw	offset Proc_RD SMI_OFFSET	;ResumeDetected
	dw	offset Proc_UE SMI_OFFSET	;UnrecoverableError
	dw	offset Proc_FNO SMI_OFFSET	;FrameNumberOverflow
	dw	offset Proc_RHSC SMI_OFFSET	;RootHubStatusChange

Proc_SO:
Proc_SF:
Proc_RD:
Proc_UE:
Proc_FNO:
	ret

Proc_WDH:
	mov	eax, HccaDoneHead

Proc_WDH_Loop:
	or	eax, eax
	jz	short Proc_WDH_Exit

	call	Physical_Offset
	cmp	ax, offset ControlTD		;R27;control transfer's garbage
	je	short Proc_WDH_Exit		;R27
	mov	bx, ax

	mov	si, [bx].wTdTask
	test	byte ptr [si].bTkDevStatus, TK_WFP
	jz	short Proc_WDH_Next

;R43	test	word ptr [bx].wTdControl, CC
;R43	jnz	short Proc_WDH_Next

	pushad
	call	word ptr [si].wTkProc
	popad

Proc_WDH_Next:
	mov	ax, [bx].wTdControl
	and	ax, not EC
;R43 - start
	cmp	si, offset TimerTask
	jne	short @f
	or	ax, 0800h			;error count 2 for one shut SMI
@@:
;R43 - end
	or	ax, CC
	mov	[bx].wTdControl, ax

	mov	ax, [si].wTkDataBuffer
	call	Physical_Linear
	mov	[bx].dTdCBP, eax

	mov	eax, [bx].dTdNextTD
	push	eax

	mov	ax, offset DummyTD
	call	Physical_Linear
	mov	[bx].dTdNextTD, eax

	mov	di, [si].wTkQueueHead
	mov	si, [si].wTkTransDesp
	call	Link_TD_to_QH

	pop	eax
	jmp	short Proc_WDH_Loop

Proc_WDH_Exit:
	mov	dword ptr HccaDoneHead, 0
	ret

Proc_RHSC:
	jmp	System_Control

;R36 - start
;[]========================================================================[]
;Procedure:	Smi_Get_HostMemBase
;Function:	Get host controller memory base address
;Input:		none
;Output:	EAX = linear address
;[]========================================================================[]

Smi_Get_HostMemBase:
	mov	cx, wHostID
	mov	cl, 13h
	SMI_F0CALL	Get_PCI
	mov	bl, al
	shl	ebx, 8
	dec	cl
	SMI_F0CALL	Get_PCI
	mov	bl, al
	shl	ebx, 8
	dec	cl
	SMI_F0CALL	Get_PCI
	mov	bl, al
	shl	ebx, 8
	dec	cl
	SMI_F0CALL	Get_PCI
	mov	bl, al
	and	bl, 0F0h
	mov	eax, ebx
	ret
;R36 - end

;R37 - start
;[]========================================================================[]
;Procedure:	Usb_Check_Legacy
;Function:	Check USB legacy supporting active or not.
;Input:		none
;Output:	CF = 0 USB legacy supporting active
;		CF = 1 No USB legacy supporting active
;[]========================================================================[]

Usb_Check_Legacy	proc	near
	pushad
	push	ds
	push	es

	call	Check_USB_Disabled		;legacy support disabled?
	jnz	short Usb_Check_Legacy_Fail

	call	Get_USBRAM
	mov	ds, ax
	xor	ax, ax
	mov	es, ax
	test	byte ptr ds:bUsbFlag, OWNERCHG	;ownership change?
	jnz	short Usb_Check_Legacy_Fail
	clc
	jmp	short Usb_Check_Legacy_Exit
Usb_Check_Legacy_Fail:
	stc
Usb_Check_Legacy_Exit:
	pop	es
	pop	ds
	popad
	ret
Usb_Check_Legacy	endp
;R37 - end

;R26 - 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
	xor	ax, ax
	mov	es, ax
;R33	test	byte ptr ds:bUsbFlag, 02	;ownership change?
	test	byte ptr ds:bUsbFlag, OWNERCHG	;R33;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:
	call	Get_HcControl
	or	ax, 0000011011000000b		;remote wakeup enabled/
						; USB suspend
	call	Set_HcControl

	mov	eax, 80000008h			;MIE+RD
	call	Set_HcInterruptEnable

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
	xor	ax, ax
	mov	es, ax
;R33	test	byte ptr ds:bUsbFlag, 02	;ownership change?
	test	byte ptr ds:bUsbFlag, OWNERCHG	;R33;ownership change?
	jnz	short Usb_Resume_Exit

	call	Get_HcControl
	and	al, 00111111b			;function state
	or	al, 01000000b			;USB resume
	call	Set_HcControl
	call	Resume_Delay
	and	al, 00111111b
	or	al, 10000000b			;USB operational
	call	Set_HcControl

	xor	eax, eax
	mov	al, 08				;resume detected interrupt
	call	Set_HcInterruptStatus
	call	Set_HcInterruptDisable

; 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
;R26 - 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

;[]========================================================================[]
;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
;debug	mov	cx, 40				;bx:cx=wait period
	mov	cx, 100				;debug
						; (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

	align	4
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 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:

;R28 - start
	call	Suspend_Tasks			;suspend all tasks
						;for bus enumeration

	; Process previous pending done head

	pushad
	call	Proc_WDH
	popad
;R28 - end

	; Check port 1 status changed

Check_Port1:
	mov	dl, 1
	call	Get_HcRhPortStatusN

	test	eax, CSC			;ConnectStatusChange
	jz	short Check_Port2

	test	al, CCS				;CurrentConnectStatus
	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
	; DL = port address
	; AX = port value

Enable_RootPort1:

	call	Power_RootPort
	call	Enable_RootPort
	call	Reset_RootPort

	call	Get_CtrlBuffer
	jc	short Disable_RootPort1

;R28	call	Suspend_Tasks			;suspend all tasks
						;for bus enumeration

	; SI = point to Control Buffer

	test	ax, LSDA			;LowSpeedDeviceAttached
	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

	; BX = point to Control Buffer

	mov	bx, si
	call	Init_Device
	jnc	short @f

	call	Disable_RootPort

	jmp	short Check_Port1_Exit

@@:
	call	Init_Config

Check_Port1_Exit:

	mov	si, bx
	call	Release_CtrlBuffer

;R28	call	Resume_Tasks			;resume all tasks
						;after bus enumeration

	; Check port 2 status changed

Check_Port2:
	mov	dl, 2
	call	Get_HcRhPortStatusN

	test	eax, CSC			;ConnectStatusChange
	jz	short System_Control_Exit

	test	al, CCS				;CurrentConnectStatus
	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 System_Control_Exit

	; Port 2 connected
	; DL = port address
	; AX = port value

Enable_RootPort2:

	call	Power_RootPort
	call	Enable_RootPort
	call	Reset_RootPort

	call	Get_CtrlBuffer
	jc	short Disable_RootPort2

;R28	call	Suspend_Tasks			;suspend all tasks
						;for bus enumeration

	; SI = point to Control Buffer

	test	ax, LSDA			;LowSpeedDeviceAttached
	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

	; BX = point to Control Buffer

	mov	bx, si
	call	Init_Device
	jnc	short @f

	call	Disable_RootPort

	jmp	short Check_Port2_Exit

@@:
	call	Init_Config			;BX=point to control buffer

Check_Port2_Exit:

	mov	si, bx
	call	Release_CtrlBuffer

;R28	call	Resume_Tasks			;resume all tasks
						;after bus enumeration

System_Control_Exit:
	mov	eax, ALLSC
	mov	dl, 1
	call	Set_HcRhPortStatusN
	mov	dl, 2
	call	Set_HcRhPortStatusN
	call	Resume_Tasks			;R28;resume all tasks
						;after bus enumeration

	ret

ifndef	NO_UPDATE_USBKB_LED			;R12
ifndef	IOTRAP_SUPPORT				;R42
;R08 - start
;[]========================================================================[]
;Procedure:	Check_Led
;Function:	Check LED changed for all USB keyboards
;Input:		none
;Output:	none
;[]========================================================================[]

Check_Led:
	test	word ptr wKbdDevMap, 0FFFFh
	jz	short Check_Led_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 Check_Led_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
Check_Led_Exit:
	ret
;R08 - end
endif	;IOTRAP_SUPPORT				;R42

;[]========================================================================[]
;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

	call	Get_CtrlBuffer
	jc	short Update_Led_Exit
;R01	call	Init_CtrlBuffer

	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
;R22	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

;R22	mov	al, [di].bTkDevEndp
;R22	mov	byte ptr [si].wIndex, al
;R22 - 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
;R22 - 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
	call	Release_CtrlBuffer
Update_Led_Exit:
	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			;R12

;[]========================================================================[]
;Procedure:	Control_Transfer
;Function:	Control transfer
;Input:		BX = point to control parameter block
;Output:	CF = 0 successful
;		CF = 1 fail
;[]========================================================================[]

Control_Transfer:
	pushad

	mov	si, offset ControlQH
	call	Init_QH

	mov	di, si

	; DI = point to Endpoint Descriptor

	mov	word ptr [di].wEdMps, 8

	movzx	dx, byte ptr [bx].bDevAddr
	test	byte ptr [bx].bCtrlByte, CP_LS
	jz	short @f
	or	dx, SPEED
@@:
	movzx	ax, byte ptr [bx].bDevEndp
	shl	ax, BIT_EN
	or	dx, ax
	mov	[di].wEdControl, dx

	mov	si, offset ControlTD
	call	Init_TD

	; SETUP stage

	mov	ax, [bx].wReqBuffer
	call	Physical_Linear
	mov	[si].dTdCBP, eax
	add	eax, 7
	mov	[si].dTdBE, eax

	call	Delay_1ms			;wait device stable
	call	Delay_1ms			;debug

	call	Link_ControlED

	call	Wait_Ack
	jc	Control_Transfer_Fail

	; DATA stage

	cmp	word ptr [bx].wTotalSize, 0
	je	short Status_Stage

	mov	ax, word ptr [bx].wMaxSize
	mov	[di].wEdMps, ax

	xor	ax, ax
	mov	dx, [si].wTdControl
	mov	al, PID_IN
	test	byte ptr [bx].bCtrlByte, CP_RD
	jnz	short @f
	mov	al, PID_OUT
@@:
	and	dx, NOT DP
	shl	ax, BIT_DP
	or	dx, ax
	mov	[si].wTdControl, dx

	xor	dx, dx
	mov	cx, [bx].wTotalSize

Data_Stage_Loop:
	push	edx

	mov	ax, [bx].wDataBuffer
	add	ax, dx
	call	Physical_Linear
	mov	[si].dTdCBP, eax

	mov	ax, [bx].wMaxSize
	add	ax, dx
	cmp	ax, [bx].wTotalSize
	jbe	short @f
	mov	ax, [bx].wTotalSize
@@:
	dec	ax
	add	ax, [bx].wDataBuffer
	call	Physical_Linear
	mov	[si].dTdBE, eax

	call	Delay_1ms			;wait device stable

	call	Link_ControlED

	call	Wait_Ack
	pop	edx
	jc	short Control_Transfer_Fail

	add	dx, [bx].wMaxSize
	cmp	dx, cx
	jb	short Data_Stage_Loop

	; STATUS stage

Status_Stage:
	xor	ax, ax
	mov	dx, [si].wTdControl
	mov	al, PID_IN
	cmp	word ptr [bx].wTotalSize, 0
	je	short @f
	test	byte ptr [bx].bCtrlByte, CP_RD
	jz	short @f
	mov	al, PID_OUT
@@:
	or	dx, DATOGLSB			;terminated with DATA1
	shl	ax, BIT_DP
	and	dx, NOT DP
	or	dx, ax
	mov	[si].wTdControl, dx

	mov	dword ptr [si].dTdCBP, 0	;null packet
	mov	dword ptr [si].dTdBE, 0

	call	Delay_1ms			;wait device stable

	call	Link_ControlED

	call	Wait_Ack
	jc	short Control_Transfer_Fail

	xor	eax, eax
	call	Set_HcDoneHead
	call	ControlListDisable
	popad
	clc
	ret

Control_Transfer_Fail:
	xor	eax, eax
	call	Set_HcDoneHead
	call	ControlListDisable
	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	eax
	push	cx

	mov	cx, WAIT_ACK_COUNT

Wait_Ack_Loop:

	mov	eax, [di].dEdHeadP
	and	al, 0F0h
	cmp	eax, [di].dEdTailP
	jne	short @f

	test	word ptr [si].wTdControl, CC
	jz	short Wait_Ack_Success

@@:
	call	Delay_1ms

	loop	short Wait_Ack_Loop

Wait_Ack_Fail:

	pop	cx
	pop	eax
	stc
	ret

Wait_Ack_Success:
	pop	cx
	pop	eax
	clc
	ret

;[]========================================================================[]
;Procedure:	Link_ControlED
;Function:	Link ControlED to HcControlHeadED, and link ControlTD to
;		ControlED
;Input:		SI = point to TD
;		DI = point to ED
;Output:	none
;[]========================================================================[]

Link_ControlED:
	push	eax

	call	ControlListDisable

	mov	ax, di
	call	Physical_Linear
	call	Set_HcControlHeadED
	call	Set_HcControlCurrentED

	mov	ax, si
	call	Physical_Linear
	mov	[di].dEdHeadP, eax

	mov	ax, offset DummyTD
	call	Physical_Linear
	mov	[di].dEdTailP, eax
	mov	[si].dTdNextTD, eax

	call	ControlListEnable

	pop	eax
	ret

;[]========================================================================[]
;Procedure:	Link_ED_to_CHED
;Function:	Link Endpoint Descriptor to HcControlHeadED
;Input:		SI = point to ED
;Output:	none
;[]========================================================================[]

Link_ED_to_CHED:
	push	eax

	call	ControlListDisable

	mov	ax, si
	call	Physical_Linear
	call	Set_HcControlHeadED
	call	Set_HcControlCurrentED

	call	ControlListEnable

	pop	eax
	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	cx, [si].wEdMps
	shr	cx, BIT_EDINT
	inc	cx
	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]
	cmp	di, offset FrameList
	jae	short @f
	mov	eax, [di].dEdNextED		;link pointer
@@:

	or	eax, eax
	jz	short Link_QF_Append

	call	Physical_Offset			;get offset in USB_RAM
	mov	bx, ax

	cmp	si, bx
	je	short Link_QF_Next

	mov	ax, [bx].wEdMps
	shr	ax, BIT_EDINT
	inc	ax
	cmp	cx, ax
	jae	short Link_QF_Insert

	mov	di, bx				;next queue head address
	jmp	short Link_QF_Check

Link_QF_Insert:
	mov	eax, [di]
	cmp	di, offset FrameList
	jae	short @f
	mov	eax, [di].dEdNextED
@@:
	mov	[si].dEdNextED, eax
	jmp	short Link_QF_Previous

Link_QF_Append:

Link_QF_Previous:
	mov	ax, si
	call	Physical_Linear
	cmp	di, offset FrameList
	jb	short @f
	mov	[di], eax
	jmp	short Link_QF_Next
@@:
	mov	[di].dEdNextED, eax

Link_QF_Next:
	pop	dx

	add	dx, cx				;next interval
	cmp	dx, 32				;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].dEdHeadP, 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].wEdMps			;interval
	shr	cx, BIT_EDINT
	inc	cx
	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]			;link pointer
	cmp	di, offset FrameList
	jae	short @f
	mov	eax, [di].dEdNextED		;link pointer
@@:

	or	eax, eax
	jz	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:

	mov	eax, [si].dEdNextED
	cmp	di, offset FrameList
	jb	short @f
	mov	[di], eax			;merge next task
	jmp	short Remove_QF_Next
@@:
	mov	[di].dEdNextED, eax		;merge next task

Remove_QF_Next:
	pop	dx

	add	dx, cx				;next interval
	cmp	dx, 32				;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:
	push	eax
	mov	ax, offset DummyTD
	call	Physical_Linear
	mov	[di].dEdHeadP, eax
	pop	eax
	ret

;[]========================================================================[]
;Procedure:	Init_FL
;Function:	Initialize Frame List
;Input:		none
;Output:	none
;[]========================================================================[]

Init_FL:
	pushad

	mov	si, offset DummyQH
	call	Init_QH
	or	[si].wEdControl, SKIP

	mov	ax, si
	call	Physical_Linear

	xor	esi, esi
	mov	cx, 32				;32 interrupt lists
@@:
	mov	FrameList[esi*4], eax
	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:
	pushad

	mov	cx, SIZE QH
	call	Clear_Buffer

	mov	ax, offset DummyTD
	call	Physical_Linear
	mov	[si].dEdTailP, eax
	mov	[si].dEdHeadP, eax

	popad
	ret

;[]========================================================================[]
;Procedure:	Init_TD
;Function:	Initialize Transfer Descriptor data block
;Input:		SI = point to transfer descriptor
;Output:	none
;[]========================================================================[]

Init_TD:
	pushad

	mov	cx, SIZE TD
	call	Clear_Buffer

	mov	word ptr [si].wTdControl, DEF_TDCTRL

	mov	ax, offset DummyTD
	call	Physical_Linear
	mov	[si].dTdNextTD, eax

	popad
	ret

;[]========================================================================[]
;Procedure:	Host_Stop
;Function:	Stop host controller working
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Stop:
	call	Suspend_Tasks			;R06
	ret

;[]========================================================================[]
;Procedure:	Host_Run
;Function:	Start host controller working
;Input:		none
;Output:	none
;[]========================================================================[]

Host_Run:
	ret

;[]========================================================================[]
;Procedure:	ControlListEnable
;Function:	Enable Control List
;Input:		none
;Output:	none
;[]========================================================================[]

ControlListEnable:
	call	Get_HcCommandStatus
	or	eax, CLF			;Control List Filled
	call	Set_HcCommandStatus
	call	Get_HcControl
	or	eax, CLE			;Control List Enabled
	call	Set_HcControl
	ret

;[]========================================================================[]
;Procedure:	ControlListDisable
;Function:	Disable Control List
;Input:		none
;Output:	none
;[]========================================================================[]

ControlListDisable:
	call	Get_HcControl
	and	eax, not CLE			;Control List Enabled=0
	call	Set_HcControl
	call	Get_HcCommandStatus
	and	eax, not CLF			;Control List Filled=0
	call	Set_HcCommandStatus
	ret

;[]========================================================================[]
;Procedure:	Get_Hc????
;Function:	Get host controller register value
;Input:		none
;Output:	EAX = value
;[]========================================================================[]

Get_HcControl:
	push	dx
	mov	dl, HcControl
	jmp	short @f

Get_HcCommandStatus:
	push	dx
	mov	dl, HcCommandStatus
	jmp	short @f

Get_HcInterruptStatus:
	push	dx
	mov	dl, HcInterruptStatus
	jmp	short @f

Get_HcInterruptEnable:
	push	dx
	mov	dl, HcInterruptEnable
	jmp	short @f

Get_HcInterruptDisable:
	push	dx
	mov	dl, HcInterruptDisable
	jmp	short @f

Get_HcHCCA:
	push	dx
	mov	dl, HcHCCA
	jmp	short @f

Get_HcControlHeadED:
	push	dx
	mov	dl, HcControlHeadED
	jmp	short @f

Get_HcControlCurrentED:
	push	dx
	mov	dl, HcControlCurrentED
	jmp	short @f

Get_HcDoneHead:
	push	dx
	mov	dl, HcDoneHead
	jmp	short @f

Get_HcFmInterval:
	push	dx
	mov	dl, HcFmInterval
	jmp	short @f

Get_HcPeriodicStart:
	push	dx
	mov	dl, HcPeriodicStart
	jmp	short @f

Get_HcRhDescriptorA:
	push	dx
	mov	dl, HcRhDescriptorA
	jmp	short @f

Get_HcRhStatus:
	push	dx
	mov	dl, HcRhStatus
	jmp	short @f

;R42 - start
ifdef	IOTRAP_SUPPORT
Get_HceControl:
	push	dx
	mov	dx, HceControl
	jmp	short Go_Get_Host_Dword

Get_HceInput:
	push	dx
	mov	dx, HceInput
	jmp	short Go_Get_Host_Dword

Get_HceOutput:
	push	dx
	mov	dx, HceOutput
	jmp	short Go_Get_Host_Dword

Get_HceStatus:
	push	dx
	mov	dx, HceStatus
	jmp	short Go_Get_Host_Dword
endif	;IOTRAP_SUPPORT
;R42 - end

@@:
	xor	dh, dh				;R42
Go_Get_Host_Dword:				;R42
	call	Get_Host_Dword
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Set_Hc????
;Function:	Set host controller register value
;Input:		none
;Output:	EAX = value
;[]========================================================================[]

Set_HcControl:
	push	dx
	mov	dl, HcControl
	jmp	short @f

Set_HcCommandStatus:
	push	dx
	mov	dl, HcCommandStatus
	jmp	short @f

Set_HcInterruptStatus:
	push	dx
	mov	dl, HcInterruptStatus
	jmp	short @f

Set_HcInterruptEnable:
	push	dx
	mov	dl, HcInterruptEnable
	jmp	short @f

Set_HcInterruptDisable:
	push	dx
	mov	dl, HcInterruptDisable
	jmp	short @f

Set_HcHCCA:
	push	dx
	mov	dl, HcHCCA
	jmp	short @f

Set_HcControlHeadED:
	push	dx
	mov	dl, HcControlHeadED
	jmp	short @f

Set_HcControlCurrentED:
	push	dx
	mov	dl, HcControlCurrentED
	jmp	short @f

Set_HcDoneHead:
	push	dx
	mov	dl, HcDoneHead
	jmp	short @f

Set_HcFmInterval:
	push	dx
	mov	dl, HcFmInterval
	jmp	short @f

Set_HcPeriodicStart:
	push	dx
	mov	dl, HcPeriodicStart
	jmp	short @f

Set_HcRhDescriptorA:
	push	dx
	mov	dl, HcRhDescriptorA
	jmp	short @f

Set_HcRhDescriptorB:				;R04
	push	dx				;R04
	mov	dl, HcRhDescriptorB		;R04
	jmp	short @f			;R04

Set_HcRhStatus:
	push	dx
	mov	dl, HcRhStatus
	jmp	short @f

;R42 - start
ifdef	IOTRAP_SUPPORT
Set_HceControl:
	push	dx
	mov	dx, HceControl
	jmp	short Go_Set_Host_Dword

Set_HceInput:
	push	dx
	mov	dx, HceInput
	jmp	short Go_Set_Host_Dword

Set_HceOutput:
	push	dx
	mov	dx, HceOutput
	jmp	short Go_Set_Host_Dword

Set_HceStatus:
	push	dx
	mov	dx, HceStatus
	jmp	short Go_Set_Host_Dword
endif	;IOTRAP_SUPPORT
;R42 - end

@@:
	xor	dh, dh				;R42
Go_Set_Host_Dword:				;R42
	call	Set_Host_Dword
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Get_HcRhPortStatusN
;Function:	Get root port status
;Input:		DL = Port number to get
;Output:	EAX = port status
;[]========================================================================[]

Get_HcRhPortStatusN:
	push	dx
	mov	al, 4
	dec	dl
	mul	dl
;R42	mov	dl, al
	mov	dx, ax				;R42
	add	dl, HcRhPortStatusN
	call	Get_Host_Dword
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Set_HcRhPortStatusN
;Function:	Set root port status
;Input:		DL = Port number to set
;		EAX = value to set
;Output:	none
;[]========================================================================[]

Set_HcRhPortStatusN:
	push	dx
	push	ax
	mov	al, 4
	dec	dl
	mul	dl
;R42	mov	dl, al
	mov	dx, ax				;R42
	add	dl, HcRhPortStatusN
	pop	ax
	call	Set_Host_Dword
	pop	dx
	ret

;[]========================================================================[]
;Procedure:	Power_RootPort
;Function:	Set power to root port
;Input:		DL = Port number to set power
;Output:	none
;[]========================================================================[]

Power_RootPort:
	push	eax
	mov	eax, SPP
	call	Set_HcRhPortStatusN
	mov	eax, ALLSC
	call	Set_HcRhPortStatusN
	pop	eax
	ret

;[]========================================================================[]
;Procedure:	Reset_RootPort
;Function:	Reset root port
;Input:		DX = Port address to reset
;Output:	none
;[]========================================================================[]

Reset_RootPort:
	push	eax
	mov	eax, SPR
	call	Set_HcRhPortStatusN
@@:
	call	Get_HcRhPortStatusN
	test	eax, PRS
	jnz	short @b
	mov	eax, ALLSC
	call	Set_HcRhPortStatusN
	pop	eax
	ret

;[]========================================================================[]
;Procedure:	Enable_RootPort
;Function:	Enable root port
;Input:		DX = Port address to enable
;Output:	none
;[]========================================================================[]

Enable_RootPort:
	push	eax
	mov	eax, SPE
	call	Set_HcRhPortStatusN
	mov	eax, ALLSC
	call	Set_HcRhPortStatusN
	pop	eax
	ret

;[]========================================================================[]
;Procedure:	Disable_RootPort
;Function:	Disable root port
;Input:		DX = Port address to disable
;Output:	none
;[]========================================================================[]

Disable_RootPort:
	push	eax
	mov	eax, CPE
	call	Set_HcRhPortStatusN
	mov	eax, ALLSC
	call	Set_HcRhPortStatusN
	pop	eax
	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	ebx
;R42	movzx	ebx, dl
	movzx	ebx, dx				;R42
	add	ebx, dHostMemBase
	mov	eax, es:[ebx]
	pop	ebx
	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	ebx
;R42	movzx	ebx, dl
	movzx	ebx, dx				;R42
	add	ebx, dHostMemBase
	mov	es:[ebx], eax
	pop	ebx
	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

;R42 - start
	; Check BIOS supported device for this configuration

	call	Check_BIOS_Device
	jc	short Init_Config_Next
;R42 - end
;R42	push	cx
;R42
;R42	mov	cx, BIOS_Device_Num
;R42	mov	dx, offset Init_Proc SMI_OFFSET
;R42	mov	di, offset BIOS_Device SMI_OFFSET
;R42	mov	si, offset CfgDespBuffer.StdIDsp	;interface descriptor
;R42
;R42Init_BIOS_Device_Loop:
;R42
;R42	mov	al, cs:[di]
;R42	cmp	al, [si].IDbClass
;R42	jne	short Next_BIOS_Device
;R42	mov	al, cs:[di+1]
;R42	cmp	al, 0FFh
;R42	je	short BIOS_Device_Found
;R42	cmp	al, [si].IDbSubClass
;R42	jne	short Next_BIOS_Device
;R42	mov	al, cs:[di+2]
;R42	cmp	al, 0FFh
;R42	je	short BIOS_Device_Found
;R42	cmp	al, [si].IDbProtocol
;R42	jne	short Next_BIOS_Device
;R42
;R42BIOS_Device_Found:
;R42
;R42	pop	cx
;R42
;R42	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

;R42 - 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
;R42 - end
;R42	; Call corresponding procedure to initialize BIOS devices
;R42
;R42	pushad
;R42	call	word ptr cs:[di]
;R42	popad
;R42	jmp	short Init_Config_Exit
;R42
;R42Next_BIOS_Device:
;R42	add	di, 3
;R42	add	dx, 2
;R42	loop	short Init_BIOS_Device_Loop
;R42
;R42	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
	db	09, 0FFh, 0FFh			;Hub
	db	03, 01, 01			;Keyboard
ifdef	USB_MOUSE_SUPPORT			;R42
	db	03, 01, 02			;R42;mouse
endif	;USB_MOUSE_SUPPORT			;R42
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			;R42
	dw	offset Init_Mouse SMI_OFFSET	;R42
endif	;USB_MOUSE_SUPPORT			;R42

;R42 - 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
;R42 - 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
;Note:		Interval value have to be valid.
;[]========================================================================[]

Link_Task:
	pusha

;R33	or	byte ptr bUsbFlag, 04		;task link updated
	or	byte ptr bUsbFlag, TASKCHG	;R33;task link updated

	; Link Task to Task Chain

	mov	cx, [si].wTkInterval		;interval

	mov	di, offset wTaskLink		;task link point

Link_TK_Loop:
	cmp	word ptr [di].wTkLink, 0FFFFh
	je	short Link_TK_Append

	mov	bx, [di].wTkLink

	cmp	cx, [bx].wTkInterval
	jb	short Link_TK_Insert

	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 Queue Head to Frame List

	mov	si, [si].wTkQueueHead
	call	Link_QH_to_FL

;R43 - start
	test	word ptr wKbdDevMap, 0FFFFh	;any USB keyboard present?
	jz	short Link_TK_Exit

	test	bUsbFlag, TIMERINST		;timer task installed?
	jnz	short Link_TK_Exit

	or	bUsbFlag, TIMERINST		;timer task installed
	call	Init_TimerTD
;R43 - end

Link_TK_Exit:
	popa
	ret

;[]========================================================================[]
;Procedure:	Remove_Task
;Function:	Remove one task from the Task Link
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Remove_Task:
	pusha

;R33	or	byte ptr bUsbFlag, 04		;task link updated
	or	byte ptr bUsbFlag, TASKCHG	;R33;task link updated

	; 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				;R43
	mov	ax, [si].wTkLink
	mov	[di].wTkLink, ax

	call	Do_Remove_Task
	pop	ax				;R43
	jmp	short Remove_DTK_Loop		;R43

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					;R43

	; 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

Do_Remove_Exit:

;R43 - start
	test	word ptr wKbdDevMap, 0FFFFh	;any USB keyboard present?
	jnz	short @f

	test	bUsbFlag, TIMERINST		;timer task installed?
	jz	short @f

	and	bUsbFlag, NOT TIMERINST		;no timer task installed
	mov	si, offset TimerQH
	or	[si].wEdControl, SKIP		;skip timer task
@@:
;R43 - end

	popad					;R43
	ret

;[]========================================================================[]
;Procedure:	Init_Task
;Function:	Initialize task data block
;Input:		SI = point to task
;Output:	none
;[]========================================================================[]

Init_Task:
	pusha
	mov	cx, SIZE TASK
	call	Clear_Buffer
	popa
	ret

;[]========================================================================[]
;Procedure:	Suspend_Tasks
;Function:	Suspend all tasks for Control Transfer
;Input:		none
;Output:	none
;[]========================================================================[]

Suspend_Tasks:
	push	eax
	call	Get_HcControl
	and	eax, not PLE
	call	Set_HcControl
	mov	eax, WDH
	call	Set_HcInterruptDisable
	pop	eax
	ret

;[]========================================================================[]
;Procedure:	Resume_Tasks
;Function:	Resume all tasks after Control Transfer
;Input:		none
;Output:	none
;[]========================================================================[]

Resume_Tasks:
	cmp	word ptr wTaskLink, 0FFFFh
	je	short @f
	push	eax
	call	Get_HcControl
	or	eax, PLE
	call	Set_HcControl
	mov	eax, WDH
	call	Set_HcInterruptEnable
	pop	eax
@@:
	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, 5				;maximum interval=32
@@:
	cmp	bx, ax
	jbe	short @f
	mov	dx, 2
	mul	dx
	loop	short @b
@@:
	dec	ax				;for record
	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
	mov	cx, SIZE DEVREQ
	call	Clear_Buffer
	popa
	ret

;[]========================================================================[]
;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			;R01

	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

;[]========================================================================[]
;Procedure:	Init_CtrlBuffer
;Function:	Initialize control parameter block
;Input:		SI = point to control parameter block
;Output:	none
;[]========================================================================[]

Init_CtrlBuffer:
	pusha
	mov	cx, SIZE CTLPARA
	call	Clear_Buffer
	popa
	ret

;[]========================================================================[]
;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

;R19 - start
;[]========================================================================[]
;Procedure:	Find_EndpDesp
;Function:	Find endpoint descriptor
;R42;Input:		DI = point to configuration descriptor
;Input:		DI = point to interface descriptor			;R42
;Output:	CF = 0 descriptor found
;			DI = point to endpoint descriptor
;		CF = 1 descriptor not found
;[]========================================================================[]

Find_EndpDesp:
;R42 - 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
;R42 - end
;R42	push	ax
;R42	push	cx
;R42	mov	cx, [di].CDwTotalLen
;R42Find_EndpDesp_Loop:
;R42	cmp	byte ptr [di+1], 05		;descriptor type byte
;R42	jne	short Find_EndpDesp_Next
;R42	pop	cx
;R42	pop	ax
;R42	clc
;R42	ret
;R42Find_EndpDesp_Next:
;R42	movzx	ax, byte ptr [di+0]		;descriptor length
;R42	add	di, ax				;next descriptor
;R42	sub	cx, ax
;R42	jnb	short Find_EndpDesp_Loop
;R42	pop	cx
;R42	pop	ax
;R42	stc
;R42	ret
;R19 - 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	;R20
	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
	movzx	cx, byte ptr ClassDespBuffer.UDbNumPort

	push	cx				;number of down stream ports
	push	dx				;hub index number
	xor	ax, ax
	xor	dl, dl
	mov	dh, 02

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				;hub index number
	push	dx				;connection status of hub ports
	mov	dx, ax				;hub index nubmer

	; 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
	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				;task control pointer
	mov	al, 8
	movzx	cx, al
	mul	dl
	add	ax, offset HubDataBuffer
	mov	si, ax
	call	Clear_Buffer
	pop	si				;task control pointer
	mov	[si].wTkDataBuffer, ax

	push	si				;task control pointer
	mov	al, SIZE HUBCTRL
	movzx	cx, al
	mul	dl
	add	ax, offset HubCtrlBuffer
	mov	si, ax
	call	Clear_Buffer
	mov	cl, ClassDespBuffer.UDbNumPort
	mov	[si].bHcNumPort, cl
	pop	si
	mov	[si].wTkCtrlBuffer, ax		;task control pointer

	push	si				;task control pointer
	mov	al, 16
	mul	dl
	add	ax, offset HubIntQH
	mov	si, ax
	call	Init_QH
	pop	si				;task control pointer
	mov	[si].wTkQueueHead, ax
	mov	di, ax				;QueueHead pointer

	movzx	cx, byte ptr [si].bTkDevAddr
	movzx	ax, byte ptr [si].bTkDevEndp
	shl	ax, BIT_EN
	or	cx, ax
	mov	[di].wEdControl, cx

	mov	ax, [si].wTkPacketSize
	mov	cx, [si].wTkInterval
	shl	cx, BIT_EDINT
	or	ax, cx
	mov	[di].wEdMps, ax

	push	si				;task control pointer
	mov	al, SIZE TD
	mul	dl
	add	ax, offset HubIntTD
	mov	si, ax
	call	Init_TD
	pop	si				;task control pointer

	mov	[si].wTkTransDesp, ax
	mov	di, ax				;TransDescriptor pointer

	mov	[di].wTdTask, si

	mov	[di].wTdControl, 0F214H		;Buffer rounding=1
						;PID = 10b (PID_IN)
						;zero delay interrupt
						;use TD's data toggle
						;Error Count=0
						;Condition Code=NOTACCESSED

	mov	ax, [si].wTkDataBuffer
	call	Physical_Linear
	mov	[di].dTdCBP, eax
	mov	ax, [si].wTkDataBuffer
	add	ax, [si].wTkPacketSize
	dec	ax
	call	Physical_Linear
	mov	[di].dTdBE, eax

	push	si
	mov	di, [si].wTkQueueHead
	mov	si, [si].wTkTransDesp
	call	Link_TD_to_QH
	pop	si

	call	Link_Task

	pop	ax				;connection status of hub port
	pop	cx				;number of down stream ports

	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
;		BX = point to TD		;R43
;Output:	none
;[]========================================================================[]

Proc_Hub:
	test	word ptr [bx].wTdControl, CC	;R43;condition code
	jnz	short Proc_Hub_End		;R43

	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:
	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

	call	Get_CtrlBuffer
	jc	Check_HubPort_End
;R01	call	Init_CtrlBuffer

	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

	mov	word ptr [bx].wTotalSize, 0

	call	Control_Transfer
;R18	jc	Check_HubPort_Exit

;R18 - start
	mov	byte ptr [si].wValue, C_PORT_ENABLE
	call	Control_Transfer
;R18 - end

	mov	al, [di].bTkDevAddr		;device address
						;AH = port number
	call	Release_ChildDev
	jmp	Check_HubPort_Exit

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
	jc	Check_HubPort_Exit

	; 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
	mov	byte ptr [si].bRequest, CLEAR_FEATURE
	mov	byte ptr [si].wValue, C_PORT_ENABLE
	mov	byte ptr [si].wLength, 0
	call	Control_Transfer
	jc	short Check_HubPort_Exit

	; Enumerate device attached

	call	Get_CtrlBuffer
	jc	Disable_HubPort
;R01	call	Init_CtrlBuffer

	push	bx

	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
	call	Release_CtrlBuffer
	pop	bx

	jmp	Disable_HubPort

@@:
	call	Init_Config			;BX=point to control buffer

	mov	si, bx
	call	Release_CtrlBuffer
	pop	bx

Check_HubPort_Exit:
	mov	si, bx
	call	Release_CtrlBuffer
Check_HubPort_End:
	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		;R42;USB kb supported?
	jz	Init_Kbd_Exit			;R42

	; Query/record available keyboard index number

	call	Query_Kbd_Index
	jc	Init_Kbd_Exit

	call	Record_Kbd_Index

;R22	mov	dl, al				;keyboard index number

;R19 - start
;R42	mov	di, offset CfgDespBuffer
	mov	di, wIntDspPoint		;R42;interface descriptor point
	call	Find_EndpDesp
;R19 - end

	call	Init_Keyboard_Task		;R22

;R39 - 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
;R39 - end

	; Set idle rate
	; Idle rate value is zero, that is the USB kb just respond	;R43
	; while key pressing.						;R43

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
;R22	mov	byte ptr [si].bmRequestType, 00100010b
	mov	byte ptr [si].bRequest, SET_IDLE
;R10	mov	word ptr [si].wValue, 0201h
;R43	mov	word ptr [si].wValue, 0400h		;R10
;R19	mov	al, CfgDespBuffer.HidEDsp.EDbEndpAddr
;R22	mov	al, [di].EDbEndpAddr			;R19
;R22	and	al, 07Fh				;mask direction bit
;R22 - 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
@@:
;R22 - end
	mov	byte ptr [si].wIndex, al

	mov	word ptr [bx].wReqBuffer, si
	mov	word ptr [bx].wTotalSize, 0

	call	Control_Transfer
;R02	jc	Init_Kbd_Exit
;R11 - start
	; Get report descriptor

	mov	si, offset RequestBuffer
	call	Init_ReqBuffer
;R42	mov	byte ptr [si].bmRequestType, 10000010b
	mov	byte ptr [si].bRequest, GET_DESCRIPTOR
	mov	byte ptr [si+1].wValue, 22h		;report descriptor
;R19	mov	al, CfgDespBuffer.HidEDsp.EDbEndpAddr
;R22	mov	al, [di].EDbEndpAddr			;R19
;R22	and	al, 07Fh				;mask direction bit
;R42	mov	al, [di].bTkDevEndp			;R22
;R42	mov	byte ptr [si].wIndex, al
	mov	word ptr [si].wLength, 003Fh		;descriptor length
;R42 - 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
;R42 - 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
;R11 - end

;R22	; Configure Keyboard interrupt transaction task
;R22	; DL = keyboard index number
;R22
;R22	mov	al, SIZE TASK
;R22	mul	dl
;R22	add	ax, offset KbdIntTask
;R22	mov	si, ax
;R22	call	Init_Task
;R22
;R22	mov	al, TK_WFP+TK_KBD
;R22	test	byte ptr [bx].bCtrlByte, CP_LS
;R22	jz	short @f
;R22	or	al, TK_LS
;R22@@:
;R22	mov	[si].bTkDevStatus, al
;R22
;R22	mov	byte ptr [si].bTkDevIndex, dl
;R22
;R22	mov	word ptr [si].wTkProc, offset Proc_Keyboard SMI_OFFSET
;R22
;R22	mov	al, [bx].bDevAddr
;R22	mov	[si].bTkDevAddr, al
;R22
;R22	mov	al, [bx].bParentAddr
;R22	mov	[si].bTkParentAddr, al
;R22
;R22	mov	al, [bx].bParentPort
;R22	mov	[si].bTkParentPort, al
;R22
;R22;R19	mov	di, offset CfgDespBuffer.HidEDsp
;R22
;R22	movzx	ax, byte ptr [di].EDbInterval
;R22	call	Validate_Interval
;R22	mov	[si].wTkInterval, ax
;R22
;R22	mov	ax, [di].EDwMaxPackSize
;R22	mov	[si].wTkPacketSize, ax
;R22
;R22	mov	al, byte ptr [di].EDbEndpAddr
;R22	and	al, 7Fh				;mask direction bit
;R22	mov	[si].bTkDevEndp, al
;R22
;R22	push	si				;task control pointer
;R22	mov	al, 8
;R22	movzx	cx, al
;R22	mul	dl
;R22	add	ax, offset KbdDataBuffer
;R22	mov	si, ax
;R22	call	Clear_Buffer
;R22	pop	si				;task control pointer
;R22	mov	[si].wTkDataBuffer, ax
;R22
;R22	push	si				;task control pointer
;R22	mov	al, SIZE KBDCTRL
;R22	movzx	cx, al
;R22	mul	dl
;R22	add	ax, offset KbdCtrlBuffer
;R22	mov	si, ax
;R22	call	Clear_Buffer
;R22	mov	byte ptr [si].bDelayRate,  12
;R22	mov	byte ptr [si].bRepeatRate, 4
;R22	pop	si				;task control pointer
;R22	mov	[si].wTkCtrlBuffer, ax
;R22
;R22	push	si				;task control pointer
;R22	mov	al, 16
;R22	mul	dl
;R22	add	ax, offset KbdIntQH
;R22	mov	si, ax
;R22	call	Init_QH
;R22	pop	si				;task control pointer
;R22	mov	[si].wTkQueueHead, ax
;R22
;R22	mov	di, ax				;QueueHead pointer
	mov	si, di				;R22;task control pointer
	mov	di, [si].wTkQueueHead		;R22;QueueHead pointer

	movzx	cx, byte ptr [si].bTkDevAddr
	test	byte ptr [bx].bCtrlByte, CP_LS
	jz	short @f
	or	cx, SPEED
@@:
	movzx	ax, byte ptr [si].bTkDevEndp
	shl	ax, BIT_EN
	or	cx, ax
	mov	[di].wEdControl, cx

	mov	ax, [si].wTkPacketSize
	mov	cx, [si].wTkInterval
	shl	cx, BIT_EDINT
	or	ax, cx
	mov	[di].wEdMps, ax

;R22	push	si				;task control pointer
;R22	mov	al, SIZE TD
;R22	mul	dl
;R22	add	ax, offset KbdIntTD
;R22	mov	si, ax
;R22	call	Init_TD
;R22	pop	si				;task control pointer
;R22
;R22	mov	[si].wTkTransDesp, ax
;R22	mov	di, ax				;TransDescriptor pointer
	mov	di, [si].wTkTransDesp		;R22;TransDescriptor pointer

	mov	[di].wTdTask, si

	mov	[di].wTdControl, 0F214H		;Buffer rounding=1
						;PID = 10b (PID_IN)
						;zero delay interrupt
						;use TD's data toggle
						;Error Count=0
						;Condition Code=NOTACCESSED

	mov	ax, [si].wTkDataBuffer
	call	Physical_Linear
	mov	[di].dTdCBP, eax
	mov	ax, [si].wTkDataBuffer
	add	ax, [si].wTkPacketSize
	dec	ax
	call	Physical_Linear
	mov	[di].dTdBE, eax

	push	si				;task control pointer
	mov	di, [si].wTkQueueHead
	mov	si, [si].wTkTransDesp
	call	Link_TD_to_QH
	pop	si				;task control pointer

	call	Link_Task

ifndef	NO_UPDATE_USBKB_LED			;R12
	push	ds
	mov	ax, 0040h
	mov	ds, ax
	mov	al, byte ptr ds:[0017h]		;BIOS key status flag
	pop	ds
	mov	bLedStatus, al

	call	Update_Led			;update all keyboards' LED
endif	;NO_UPDATE_USBKB_LED			;R12

Init_Kbd_Exit:
	ret

;R22 - 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		;R42
;Output:	DI = point to task
;[]========================================================================[]

Init_Keyboard_Task:

	mov	dl, al

	; DL = keyboard index number			;R42

	mov	al, SIZE TASK
	mul	dl
	add	ax, offset KbdIntTask
	mov	si, ax
	call	Init_Task

	; SI = task buffer pointer			;R42

	mov	al, TK_WFP+TK_KBD
;R42 - start
	mov	cx, di
	sub	cx, wIntDspPoint
	cmp	cx, 9				;Old kb: Interface-Endpoint-HID
						;length: 9	   7	    9
	je	short @f
;R42 - end
;R42	cmp	di, offset CfgDespBuffer.HidEDsp
;R42	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

;R42	mov	al, CfgDespBuffer.StdIDsp.IDbAltSet
;R42 - start
	push	di
	mov	di, wIntDspPoint
	mov	al, [di].IDbIntNum
	pop	di
;R42 - 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
;R32	mov	byte ptr [si].bDelayRate,  12
;R32	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
;R22 - end

;[]========================================================================[]
;Procedure:	Proc_Keyboard
;Function:	Keyboard interrupt transaction process routine
;Input:		SI = point to task
;		BX = point to TD		;R43
;Output:	none
;[]========================================================================[]

Proc_Keyboard:

;R43ifndef	IOTRAP_SUPPORT				;R42
;R43	mov	bx, [si].wTkCtrlBuffer
;R43
;R43	cmp	byte ptr [bx].bKeyLength, 0
;R43	je	short Check_Kbd_Data
;R43
;R43	push	si
;R43	push	es
;R43	push	ds
;R43	pop	es
;R43
;R43	mov	si, bx
;R43	call	Proc_Key_Buffer
;R43
;R43	pop	es
;R43	pop	si
;R43
;R43	jmp	short Proc_Kbd_End
;R43
;R43Check_Kbd_Data:
;R43endif	;IOTRAP_SUPPORT				;R42
;R43
;R43	push	si
;R43	push	es
;R43	push	ds
;R43	pop	es

;R43 - start
	push	si
	push	es
	push	ds
	pop	es

	test	word ptr [bx].wTdControl, CC	;condition code
	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:
;R43 - end

	mov	di, [si].wTkDataBuffer
	mov	si, [si].wTkCtrlBuffer
	call	Proc_Kbd_Data

;R42 - start
;R43ifdef	IOTRAP_SUPPORT
;R43	cmp	byte ptr [si].bKeyLength, 0
;R43	je	short No_Key_In
;R43	pop	es
;R43	call	Proc_Key_Buffer
;R43	call	Proc_CharPending
;R43	pop	si
;R43	ret
;R43No_Key_In:
;R43endif	;IOTRAP_SUPPORT
;R42 - end

Proc_Kbd_End:					;R43
	pop	es
	pop	si

;R43Proc_Kbd_End:

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	Clear_Current_Buffer		;clear current key map

	call	Check_RollOver
;R43	jz	Roll_Over_Exit
	jz	short Proc_Kbd_Data_Exit	;R43

	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?
;R43	jz	short Proc_KeyCode		;skip if empty
	jz	short Proc_Kbd_Data_Exit	;R43

	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

;R43 - start
Proc_Kbd_Data_Exit:
	ret

;[]========================================================================[]
;Input:		SI = point to control buffer
;[]========================================================================[]
;R43 - 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
@@:
;R42 - start
ifdef	IOTRAP_SUPPORT
	mov	al, bLedStatus
	and	al, 70h				;LED status
	and	byte ptr [si].bBiosFlag, 8Fh
	or	byte ptr [si].bBiosFlag, al
else	;IOTRAP_SUPPORT
;R42 - end
	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				;R42

	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

;R32	mov	al, [si].bDelayRate		;typematic delay rate
	mov	al, bDelayRate			;R32;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

;R32	mov	al, [si].bRepeatRate		;typematic repeat rate
	mov	al, bRepeatRate			;R32;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
;R09 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;R09
 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
;R09 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;R09
 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;R21

;[]========================================================================[]
; 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;R21

;[]========================================================================[]
;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:
;R42 - start
ifdef	IOTRAP_SUPPORT
	push	bx
	push	di

	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
	test	byte ptr bDevCtrl, KBDISABLE	;keyboard disabled
	jnz	short Proc_Key_Buffer_Exit

	movzx	bx, byte ptr [si].bKeyPoint
	lea	di, [si].KeyBuffer
	mov	al, [bx+di]

	movzx	bx, byte ptr bKbDataLength
	cmp	bl, 16
	jae	short Proc_Key_Buffer_Exit

	inc	byte ptr bKbDataLength
	movzx	bx, byte ptr bKbDataPoint
	add	bx, offset KbDataBuffer
	mov	[bx], al

	inc	byte ptr [si].bKeyPoint
	and	byte ptr [si].bKeyPoint, 0Fh
	dec	byte ptr [si].bKeyLength

Proc_Key_Buffer_Exit:
	pop	di
	pop	bx
	ret
else	;IOTRAP_SUPPORT
;R42 - end
	push	bx
	push	di

	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 			;R07;read ISR
	out	0A0h, al			;R07
	NEWIODELAY				;R07
	in	al, 0A0h			;R07
	test	al, 10h				;R07;IRQ12 in service
	jnz	short Proc_Key_Buffer_Exit	;R07

	movzx	bx, byte ptr [si].bKeyPoint
	lea	di, [si].KeyBuffer
	mov	al, [bx+di]
	call	Send_KeyCode
	jc	short Proc_Key_Buffer_Exit

;R13A	cmp	byte ptr [si].bKeyLength, 17
;R13A	jne	short @f
;R13A	movzx	bx, byte ptr [si].bKeyPoint
;R13A	lea	di, [si].KeyBuffer
;R13A;R13	mov	byte ptr [bx+di], 0		;roll over key
;R13A	mov	byte ptr [bx+di], 0FFh		;R13;roll over key
;R13A@@:
	inc	byte ptr [si].bKeyPoint
	and	byte ptr [si].bKeyPoint, 0Fh
	dec	byte ptr [si].bKeyLength

Proc_Key_Buffer_Exit:
	pop	di
	pop	bx
	ret
endif	;IOTRAP_SUPPORT				;R42

;[]========================================================================[]
;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		;R13A
;R13A	ja	short Store_Code_Exit
;R13A	jb	short @f
;R13A	inc	byte ptr [si].bKeyLength	;length=17:roll over
;R13A	jmp	short Store_Code_Exit
;R13A@@:
	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
	mov	cx, 8
	repe	scasb
	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				;R21
	jae	short @f			;R21
	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
@@:						;R21
	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

ifndef	IOTRAP_SUPPORT				;R42
;[]========================================================================[]
;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
	in	al, 64h
	test	al, 03				;IBF/OBF
	jz	short @f
kc_write_fail:
	pop	ax
	stc
	jmp	short kc_write_exit
@@:
ifdef	PATCH_SIS5571_KC
	call	Clear_Break_Flag
	jc	short kc_write_fail
endif	;PATCH_SIS5571_KC
	mov	al, 0D2h			;write output buffer command
	out	64h, al
	NEWIODELAY
	xor	cx, cx
@@:
	in	al, 64h
	NEWIODELAY
	test	al, 01				;R07
	jnz	short kc_write_fail		;R07
	test	al, 02				;IBF
	jz	short @f
	loop	short @b
	jmp	short kc_write_fail
@@:
	pop	ax
	out	60h, al
	clc
kc_write_exit:
	pop	cx
	ret

ifdef	PATCH_SIS5571_KC
Clear_Break_Flag:
	push	ds
	mov	ax, 0F000h
	mov	ds, ax
	assume	ds:DGROUP
	test	byte ptr ds:USB_STATUS, 02
	pop	ds
	assume	ds:USB_RAM
	jnz	short Clear_BFlag_Exit

	mov	al, 0EEh
	out	60h, al

	call	Wait_IBF_Clear
	jnz	short Clear_BFlag_Fail
	call	Wait_OBF_Set
	jz	short Clear_BFlag_Fail

	in	al, 60h

Clear_BFlag_Exit:
	clc
	ret

Clear_BFlag_Fail:
	stc
	ret

Wait_IBF_Clear:
	push	cx
	push	ax
	mov	cx, 180				;maybe reduce
@@:
	in	al, 64h
	test	al, 02				;IBF
	jz	short @f
	call	Delay_1ms
	loop	short @b
	or	al, 0FFh			;ZF=0
@@:
	pop	ax
	pop	cx
	ret

Wait_OBF_Set:
	push	cx
	push	ax
	mov	cx, 180				;maybe reduce
@@:
	in	al, 64h
	test	al, 01				;OBF
	jnz	short @f
	call	Delay_1ms
	loop	short @b
	xor	al, al				;ZF=1
@@:
	pop	ax
	pop	cx
	ret
	ret

endif	;PATCH_SIS5571_KC
endif	;IOTRAP_SUPPORT				;R42

;R42 - 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

	; 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

	; 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

	; 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].wTkQueueHead		;QueueHead pointer

	movzx	cx, byte ptr [si].bTkDevAddr
	test	byte ptr [bx].bCtrlByte, CP_LS
	jz	short @f
	or	cx, SPEED
@@:
	movzx	ax, byte ptr [si].bTkDevEndp
	shl	ax, BIT_EN
	or	cx, ax
	mov	[di].wEdControl, cx

	mov	ax, [si].wTkPacketSize
	mov	cx, [si].wTkInterval
	shl	cx, BIT_EDINT
	or	ax, cx
	mov	[di].wEdMps, ax

	mov	di, [si].wTkTransDesp		;TransDescriptor pointer

	mov	[di].wTdTask, si

	mov	[di].wTdControl, 0F214H		;Buffer rounding=1
						;PID = 10b (PID_IN)
						;zero delay interrupt
						;use TD's data toggle
						;Error Count=0
						;Condition Code=NOTACCESSED

	mov	ax, [si].wTkDataBuffer
	call	Physical_Linear
	mov	[di].dTdCBP, eax
	mov	ax, [si].wTkDataBuffer
	add	ax, [si].wTkPacketSize
	dec	ax
	call	Physical_Linear
	mov	[di].dTdBE, eax

	push	si				;task control pointer
	mov	di, [si].wTkQueueHead
	mov	si, [si].wTkTransDesp
	call	Link_TD_to_QH
	pop	si				;task control pointer

	call	Link_Task

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
;		BX = point to TD		;R43
;Output:	none
;[]========================================================================[]

Proc_Mouse:
	test	word ptr [bx].wTdControl, CC	;R43;condition code
	jnz	short Proc_Mouse_Exit		;R43
	test	byte ptr bEmuCmdByte, MSIFDIS	;mouse interface disabled
	jnz	short Proc_Mouse_Exit
	test	byte ptr bDevCtrl, MSDISABLE	;mouse disabled
	jnz	short Proc_Mouse_Exit
	mov	bx, [si].wTkDataBuffer		;data buffer point of task
	call	Proc_MsData			;convert received data
	call	Proc_CharPending
Proc_Mouse_Exit:
	ret

;[]========================================================================[]
;Procedure:	Proc_MsData
;Function:	Translate USB mouse data to PS/2 mouse data
;Input:		BX = point to data buffer
;Output:	MsPacketBuffer = mouse data packet
;		bMsPacketLength = mouse data packet length
;		bMsPacketPoint = mouse data packet pointer
;[]========================================================================[]

Proc_MsData:
	push	si

	mov	al, 13				;minimum length 3 for mode 0
	cmp	bMsID, 3
	jne	short @f
	mov	al, 12				;minimum length 4 for mode 3
@@:
	cmp	bMsPacketLength, al
	ja	short Proc_MsData_Exit

	mov	al, bMsPacketPoint
	add	al, bMsPacketLength
	and	al, 0Fh
	mov	bMsPacketIndex, al		;for command 0EBh read data
	movzx	si, al

	mov	al, [bx+1]			;X axis displacement
	mov	dl, al				;DL = X axis displacement
	mov	al, [bx+2]			;Y axis displacement
	neg	al
	mov	dh, al				;DH = Y axis displacement
	mov	al, [bx]			;pressed buttons status
	and	al, 07				;3 buttons
	or	al, 08				;reserved bit of PS2 mouse data
	test	dl, 80h				;X data sign
	jz	short @f
	or	al, 10h				;negative X data sign
@@:
	test	dh, 80h				;Y data sign
	jz	short @f
	or	al, 20h				;negative Y data sign
@@:
	mov	MsPacketBuffer[si], al		;pressed buttons status
	call	Next_MsPoint
	mov	MsPacketBuffer[si], dl		;X axis displacement
	call	Next_MsPoint
	mov	MsPacketBuffer[si], dh		;Y axis displacement
	call	Next_MsPoint

	mov	al, 3				;length 3 for mode 0
	cmp	bMsID, 3
	jne	short @f
	inc	al				;length 4 for mode 3
	mov	byte ptr MsPacketBuffer[si], 0	;clear 4th byte
@@:
	add	bMsPacketLength, al

Proc_MsData_Exit:
	pop	si
	ret

Next_MsPoint:
	inc	si
	and	si, 0Fh
	ret

endif	;USB_MOUSE_SUPPORT

ifdef	IOTRAP_SUPPORT
;[]========================================================================[]
;Procedure:	UsbLegSmi
;Function:	Emulation interrupt handler
;		Interrupt source:
;			1. Write port 60h/64h
;			2. Change A20M sequence
;			3. External IRQ1/IRQ12
;			4. Character pending and OBF empty
;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:	none
;Note:	Abbreviation:
;		KC : keyboard controller
;		KB : keyboard
;		MS : mouse
;[]========================================================================[]
	public	UsbLegSmi
UsbLegSmi:
	call	Get_HceControl			;get trap status
	mov	bl, al
	call	Get_HceStatus			;get emulated status port
	mov	bh, al
	push	bx
	and	al, not KCIBF			;clear IBF status
	call	Set_HceStatus
	call	GetTrapData			;get emulated input port value
	call	DisableUsbLegacySmi
	test	bh, KCIBF			;input buffer full?
	jz	short Check_Char_Pending
	test	bl, A20SEQ			;in change A20 sequence?
	jnz	short DoA20
	test	bh, KCCMD			;IBF from 64h write?
	jnz	short Do64W
	jmp	short Do60W

;Change A20M sequence handler

DoA20:
	call	Get_HceControl
	and	ax, not A20STATE		;A20M low
	test	IoTrapData, 00000010b		;gate a20 bit
	jz	short Change_A20_State
	or	ax, A20STATE			;A20M high
Change_A20_State:
	and	al, not (IRQ1ACT+IRQ12ACT)	;don't clear IRQ flag
	call	Set_HceControl
	call	SMI_Ct_A20M_Patch
;R44 - start
ifdef	FAST_CHANGE_A20M
	mov	al, IoTrapData
	SMI_F0CALL	Ct_A20
else	;FAST_CHANGE_A20M
;R44 - end
	call	Wait_Ibf_Clear
	jc	short DoA20_Exit
	mov	al, 0D1h			;write output port command
	out	64h, al				;write to command port
	call	Wait_Ibf_Clear
	jc	short DoA20_Exit
	call	SmiOut60			;write output port value
endif	;FAST_CHANGE_A20M			;R44
DoA20_Exit:
	jmp	short Check_Char_Pending

;Port 64h write handler

Do64W:
	call	Proc_KcCmd			;process kc command
	jmp	short Check_Char_Pending

;Port 60h write handler

Do60W:
	test	bCipFlag, KCWFP			;kc command wait for process
	jz	short Do60W_Cont
	call	wKcCmdProc
	jmp	short Check_Char_Pending

Do60W_Cont:
	test	bCipFlag, WKBWFP		;kb command wait for process
	jz	short First_60W
	call	wKbCmdProc
	jmp	short Check_Char_Pending

First_60W:
	call	Proc_KbCmd			;process kb command

Check_Char_Pending:
	pop	bx
	test	bl, CHARPENDING			;character pending?
	jz	short Check_External_Irq
	test	bh, KCOBF			;output buffer empty
	jnz	short Check_External_Irq

;Character pending handler

	call	Proc_CharPending		;character pending handler

Check_External_Irq:
	call	Get_HceControl
	test	al, IRQ1ACT			;external IRQ1 from kc?
	jnz	short DoIrq1
	test	al, IRQ12ACT			;external IRQ12 from kc?
	jnz	short DoIrq12
	jmp	short UsbLegSmi_Exit

;External IRQ1 handler

DoIrq1:
	and	al, not IRQ12ACT		;don't clear IRQ12 flag
	call	Set_HceControl
	in	al, 60h				;get code from kc
	call	Append_KbData
	jmp	short Check_External_Irq

;External IRQ12 handler

DoIrq12:
	and	al, not IRQ1ACT			;don't clear IRQ1 flag
	call	Set_HceControl
	in	al, 60h				;get code form kc
	test	byte ptr bUsbFlag, USBMSSUPPORT
	jnz	short Check_External_Irq
	call	Append_MsReply
	jmp	short Check_External_Irq

UsbLegSmi_Exit:
	call	Get_HceControl
	call	Set_HceControl			;clear status
	call	EnableUsbLegacySmi
	ret

;[]========================================================================[]
;Procedure:	SmiOut60
;Function:      Output data (in IoTrapData) to port 60h in USB Legacy SMM
;Input:		IoTrapData
;Output:        None
;[]========================================================================[]
SmiOut60	proc	near
	push	ax
	call	Wait_Ibf_Clear			;wait kc IBF clear
	mov	al, IoTrapData
	out	60h, al				;write to kc data port
	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
	call	Wait_Ibf_Clear			;wait kc IBF clear
	mov	al, IotrapData
	out	64h, al				;write to kc command port
	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				;read from kc data port
	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				;read from kc status port
	mov	IoTrapData, al
	pop	ax
	ret
SmiIn64	endp

;[]========================================================================[]
;Procedure:	GetTrapData
;Function:      Retrieve the code from system to kb input buffer.
;Input:		None
;Output:	IoTrapData = Contents of input buffer
;[]========================================================================[]
GetTrapData	proc	near
        push    ax
	call	Get_HceInput			;emulated input buffer
        mov     IoTrapData, al
        pop     ax
        ret
GetTrapData	endp

;[]========================================================================[]
;Procedure:	SetTrapData
;Function:      Set output buffer with IoTrapData.
;Input:		IoTrapData
;Output:	None
;[]========================================================================[]
SetTrapData	proc	near
        push    ax
	movzx	eax, byte ptr IoTrapData
	call	Set_HceOutput			;emulated output buffer
        pop     ax
        ret
SetTrapData	endp

;[]========================================================================[]
;Procedure:	SetObfIrq
;Function:      Determine whether to issue IRQ1 with OBF or not.
;Input:		None
;Output:	None
;[]========================================================================[]
SetObfIrq	proc	near
	push	eax
	push	bx
	call	Get_HceControl
	mov	bx, ax
	and	bx, not IRQEN			;no IRQ1 issued
	call	Get_HceStatus
	and	al, not (KCOBF+KCAUXOBF)	;clear all OBF status
	or	al, KCOBF
	test	bEmuCmdByte, OBFINT		;to issue IRQ1?
	jz	short No_SetObfIrq
	or	bx, IRQEN			;issue IRQ1
No_SetObfIrq:
	push	eax
	movzx	eax, bx
	and	al, not (IRQ1ACT+IRQ12ACT)	;don't clear IRQ flag
	call	Set_HceControl			;control register for IRQEN
	pop	eax
	call	Set_HceStatus			;status register for OBF
	pop	bx
	pop	eax
	ret
SetObfIrq	endp

;[]========================================================================[]
;Procedure:	SetAuxObfIrq
;Function:      Determine whether to issue IRQ12 with AUXOBF or not.
;Input:		None
;Output:	None
;[]========================================================================[]
SetAuxObfIrq	proc	near
	push	eax
	push	bx
	call	Get_HceControl
	and	ax, not (IRQEN+IRQ1ACT+IRQ12ACT)	;don't clear IRQ flag
	mov	bx, ax
	call	Get_HceStatus
	or	al, (KCOBF+KCAUXOBF)		;aux device OBF
	test	bEmuCmdByte, AOBFINT		;to issue IRQ12?
	jz	short No_SetAuxObfIrq
	or	bx, IRQEN			;issue IRQ12
No_SetAuxObfIrq:
	push	eax
	movzx	eax, bx
	call	Set_HceControl			;control register for IRQEN
	pop	eax
	call	Set_HceStatus			;status register for OBF
	pop	bx
	pop	eax
	ret
SetAuxObfIrq	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:		None
;Output:	None
;[]========================================================================[]
DisableUsbLegacySmi	proc	near
	push	es
	push	eax
	xor	ax, ax
	mov	es, ax
	call	Get_HceControl
	and	al, not EMEN			;emulation disabled
	and	al, not (IRQ1ACT+IRQ12ACT)	;don't clear IRQ flag
	call	Set_HceControl
	pop	eax
	pop	es
	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:		None
;Output:	None
;[]========================================================================[]
EnableUsbLegacySmi	proc	near
	push	es
	push	eax
	xor	ax, ax
	mov	es, ax
	call	Get_HceControl
	or	al, EMEN			;emulation enabled
	and	al, not (IRQ1ACT+IRQ12ACT)	;don't clear IRQ flag
	call	Set_HceControl
	pop	eax
	pop	es
	ret
EnableUsbLegacySmi	endp

;[]========================================================================[]
;Procedure:	Disable_CharPending
;Function:	Disable character pending smi
;Input:		None
;Output:	None
;[]========================================================================[]
Disable_CharPending	proc	near
	push	es
	push	eax
	xor	ax, ax
	mov	es, ax
	call	Get_HceControl
	and	al, not CHARPENDING		;character pending smi
	and	al, not (IRQ1ACT+IRQ12ACT)	;don't clear IRQ flag
	call	Set_HceControl
	pop	eax
	pop	es
	ret
Disable_CharPending	endp

;[]========================================================================[]
;Procedure:	Enable_CharPending
;Function:	Enable character pending smi
;Input:		None
;Output:	None
;[]========================================================================[]
Enable_CharPending	proc	near
	push	es
	push	eax
	xor	ax, ax
	mov	es, ax
	call	Get_HceControl
	or	al, CHARPENDING			;character pending smi
	and	al, not (IRQ1ACT+IRQ12ACT)	;don't clear IRQ flag
	call	Set_HceControl
	pop	eax
	pop	es
	ret
Enable_CharPending	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

;************************************************************************
;*									*
;*	CHARACTER PENDING HANDLER					*
;*									*
;************************************************************************

Proc_CharPending	proc	near
	push	es
	push	ds
	pop	es
	mov	di, offset LengthTable
	mov	cx, 5
	xor	al, al
	repe	scasb
	jne	short Check_KcReply
	call	Disable_CharPending		;no character pending
	pop	es
	ret

;Check keyboard controller reply buffer

Check_KcReply:

	; Delay to patch the Fujitsu keyboard hang-up while running its
	; testing utility.

	mov	al, bSendCodeDelay
	inc	al
	and	al, 1
	mov	bSendCodeDelay, al
	jnz	Proc_CharPending_Exit

	; patch end

	xor	ax, ax
	mov	es, ax
	cmp	byte ptr bKcReplyLength, 0
	je	short Check_KbReply
	movzx	si, byte ptr bKcReplyPoint	;current pointer
	mov	al, KcReplyBuffer[si]		;pending code
	call	Check_OBF			;check output buffer full
	jnz	short Proc_KcReply_Exit
	dec	byte ptr bKcReplyLength		;reduce total length
	inc	byte ptr bKcReplyPoint		;point to next pending code
	and	byte ptr bKcReplyPoint, 0Fh	;validate pointer value
	mov	IoTrapData, al
	call	SetTrapData			;write to emulated output port
	call	SetObfIrq			;issue IRQ according to OBFINT
Proc_KcReply_Exit:
	jmp	Proc_CharPending_Exit

;Check keyboard reply buffer

Check_KbReply:
	cmp	byte ptr bKbReplyLength, 0
	je	short Check_MsReply
	test	bCipFlag, KCWFP			;check kc command in process
	jnz	short Proc_KbReply_Exit
	movzx	si, byte ptr bKbReplyPoint	;current pointer
	mov	al, KbReplyBuffer[si]		;pending code
	call	Check_OBF			;check output buffer full
	jnz	short Proc_KbReply_Exit
	dec	byte ptr bKbReplyLength		;reduce total length
	inc	byte ptr bKbReplyPoint		;point to next pending code
	and	byte ptr bKbReplyPoint, 0Fh	;validate pointer value
	mov	IoTrapData, al
	call	SetTrapData			;write to emulated output port
	call	SetObfIrq			;issue IRQ according to OBFINT
Proc_KbReply_Exit:
	jmp	Proc_CharPending_Exit

;Check mouse reply buffer

Check_MsReply:
	cmp	byte ptr bMsReplyLength, 0
	je	short Check_MsPacket
	test	bCipFlag, KCWFP+KBWFP		;check kc,kb command in process
	jnz	short Proc_MsReply_Exit
	test	byte ptr bEmuCmdByte, MSIFDIS	;mouse interface disabled
	jnz	short Proc_MsReply_Exit
	movzx	si, byte ptr bMsReplyPoint	;current pointer
	mov	al, MsReplyBuffer[si]		;pending code
	call	Check_OBF			;check output buffer full
	jnz	short Proc_MsReply_Exit
	dec	byte ptr bMsReplyLength		;reduce total length
	inc	byte ptr bMsReplyPoint		;point to next pending code
	and	byte ptr bMsReplyPoint, 0Fh	;validate pointer value
	mov	IoTrapData, al
	call	SetTrapData			;write to emulated output port
	call	SetAuxObfIrq			;issue IRQ according to AOBFINT
Proc_MsReply_Exit:
	jmp	Proc_CharPending_Exit

;Check mouse packet data buffer

Check_MsPacket:
	cmp	byte ptr bMsPacketLength, 0
	je	short Check_KbData
	test	byte ptr bDevCtrl, MSDISABLE	;mouse disabled
	jnz	short Check_KbData
	test	byte ptr bEmuCmdByte, MSIFDIS	;mouse interface disabled
	jnz	short Check_KbData
	test	bCipFlag, WFPMASK		;check command in process
	jnz	short Proc_MsPacket_Exit
	movzx	si, byte ptr bMsPacketPoint	;current pointer
	mov	al, MsPacketBuffer[si]		;pending code
	call	Check_OBF			;check output buffer full
	jnz	short Proc_MsPacket_Exit
	dec	byte ptr bMsPacketLength	;reduce total length
	inc	byte ptr bMsPacketPoint		;point to next pending code
	and	byte ptr bMsPacketPoint, 0Fh	;validate pointer value
	mov	IoTrapData, al
	call	SetTrapData			;write to emulated output port
	call	SetAuxObfIrq			;issue IRQ according to AOBFINT
Proc_MsPacket_Exit:
	jmp	Proc_CharPending_Exit

;Check keyboard data buffer

Check_KbData:
	cmp	byte ptr bKbDataLength, 0
	je	short Proc_CharPending_Exit
	test	byte ptr bDevCtrl, KBDISABLE	;keyboard disabled
	jnz	short Proc_CharPending_Exit
	test	byte ptr bEmuCmdByte, KBIFDIS	;keyboard interface disabled
	jnz	short Proc_CharPending_Exit
	test	bCipFlag, WFPMASK		;check command in process
	jnz	short Proc_KbData_Exit
	movzx	si, byte ptr bKbDataPoint	;current pointer
	mov	al, KbDataBuffer[si]		;pending code
	call	Check_In_Isr
	jnz	short Proc_MsPacket_Exit
	call	Check_OBF			;check output buffer full
	jnz	short Proc_KbData_Exit
	dec	byte ptr bKbDataLength		;reduce total length
	inc	byte ptr bKbDataPoint		;point to next pending code
	and	byte ptr bKbDataPoint, 0Fh	;validate pointer value
	mov	IoTrapData, al
	call	SetTrapData			;write to emulated output port
	call	SetObfIrq			;issue IRQ according to OBFINT
Proc_KbData_Exit:
	jmp	Proc_CharPending_Exit

Proc_CharPending_Exit:
	call	Enable_CharPending
	pop	es
	ret
Proc_CharPending	endp

;[]========================================================================[]
;Procedure:	Append_MsReply
;Function:	Append 1 byte reply code to ms reply buffer
;Input:		AL = reply code
;Output:	none
;[]========================================================================[]
Append_MsReply	proc	near
	cmp	byte ptr bMsReplyLength, 16
	jae	short Append_MsReply_Exit
	mov	ah, bMsReplyPoint		;get current point
	add	ah, bMsReplyLength		;plus total length
	and	ah, 0Fh
	movzx	si, ah
	mov	MsReplyBuffer[si], al
	inc	byte ptr bMsReplyLength		;increase total length
	call	Enable_CharPending
Append_MsReply_Exit:
	ret
Append_MsReply	endp

;[]========================================================================[]
;Procedure:	Append_KbData
;Function:	Append 1 byte keyboard code to keyboard data buffer
;Input:		AL = code to append
;Output:	none
;[]========================================================================[]
Append_KbData:
	cmp	byte ptr bKbDataLength, 16
	jae	short Append_KbData_Exit
	mov	ah, bKbDataPoint
	add	ah, bKbDataLength
	and	ah, 0Fh
	movzx	si, ah
	mov	KbDataBuffer[si], al
	inc	byte ptr bKbDataLength		;increase total length
Append_KbData_Exit:
	call	Proc_CharPending
	ret

;[]========================================================================[]
;Procedure:	Append_MsPacket
;Function:	Append 1 byte mouse code to mouse packet data buffer
;Input:		AL = code to append
;Output:	none
;[]========================================================================[]
Append_MsPacket:
	cmp	byte ptr bMsPacketLength, 16
	jae	short Append_MsPacket_Exit
	mov	ah, bMsPacketPoint		;get current point
	add	ah, bMsPacketLength		;plus total length
	and	ah, 0Fh
	movzx	si, ah
	mov	MsPacketBuffer[si], al
	inc	byte ptr bMsPacketLength	;increase total length
Append_MsPacket_Exit:
	call	Proc_CharPending		;process char pending
	ret

;[]========================================================================[]
;Procedure:	Check_OBF
;Function:	Check output buffer full flag in HceStatus register
;Input:		none
;Output:	ZF = 0 OBF
;		ZF = 1 no OBF
;[]========================================================================[]
Check_OBF:
	push	ax
	call	Get_HceStatus
	test	al, KCOBF
	pop	ax
	ret

;[]========================================================================[]
;Procedure:	Check_In_Isr
;Function:	Check whether system in IRQ1/IRQ12 Service Routine
;Input:		none
;Output:	ZF = 0 in ISR
;		ZF = 1 not in ISR
;[]========================================================================[]
Check_In_Isr:
	push	ax
	mov	al, 0Bh 			;read ISR
	out	20h, al
	NEWIODELAY
	in	al, 20h
	test	al, 02				;IRQ1 in service
	jnz	short Check_In_Isr_Exit

	mov	al, 0Bh 			;read ISR
	out	0A0h, al
	NEWIODELAY
	in	al, 0A0h
	test	al, 10h				;IRQ12 in service
	jnz	short Check_In_Isr_Exit
Check_In_Isr_Exit:
	pop	ax
	ret

;************************************************************************
;*									*
;*	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
	or	byte ptr bDevCtrl, KBDISABLE
	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
	and	byte ptr bDevCtrl, not KBDISABLE
	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
	and	bDevCtrl, not MSWRAPMODE	;not in wrap mode
	or	bDevCtrl, MSDISABLE		;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
	mov	byte ptr bKcReplyLength, 0	;clear previous pending char
	mov	byte ptr bKcReplyPoint, 0

	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:	Append_KcReply
;Function:	Set 1 byte kc reply code to reply buffer and enable character
;		pending smi
;Input:		AL = code to reply
;Output:	none
;[]========================================================================[]
Append_KcReply	proc	near
	mov	KcReplyBuffer, al
	mov	byte ptr bKcReplyLength, 1
	call	Enable_CharPending
	ret
Append_KcReply	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
	mov	al, bEmuCmdByte			;emulated command byte
	call	Append_KcReply			;let reply engine to handle
	ret
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
	or	al, (OBFINT+AOBFINT)
	mov	bRealCmdByte, al
	test	bUsbFlag, USBMSSUPPORT		;check usb mice support
	jz	short KcCmd_Write_Cmd2_Cont
	or	bRealCmdByte, MSIFDIS		;PS2 mice disabled if USB mice
						; installed
KcCmd_Write_Cmd2_Cont:
	mov	al, bRealCmdByte
	mov	IoTrapData, al
	call	SmiOut60
	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
	test	bUsbFlag, USBMSSUPPORT		;check usb mice support
	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
	and	bEmuCmdByte, not MSIFDIS	;mouse interface enabled
	test	byte ptr bUsbFlag, USBMSSUPPORT
	jz	KcCmd_Pass_2Cmd
	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
	mov	al, 30h				;default command byte
	mov	bEmuCmdByte, al
	mov	bRealCmdByte, al
	mov	al, 055h			;no error
	call	Append_KcReply			;let reply engine to handle
	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	Append_KcReply			;let reply engine to handle
	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
	mov	byte ptr bKbReplyLength, 0	;clear prev. pending reply code
	mov	byte ptr bKbReplyPoint, 0

	; any command to kb should enable kb interface

	and	bEmuCmdByte, not KBIFDIS	;keyboard interface Enabled
	and	bRealCmdByte, not KBIFDIS
	and	bDevCtrl, not KBDISABLE		;keyboard enabled

	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:	Append_KbReply
;Function:	Append 1 byte reply code to kb reply buffer
;Input:		AL = reply code
;Output:	none
;[]========================================================================[]
Append_KbReply	proc	near
	cmp	byte ptr bKbReplyLength, 16
	jae	short Append_KbReply_Exit
	mov	ah, bKbReplyPoint		;get current point
	add	ah, bKbReplyLength		;plus total length
	and	ah, 0Fh
	movzx	si, ah
	mov	KbReplyBuffer[si], al
	inc	byte ptr bKbReplyLength		;increase total length
	call	Enable_CharPending
Append_KbReply_Exit:
	ret
Append_KbReply	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	Append_KbReply			;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	Append_KbReply			;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
	mov	bKbDataLength, 0
	mov	bKbDataPoint, 0
        mov     si, offset KbReplyBuffer
        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 bKbReplyPoint, 0
        mov     byte ptr bKbReplyLength, 2
	call	Enable_CharPending
        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
        mov     si, offset KbReplyBuffer
        mov     byte ptr [si], 0FAh		;acknowledge code
        mov     byte ptr [si+1], 0ABh		;first ID code
        mov     byte ptr [si+2], 041h		;second ID code
        mov     byte ptr bKbReplyPoint, 0
        mov     byte ptr bKbReplyLength, 3
	call	Enable_CharPending
        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	Append_KbReply			;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	Append_KbReply			;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	Append_KbReply			;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	Append_KbReply			;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	Append_KbReply			;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	Append_KbReply			;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	Append_KbReply			;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	Append_KbReply			;reply to system
	call	UsbKb_Default
	ret
KbCmd_Default	endp

;************************************************************************
;*									*
;*	MOUSE COMMAND PROCESS MODULE					*
;*									*
;************************************************************************

ifndef	USB_MOUSE_SUPPORT
Proc_MsCmd	proc	near
	jmp	KcCmd_Pass_2Cmd
Proc_MsCmd	endp
else	;USB_MOUSE_SUPPORT
;[]========================================================================[]
; 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

	; any command to ms should enable ms interface

	and	bEmuCmdByte, not MSIFDIS

	; Check in wrap mode

	test	bDevCtrl, MSWRAPMODE		;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	Append_MsReply			;echo all command/data
	ret

Not_In_Wrap_Mode:
	and	bDevCtrl, not MSWRAPMODE	;clear wrap mode flag
	test	bCipFlag, WMSWFP
	jz	short First_MsCmd
	call	wMsCmdProc
	jmp	short Proc_MsCmd_Exit

First_MsCmd:
	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:
	and	bCipFlag, not (WMSWFP+RMSWFP)	;clear previous pending cmd
	mov	byte ptr bMsReplyLength, 0	;clear prev. pending reply code
	mov	byte ptr bMsReplyPoint, 0

	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

;[]========================================================================[]
;Procedure:	Reply_System
;Function:	Emulate mouse reply to system with 0FAh
;Input:		none
;Output:	none
;[]========================================================================[]

Reply_System	proc	near
	push	ax
	mov	al, 0FAh			;acknowledge to system
	call	Append_MsReply
	pop	ax
	ret
Reply_System	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:	none
;[]========================================================================[]
MsCmd_Reset	proc	near
	call	UsbMs_Default			;reset data to default
	mov	byte ptr bMsID, 0		;normal mode
	mov	bMsReplyLength, 3
	mov	MsReplyBuffer[0], 0FAh		;ACK
	mov	MsReplyBuffer[1], 0AAh		;reset completion
	mov	MsReplyBuffer[2], 000h		;mouse ID
	call	Enable_CharPending
	ret
MsCmd_Reset	endp

;[]========================================================================[]
;Procedure:	MsCmd_Enable
;Function:	Mouse command 0F4h handler
;		Enable
;Input:		none
;Output:	bMsStatus affected
;[]========================================================================[]
MsCmd_Enable	proc	near
	or	bMsStatus, MSENABLE		;mouse enabled
	and	bDevCtrl, not MSDISABLE		;mouse enabled
	call	Reply_System
	ret
MsCmd_Enable	endp

;[]========================================================================[]
;Procedure:	MsCmd_Disable
;Function:	Mouse command 0F5h handler
;		Disable
;Input:		none
;Output:	bMsStatus affected
;[]========================================================================[]
MsCmd_Disable	proc	near
	and	bMsStatus, not MSENABLE		;mouse disabled
	or	bDevCtrl, MSDISABLE		;mouse disabled
	call	Reply_System
	ret
MsCmd_Disable	endp

;[]========================================================================[]
;Procedure:	MsCmd_Scaling1
;Function:	Mouse command 0E6h handler
;		Reset scaling to 1:1
;Input:		none
;Output:	bMsStatus affected
;[]========================================================================[]
MsCmd_Scaling1	proc	near
	and	bMsStatus, not MSSCALE2		;scanling 1:1
	call	Reply_System
	ret
MsCmd_Scaling1	endp

;[]========================================================================[]
;Procedure:	MsCmd_Scaling2
;Function:	Mouse command 0E7h handler
;		Set scaling to 2:1
;Input:		none
;Output:	bMsStatus affected
;[]========================================================================[]
MsCmd_Scaling2	proc	near
	or	bMsStatus, MSSCALE2		;scanling 2:1
	call	Reply_System
	ret
MsCmd_Scaling2	endp

;[]========================================================================[]
;Procedure:	MsCmd_Resolution
;Function:	Mouse command 0E8h handler
;		Set resolution
;Input:		IoTrapData
;Output:	bResolution affected
;[]========================================================================[]
MsCmd_Resolution	proc	near
	mov	wMsCmdProc, offset MsCmd_Resolution2 SMI_OFFSET
	or	bCipFlag, WMSWFP
	call	Reply_System
	ret

	; 2nd trapping: system issue resolution rate value

MsCmd_Resolution2:
	and	bCipFlag, not WMSWFP
	mov	al, IoTrapData			;resolution value
	mov	bResolution, al
	call	Reply_System
	ret
MsCmd_Resolution	endp

;[]========================================================================[]
;Procedure:	MsCmd_Sample_Rate
;Function:	Mouse command 0F3h handler
;		Set sample rate
;Input:		IoTrapData
;Output:	bSampleRate affected
;[]========================================================================[]
MsCmd_Sample_Rate	proc	near
	mov	wMsCmdProc, offset MsCmd_Sample_Rate2 SMI_OFFSET
	or	bCipFlag, WMSWFP
	call	Reply_System
	ret

	; 2nd trapping: system issue sample rate value

MsCmd_Sample_Rate2:
	and	bCipFlag, not WMSWFP
	mov	al, IoTrapData			;sample rate value
	mov	bSampleRate, al
	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:
	ret
MsCmd_Sample_Rate	endp

CHANGE_MODE_SEQUENCE	db	0C8h, 064h, 050h

;[]========================================================================[]
;Procedure:	MsCmd_Default
;Function:	Mouse command 0F6h handler
;		Set default
;Input:		none
;Output:	none
;[]========================================================================[]
MsCmd_Default	proc	near
	call	UsbMs_Default			;reset data to default
	call	Reply_System
	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:	none
;[]========================================================================[]
MsCmd_Status	proc	near
	mov	bMsReplyLength, 4
	mov	al, 0FAh
	mov	MsReplyBuffer[0], al
	mov	al, bMsStatus
	mov	MsReplyBuffer[1], al
	mov	al, bResolution
	mov	MsReplyBuffer[2], al
	mov	al, bSampleRate
	mov	MsReplyBuffer[3], al
	call	Enable_CharPending
	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:	none
;[]========================================================================[]
MsCmd_Read_ID	proc	near
	mov	bMsReplyLength, 2
	mov	MsReplyBuffer[0], 0FAh		;ACK
	mov	al, bMsID			;mouse ID
	mov	MsReplyBuffer[1], al
	call	Enable_CharPending
	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	Append_MsReply
	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:	none
;[]========================================================================[]
MsCmd_Read_Data	proc	near
	movzx	si, byte ptr bMsPacketIndex	;packet index
	mov	al, 0FAh
	mov	MsReplyBuffer[0], al
	mov	al, MsPacketBuffer[si]
	mov	MsReplyBuffer[1], al
	call	Next_MsPoint
	mov	al, MsPacketBuffer[si]
	mov	MsReplyBuffer[2], al
	call	Next_MsPoint
	mov	al, MsPacketBuffer[si]
	mov	MsReplyBuffer[3], al
	call	Next_MsPoint
	mov	ah, 4
	cmp	bMsID, 3
	jne	short @f
	mov	al, MsPacketBuffer[si]
	mov	MsReplyBuffer[4], al
	inc	ah
@@:
	mov	bMsReplyLength, ah
	call	Enable_CharPending
	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
	call	Reply_System
	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
	call	Reply_System
	ret
MsCmd_Remote_Mode	endp

;[]========================================================================[]
;Procedure:	MsCmd_Reset_Wrap
;Function:	Mouse command 0ECh handler
;		Reset wrap mode
;Input:		none
;Output:	bDevCtrl affected
;[]========================================================================[]
MsCmd_Reset_Wrap	proc	near
	and	bDevCtrl, not MSWRAPMODE	;normal mode
	call	Reply_System
	ret
MsCmd_Reset_Wrap	endp

;[]========================================================================[]
;Procedure:	MsCmd_Set_Wrap
;Function:	Mouse command 0EEh handler
;		Set wrap mode
;Input:		none
;Output:	bDevCtrl affected
;[]========================================================================[]
MsCmd_Set_Wrap	proc	near
	or	bDevCtrl, MSWRAPMODE		;normal mode
	call	Reply_System
	ret
MsCmd_Set_Wrap	endp
endif	;USB_MOUSE_SUPPORT

endif	;IOTRAP_SUPPORT
;R42 - end

	assume	ds:nothing

ENDIF	;COMPILE_FOR_USBBIOS EQ 3
