📄 ehci.asm
字号:
and ax, BIT2 + BIT3 ; Mask off unwanted bits
shr ax, 2
; AX = 0 or 1 or 2
; Convert AL to 5 if original value is 0, 4 if 1 and 3 if 2
mov ah, al
neg al
add al, 10
mov cl, al
xor ax, ax
inc ax
shl ax, cl
; AX Number of elements in the asynchronous list
; Store the value in the HCStruc
mov (HCStruc PTR [si]).wAsyncListSize, ax
; Set the max bulk data size
mov (HCStruc PTR [si]).dMaxBulkDataSize, MAX_EHCI_DATA_SIZE
; Initialize the frame list pointers
mov eax, EHCI_TERMINATE ; Value to initialize with
call USBMiscInitFrameList ; SI HCStruc pointer
; Write the base address of the Periodic Frame List to the PERIODIC BASE
; register
mov eax, (HCStruc PTR [si]).dHcdDataArea
EHCI_DWORD_WRITE_MEM si, EHCI_PERIODICLISTBASE, eax
;Initialize the periodic schedule
call EHCIInitializePeriodicSchedule ; SI HCStruc pointer
IF MKF_EHCI_ASYNC_BELL_SUPPORT
; Allocate and initialize an queue head for Async transfer
; Set the QHDummy as Async list head
mov al, USB_EHCI_QH_SIZE_BLK
call USBMem_Alloc
jz esErrorExit
mov pQHAsyncXfer, ax
mov bx, ax
mov (EHCI_QH PTR [bx]).dEndPntCap, QH_ONE_XFER
xor eax, eax
mov (EHCI_QH PTR [bx]).pFirstqTD, ax
inc eax ; EHCI_TERMINATE
mov (EHCI_QH PTR [bx]).dAltNextqTDPtr, eax
mov (EHCI_QH PTR [bx]).dNextqTDPtr, eax
; Assume as a high speed device
mov eax, QH_HIGH_SPEED ; 10b - High speed
; Use data toggle from qTD and this QH is the head of the queue
or eax, (QH_USE_QTD_DT OR QH_HEAD_OF_LIST)
or al, DUMMY_DEVICE_ADDR ; Endpoint is 0
; EAX[6:0] = Dev. Addr, EAX[7] = I bit(0) & EAX[11:8] = Endpoint (0)
mov (EHCI_QH PTR [bx]).dEndPntCharac, eax
; Set the ASYNCLISTADDR register to point to the QHDummy
movzx eax, bx
add eax, HcdGlobalDataArea
EHCI_DWORD_WRITE_MEM si, EHCI_ASYNCLISTADDR, eax
; Set next QH pointer to itself (circular link)
or eax, EHCI_QUEUE_HEAD
mov (EHCI_QH PTR [bx]).dLinkPointer, eax
mov (EHCI_QH PTR [bx]).bActive, TRUE
ENDIF ; IF MKF_EHCI_ASYNC_BELL_SUPPORT
; Allocate QH/qTD for QHControl, qTDControlSetup, qTDControlData,
; qTDControlStatus, QHBulk, qTDBulkData, QHInterrupt & qTDInterruptData (3 QH & 5 qTDs)
mov al, ((3 * USB_EHCI_QH_SIZE_BLK) + (5 * USB_EHCI_QTD_SIZE_BLK))
call USBMem_Alloc
jz esErrorExit
; Save the 2 QH and 4 qTDs in appropriate location
mov bx, (HCStruc PTR [si]).pDescriptorPtr
mov (EHCIDescriptors PTR [bx]).QHControl, ax
add ax, SIZE EHCI_QH
mov (EHCIDescriptors PTR [bx]).qTDControlSetup, ax
add ax, SIZE EHCI_QTD
mov (EHCIDescriptors PTR [bx]).qTDControlData, ax
add ax, SIZE EHCI_QTD
mov (EHCIDescriptors PTR [bx]).qTDControlStatus, ax
add ax, SIZE EHCI_QTD
mov (EHCIDescriptors PTR [bx]).QHBulk, ax
add ax, SIZE EHCI_QH
mov (EHCIDescriptors PTR [bx]).qTDBulkData, ax
add ax, SIZE EHCI_QTD
mov (EHCIDescriptors PTR [bx]).QHInterrupt, ax
add ax, SIZE EHCI_QH
mov (EHCIDescriptors PTR [bx]).qTDInterruptData, ax
; Schedule QHInterrupt to 1millisec schedule
sub ax, SIZE EHCI_QH
; AX - QHInterrupt
push edi
mov di, ax
; Intialize the queue head
xor eax, eax
inc eax
mov (EHCI_QH PTR [di]).dNextqTDPtr, eax
mov (EHCI_QH PTR [di]).dAltNextqTDPtr, eax
mov (EHCI_QH PTR [di]).dLinkPointer, eax
; Schedule the QHInterrupt to 1msec schedule
movzx edi, di
add edi, HcdGlobalDataArea
mov ax, EHCIDescriptors.QH1ms
call EHCIScheduleQH
pop edi
; Capture the HC IRQ to point to the common IRQ handler
; SI HCStruc pointer
call USBCaptureHCInterrupt
; Program the HC BIOS owned bit and return the legacy
; support register offset
mov al, 1 ; Set HC BIOS owned semaphore
call EHCIProgramLegacyRegisters
jz esLegacyDone
; AH Legacy register start offset
; If SMI mode is chosen then enable the SMI generation
IF MKF_USB_MODE EQ 2
add ah, 4
; Enable USB SMI, SMI on port change
xor ebx, ebx
mov bl, BIT0+BIT2
call write_pci_dword_far
ENDIF
esLegacyDone:
; Program chipset to enable USB interrupts
mov bx, (HCStruc PTR [si]).wBusDevFuncNum
mov ax, ((USB_ENABLE_INTERRUPT SHL 8) + USB_EHCI)
call USBPort_ProgramHardwareInterrupt
; Turn HC on
EHCI_DWORD_SET_MEM si, EHCI_USBCMD, \
(EHCI_RUNSTOP OR EHCI_INTTHRESHOLD OR EHCI_PER_SCHED_ENABLE)
; Disconnect all ports from companion HC (if any) and route them to EHCI
EHCI_DWORD_SET_MEM si, EHCI_CONFIGFLAG, BIT0
jmp esExit
esErrorExit:
xor eax, eax
jmp SHORT esRet
esExit:
; Set the HC state to running
or (HCStruc PTR [si]).bHCFlag, HC_STATE_RUNNING
mov eax, EHCI_DATA_AREA_SIZE
esRet:
IF MKF_USB_MODE NE 1
pop fs
ENDIF
pop edi
pop dx
pop cx
pop ebx
ret
EHCIStart ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: EHCIGetLegacySupportOffset
;
; Description: This function returns the PCI register offset for the legacy
; support in EHCI controller
;
; Input: DX PCI address of the EHCI host controller
; SI HCStruc pointer
;
; Output: ZR If the feature is not present
; NZ If the feature is present
; AH Legacy support capability offset
;
; Modified: AH only
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCIGetLegacySupportOffset PROC NEAR PUBLIC
push ebx
push eax
; Check whether EHCI extended capabilities pointer is present
mov eax, dHCCParams
eglso_CheckNext:
or ah, ah
jz eglso_Exit ; Not present
; Value in AH. Look for legacy support capability value
; DX PCI address of the HC
call read_pci_dword_far
cmp bl, 01h
je eglso_Found
; Pointer to the next capability pointer is in AH
jmp SHORT eglso_CheckNext
eglso_Found:
; AH Legacy support capability offset
mov bl, ah
; Clear zero flag
or sp, sp
eglso_Exit:
pop eax
mov ah, bl
pop ebx
ret
EHCIGetLegacySupportOffset ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: EHCIProgramLegacyRegisters
;
; Description: This function programs the EHCI legacy registers as per the
; input. Also this routine returns the PCI register offset
; for the legacy support in EHCI controller
;
; Input: AL 0 Reset HC BIOS owned bit
; 1 Set HC BIOS owned bit
; SI HCStruc pointer
;
; Output: ZR If the feature is not present
; NZ If the feature is present
; AH Legacy support capability offset
;
; Modified: CX, DX, EBX, AH
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCIProgramLegacyRegisters PROC NEAR SYSCALL
mov ch, al ; Save AL
; Get the PCI address for this HC
mov dx, (HCStruc PTR [si]).wBusDevFuncNum
; Get the legacy support register offset
; DX PCI address of the HC
call EHCIGetLegacySupportOffset
jz eplrLegacyDone
; AH Register offset. Save it in CL
mov cl, ah
; Program 'HC BIOS owned semaphore bit'
call read_pci_dword_far
; Reset bit 16
and ebx, NOT BIT16
or ch, ch
jz eplr_ProgramSemaphore
; Set bit 16
or ebx, BIT16
eplr_ProgramSemaphore:
call write_pci_dword_far
; Reset all enable bits and clear the status
mov ebx, 0FFFF0000h
mov ah, cl
push ax
add ah, 4
call write_pci_dword_far
pop ax
eplrLegacyDone:
ret
EHCIProgramLegacyRegisters ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: EHCIEnumeratePorts
;
; Description: This function enumerates the HC ports for devices
;
; Input: SI Host controller's HCStruc structure
; DS USB data area
;
; Output: None
;
; Modified: Nothing
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCIEnumeratePorts PROC NEAR SYSCALL PUBLIC
push eax
push ebx
push dx
EHCI_SET_FS_EDI
; Enable port power so that new devices can be detected.
; Check whether enumeration flag is set by us or by somebody else by checking
; local enum flag
cmp bEnumFlag, TRUE
je esPortEnumerationComplete ; Set by somebody else
mov bIgnoreConnectStsChng, TRUE
; Set enumeration flag and avoid hub port enumeration
mov bEnumFlag, TRUE
pushf
cli
; Check the root hub ports to see if a device is connected. If so, then
; call UsbHubPortChange to handle the attachment of a new device.
mov dl, 1 ; CL will count through port numbers
mov ebx, EHCI_PORTSC ; Port Status and Control Register (44h)
mov dh, (HCStruc PTR [si]).bHCNumber
or dh, BIT7 ; Indicate as root hub
esInitRootHubNextPort:
; Enable port power
EHCI_DWORD_SET_MEM si, ebx, EHCI_PORTPOWER
; Delay till the port power is stabilised
mov ax, ((100 * 1000) / 15) ; 100ms delay
call USBMisc_FixedDelay
; Process device connect/disconnect
; Note: port connect status is cleared while processing
; connect/disconnect (EHCIGetRootHubStatus)
; DH HC number
; DL port number
; SI HCStruc pointer
call USBCheckPortChange
add bx, 4 ; BX = next root hub status port
inc dl ; CL = next port number
cmp dl, (HCStruc PTR [si]).bNumPorts
jbe esInitRootHubNextPort ;Br if still more ports to check
; Clear the EHCI_PCD bit of the interrupt status register EHCI_USBSTS
EHCI_DWORD_WRITE_MEM si, EHCI_USBSTS, EHCI_PORT_CHANGE_DETECT
mov bIgnoreConnectStsChng, FALSE
; Reset enumeration flag and enable hub enumeration
mov bEnumFlag, FALSE
popf
esPortEnumerationComplete:
; Enable appropriate interrupts
EHCI_DWORD_WRITE_MEM si, EHCI_USBINTR, (EHCI_USBINT_EN + EHCI_PCDINT_EN)
RESTORE_FS_EDI
pop dx
pop ebx
pop eax
ret
EHCIEnumeratePorts ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: EHCICheckHCStatus
;
; Description: This function checks whether the host controller is still
; under BIOS
;
; Input: SI Host controller's HCStruc structure
; DS USB data area
;
; Output: ZR If the control is with the BIOS
; NZ If the control is not with the BIOS
;
; Modified: Nothing
;
; Referrals: HCDHeader, HCStruc
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCICheckHCStatus PROC NEAR
push eax
EHCI_SET_FS_EDI
; Check whether the controller is still under BIOS control
; Read the base address of the Periodic Frame List to the PERIODIC BASE
; register and compare with stored value
EHCI_DWORD_READ_MEM si, EHCI_PERIODICLISTBASE
and eax, (NOT 0FFFh)
RESTORE_FS_EDI
cmp eax, (HCStruc PTR [si]).dHcdDataArea
; ZR On success (Control is with BIOS)
; NZ On error
pop eax
ret
EHCICheckHCStatus ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: EHCIStop
;
; Description: This function stops the EHCI controller.
;
; Input: SI Host controller's HCStruc structure
; DS USB Data Area
;
; Output: None
;
; Modified: Nothing
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCIStop PROC NEAR SYSCALL PUBLIC
push ax
push bx
push dx
EHCI_SET_FS_EDI
; Check whether the control is with BIOS or not
call EHCICheckHCStatus
jnz esExit ; Control is with OS
; Disconnect all the devices connected to its ports
mov dl, 1 ; DL will count through port numbers
mov dh, (HCStruc PTR [si]).bHCNumber
or dh, BIT7 ; Indicate as root hub
esDisConnectNextPort:
; DH Hub/HC number
; DL Port number
; SI HCStruc pointer
call USBDisconnectDevice
inc dl ;CL = next port number
cmp dl, (HCStruc PTR [si]).bNumPorts
jbe esDisConnectNextPort ;Br if still more ports to check
; Stop the host controller (Reset bit 0)
EHCI_DWORD_RESET_MEM si, EHCI_USBCMD, EHCI_RUNSTOP
; Wait for 1ms
mov ax, ((1 * 1000) / 15) ; 1ms delay
call USBMisc_FixedDelay
; Reset the host controller
call EHCIResetHC ; SI - HCStruc
; ERROR CONDITION RETURNED IS NOT TAKEN CARE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -