📄 uhci_bb.asm
字号:
mov eax, dUHCIControlStatus
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, si
jbe UBBT_PktSizeAdjusted ; Packet size is valid
mov ax, si
UBBT_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, dUHCIToken
mov (UHCI_TD PTR [di]).Token, eax
mov (UHCI_TD PTR [di]).CSReloadValue, 0
mov (UHCI_TD PTR [di]).pCallback, OFFSET CS:UHCIBB_BulkTDCallback
mov (UHCI_TD PTR [di]).ActiveFlag, TRUE
xor dUHCIToken, DATA_TOGGLE ; Toggle between DATA1/DATA0
; Position to next data TD
add di, SIZE UHCI_TD
; Check and build more data TDs
cmp cx, 0
jnz UBBT_PrepareNextBulkTD
; Position to the last TD
sub di, SIZE UHCI_TD
; End the data TD list
mov (UHCI_TD PTR [di]).LinkPointer, UHCI_TERMINATE
; Update the data toggle value into the mass info structure
mov cl, 1
test dUHCIToken, DATA_TOGGLE ; Toggle between DATA1/DATA0
jnz UBBT_UpdateToggle
dec cl ; CL = 0
UBBT_UpdateToggle:
; DL Xfer direction
; CL Data toggle value
call USBMBB_UpdateBulkDataSync
; Clear bulk stall condition flag
mov bLastBulkCommandStalled, FALSE
; Schedule the bulk TDs by adding them in the bulk queue head
push di
mov di, OFFSET QHControl
mov eax, OFFSET TDData
; Save the bulk data TD pointer
add eax, dGlobalDataArea
; 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
call UHCIBB_WaitForTransferComplete
; SI - HCStruc Ptr (returned from UHCIWaitForTransferComplete)
; Remove the bulk data TDs from the HC's schedule by pointing QHControl
; element pointer to TERMINATE.
push di
mov di, OFFSET QHControl
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_CRC_TIMEOUT_ERROR OR UHCI_TD_NAK_RECEIVED OR \
UHCI_TD_BABBLE_DETECTED OR UHCI_TD_DATA_BUFFER_ERROR)
jnz UBBT_ErrorExit ; Br if any error bits set in status
; Check for endpoint STALL condition
test (UHCI_TD PTR [di]).ControlStatus, UHCI_TD_STALLED
jz UBBT_NotStalled
; Bulk stall condition is checked and cleared elsewhere
mov bLastBulkCommandStalled, TRUE
jmp SHORT UBBT_ErrorExit
UBBT_NotStalled:
; Calculate amount of data transferred and return the value
mov di, OFFSET TDData
xor cx, cx
UBBT_NextTD:
mov eax, (UHCI_TD PTR [di]).ControlStatus
and ax, UHCI_TD_DATA_LENGTH ; AX = actual byte count - 1
or ax, ax ; Assume zero as zero!!!!
jnz UBBT_Cnt
; Check for short packet detect
test eax, UHCI_TD_SHORT_PACKET_DETECT
jnz UBBT_SizeOkay
UBBT_Cnt:
inc ax
cmp ax, (UHCI_TD_DATA_LENGTH+1) ; (07FFh + 1)
jne UBBT_SizeOkay
; Zero length. Set ax accordingly
xor ax, ax
UBBT_SizeOkay:
; Add to total size transferred
add cx, ax
mov ebx, (UHCI_TD PTR [di]).LinkPointer
test ebx, UHCI_TERMINATE
jnz UBBT_EndLoop
; Mask off low order bits
and bl, NOT UHCI_VERTICAL_FLAG
sub ebx, dGlobalDataArea ; Point to next TD
mov di, bx
jmp SHORT UBBT_NextTD
UBBT_EndLoop:
push cx
pop fs
UBBT_Success:
or sp, sp
jmp SHORT UBBT_Exit
UBBT_ErrorExit:
; Set the error flags
cmp sp, sp
UBBT_Exit:
popad
mov ax, fs
pop fs
ret
UHCIBB_BulkTransfer ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: UHCIBB_InterruptTransfer
;
; 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: 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: ZR On error
; NZ On success
;
; Modified: EAX
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
UHCIBB_InterruptTransfer PROC NEAR PUBLIC
push eax
push ecx
push edx
push di
; Change Seg:Off in fpBuffer to 32 bit absolute address
push ds
pop ax
shl eax, 4
movzx edx, dx
add edx, eax
; Check for 0 length transfer (if so, exit)
or cx, cx
je UIT_Exit
mov di, OFFSET TDData
mov (UHCI_TD PTR [di]).ActiveFlag, FALSE
; Set the endpoint speed
movzx eax, CurrentDevice.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)
mov (UHCI_TD PTR [di]).ControlStatus, eax
; Set the buffer pointer
mov (UHCI_TD PTR [di]).BufferPointer, edx
xor edx, edx
; Now EDX is free form the device address in it
mov dl, CurrentDevice.bDeviceAddress
; EDX[6:0] = Device address
; Form device address and endpoint in proper order and bit position
movzx eax, CurrentDevice.bIntEndpoint
; EAX[3:0] = Endpoint
shl eax, 7 ; EAX[10:7] = Endpoint
or edx, eax
shl edx, 8 ; EDX[18:8] = DevAddr & Endp
; Fill in various fields in the interrupt data TD
; Set length field
mov eax, ecx ; wLength = data length
dec ax ; AX = packet data size - 1
shl eax, 21
or edx, eax ; EDX[18:8]=Dev. addr & endp
mov al, CurrentDevice.bDataSync
and al, USB_INT_DATA_SYNC
shr al, USB_INT_DATA_SYNC_SHIFT
mov dl, IN_PACKET ; EAX[7:0] = IN PID
test al, 1
jz UIT_DataToggle ; DATA0 packet
or edx, DATA_TOGGLE ; Make packet into a data 1
UIT_DataToggle:
mov (UHCI_TD PTR [di]).Token, edx
xor al, 1 ; Toggle between DATA1/DATA0
push ax
; Update the data toggle value into the structure
mov cl, USB_INT_DATA_SYNC_SHIFT
; Reset toggle bit
mov al, 1
shl al, cl
not al
and CurrentDevice.bDataSync, al
pop ax ; AL - Updated data toggle
; Set toggle bit appropriately
shl al, cl
or CurrentDevice.bDataSync, al
mov (UHCI_TD PTR [di]).CSReloadValue, 0
mov (UHCI_TD PTR [di]).pCallback, OFFSET cs:UHCIBB_InterruptTDCallback
mov (UHCI_TD PTR [di]).ActiveFlag, TRUE
; Schedule the interrupt TD
push di
mov di, OFFSET QHControl
mov eax, OFFSET TDData
; Save the bulk data TD pointer
add eax, dGlobalDataArea
mov (UHCI_QH PTR [di]).ElementPointer, eax
pop di
; Now wait for the interrupt data TD to complete.
call UHCIBB_WaitForTransferComplete
; Finally check for errors in the completed interrupt data TD
; If the TD did not complete successfully, return with error.
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 UIT_ErrorExit ; Br if any error bits set in status
or sp, sp ; Clear zero flag
jmp SHORT UIT_Exit
UIT_ErrorExit:
cmp sp, sp ; Set zero flag
UIT_Exit:
pop di
pop edx
pop ecx
pop eax
ret
UHCIBB_InterruptTransfer ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: UHCIBB_ProcessInterrupt
;
; Description: This function is called when the USB interrupt bit is
; set. This function will parse through the TDs and QHs to
; find out completed TDs and call their respective call
; back functions
;
; Input: Nothing (All necessary data are in global variables)
;
; Output: Nothing
;
; Modified: None
;
; Referrals: UHCI_TD
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
UHCIBB_ProcessInterrupt PROC NEAR SYSCALL PUBLIC
push eax
push dx
push edi
; Read the UHCI status register
mov dx, (MKF_USB_BB_IO_BASE + UHCI_STATUS_REG)
in ax, dx
; Check whether any USB transaction completion interrupt is generated
test al, UHC_USB_INTERRUPT
jz UBPI_NoTransCompInt ; No interrupt asserted
; Clear interrupt status in the host controller
jcxz SHORT $+2
jcxz SHORT $+2
in ax, dx
jcxz SHORT $+2
jcxz SHORT $+2
out dx, ax
mov di, OFFSET TDControlSetup
call UHCIBB_ParseAndProcessTD
mov di, OFFSET TDData
call UHCIBB_ParseAndProcessTD
IF MKF_USB_BB_DEV_KBD
mov di, OFFSET TDKeyboard
call UHCIBB_ProcessTD
ENDIF ;; IF MKF_USB_BB_DEV_KBD
UBPI_NoTransCompInt:
pop edi
pop dx
pop eax
ret
UHCIBB_ProcessInterrupt ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: UHCIBB_ActivateKeyboardPolling
;
; Description: This function activates the polling TD for the USB keyboard
;
; Input: None
;
; Output: ZR On error
; NZ On successfull completion
;
; Modified: Nothing
;
; Referrals: UHCI_TD, DeviceInfo
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
UHCIBB_ActivateKeyboardPolling PROC NEAR PUBLIC
IF MKF_USB_BB_DEV_KBD
push eax
push ebx
push dx
push di
mov di, OFFSET TDKeyboard
mov (UHCI_TD PTR [di]).ControlStatus, 0 ; Inactive
; Save the pointer in DeviceInfo
mov CurrentDevice.pPollTDPtr, di
; Set the packet PID & packet length
mov eax, IN_PACKET OR ((DEFAULT_PACKET_LENGTH - 1) SHL 21)
; Set PID=In, and MaxLen
mov (UHCI_TD PTR [di]).Token, eax
; Set the address and endpoint fields in the TD's token field
movzx eax, CurrentDevice.bEndPointNum
shl eax, 7 ; EAX[10:7] = Endpoint number to poll
or al, CurrentDevice.bDeviceAddress
; EAX[6:0] = Addr
shl eax, 8 ; EAX[18:15]/[14:8] = Endp/Addr
and (UHCI_TD PTR [di]).Token, NOT (ENDPOINT OR DEVICE_ADDRESS)
or (UHCI_TD PTR [di]).Token, eax
lea ax, (UHCI_TD PTR [di]).DataArea
; AX = Pointer to TD's data area
movzx eax, ax ; Clear upper half of EAX
add eax, dGlobalDataArea ; EAX = Absolute address of TD's buff
mov (UHCI_TD PTR [di]).BufferPointer, eax
mov (UHCI_TD PTR [di]).pCallback, OFFSET CS:UHCIBB_KeyboardPollingCallback
; Make the TD active and set the high/low speed flag in the TD's
; control status and CSReloadValue fields.
movzx eax, CurrentDevice.bEndPointSpeed
; AL = 11/01/10 for HI/LO/FULL
and al, 1 ; Mask off MSb
shl eax, 26
or eax, (UHCI_TD_ACTIVE OR UHCI_TD_INTERRUPT_ON_COMPLETE OR UHCI_TD_THREE_ERRORS)
mov (UHCI_TD PTR [di]).CSReloadValue, eax
mov (UHCI_TD PTR [di]).ActiveFlag, TRUE
mov (UHCI_TD PTR [di]).ControlStatus, eax
; Capture the HC IRQ to point to the common IRQ handler
call USBBB_CaptureHCInterrupt
; Program HC to enable USB interrupts
mov ah, SB_USB_REG_LEGSUP
mov dx, CurrentHC.wBusDevFuncNum
call read_pci_dword_FAR
and bx, 00CFh
; Enable PIRQD
or bx, 2000h ; For BootBlock or IRQ mode
call write_pci_dword_FAR
; Finally enable interrupts (SMIs) from the host controller.
mov dx, (MKF_USB_BB_IO_BASE + UHCI_INTERRUPT_ENABLE)
mov ax, (UHC_IOC_ENABLE OR UHC_TIMEOUT_CRC_ENABLE)
out dx, ax
pop di
pop dx
pop ebx
pop eax
ENDIF ;; IF MKF_USB_BB_DEV_KBD
or sp, sp ; Clear zero flag
ret
UHCIBB_ActivateKeyboardPolling ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: UHCIBB_DeactivateKeyboardPolling
;
; Description: This function de-activates the polling TD for the USB keyboard
;
; Input: None
;
; Output: ZR On error
; NZ On successfull completion
;
; Modified: Nothing
;
; Referrals: UHCI_TD, DeviceInfo
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
UHCIBB_DeactivateKeyboardPolling PROC NEAR PUBLIC
IF MKF_USB_BB_DEV_KBD
push di
; Get a pointer to the device's TD from the poll TD pointer
mov di, OFFSET TDKeyboard
; Set the TD to inactive and prevent the HC from processing it.
mov (UHCI_TD PTR [di]).ControlStatus, UHCI_TD_THREE_ERRORS
mov (UHCI_TD PTR [di]).CSReloadValue, UHCI_TD_THREE_ERRORS
mov (UHCI_TD PTR [di]).ActiveFlag, FALSE
; Remove the polling TD from the schedule
mov CurrentDevice.pPollTDPtr, 0
pop di
ENDIF ;; IF MKF_USB_BB_DEV_KBD
or sp, sp ; Clear zero flag
ret
UHCIBB_DeactivateKeyboardPolling ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: UHCIBB_FillCntrlXferFields
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -