📄 ohci.asm
字号:
mov (General_Transfer_Descriptor ptr [di]).GTD_Next_TD, eax
mov (General_Transfer_Descriptor ptr [di]).CSReloadValue, 0
mov (General_Transfer_Descriptor ptr [di]).pCallback, offset cgroup:ControlTdCallback
add (General_Transfer_Descriptor ptr [di]).pCallback, orgbase
mov (General_Transfer_Descriptor ptr [di]).ActiveFlag, TRUE
; Fill in various fields in the TdControlData.
; The TD_Control field will be set so BUFFER_ROUNDING=1,
; DIRECTION_PID=OUT_PACKET/IN_PACKET, DELAY_INTERRUPT=IntD,
; DATA_TOGGLE=DATA1_TOGGLE, ERROR_COUNT=NO_ERRORS, CONDITION_CODE=NOT_ACCESSED
; The GTD_Current_Buffer_Pointer field will point to the caller's buffer
; which is now in EBP.
; The GTD_Buffer_End field will point to the last byte of the caller's buffer.
; The GTD_Next_TD field will point to the TdControlStatus.
; The CSReloadValue field will contain 0 because this is a "one shot" packet.
; The pCallback will be set to point to the ControlTdCallback routine.
; The ActiveFlag field will be set to TRUE.
; The DeviceAddress field does not need to be set since the Control TDs do
; not need rebinding to the EdControl.
or si, si
jz DevReqSkipDataTd ;Br if no data transfer (data length=0)
mov di, offset TdControlData ;DI = ptr of TdControlData
mov eax, BUFFER_ROUNDING or OUT_PACKET or DELAY_INTERRUPT or DATA1_TOGGLE or NO_ERRORS or (NOT_ACCESSED shl 28)
test dl, 80h
jz @f ;Br if host sending data to device (OUT)
mov eax, BUFFER_ROUNDING or IN_PACKET or IntD or DATA1_TOGGLE or NO_ERRORS or (NOT_ACCESSED shl 28)
@@: mov (General_Transfer_Descriptor ptr [di]).GTD_Control, eax
mov (General_Transfer_Descriptor ptr [di]).GTD_Current_Buffer_Pointer, ebp
movzx eax, si ;ESI = data length
cmp ax, size DeviceRequestDataBuf
jbe @f ;Br if processedn data <= buffer size
mov ax, size DeviceRequestDataBuf
@@: add ebp, eax ;Update the buffer pointer
dec ebp
mov (General_Transfer_Descriptor ptr [di]).GTD_Buffer_End, ebp
mov eax, HcdDataArea ;EAX = seg containing TDs
add eax, offset TdControlStatus ;EAX = abs addr of TdControlStatus
mov (General_Transfer_Descriptor ptr [di]).GTD_Next_TD, eax
mov (General_Transfer_Descriptor ptr [di]).CSReloadValue, 0
mov (General_Transfer_Descriptor ptr [di]).pCallback, offset cgroup:ControlTdCallback
add (General_Transfer_Descriptor ptr [di]).pCallback, orgbase
mov (General_Transfer_Descriptor ptr [di]).ActiveFlag, TRUE
DevReqSkipDataTd:
; Fill in various fields in the TdControlStatus.
; The TD_Control field will be set so BUFFER_ROUNDING=1,
; DIRECTION_PID=IN_PACKET/OUT_PACKET, DELAY_INTERRUPT=IntD,
; DATA_TOGGLE=DATA1_TOGGLE, ERROR_COUNT=NO_ERRORS, CONDITION_CODE=NOT_ACCESSED
; The GTD_Current_Buffer_Pointer field will point to NULL
; The GTD_Buffer_End field will point to NULL.
; The GTD_Next_TD field will point to TERMINATE.
; The CSReloadValue field will contain 0 because this is a "one shot" packet.
; The pCallback will be set to point to the ControlTdCallback routine.
; The ActiveFlag field will be set to TRUE.
; The DeviceAddress field does not need to be set since the Control TDs do
; not need rebinding to the EdControl.
mov di, offset TdControlStatus ;DI = ptr to TdControlStatus
mov eax, BUFFER_ROUNDING or IN_PACKET or IntD or DATA1_TOGGLE or NO_ERRORS or (NOT_ACCESSED shl 28)
test dl, 80h
jz @f ;Br if host sending data to device (OUT)
mov eax, BUFFER_ROUNDING or OUT_PACKET or IntD or DATA1_TOGGLE or NO_ERRORS or (NOT_ACCESSED shl 28)
@@: mov (General_Transfer_Descriptor ptr [di]).GTD_Control, eax
xor eax, eax
mov (General_Transfer_Descriptor ptr [di]).GTD_Current_Buffer_Pointer, eax
mov (General_Transfer_Descriptor ptr [di]).GTD_Buffer_End, eax
mov (General_Transfer_Descriptor ptr [di]).GTD_Next_TD, eax
mov (General_Transfer_Descriptor ptr [di]).CSReloadValue, eax
mov (General_Transfer_Descriptor ptr [di]).pCallback, offset cgroup:ControlTdCallback
add (General_Transfer_Descriptor ptr [di]).pCallback, orgbase
mov (General_Transfer_Descriptor ptr [di]).ActiveFlag, TRUE
; Now complete the Control queue, so set SKIP_TDQ=0
mov di, offset EdControl
and (Endpoint_Descriptor ptr [di]).ED_Control,not SKIP_TDQ
; Set the HcControlHeadED register to point to the EdControl.
mov eax, offset EdControl
add eax, HcdDataArea
mov dx, OHCI_CONTROL_HEAD_ED
call WriteUsbOperRegDword
; Now put the TdControlSetup, TdControlData, and TdControlStatus into the
; HC's schedule by setting the ControllListFilled field of HcCommandStatus reg.
; This will cause the HC to execute the transaction in the next active frame.
mov eax, CONTROL_LIST_FILLED
mov dx, OHCI_COMMAND_STATUS
call WriteUsbOperRegDword
; Now wait for the TdControlStatus to complete. When it has completed,
; the ControlTdCallback will its active flag to FALSE.
; mov bx, 20000d ;Repeat this loop this number of times
; before giving up (~50us per iteration)
mov bx, 2500
WaitForComplete:
mov dx, OHCI_INTERRUPT_STATUS
call ReadUsbOperRegDword ;AX = value from status register
test eax, WRITEBACK_DONEHEAD
jz @f ;Br if HC is not asserting IRQ
ifdef DOS_DEBUG
pushf ;Simulate IRQ from the HC
push cs
cli
endif
call UsbHcIsr
@@:
cmp TdControlSetup.ActiveFlag, FALSE
jne DevReqNotComplete ;Br if TdControlSetup not completed
cmp TdControlData.ActiveFlag, FALSE
jne DevReqNotComplete ;Br if TdControlData not completed
cmp TdControlStatus.ActiveFlag, FALSE
je DevReqComplete ;Br if TdControlStatus completed
DevReqNotComplete:
;; for port 1 cannot work
mov cx, 3
; mov cx, 96*2
call pm_fixed_delay ;Delay 45us
dec bx ;Dec timeout counter
jnz WaitForComplete ;Br if not time to give up yet
or (General_Transfer_Descriptor ptr [di]).GTD_Control, (DEVICE_NOT_RESPOND shl 28)
DevReqComplete:
; Stop the HC from processing the EdControl by setting its Skip bit.
mov di, offset EdControl
or (Endpoint_Descriptor ptr [di]).ED_Control, SKIP_TDQ
; Finally check for any error bits set in both the TdControlStatus.
; If the TD did not complete successfully, return STC.
mov eax, TdControlStatus.GTD_Control
shr eax, 28 ;AL[3:0] = Completion status
or al, al
clc ;Indicate success
jz DeviceRequestDone ;Br if no error bits are set
;----------------------------------------------------------------------
; Patch for Compaq OHCI HC which reports DataUnderrun error on any
; short packet (even if buffer rounding is enabled).
ifdef HC_PATCH_COMPAQ_OHCI
cmp al, DATA_UNDERRUN
clc ;Indicate success
je DeviceRequestDone ;Br if DataUnderrun error
endif
;----------------------------------------------------------------------
stc ;Indicate error
DeviceRequestDone:
popad
ret
UsbDeviceRequest endp
;---------------------------------------;
; UsbGetRootHubPortStatus ;
;---------------------------------------;--------------------------------------;
; This function returns the status of one port on the root hub. ;
; ;
; Input: AH = Port number within hub ;
; ;
; Output: BL = Port status flags ;
; Bit 0: Connect status ;
; 0 = No device is connected to port ;
; 1 = A device is connected to port ;
; Bit 1: Device speed ;
; 0 = Full speed device attached ;
; 1 = Low speed device attached ;
; Bit 2: Connect status change ;
; 0 = Connect status has not changed ;
; 1 = Device has been attached/removed ;
; Bit 3-7: Reserved ;
; CF = Clear if the hub port's status was determined successfully ;
; Set if the hub port's status cannot be determined ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbGetRootHubPortStatus proc near
push eax
push dx
shl ah, 2 ;AH = 4/8 for port 1/2
mov dx, OHCI_RH_PORT1_STATUS - 4
add dl, ah ;DX = Port 1/2 control reg
call ReadUsbOperRegDword ;EAX = value from port control reg
xor bl, bl ;Init the output values
test al, CURRENT_CONNECT_STATUS
jz @f ;Br if no device present
or bl, 00000001b ;Set connect status bit
@@:
test ax, LOW_SPEED_DEVICE_ATTACHED
jz @f ;Br if high speed device
or bl, 00000010b ;Set low speed bit
@@:
test eax, CONNECT_STATUS_CHANGE
jz @f ;Br if no change in connect status
or bl, 00000100b ;Set connect status change bit
@@:
pop dx
pop eax
clc
ret
UsbGetRootHubPortStatus endp
;---------------------------------------;
; UsbEnableRootHubPort ;
;---------------------------------------;--------------------------------------;
; This function powers, resets, and enables one port on the root hub. ;
; ;
; Input: AH = Port number within hub ;
; ;
; Output: CF = Clear if the hub port was enabled successfully ;
; Set if the hub port was not enabled ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbEnableRootHubPort proc near
pushad
shl ah, 2 ;AH = 4/8 for port 1/2
mov dx, OHCI_RH_PORT1_STATUS - 4
add dl, ah ;DX = Port 1/2 control reg
mov eax, SET_PORT_ENABLE
call WriteUsbOperRegDword ;Enable the port
mov cx, 29Ah ;10ms / 15us
call pm_fixed_delay ;Delay 10ms
mov eax, SET_PORT_RESET ;Make reset signaling active
call WriteUsbOperRegDword
EnablePortWaitForReset:
call ReadUsbOperRegDword
test eax, PORT_RESET_STATUS
jnz EnablePortWaitForReset ;Br if reset still active
mov eax, PORT_RESET_STATUS_CHANGE
call WriteUsbOperRegDword ;Clear reset status change bit
mov cx, (100 * 1000) / 15 ;100ms / 15us
call pm_fixed_delay ;Delay 100ms
ifdef HC_PATCH_NAT_OHCI
mov eax, SET_PORT_ENABLE
call WriteUsbOperRegDword ;Enable the port
endif
popad
clc
ret
UsbEnableRootHubPort endp
;---------------------------------------;
; UsbDisableRootHubPort ;
;---------------------------------------;--------------------------------------;
; This function disables one port on a USB hub or the root hub. ;
; ;
; Input: AH = Port number within hub ;
; ;
; Output: CF = Clear if the hub port was disabled successfully ;
; Set if the hub port was not disabled ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbDisableRootHubPort proc near
pusha
shl ah, 2 ;AH = 4/8 for port 1/2
mov dx, OHCI_RH_PORT1_STATUS - 4
add dl, ah ;DX = Port 1/2 control reg
call ReadUsbOperRegDword ;AX = value from port control reg
or eax, CLEAR_PORT_ENABLE ;Clear enable bit
call WriteUsbOperRegDword
popa
clc
ret
UsbDisableRootHubPort endp
;---------------------------------------;
; UsbHcCheckActive ;
;---------------------------------------;--------------------------------------;
; This function returns a flag indicating if the USB host controller is ;
; currently active and under BIOS control. ;
; ;
; Input: Nothing (even DS and ES are undefined) ;
; ;
; Output: CL = Flags ;
; Bit[7:4] = Reserved ;
; Bit[3:1] = Number of ports on root hub of host controller ;
; Bit[0] = 1 if USB BIOS is running host controller ;
; 0 if USB BIOS is not running host controller ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbHcCheckActive proc near
pushad
;...............................................
; call GetUsbHcBusDevFunc ;Returns BX = b/d/f, destroys AX,ECX,EDX
;
; call UsbHcChipsetGetStatus ;Returns CL[4:0] = USB & 60/64 r/w trap flags
; test cl, 00010000b ;Bit 4 enables SMI on HC IRQ if set
; jz CheckActiveNo ;Br if HC int not routed to SMI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -