⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ohci.asm

📁 <BIOS研发技术剖析>书的源代码,包括完整的BIOS汇编语言源程序.
💻 ASM
📖 第 1 页 / 共 5 页
字号:
; 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 + -