📄 ohci.asm
字号:
; UsbHcIsr ;
;---------------------------------------;--------------------------------------;
; This is the main entry point that handles all interrupts generated by the ;
; USB host controller. ;
; ;
; Input: Nothing ;
; ;
; Output: Nothing ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbHcIsr proc near
pushad
ifdef DOS_DEBUG
push ds
push es
push DOS_DEBUG_DATA_AREA
push DOS_DEBUG_DATA_AREA
pop ds
pop es
endif
; Check the interrupt status register for an ownership change. If this bit is,
; set, it means that the O/S USB device driver is attempting to takeover control
; of the host controller. In this case the host controller is shut down and the
; interrupt routing bit in the control register is cleared (this disables SMI
; generation and enebles standard IRQ generation from the USB host controller.
mov dx, OHCI_INTERRUPT_STATUS
call ReadUsbOperRegDword ;EAX = value from status register
test eax, OWNERSHIP_CHANGE
jz Check_root_hub_status ;Br if no O/S driver not taking control
mov dx, OHCI_HCCA_REG
call ReadUsbOperRegDword ;Read addr of USB data area
cmp eax, HcdDataArea
jne IsrReinit ;Br if O/S asking to re init USB BIOS
call _UsbHcClose ;Shut down the USB host controller
; Turn Off EV6 Mode
mov eax,80000084h
mov dx,0cf8h
out dx,eax
jmp short $+2
mov dl,0fch
in al,dx
jmp short $+2
and al,11101111b
out dx,al
jmp IsrTdsDone ;Exit from SMI
IsrReinit:
cmp byte ptr cs:[legacy_usb],0
jz IsrTdsDone ;Br is USB BIOS setup Q is disabled
; Turn On EV6 Mode
mov eax,80000084h
mov dx,0cf8h
out dx,eax
jmp short $+2
mov dl,0fch
in al,dx
jmp short $+2
or al,00010000b
out dx,al
movzx ebx,word ptr cs:[usb_segment]
shl ebx,4
mov cl,10h ;Enumerate, No Beep
extrn UsbBiosInitialize:near
call UsbBiosInitialize
jmp IsrTdsDone ;Exit from SMI
Check_root_hub_status:
; Check the interrupt status register for a root hub status change. If
; this bit is set, then a device has been attached or removed from one of
; the ports on the root hub.
mov dx, OHCI_INTERRUPT_STATUS
call ReadUsbOperRegDword ;EAX = value from status register
test al, RH_STATUS_CHANGE
jz IsrRhscDone ;Br if no root hub status change
; Clear the RH_STATUS_CHANGE bit of the interrupt status register
; in the host controller
mov eax, RH_STATUS_CHANGE
call WriteUsbOperRegDword ;Write 1 to bit to clear it
; Now check if we are already processing a root hub status change. If
; we are not, then set the StatusChangeInProgress flag and then call
; RootHubCallback which will check for a new device attached or an existing
; device detached.
mov al, TRUE
xchg StatusChangeInProgress, al
cmp al, TRUE
je IsrRhscDone ;Br if already processing root hub change
mov dx, OHCI_CONTROL_REG
call ReadUsbOperRegDword
and eax, not PERIODIC_LIST_ENABLE
call WriteUsbOperRegDword
call RootHubCallback ;Handle root hub change
mov dx, OHCI_CONTROL_REG
call ReadUsbOperRegDword
or eax, PERIODIC_LIST_ENABLE
call WriteUsbOperRegDword
mov StatusChangeInProgress, FALSE
IsrRhscDone:
; Check the interrupt status register for a one or more TDs completing.
mov dx, OHCI_INTERRUPT_STATUS
call ReadUsbOperRegDword ;EAX = value from status register
test al, WRITEBACK_DONEHEAD
jz IsrTdsDone ;Br if no TDs have completed
; The memory dword at HCCADONEHEAD has been updated to contain the head
; pointer of the linked list of TDs that have completed. Walk through
; this list processing TDs as we go.
IsrCheckForMoreTds:
xor edi, edi
xchg edi, HCCADONEHEAD ;EDI = abs addr of 1st completed TD
or edi, edi
jz IsrTdsDone ;Br if no TDs in list
; Clear the WRITEBACK_DONEHEAD bit of the interrupt status register
; in the host controller
push cx
mov cx,01000h
mov eax, WRITEBACK_DONEHEAD
call WriteUsbOperRegDword ;Write 1 to bit to clear it
IsrProcessNextTd:
sub edi, HcdDataArea ;DI = offset of 1st completed TD
and di, 0FFF0h ;Ignore any lower bits that may be set
call ProcessTdIfNeeded ;Check if complete and do callback
mov edi, (General_Transfer_Descriptor ptr [di]).GTD_Next_TD
or edi, edi
;; jnz IsrProcessNextTd ;Br if more TDs in list
loopnz IsrProcessNextTd
pop cx
jmp IsrCheckForMoreTds ;Check if any TDs completed while processing
IsrTdsDone:
; Issue EOI to the 8259
ifdef DOS_DEBUG
mov al, 20h ;AL = EOI command
cmp HC_Interrupt_Level, 8
jb IsrEoiPri ;Br if using IRQ 0..7 (2nd 8259 needs no EOI)
out 0A0h, al
jcxz $+2
jcxz $+2
IsrEoiPri:
out 20h, al
jcxz $+2
jcxz $+2
endif
ifdef DOS_DEBUG
pop es
pop ds
endif
popad
ifdef DOS_DEBUG
iret
else
ret
endif
UsbHcIsr endp
;---------------------------------------;
; ProcessTdIfNeeded ;
;---------------------------------------;--------------------------------------;
; This function examines a TD and determines if it has completed. If the TD ;
; has completed, the TD's callback routine is given control. ;
; ;
; Input: DS:DI = Pointer to TD that completed ;
; ;
; Output: Nothing ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
ProcessTdIfNeeded proc near
cmp (General_Transfer_Descriptor ptr [di]).ActiveFlag, TRUE
jne @f ;Br if TD is not active
cmp (General_Transfer_Descriptor ptr [di]).pCallback, 0
jz @f ;Br if TD's callback ptr is NULL
call (General_Transfer_Descriptor ptr [di]).pCallback
@@:
ret
ProcessTdIfNeeded endp
;---------------------------------------;
; PollingTdCallback ;
;---------------------------------------;--------------------------------------;
; This function is called when a polling TD from the TD pool completes an ;
; interrupt transaction to its assigned device. This routine should process ;
; any data in the TD's data buffer, handle any errors, and then copy the ;
; TD's CSReloadValue field into its TD_Control field to put the TD back ;
; into service. ;
; ;
; Input: DS:DI = Pointer to TD that completed ;
; ;
; Output: Nothing ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
PollingTdCallback proc near
push eax
push si
mov (General_Transfer_Descriptor ptr [di]).ActiveFlag, FALSE
; If any error bit is set in the TD's status field, ignore the TD's data.
test (General_Transfer_Descriptor ptr [di]).GTD_Control, STATUS_FIELD
jnz PollingTdError
; Search through the device table and find the entry associated with this
; polling TD by looking at each DeviceTableEntry's TdPoolPtr.
mov bx, offset DeviceTable ;BX = ptr to DeviceTable[0]
FindEntryNextEntry:
cmp (DeviceTableEntry ptr [bx]).Present, TRUE
jne FindEntrySkipEntry ;Br if this DeviceTableEntry is not in use
cmp (DeviceTableEntry ptr [bx]).TdPoolPtr, di
je FindEntryFound ;Br if matching entry found
FindEntrySkipEntry:
add bx, size DeviceTableEntry
cmp bx, offset DeviceTableEnd
jb FindEntryNextEntry ;Br if more entries to check
jmp short PollingTdError ;Could not find accociated DeviceTableEntry
FindEntryFound:
; BX now points to the DeviceTableEntry that goes with this TD.
; Set DS:SI = ptr to data (GTD_Setup[0]), AH = USB device address
; CX = 11 bit time stamp value (0 - 7FF), and call device's callback function.
mov dx, OHCI_CONTROL_REG
call ReadUsbOperRegDword
and eax, not PERIODIC_LIST_ENABLE
call WriteUsbOperRegDword
mov dx, OHCI_FRAME_NUMBER
call ReadUsbOperRegDword ;EAX = Frame number (0 - FFFF)
and ax, 07FFh ;Limit to 11 bits
mov cx, ax ;BX[10:0] = Frame number
mov ah, (DeviceTableEntry ptr [bx]).DeviceAddress
lea si, (General_Transfer_Descriptor ptr [di]).GTD_Setup
call (DeviceTableEntry ptr [bx]).pDeviceCallback
mov dx, OHCI_CONTROL_REG
call ReadUsbOperRegDword
or eax, PERIODIC_LIST_ENABLE
call WriteUsbOperRegDword
PollingTdError:
; Reset the TD's control and buffer pointer fields to their original values.
mov eax, (General_Transfer_Descriptor ptr [di]).CSReloadValue
mov (General_Transfer_Descriptor ptr [di]).GTD_Control, eax
lea ax, (General_transfer_Descriptor ptr [di]).GTD_Setup ;AX = ptr to TD's data buffer
movzx eax, ax ;Clear upper half of EAX
add eax, HcdDataArea ;EAX = abs addr of TD's data buffer
mov (General_transfer_Descriptor ptr [di]).GTD_Current_Buffer_Pointer, eax
; Rebind the TD to its parent ED.
mov si, (DeviceTableEntry ptr [bx]).EdPoolPtr
movzx eax, di ;EAX = offset of this TD
add eax, HcdDataArea ;EAX = addr of this TD
and (Endpoint_Descriptor ptr [si]).TDQ_Head_Pointer, TOGGLE_CARRY
or (Endpoint_Descriptor ptr [si]).TDQ_Head_Pointer, eax
mov (General_Transfer_Descriptor ptr [di]).ActiveFlag, TRUE
pop si
pop eax
ret
PollingTdCallback endp
;---------------------------------------;
; ControlTdCallback ;
;---------------------------------------;--------------------------------------;
; This function is called when the ControlSetup and ControlData TDs complete a ;
; control transaction to the assigned device. ;
; ;
; Input: DS:DI = Pointer to TD that completed ;
; ;
; Output: Nothing ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
ControlTdCallback proc near
push eax
; Check to see if the TD that just completed has any error bits set. If
; any of the ControlTds (Setup, Data, or Status) complete with an error, set
; ActiveFlag of the TdControlStatus and copy the error information from the
; TD that just completed into the TdControlStatus.
mov eax, (General_Transfer_Descriptor ptr [di]).GTD_Control
shr eax, 28 ;AL[3:0] = Completion status
or al, al
jz ControlDone ;Br if the TD completed with no error
;-----------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -