📄 ehci.asm
字号:
; shown below. In any case this routine will get the device
; address of the hub number HISP_A :
; Notations used:
; MBPortX Motherboard USB port
; HISP_X Hi-speed hub number X
; FUSP_X Full-speed hub number X
; Device Low/Full speed device
; Config 1:
; MBPortX --> HISP_A --> Device
; Config 2:
; MBPortX --> HISP_A --> FUSP_1 --> Device
; Config 3:
; MBPortX --> HISP_B --> HISP_A --> Device
; Config 4:
; MBPortX --> HISP_A --> FUSP_1 --> HISP_B --> Device
; In the above configuration the HISP_B will be operated in
; full speed rather than hi-speed since it is connected to a
; full speed hub
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCI_GetHiSpeedHubPortNumber PROC NEAR PUBLIC
push bx
push dx
eghshpn_TryNextHub:
; Get the device number of the immediate hub
mov dl, (DeviceInfo PTR [bx]).bHubDeviceNumber
; Get the device info structure for this device number
call USBGetDeviceInfoFromDevAddr ; DL device number
; AX Pointer to the device info structure
or ax, ax
jz eghshpn_Exit
xchg bx, ax
; Check whether the hub is a USB 2.0 hub
cmp (DeviceInfo PTR [bx]).bEndpointSpeed, 0
jne eghshpn_TryNextHub
; The first USB 2.0 hub found to which the low/full speed device is connected
xchg bx, ax ; Restore the previous (USB 1.1) devices struc
movzx ax, (DeviceInfo PTR [bx]).bHubPortNumber
shl ax, 7
or al, (DeviceInfo PTR [bx]).bHubDeviceNumber
eghshpn_Exit:
pop dx
pop bx
ret
EHCI_GetHiSpeedHubPortNumber ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: EHCIControlTransfer
;
; Description: This function executes a device request command transaction
; on the USB. One setup packet is generated containing the
; device request parameters supplied by the caller. The setup
; packet may be followed by data in or data out packets
; containing data sent from the host to the device
; or vice-versa. This function will not return until the
; request either completes successfully or completes in error
; (due to time out, etc.)
;
; Input: BX DeviceInfo structure (if available else 0)
; The temp data area in the BX contains the following data:
; wRequest Request type (low byte)
; Bit 7 : Data direction
; 0 = Host sending data to device
; 1 = Device sending data to host
; Bit 6-5 : Type
; 00 = Standard USB request
; 01 = Class specific
; 10 = Vendor specific
; 11 = Reserved
; Bit 4-0 : Recipient
; 00000 = Device
; 00001 = Interface
; 00010 = Endpoint
; 00100 - 11111 = Reserved
; Request code (high byte), a one byte code
; describing the actual device request to be
; executed (ex: Get Configuration, Set Address, etc.)
; wIndex wIndex request parameter (meaning varies)
; wValue wValue request parameter (meaning varies)
; fpBuffer Buffer containing data to be sent to the
; device or buffer to be used to receive data
; wLength wLength request parameter, number of bytes
; of data to be transferred in or out
; of the host controller
;
; Output: AX 0xFFFF SUCCESS
; AX 0 ERROR
;
; Modified: EAX
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCIControlTransfer PROC NEAR SYSCALL PUBLIC
LOCAL wLength:WORD
push bx
push cx
push edx
push si
push di
; Setup the local variables
mov ax, (DeviceInfo PTR [bx]).CntrlXfer.wLength
mov wLength, ax
mov si, (DeviceInfo PTR [bx]).pHCStrucPtr
; Get the control setup TD address in register DI
mov di, (HCStruc PTR [si]).pDescriptorPtr
; Build the device request in the data area of the control setup qTD
push di
mov di, OFFSET aControlSetupData
call USBMiscFormDeviceRequest ; BX DeviceInfo structure
pop di
; Prepare the registers that will be used in building the qTDs below.
; BX will contain a pointer to the DeviceInfo structure for the given device.
; DI will be left free to use as a pointer to the qTD being built.
; EAX will be left free to use as a scratch register.
; Ready the QHControl for the control transfer
push di
mov di, (EHCIDescriptors PTR [di]).QHControl
; The QH endpoint characteristic field will be set so
; Function address & Endpoint number = From DeviceInfo structure,
; Direction = From TD,
; Speed = DeviceInfo.bEndpointSpeed,
; Skip = 1, Format = 0,
; Max packet size = DeviceInfo.wEndp0MaxPacket
; The dNextqTDPtr field will be set to qTDControlSetup
; The dAltNextqTDPtr field will be set to EHCI_TERMINATE
; The dCurrentqTDPtr field will be set to 0
; Intialize the queue head with null pointers
call EHCIInitializeQueueHead ; DI Queue head pointer
mov dl, (DeviceInfo PTR [bx]).bEndpointSpeed
; DL = 00/01/10 for HI/LO/FULL
; Assume as a high speed device
mov eax, QH_HIGH_SPEED ; 10b - High speed
; Check for high speed
or dl, dl
je ectSpeedFound ; Yes. HI-speed
mov al, dl
and al, 1 ; Mask off most-significant bit
shl ax, 12 ; EAX[12] = full/low speed flag
; Set bit15 to indicate that it is not a high speed device and the transfer
; is a control transfer
or eax, QH_CONTROL_ENDPOINT
push eax
; Set the hub address and port number
call EHCI_GetHiSpeedHubPortNumber
; AX Hispeed hub port number & device number
shl eax, 16
;; or eax, BIT15 ; Split complete Xaction
or eax, BIT10+BIT11+BIT12 ; Split complete Xaction
or (EHCI_QH PTR [di]).dEndPntCap, eax
pop eax
ectSpeedFound:
; Use data toggle from qTD and this QH is the head of the queue
IF MKF_EHCI_ASYNC_BELL_SUPPORT
or eax, QH_USE_QTD_DT
ELSE
or eax, (QH_USE_QTD_DT OR QH_HEAD_OF_LIST)
ENDIF ;; MKF_EHCI_ASYNC_BELL_SUPPORT
or al, (DeviceInfo PTR [bx]).bDeviceAddress
; EAX[6:0] = Dev. Addr, EAX[7] = I bit(0) & EAX[11:8] = Endpoint (0)
mov dx, (DeviceInfo PTR [bx]).wEndp0MaxPacket
shl edx, 16 ; EDX[26:16] = device's packet size
or eax, edx
mov (EHCI_QH PTR [di]).dEndPntCharac, eax
; Pointers in QH are initialized later
pop di
; Fill in various fields in the qTDControlSetup.
push di
mov di, (EHCIDescriptors PTR [di]).qTDControlSetup
; DI - Pointer to TDControlSetup
; The token field will be set so
; Direction PID = QTD_SETUP_TOKEN,
; Size = size of the data,
; Data Toggle = QTD_SETUP_TOGGLE,
; Error Count = QTD_NO_ERRORS,
; Status code = QTD_DO_OUT + QTD_ACTIVE
; The buffer pointers field will point to the aControlSetupData buffer
; which was before initialized to contain a DeviceRequest struc.
; The dNextqTDPtr field will point to the qTDControlData if data will
; be sent/received or to the qTDControlStatus if no data is expected.
; The dAltNextqTDPtr field will be set to EHCI_TERMINATE
mov (EHCI_QTD PTR [di]).dToken, QTD_SETUP_TOKEN OR \
QTD_SETUP_TOGGLE OR QTD_IOC_BIT OR \
QTD_NO_ERRORS OR QTD_DO_OUT OR QTD_ACTIVE \
(8 SHL 16) ; Data size
; Update buffer pointers
mov eax, OFFSET aControlSetupData
; EAX = Pointer to setup data
add eax, HcdGlobalDataArea ; EAX = abs addr of TD's 8 byte data buffer
mov cx, 8
; DI QTD pointer
; EAX Buffer address (32bit absolute)
; CX Size of the buffer
call EHCISetQTDBufferPointers
pop di
cmp wLength, 0
jz ectSkipDataTds ; No data to transfer
; Fill in various fields in the qTDControlData
push di
mov di, (EHCIDescriptors PTR [di]).qTDControlData
; DI - Pointer to TDControlData
; The token field will be set so
; Direction PID = QTD_OUT_TOKEN/QTD_IN_TOKEN,
; Size = size of the data,
; Data Toggle = QTD_DATA1_TOGGLE,
; Error Count = QTD_NO_ERRORS,
; Status code = QTD_DO_OUT(if it is out) + QTD_ACTIVE
; The buffer pointers field will point to the fpBuffer buffer
; which was before initialized to contain a DeviceRequest struc.
; The dNextqTDPtr field will point to the qTDControlSetup
; The dAltNextqTDPtr field will be set to EHCI_TERMINATE
mov (EHCI_QTD PTR [di]).dToken, QTD_IN_TOKEN OR \
QTD_DATA1_TOGGLE OR QTD_IOC_BIT OR \
QTD_NO_ERRORS OR QTD_ACTIVE
test (DeviceInfo PTR [bx]).CntrlXfer.wRequest, BIT7
jnz ectInPacket ; Br if host sending data to device (OUT)
; OUT packet
mov (EHCI_QTD PTR [di]).dToken, QTD_OUT_TOKEN OR \
QTD_DATA1_TOGGLE OR QTD_IOC_BIT OR \
QTD_NO_ERRORS OR QTD_DO_OUT OR QTD_ACTIVE
ectInPacket:
; Set length
mov ax, wLength
mov cx, ax ; Needed later
shl eax, 16
or (EHCI_QTD PTR [di]).dToken, eax
; Change Seg:Off in fpBuffer to 32 bit absolute address
call USBMiscGetFarBufferAddress ; BX DevInfo
; Return value in EDX
mov eax, edx
; Update buffer pointers
; DI QTD pointer
; EAX Buffer address (32bit absolute)
; CX Size of the buffer
call EHCISetQTDBufferPointers
pop di
ectSkipDataTds:
; Fill in various fields in the qTDControlStatus
push di
mov di, (EHCIDescriptors PTR [di]).qTDControlStatus
; DI - Pointer to TDControlStatus
; The token field will be set so
; Direction PID = QTD_OUT_TOKEN/QTD_IN_TOKEN,
; Size = 0,
; Data Toggle = QTD_DATA1_TOGGLE,
; Error Count = QTD_NO_ERRORS,
; Status code = QTD_DO_OUT(if it is out) + QTD_ACTIVE
; The buffer pointers field will be 0
; The dNextqTDPtr field will set to EHCI_TERMINATE
; The dAltNextqTDPtr field will be set to EHCI_TERMINATE
; For OUT control transfer status should be IN and
; for IN cotrol transfer, status should be OUT
mov (EHCI_QTD PTR [di]).dToken, QTD_IN_TOKEN OR \
QTD_DATA1_TOGGLE OR QTD_IOC_BIT OR \
QTD_NO_ERRORS OR QTD_ACTIVE
test (DeviceInfo PTR [bx]).CntrlXfer.wRequest, BIT7
jz ectInPacket0 ; Br if host sending data to device (OUT)
; OUT packet
mov (EHCI_QTD PTR [di]).dToken, QTD_OUT_TOKEN OR \
QTD_DATA1_TOGGLE OR QTD_IOC_BIT OR \
QTD_NO_ERRORS OR QTD_DO_OUT OR QTD_ACTIVE
ectInPacket0:
; Update buffer pointers (with null values)
; DI QTD pointer
; EAX Buffer address (32bit absolute)
; CX Size of the buffer
xor cx, cx
call EHCISetQTDBufferPointers
pop di ; Control setup TD
; Link the qTD formed now and connect them with the control queue head
push bx
push si
mov bx, (EHCIDescriptors PTR [di]).QHControl
mov si, (EHCIDescriptors PTR [di]).qTDControlSetup
movzx eax, si
mov (EHCI_QH PTR [bx]).pFirstqTD, ax
add eax, HcdGlobalDataArea
mov (EHCI_QH PTR [bx]).dNextqTDPtr, eax
mov bx, (EHCIDescriptors PTR [di]).qTDControlData
; BX Offset of TDControlData
cmp wLength, 0
jnz ectNoData ; Br if data length is non-zero
mov bx, (EHCIDescriptors PTR [di]).qTDControlStatus
; BX Offset of TDControlStatus
ectNoData:
movzx eax, bx
add eax, HcdGlobalDataArea ; EAX 32bit absolute address
mov (EHCI_QTD PTR [si]).dNextqTDPtr, eax
cmp bx, (EHCIDescriptors PTR [di]).qTDControlData
jne ectTDLinkDone
movzx eax, (EHCIDescriptors PTR [di]).qTDControlStatus
push ax
add eax, HcdGlobalDataArea ; EAX 32bit absolute address
mov (EHCI_QTD PTR [bx]).dNextqTDPtr, eax
pop bx
ectTDLinkDone:
xor eax, eax
inc eax
mov (EHCI_QTD PTR [bx]).dNextqTDPtr, eax
pop si
pop bx
mov bx, (EHCIDescriptors PTR [di]).QHControl
; BX - Pointer to QHControl
IF MKF_EHCI_ASYNC_BELL_SUPPORT
; EAX = EHCI_TERMINATE
mov (EHCI_QH PTR [bx]).dLinkPointer, eax
mov (EHCI_QH PTR [bx]).bActive, TRUE
; Insert the QHControl into the Async list
mov ax, bx
add eax, HcdGlobalDataArea
or eax, EHCI_QUEUE_HEAD
push bx
mov bx, pQHAsyncXfer
xchg (EHCI_QH PTR [bx]).dLinkPointer, eax
pop bx
mov (EHCI_QH PTR [bx]).dLinkPointer, eax
ENDIF
EHCI_SET_FS_EDI
IFE MKF_EHCI_ASYNC_BELL_SUPPORT
; Set the ASYNCLISTADDR register to point to the QHControl
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
; Now put the control setup, data and status into the HC's schedule by
; setting the Async. schedule enabled field of USBCMD register
; This will cause the HC to execute the transaction in the next active frame.
call EHCIStartAsyncSchedule ; SI HCStruc pointer
; Now wait for the control transfer to complete
; SI HCStruc pointer
; BX QH to wait for
call EHCIWaitForTransferComplete
IF MKF_EHCI_ASYNC_BELL_SUPPORT
; Disconnect QHControl from the Async list
; BX Pointer to the QHControl
call EHCIRemoveQHFromAsyncList
ENDIF
; Clear the stalled condition flag
and bLastCommandStatus, NOT USB_CONTROL_STALLED
; Check whether the QH stopped or timed out
cmp (EHCI_QH PTR [bx]).bActive, FALSE
je ectXferCheckError
IFE MKF_EHCI_ASYNC_BELL_SUPPORT
; Stop the Async transfer
call EHCIStopAsyncSchedule ; SI HCStruc pointer
ENDIF
mov (EHCI_QH PTR [bx]).bActive, FALSE
xor ax, ax ; Error
jmp SHORT ectExit
ectXferCheckError:
; Check for the stall condition
test (EHCI_QH PTR [bx]).bErrorStatus, QTD_HALTED
jz ectXferOkay
; Command stalled set the error bit appropriately
or bLastCommandStatus, USB_CONTROL_STALLED
jmp SHORT ectExit
ectXferOkay:
mov ax, 0FFFFh ; Indicate success
ectExit:
push ax
xor eax, eax
mov (EHCI_QH PTR [bx]).pFirstqTD, ax
inc eax
mov (EHCI_QH PTR [bx]).dNextqTDPtr, eax
pop ax
RESTORE_FS_EDI
pop di
pop si
pop edx
pop cx
pop bx
ret
EHCIControlTransfer ENDP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -