⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uhci.asm

📁 AMI 主板的BIOS源码
💻 ASM
📖 第 1 页 / 共 5 页
字号:

	mov	dx, USB_COMMAND_REG	;DX = command reg
	add	dx, cx			;DX = command reg + USB HC base addr
	in	ax, dx
	test	ax, HOST_CONTROLLER_RUN
	jz	CheckActiveNo		;Br if HC is not running

CheckActiveYes:
	popad
	mov	cl, 00000101b		;Indicate USB BIOS is in control and running
	ret				;   and HC has two root hub ports

CheckActiveNo:
	popad
	mov	cl, 00000100b		;Indicate USB BIOS is not in control or not running
	ret				;   and HC has two root hub ports
UsbHcCheckActive	endp


;---------------------------------------;
; GetUsbHcBusDevFunc                    ;
;---------------------------------------;--------------------------------------;
; This function returns the PCI bus, device, and function number of the USB    ;
; host controller.                                                             ;
;                                                                              ;
; Input: Nothing                                                               ;
;                                                                              ;
; Output: BH = PCI Bus number                                                  ;
;         BL = Device / Function number                                        ;
;              Bits 7-3: PCI device number                                     ;
;              Bits 2-0: Function number within the device                     ;
;         CF = Clear if USB host controller was found, set if not found        ;
;                                                                              ;
; Destroys: AX, ECX, EDX                                                       ;
;------------------------------------------------------------------------------;
GetUsbHcBusDevFunc	proc near

; Find the PCI bus/device/function number of the USB host controller by calling
; a chipset hook to get the Device/Vendor ID of the USB HC and then search for
; that HC on the PCI bus.

ifdef DOS_DEBUG
	mov	ecx, USB_HC_CLASS_CODE	;Defined by UHCI.EQU or OHCI.EQU
	xor	si, si
	mov	ax, 0B103h		;PCI Find Class function
	int	1Ah			;Returns CF, BX=bus/dev/func of USB HC
else
	call	UsbGetHostControllerId	;Returns EDX = Vendor/Device ID
	or	edx, edx
	clc
	jz	UsbFindDone		;Br if hook returned bus/dev/func #
	call	smi_pci_find_device	;Returns CF, BX=bus/dev/func of USB HC
endif

UsbFindDone:
	ret
GetUsbHcBusDevFunc	endp


;---------------------------------------;
; UsbHcInit                             ;
;---------------------------------------;--------------------------------------;
; This function initializes the host controller, its schedule, and all other   ;
; associated data structures, and then starts the host controller.             ;
;                                                                              ;
; Input:  DS = ES = Usb Data Area                                              ;
;                                                                              ;
; Output: Nothing                                                              ;
;                                                                              ;
; Destroys: Nothing                                                            ;
;------------------------------------------------------------------------------;
_UsbHcInit	proc near
	pushad
	
ifdef DOS_DEBUG
	push	ds
	push	es
	push	DOS_DEBUG_DATA_AREA
	push	DOS_DEBUG_DATA_AREA
	pop	ds
	pop	es

	pusha
	xor	di, di			;Start at offset 0
	mov	cx, 1000h		;Clear 4k words
	xor	ax, ax
	rep	stosw			;Clear 8k data area
	popa
endif

; Find the PCI bus/device/function number of the USB host controller and
; store it for later use.

	call	GetUsbHcBusDevFunc	;Returns BX = b/d/f, destroys AX,ECX,EDX
	jc	UsbInitDone		;Br if USB HC not found
	mov	UsbHcBusDevFuncNum, bx	;Save bus/dev/func for later

; Get I/O base address of the HC and store it in the variable
; IO_Space_Base_Address in the USB data segment.

	;mov	bx, UsbHcBusDevFuncNum	;BX = bus/dev/func # of USB HC
	mov	di, USB_BASE_ADDRESS
	mov	si, PCI_REG_ADDRESS_WORD
	call	smi_pci_read_cfg	;Returns CX = I/O base of HC
	and	cl, 0FCh		;Mask out 2 reserved bits
	mov	IO_Space_Base_Address, cx


; First stop the host controller if it is at all active

	mov	dx, USB_COMMAND_REG
	call	ReadUsbIoRegByte
	and	al, NOT HOST_CONTROLLER_RUN
	call	WriteUsbIoRegByte

;
; Disable both ports for warm boot purposes
;
	mov	dx,USB_PORT1_CONTROL
	call	ReadUsbIoRegByte
	and	al,NOT PORT_ENABLE
	call	WriteUsbIoRegByte

	mov	dx,USB_PORT2_CONTROL
	call	ReadUsbIoRegByte
	and	al,NOT PORT_ENABLE
	call	WriteUsbIoRegByte

; Reset the host controller
	mov	dx, USB_COMMAND_REG
	mov	ax, GLOBAL_RESET
	call	WriteUsbIoRegByte

	mov	cx, 6660		; 100 ms
	call	pm_fixed_delay
	
	xor	ax, ax		   	;Reset the usb command register
	call	WriteUsbIoRegByte

	call	UsbDataInit		;Initialize any data structures

; Program the frame list base address register

	mov	eax, HcdDataArea	;EAX = absolute addr of FrameList
	add	ax, offset FrameList
	mov	dx, USB_FRAME_LIST_BASE
	call	WriteUsbIoRegDword	;Write addr of frame list into HC

; Initialize the host controller's 1024 entry frame list to point to the
; first column of HID TDs.

	mov	di, offset FrameList

InitFrameListNextRepeat:
	mov	cx, ACTIVE_FRAMES	;CX = number of active frames
	mov	eax, HcdDataArea	;EAX = seg containing TD pool
	add	eax, offset TdHid	;EAX = addr of first HID TD

InitFrameListNextFrame:
	stosd				;Set frame list entry = TD[cx]
	add	eax, size Transfer_Descriptor	;EAX = addr of next TD

	mov	bx, IDLE_FRAMES		;BX = # of idle frames between actives
InitFrameListNextIdle:
	mov	dword ptr [di], TERMINATE ;Set frame list entry to be idle
	add	di, 4			;DI = ptr to next frame list entry
	dec	bx			;Dec idle frame counter
	jnz	InitFrameListNextIdle	;Br if more idle frames to insert

	loop	InitFrameListNextFrame	;Loop for all active frames

	cmp	di, offset FrameList + (FRAME_LIST_SIZE * 4)
	jb	InitFrameListNextRepeat	;Br if entire frame list is not done

; Now "hook" the first frame list entry and point it to the array of Hub
; TDs.  Then link the root hub TD and the TDs in the TdHub array together
; in a linear linked list.

	mov	di, offset FrameList	;DI = ptr to first frame list entry
	mov	ebx, dword ptr [di]	;Save contents of first frame list entry
	mov	eax, HcdDataArea	;EAX = seg containing TD pool
	add	eax, offset TdRootHub	;EAX = addr of root hub TD
	stosd				;Set frame list entry to point to root hub TD

	mov	di, offset TdRootHub	;DI = ptr to root hub TD
	mov	eax, HcdDataArea	;EAX = seg containing TDs
	add	eax, offset TdHub	;EAX = addr of first hub TD
	mov	(Transfer_Descriptor ptr [di]).TD_Link_Pointer, eax

	mov	di, offset TdHub	;DI = ptr to first TD in TdHub array
	movzx	eax, di
	add	eax, HcdDataArea
	add	eax, size Transfer_Descriptor ;EAX = ptr to next TD
	mov	cx, HUB_DEVICE_LIMIT - 1

InitHubListNext:
	mov	(Transfer_Descriptor ptr [di]).TD_Link_Pointer, eax
	add	eax, size Transfer_Descriptor
	add	di, size Transfer_Descriptor
	loop	InitHubListNext		;Fill all TdHub TDs except last

	mov	(Transfer_Descriptor ptr [di]).TD_Link_Pointer, ebx
					;Link last hub TD to the saved contents
					; of the first frame list entry

; Initialize the HID TDs into a two dimensional array.  The
; array has ACTIVE_FRAMES number of rows (each row is headed by one frame list
; entry).  The array has TDS_PER_FRAME number of columns.  The last TD in each
; row has its link pointer set to point to QhControl (except for the first row
; which has its link pointer set to TdRepeat).

	mov	edx, HcdDataArea
	add	edx, offset QhControl
	or 	edx, QUEUE_HEAD 	;EDX = Link ptr to QhControl
	mov	cl, 0			;CL will be row counter (0..ACTIVE_FRAMES-1)

InitTdArrayNextRow:
	mov	ch, 0			;CH will be column counter (0..TDS_PER_FRAME-1)

InitTdArrayNextCol:
	mov	al, ACTIVE_FRAMES	;AL = number of rows
	mul	ch			;AL = index of TD in row 0 of cur column
	add	al, cl			;AL = index of TD in cur row of cur column
	mov	bl, size Transfer_Descriptor
	mul	bl			;AX = offset within TD pool of current TD
	add	ax, offset TdHid	;AX = offset within usbdseg of current TD
	mov	di, ax			;DI = offset within usbdseg of current TD

	mov	eax, HcdDataArea ;EDX = seg containing TDs
	add	eax, offset TdRepeat	;EAX = abs addr of TdRepeat
	or	cl, cl
	jz	@f			;Br if on row 0
	mov	eax, edx		;EAX = ptr to QhControl
@@:
	cmp	ch, TDS_PER_FRAME - 1
	jae	InitTdLastCol		;Br if cur TD is last col in its row

	movzx	eax, di			;EAX = offset within usbdseg of current TD
	add	eax, HcdDataArea
	add	eax, (size Transfer_Descriptor * ACTIVE_FRAMES)
					;EAX = abs addr of next TD in row
InitTdLastCol:
	mov	(Transfer_Descriptor ptr [di]).TD_Link_Pointer, eax

	inc	ch
	cmp	ch, TDS_PER_FRAME
	jb	InitTdArrayNextCol	;Br if more cols to do

	inc	cl
	cmp	cl, ACTIVE_FRAMES
	jb	InitTdArrayNextRow	;Br if more rows to do

; Initialize the body of each HID TD and Hub TD to perform an
; interrupt transaction to an individual device address.  All TDs
; in the both arrays will initially be disabled.  As devices are found that
; need to be polled, the TD corresponding to the device's address will be
; made active.

	mov	cl, 0			;CL will count TDs (0..MAX_DEVICES-1)
	mov	di, offset TdPool	;DI = offset of first TD in array

InitPoolNextTd:
	mov	(Transfer_Descriptor ptr [di]).TD_Control_Status, THREE_ERRORS

	movzx	eax, cl			;EAX = TD number
	inc	al			;EAX = TD's device address
	shl	ax, 8			;Put device address in bits 14:8
	or	eax, IN_PACKET or ((DEFAULT_PACKET_LENGTH - 1) shl 21) ;Set PID=In, and MaxLen
	mov	(Transfer_Descriptor ptr [di]).TD_Token, eax

	lea	ax, (Transfer_Descriptor ptr [di]).DataArea ;AX = ptr to TD's data buffer
	movzx	eax, ax			;Clear upper half of EAX
	add	eax, HcdDataArea	;EAX = abs addr of TD's data buffer
	mov	(Transfer_Descriptor ptr [di]).TD_Buffer_Pointer, eax

	mov	(Transfer_Descriptor ptr [di]).CSReloadValue, THREE_ERRORS
	mov	(Transfer_Descriptor ptr [di]).pCallback, offset cgroup:PollingTdCallback
	add	(Transfer_Descriptor ptr [di]).pCallback, orgbase
	mov	(Transfer_Descriptor ptr [di]).ActiveFlag, FALSE

	add	di, size Transfer_Descriptor
	inc	cl			;Inc TD counter
	cmp	cl, MAX_DEVICES
	jb	InitPoolNextTd		;Br if more TDs to init

; Initialize the body TdRootHub.  It will run a interrupt transaction to a
; nonexistant dummy device.  This will have the effect of generating a periodic
; interrupt for the purpose of checking for attach/detach on the root
; hub's ports.

	mov	di, offset TdRootHub	;DI = ptr of TdRootHub

	mov	(Transfer_Descriptor ptr [di]).TD_Control_Status, INTERRUPT_ON_COMPLETE or ONE_ERROR or ACTIVE
	mov	(Transfer_Descriptor ptr [di]).TD_Token, IN_PACKET or (DUMMY_DEVICE_ADDR shl 8) or ((DEFAULT_PACKET_LENGTH - 1) shl 21) ;Set PID=In, Dev=Dummy, and MaxLen

	lea	ax, (Transfer_Descriptor ptr [di]).DataArea ;AX = ptr to TD's data buffer
	movzx	eax, ax			;Clear upper half of EAX
	add	eax, HcdDataArea	;EAX = abs addr of TD's data buffer
	mov	(Transfer_Descriptor ptr [di]).TD_Buffer_Pointer, eax
	mov	(Transfer_Descriptor ptr [di]).CSReloadValue, INTERRUPT_ON_COMPLETE or ONE_ERROR or ACTIVE
	mov	(Transfer_Descriptor ptr [di]).pCallback, offset cgroup:RootHubTdCallback
	add	(Transfer_Descriptor ptr [di]).pCallback, orgbase
	mov	(Transfer_Descriptor ptr [di]).ActiveFlag, TRUE

; Initialize the body of TdRepeat  It will run a interrupt transaction to a
; nonexistant dummy device.  This will have the effect of generating a periodic
; interrupt used to generate keyboard repeat.  This TD is normally inactive, and
; is only activated when a key is pressed.  TdRepeat will be set to timeout after
; two attempts.  Since the TD is in the schedule at 16ms intervals, this will
; generate an interrupt at intervals of 32ms (when the TD is active).  This 32ms
; periodic interrupt may then approximate the fastest keyboard repeat rate of
; 30 characters per second.

	mov	di, offset TdRepeat	;DI = ptr of TdRepeat

	mov	(Transfer_Descriptor ptr [di]).TD_Control_Status, TWO_ERRORS
	mov	(Transfer_Descriptor ptr [di]).TD_Token, IN_PACKET or (DUMMY_DEVICE_ADDR shl 8) or ((DEFAULT_PACKET_LENGTH - 1) shl 21) ;Set PID=In, Dev=Dummy, and MaxLen

	lea	ax, (Transfer_Descriptor ptr [di]).DataArea ;AX = ptr to TD's data buffer
	movzx	eax, ax			;Clear upper half of EAX
	add	eax, HcdDataArea	;EAX = abs addr of TD's data buffer

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -