📄 uhci.asm
字号:
mov di, pSetup
movzx eax, pStatus
add eax, HcdGlobalDataArea ; EAX = Pointer to next TD
mov (UHCI_TD PTR [di]).LinkPointer, eax
; Fill common control transfer fields (ControlStatus, call back routine,
; CSReloadValue and Active flag fields)
call UHCI_FillCntrlXferFields ; BX-DevInfo, DI-TD
mov eax, dTemp
; EAX[18:8] = Device address / endpoint
or eax, SETUP_PACKET OR ((SIZE DeviceRequest - 1) shl 21)
; Set PID=Setup, and MaxLen
mov (UHCI_TD PTR [di]).Token, eax
lea ax, (UHCI_TD PTR [di]).DataArea ; AX = PTR to TDs data buffer
movzx eax, ax ;Clear upper half of EAX
add eax, HcdGlobalDataArea ;EAX = abs addr of TD's data buffer
mov (UHCI_TD PTR [di]).BufferPointer, eax
; Fill in various fields in the control data TD. Enough control data TDs
; must be initialized to handle the amount of data expected. The length
; of the data transfer is currently in wLength.
; LinkPointer field will be set to the next data TD or the status TD.
; ControlStatus field will be se to active and interrupt on complete.
; Token field will contain the data transfer size (still in wLength), device
; address (in pDevInfo), endpoint (in dTemp), and an in or out PID
; (in wReqType).
; BufferPointer field will point to the data buffer passed in by the
; caller (currently in EDX).
; CSReloadValue field will contain 0 because this is a "one shot" packet.
; pCallback will be set to point to the UHCI_ControlTDCallback routine.
; ActiveFlag field will be set to TRUE.
mov di, pSetup ; DI - Pointer to control
; Setup TD
cmp wLength, 0
jz UCT_SkipDataTds ; No data to transfer
cmp wLength, MAX_CONTROL_DATA_SIZE
jb UCT_DataSizeOkay ; Data size within limit
mov wLength, MAX_CONTROL_DATA_SIZE ; Limit the data size
UCT_DataSizeOkay:
; DI = PTR of TD control data
mov bDatToggle, 1 ; Start with a data 1 token
UCT_NextDataTd:
;; Allocate one more TD to be used either for more data or for TD Status
call USBMem_AllocOne
jz UCT_ErrorExit
; Check whether this is the first data TD
cmp pDataTd, 0
jne UCT_NotFirst
; Yes. It is the first TD store it in the local variable
mov pDataTd, ax
UCT_NotFirst:
; Link the new TD to the previous TD
push ax
movzx eax, ax
add eax, HcdGlobalDataArea
; Set the vertical flag
or eax, UHCI_VERTICAL_FLAG
mov (UHCI_TD PTR [di]).LinkPointer, eax
pop ax
mov di, ax ; Points to new TD
mov (UHCI_TD PTR [di]).BufferPointer, edx
movzx eax, wLength ; wLength = data length
cmp ax, (DeviceInfo PTR [bx]).wEndp0MaxPacket
jbe UCT_PktSizeAdjusted ; Packet size is valid
mov ax, (DeviceInfo PTR [bx]).wEndp0MaxPacket
UCT_PktSizeAdjusted:
sub wLength, ax ; Adjust overall data size
add edx, eax ; Adjust buffer pointer
dec ax ; AX = packet data size - 1
shl eax, 21
or eax, dTemp ; EAX[18:8]=Dev. addr & endp
mov al, OUT_PACKET ; EAX[7:0] = OUT PID
test (DeviceInfo PTR [bx]).CntrlXfer.wRequest, BIT7
jz UCT_PIDFound ; OUT PID
mov al, IN_PACKET ; EAX[7:0] = IN PID
UCT_PIDFound:
test bDatToggle, 1
jz UCT_DataToggle ; DATA0 packet
or eax, DATA_TOGGLE ; Make packet into a data 1
UCT_DataToggle:
mov (UHCI_TD PTR [di]).Token, eax
; Fill common control transfer fields (ControlStatus, call back routine,
; CSReloadValue and Active flag fields)
call UHCI_FillCntrlXferFields ; BX-DevInfo, DI-TD
; Enable short packet detect
or (UHCI_TD PTR [di]).ControlStatus, UHCI_TD_SHORT_PACKET_DETECT
xor bDatToggle, 1 ; Toggle between DATA1/DATA0
cmp wLength, 0
jnz UCT_NextDataTd ; More data TDs must be built
;; End the data TD list
mov (UHCI_TD PTR [di]).LinkPointer, UHCI_TERMINATE
; Make the end of the data TD list to point to the TD control status
movzx eax, pStatus
add eax, HcdGlobalDataArea
mov (UHCI_TD PTR [di]).LinkPointer, eax
UCT_SkipDataTds:
; DI = PTR of TD control status
mov di, pStatus
; Fill in various fields in the TD control status.
; LinkPointer field will point to UHCI_TERMINATE.
; ControlStatus field will be set to active and interrupt on complete.
; Token field will contain the packet size (0), the device address,
; endpoint, and a setup PID with opposite data direction as that defined
; in the request type (wReqType).
; BufferPointer field will point to the TD's DataArea buffer even though
; we are not expecting any data transfer.
; CSReloadValue field will contain 0 because this is a "one shot" packet.
; pCallback will be set to point to the UHCI_ControlTDCallback routine.
; ActiveFlag field will be set to TRUE.
mov (UHCI_TD PTR [di]).LinkPointer, UHCI_TERMINATE
mov eax, dTemp ; EAX[18:8] = Device address / endpoint
mov al, OUT_PACKET ; EAX[7:0] = OUT PID
test (DeviceInfo PTR [bx]).CntrlXfer.wRequest, BIT7
jnz UCT_StatPIDFound ; IN PID
mov al, IN_PACKET ; EAX[7:0] = IN PID
UCT_StatPIDFound:
or eax, (DATA_TOGGLE OR (UHCI_TD_DATA_LENGTH SHL 21)) ; DATA0/DATA1
mov (UHCI_TD PTR [di]).Token, eax
lea ax, (UHCI_TD PTR [di]).DataArea ; AX = PTR to TD's data buffer
movzx eax, ax ; Clear upper half of EAX
add eax, HcdGlobalDataArea ; EAX = abs addr of TD's data buffer
mov (UHCI_TD PTR [di]).BufferPointer, eax
; Fill common control transfer fields (ControlStatus, call back routine,
; CSReloadValue and Active flag fields)
call UHCI_FillCntrlXferFields ; BX-DevInfo, DI-TD
mov pStatus, di ; Save pointer to control status TD
mov di, pSetup ; Control setup TD
; Now put the control setup, data and status into the HC's schedule by
; pointing QhControl's link pointer to control setup TD.
; This will cause the HC to execute the transaction in the next active frame.
mov si, (DeviceInfo PTR [bx]).pHCStrucPtr
mov si, (HCStruc PTR [si]).pDescriptorPtr
; BX - Device Info
; SI - UHCIDescriptor pointer
; DI - Control setup TD
; Save control setup address in UHCIDescriptors
mov ax, pSetup
mov (UHCIDescriptors PTR [si]).TDControlSetup, ax
; Save control status address in UHCIDescriptors
mov ax, pStatus
mov (UHCIDescriptors PTR [si]).TDControlStatus, ax
mov si, (UHCIDescriptors PTR [si]).QHControl
movzx edi, di
add edi, HcdGlobalDataArea
mov (UHCI_QH PTR [si]).ElementPointer, edi
; Now wait for the control status TD to complete. When it has completed,
; the UHCI_ControlTDCallback will set its active flag to FALSE.
mov di, pStatus ; Control status TD pointer
; BX - DeviceInfo Ptr, DI - TD to wait on
call UHCIWaitForTransferComplete
; SI - HCStruc Ptr (returned from )
; Remove the control setup, data, and status TDs from the
; HC's schedule by pointing QhControl's link pointer to UHCI_TERMINATE.
push di
mov di, (HCStruc PTR [si]).pDescriptorPtr
mov bx, (UHCIDescriptors PTR [di]).TDControlSetup
; Set control setup and status pointers to zero
xor ax, ax
mov (UHCIDescriptors PTR [di]).TDControlSetup, ax
mov (UHCIDescriptors PTR [di]).TDControlStatus, ax
mov di, (UHCIDescriptors PTR [di]).QHControl
mov (UHCI_QH PTR [di]).ElementPointer, UHCI_TERMINATE
pop di
; Clear the stalled condition flag
and bLastCommandStatus, NOT USB_CONTROL_STALLED
; Check for stall condition
test (UHCI_TD PTR [di]).ControlStatus, UHCI_TD_STALLED
jz uct_NotStalled
; Command stalled set the error bit appropriately
or bLastCommandStatus, USB_CONTROL_STALLED
uct_NotStalled:
; Finally check for any error bits set in both the TdControlStatus.
; If the TD did not complete successfully, return errors status.
test (UHCI_TD PTR [di]).ControlStatus, (UHCI_TD_BITSTUFF_ERROR OR \
UHCI_TD_CRC_TIMEOUT_ERROR OR UHCI_TD_NAK_RECEIVED OR \
UHCI_TD_BABBLE_DETECTED OR UHCI_TD_DATA_BUFFER_ERROR OR UHCI_TD_STALLED)
jnz UCT_ErrorExit ; Br if any error bits set in status
mov wRetStatus, 0FFFFh ; return success
UCT_ErrorExit:
; BX - pointer to the control setup
; Free control setup TD (in BX)
call USBMem_FreeOne
add bx, SIZE UHCI_TD
; Free control status TD (in BX)
call USBMem_FreeOne
; Free control data TDs
mov ax, pDataTD
call UHCI_FreeTD
UCT_Exit:
popad
pop es
mov ax, wRetStatus ; Return return status
ret
UHCI_ControlTransfer ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: UHCI_BulkTransfer
;
; 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 with error (due to time out, etc.)
;
; 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
;
; Notes: Make sure that amount of bytes to transfer should not exceed
; MAX_UHCI_BULK_DATA_SIZE
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
UHCI_BulkTransfer PROC NEAR SYSCALL PUBLIC USES EBX CX DX SI DI
LOCAL dTemp:DWORD, bDatToggle:BYTE, wRetStatus:WORD, wMaxPkt:WORD,
bEndp:BYTE, bNumBulkTD:BYTE, pBulkDataTD
; Set return status as failure
mov wRetStatus, 0
; Check for 0 length transfer (if so, exit)
or cx, cx
jz UBTS_Exit
; 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
push dx ; Save transfer direction
; Calculate number of TDs needed
mov ax, cx
xor dx, dx
div wMaxPkt
or dx, dx
jz UBTS_NoRemainder
; Adjust number of TDs needed
inc ax
UBTS_NoRemainder:
pop dx ; Restore transfer direction
; AX = Number of TDs needed. Save it in a local variable
mov bNumBulkTD, al
; Allocate required TDs for bulk transfer
call USBMem_Alloc
jz UBTS_Exit
mov pBulkDataTD, ax
; Form device address and endpoint in proper order and bit position
movzx eax, bEndp ; EAX[3:0] = Endpoint
shl eax, 7 ; EAX[10:7] = Endpoint
mov dTemp, eax
movzx eax, (DeviceInfo PTR [si]).bDeviceAddress
or eax, dTemp ; EAX[10:0] = Dev. Addr & Endpoint
shl eax, 8 ; EAX[18:8] = Dev. Addr & Endpoint
mov dTemp, eax
; Save the buffer pointer in EBX
mov ebx, edi ; Buffer pointer
; Form the bulk data TDs
mov di, pBulkDataTD
UBTS_PrepareNextBulkTD:
; Form pointer to the next TD and link it in the current TD
movzx eax, di
add eax, SIZE UHCI_TD
add eax, HcdGlobalDataArea
; Set the vertical flag
or eax, UHCI_VERTICAL_FLAG
mov (UHCI_TD PTR [di]).LinkPointer, eax
movzx eax, (DeviceInfo PTR [si]).bEndPointSpeed
; AL = 11/01/10 for HI/LO/FULL
and al, 1 ; Mask off MSH
shl eax, 26
or eax, (UHCI_TD_INTERRUPT_ON_COMPLETE OR UHCI_TD_THREE_ERRORS OR UHCI_TD_ACTIVE OR \
UHCI_TD_SHORT_PACKET_DETECT)
mov (UHCI_TD PTR [di]).ControlStatus, eax
mov (UHCI_TD PTR [di]).BufferPointer, ebx
; Adjust remaining length and buffer address
movzx eax, cx ; wLength = data length
cmp ax, wMaxPkt
jbe UBTS_PktSizeAdjusted ; Packet size is valid
mov ax, wMaxPkt
UBTS_PktSizeAdjusted:
sub cx, ax ; Adjust overall data size
add ebx, eax ; Adjust buffer pointer
dec ax ; AX = packet data size - 1
shl eax, 21
or eax, dTemp ; EAX[18:8]=Dev. addr & endp
mov al, OUT_PACKET ; EAX[7:0] = OUT PID
test dl, BIT7
jz UBTS_PIDFound ; OUT PID
mov al, IN_PACKET ; EAX[7:0] = IN PID
UBTS_PIDFound:
test bDatToggle, 1
jz UBTS_DataToggle ; DATA0 packet
or eax, DATA_TOGGLE ; Make packet into a data 1
UBTS_DataToggle:
mov (UHCI_TD PTR [di]).Token, eax
mov (UHCI_TD PTR [di]).CSReloadValue, 0
mov (UHCI_TD PTR [di]).pCallback, OFFSET cs:UHCI_BulkTDCallback
mov (UHCI_TD PTR [di]).ActiveFlag, TRUE
xor bDatToggle, 1 ; Toggle between DATA1/DATA0
; Position to next data TD
add di, SIZE UHCI_TD
; Check and build more data TDs
cmp cx, 0
jnz UBTS_PrepareNextBulkTD
; Position to the last TD
sub di, SIZE UHCI_TD
; End the data TD list
mov (UHCI_TD PTR [di]).LinkPointer, UHCI_TERMINATE
; Clear bulk stall/time out condition flag
and bLastCommandStatus, NOT (USB_BULK_STALLED + USB_BULK_TIMEDOUT)
; Schedule the bulk TDs by adding them in the bulk queue head
push di
mov bx, (DeviceInfo PTR [si]).pHCStrucPtr
mov bx, (HCStruc PTR [bx]).pDescriptorPtr
mov di, (UHCIDescriptors PTR [bx]).QHBulk
movzx eax, pBulkDataTD
; Save the bulk data TD pointer
mov (UHCIDescriptors PTR [bx]).TDBulkData, ax
add eax, HcdGlobalDataArea
; Set the vertical flag
or eax, UHCI_VERTICAL_FLAG
mov (UHCI_QH PTR [di]).ElementPointer, eax
pop di
; Wait for the last bulk data TD to complete. When the last TD completed its
; task the UHCI_BulkTDCallback routine will set its active flag to FALSE
xchg si, bx
; BX - DeviceInfo Ptr, DI - TD to wait on
call UHCIWaitForTransferComplete
; SI - HCStruc Ptr (returned from UHCIWaitForTransferComplete)
; Remove the bulk data TDs from the HC's schedule by pointing QhBulk
; link pointer to UHCI_TERMINATE.
push di
mov bx, (HCStruc PTR [si]).pDescriptorPtr
mov (UHCIDescriptors PTR [bx]).TDBulkData, 0
mov di, (UHCIDescriptors PTR [bx]).QHBulk
mov (UHCI_QH PTR [di]).ElementPointer, UHCI_TERMINATE
pop di
; Finally check for any error bits set in the ControlStatus field.
; If the TD did not complete successfully, return STC.
test (UHCI_TD PTR [di]).ControlStatus, (UHCI_TD_BITSTUFF_ERROR OR \
UHCI_TD_NAK_RECEIVED OR UHCI_TD_BABBLE_DETECTED OR \
UHCI_TD_DATA_BUFFER_ERROR)
jnz UBTS_ErrorExit ; Br if any error bits set in status
; Check for time out condition
test (UHCI_TD PTR [di]).ControlStatus, UHCI_TD_CRC_TIMEOUT_ERROR
jz UBTS_NotTimedOut
; Timed out condition is checked and cleared elsewhere
or bLastCommandStatus, USB_BULK_TIMEDOUT
jmp SHORT UBTS_ErrorExit
UBTS_NotTimedOut:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -