📄 ehci.asm
字号:
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: EHCIBulkTransfer
;
; Description: This function executes a bulk transaction on the USB. The
; transfer may be either DATA_IN or DATA_OUT packets containing
; data sent from the host to the device or vice-versa. This
; function wil not return until the request either completes
; successfully or completes in error (due to time out, etc.)
; NOTE: Make sure that amount of bytes to transfer should not
; exceed MAX_EHCI_DATA_SIZE
;
; Input: SI DeviceInfo structure (if available else 0)
; DL Transfer direction
; Bit 7 : Data direction
; 0 Host sending data to device
; 1 Device sending data to host
; Bit 6-0 : Reserved
; EDI Buffer containing data to be sent to the device or
; buffer to be used to receive data. Value in 32 bit
; absolute address
; CX Number of bytes of data to be transferred in or out
; of the host controller
;
; Output: AX Amount of data transferred
;
; Modified: EAX
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCIBulkTransfer PROC NEAR SYSCALL PUBLIC USES EBX CX DX SI DI ES
LOCAL wMaxPkt:WORD, bEndp:BYTE, bDatToggle:BYTE, fpBUFFER:DWORD
; Get Bulk IN/OUT enpoint number, data sync value & max packet size
call USBMiscGetBulkEndPointInfo
; AX Max packet value
; BL Endpoint number
; BH Data sync value
; Store the appropriate max packet size and endpoint number
; in the local variables
mov wMaxPkt, ax
mov bEndp, bl
mov bDatToggle, bh
; Save the buffer value
mov fpBuffer, edi
; Get EHCIDescriptors pointer in BX
mov bx, (DeviceInfo PTR [si]).pHCStrucPtr
mov bx, (HCStruc PTR [bx]).pDescriptorPtr
; Get the QHBulk pointer in Di
mov di, (EHCIDescriptors PTR [bx]).QHBulk
; Set the QH's dNextqTDPtr field to bulk data qTD and dAltqTDPtr field to
; EHCI_TERMINATE. Also set QH's link pointer to itself
movzx eax, (EHCIDescriptors PTR [bx]).qTDBulkData
; Intialize the queue head
call EHCIInitializeQueueHead ; DI Queue head pointer
; Set the first qTD pointer
mov (EHCI_QH PTR [di]).pFirstqTD, ax
add eax, HcdGlobalDataArea
mov (EHCI_QH PTR [di]).dNextqTDPtr, eax
movzx eax, di
add eax, HcdGlobalDataArea
or eax, EHCI_QUEUE_HEAD
mov (EHCI_QH PTR [di]).dLinkPointer, eax
push bx ; Descriptor pointer
; Get device info pointer
movzx eax, (DeviceInfo PTR [si]).bDeviceAddress
movzx bx, bEndp
shl bx, 8
or ax, bx ; AX - Device address & Endpoint
; Set max packet size
movzx ebx, wMaxPkt
shl ebx, 16
or eax, ebx
; Set the data toggle control
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
; Set the device speed
; Reset the device speed bits
xor ebx, ebx
mov bl, (DeviceInfo PTR [si]).bEndpointSpeed
; BL = 00/01/10 for HI/LO/FULL
; Assume as a high speed device
or eax, QH_HIGH_SPEED ; 10b - High speed
; Check for high speed
or bl, bl
je ebtsSpeedFound ; Yes. HI-speed
and bl, 1 ; Mask off most-significant bit
shl bx, 12 ; EAX[12] = full/low speed flag
and eax, NOT QH_ENDPOINT_SPEED
or eax, ebx
push eax
push bx
mov bx, si
; Set the hub address and port number
call EHCI_GetHiSpeedHubPortNumber
; AX Hispeed hub port number & device number
shl eax, 16
or eax, BIT14 ; Split complete Xaction
or (EHCI_QH PTR [di]).dEndPntCap, eax
pop bx
pop eax
ebtsSpeedFound:
pop bx ; Descriptor pointer
; Update the AH's endpoint characteristcs field with the data formed
mov (EHCI_QH PTR [di]).dEndPntCharac, eax
; Fill the bulk data qTD with relevant information
; The token field will be set so
; Direction PID = QTD_OUT_TOKEN/QTD_IN_TOKEN,
; Size = size of the data,
; Data Toggle = bDatToggle,
; 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 di, (EHCIDescriptors PTR [bx]).qTDBulkData
mov (EHCI_QTD PTR [di]).dToken, QTD_IN_TOKEN OR \
QTD_IOC_BIT OR \
QTD_NO_ERRORS OR QTD_ACTIVE
test dl, BIT7
jnz ebtsInPacket ; Br if host sending data to device (OUT)
; OUT packet
mov (EHCI_QTD PTR [di]).dToken, QTD_OUT_TOKEN OR \
QTD_IOC_BIT OR \
QTD_NO_ERRORS OR QTD_DO_OUT OR QTD_ACTIVE
ebtsInPacket:
; Set the data toggle depending on the bDatToggle value
movzx eax, bDatToggle
shl eax, 31
or (EHCI_QTD PTR [di]).dToken, eax
; Set length
movzx eax, cx
shl eax, 16
or (EHCI_QTD PTR [di]).dToken, eax
; Update buffer pointers
mov eax, fpBuffer
; DI QTD pointer
; EAX Buffer address (32bit absolute)
; CX Size of the buffer
call EHCISetQTDBufferPointers
; Update next & alternate next qTD pointers
mov eax, EHCI_TERMINATE
mov (EHCI_QTD PTR [di]).dNextqTDPtr, eax
mov (EHCI_QTD PTR [di]).dAltNextqTDPtr, eax
push si
mov si, (DeviceInfo PTR [si]).pHCStrucPtr
EHCI_SET_FS_EDI
mov bx, (EHCIDescriptors PTR [bx]).QHBulk
; bx - Pointer to QHBulk
IF MKF_EHCI_ASYNC_BELL_SUPPORT
; EAX = EHCI_TERMINATE
mov (EHCI_QH PTR [bx]).dLinkPointer, eax
; Insert the QHBulk 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
ELSE
; Set the ASYNCLISTADDR register to point to the QHBulk
movzx eax, bx
add eax, HcdGlobalDataArea
EHCI_DWORD_WRITE_MEM si, EHCI_ASYNCLISTADDR, eax
ENDIF
mov (EHCI_QH PTR [bx]).bActive, TRUE
; Now put the bulk QH 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
; Set bulk condition as not stalled
and bLastCommandStatus, NOT (USB_BULK_STALLED + USB_BULK_TIMEDOUT)
; Now wait for bulk transaction to be complete
; the EHCIProcessInterrupt will set its active flag to FALSE.
; Now wait for the bulk transfer to complete
; SI HCStruc pointer
; BX QH to wait for
call EHCIWaitForTransferComplete
IF MKF_EHCI_ASYNC_BELL_SUPPORT
; Disconnect QHBulk from the Async list
; BX Pointer to the QHControl
call EHCIRemoveQHFromAsyncList
ENDIF
mov ax, bx ; To test the error condition
; Check whether the QH stopped or timed out
cmp (EHCI_QH PTR [bx]).bActive, FALSE
je ebtsCheckError
IFE MKF_EHCI_ASYNC_BELL_SUPPORT
; Stop the Async transfer
call EHCIStopAsyncSchedule ; SI HCStruc pointer
ENDIF
mov (EHCI_QH PTR [bx]).bActive, FALSE
; Set time out status
or bLastCommandStatus, USB_BULK_TIMEDOUT
jmp SHORT ebtsXferError
ebtsCheckError:
; Check for the error conditions - if possible recover from them
test (EHCI_QH PTR [bx]).bErrorStatus, QTD_HALTED
jz ebtsXferOkay
; Reset time out status
and bLastCommandStatus, NOT USB_BULK_TIMEDOUT
; Stall condition is checked and cleared elsewhere
or bLastCommandStatus, USB_BULK_STALLED
ebtsXferError:
xor ax, ax ; Error
ebtsXferOkay:
RESTORE_FS_EDI
pop si ; Device info structure
or ax, ax
jz ebtsExit
push cx
; Update the data toggle value into the mass info structure
mov eax, (EHCI_QH PTR [bx]).dToken
and eax, QH_DATA_TOGGLE
shr eax, 31
and al, 1 ; Mask off top bits
mov cl, al
; SI DeviceInfo structure
; DL Xfer direction
; CL Data toggle value
call USBMiscUpdateBulkDataSync
pop cx
ebtsSuccess:
; Get the size of data transferred
; Size transferred is calculated by subtracting end address with current
; buffer pointer and subtracting that value from the total size
; Get the first qTD pointer
mov di, (EHCI_QH PTR [bx]).pFirstqTD
mov eax, (EHCI_QTD PTR [di]).dToken
and eax, NOT QTD_DATA_TOGGLE ; Reset data toggle bit
shr eax, 16
or ax, ax
jz ebtsFoundSize
sub cx, ax
ebtsFoundSize:
mov ax, cx
ebtsExit:
push ax
xor eax, eax
mov (EHCI_QH PTR [bx]).pFirstqTD, ax
inc eax
mov (EHCI_QH PTR [bx]).dNextqTDPtr, eax
pop ax
ret
EHCIBulkTransfer ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: EHCIInterruptTransfer
;
; Description: This function executes an interrupt transaction on the USB.
; The data transfer direction is always DATA_IN. This
; function wil not return until the request either completes
; successfully or completes in error (due to time out, etc.)
;
; Input: DI Pointer to HCStruc of the host controller
; SI DeviceInfo structure
; DX Buffer containing data to be sent to the device or
; buffer to be used to receive data
; CX number of bytes of data to be transferred in
;
;
; Output: AX 0xFFFF SUCCESS
; AX 0 ERROR
;
; Modified: EAX
;
; Notes: DO NOT TOUCH THE LINK POINTER OF THE TDInterruptData. It is
; statically allocated and linked with other items in the
; 1ms schedule
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
EHCIInterruptTransfer PROC NEAR SYSCALL PUBLIC USES EBX CX EDX SI DI
LOCAL bDatToggle:BYTE
push fs
push eax
; Change Seg:Off in fpBuffer to 32 bit absolute address
mov ax, ds
movzx eax, ax
shl eax, 4
movzx edx, dx
add edx, eax
mov al, (DeviceInfo PTR [si]).bDataSync
and al, USB_INT_DATA_SYNC
shr al, USB_INT_DATA_SYNC_SHIFT
mov bDatToggle, al
mov bx, (HCStruc PTR [di]).pDescriptorPtr
; Get the QHInterrupt pointer in Di
mov di, (EHCIDescriptors PTR [bx]).QHInterrupt
mov (EHCI_QH PTR [di]).pCallBackFunc, 0FFFFh
push bx ; Descriptor pointer
; Get device info pointer
movzx eax, (DeviceInfo PTR [si]).bDeviceAddress
movzx bx, (DeviceInfo PTR [si]).bIntEndpoint
shl bx, 8
or ax, bx ; AX - Device address & Endpoint
; Set max packet size
movzx ebx, (DeviceInfo PTR [si]).wIntMaxPkt
shl ebx, 16
or eax, ebx
; Set the data toggle control
or eax, (QH_USE_QTD_DT OR QH_HEAD_OF_LIST)
; Set the device speed
; Reset the device speed bits
xor ebx, ebx
mov bl, (DeviceInfo PTR [si]).bEndpointSpeed
; BL = 00/01/10 for HI/LO/FULL
; Assume as a high speed device
or eax, QH_HIGH_SPEED ; 10b - High speed
; Check for high speed
or bl, bl
je eitsSpeedFound ; Yes. HI-speed
and bl, 1 ; Mask off most-significant bit
shl bx, 12 ; EAX[12] = full/low speed flag
and eax, NOT QH_ENDPOINT_SPEED
or eax, ebx
push eax
push bx
mov bx, si
; Set the hub address and port number
call EHCI_GetHiSpeedHubPortNumber
; AX Hispeed hub port number & device number
shl eax, 16
or eax, (BIT10 + BIT11 + BIT12) ; Split complete Xaction
or (EHCI_QH PTR [di]).dEndPntCap, eax
pop bx
pop eax
eitsSpeedFound:
pop bx ; Descriptor pointer
; Update the AH's endpoint characteristcs field with the data formed
mov (EHCI_QH PTR [di]).dEndPntCharac, eax
or (EHCI_QH PTR [di]).dEndPntCap, (BIT0 OR QH_ONE_XFER)
; Interrupt schedule mask
; Fill the interrupt data qTD with relevant information
; The token field will be set so
; Direction PID = QTD_IN_TOKEN,
; Size = size of the data,
; Data Toggle = bDatToggle,
; Error Count = QTD_NO_ERRORS,
; Status code = QTD_ACTIVE
; The buffer pointers field will point to the EDX
; 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 di, (EHCIDescriptors PTR [bx]).qTDInterruptData
mov (EHCI_QTD PTR [di]).dToken, QTD_IN_TOKEN OR \
QTD_IOC_BIT OR \
QTD_NO_ERRORS OR QTD_ACTIVE
; Set the data toggle depending on the bDatToggle value
movzx eax, bDatToggle
shl eax, 31
or (EHCI_QTD PTR [di]).dToken, eax
; Set length
movzx eax, cx
shl eax, 16
or (EHCI_QTD PTR [di]).dToken, eax
; Update buffer poin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -