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

📄 ohci.asm

📁 <BIOS研发技术剖析>书的源代码,包括完整的BIOS汇编语言源程序.
💻 ASM
📖 第 1 页 / 共 5 页
字号:
	mov	eax, SKIP_TDQ or ED_IN_PACKET or (DEFAULT_PACKET_LENGTH  shl 16) ;Set PID=In, and MaxLen
	mov	(Endpoint_Descriptor ptr [di]).ED_Control, eax

	; set Delay interrupt to 1,Condition code=not accessed
	; Data toggle=DATA0=00b,
	mov	eax, BUFFER_ROUNDING or IN_PACKET or IntD or (NOT_ACCESSED shl 28)
	mov	(General_Transfer_Descriptor ptr [si]).GTD_CONTROL,eax
	mov	(General_Transfer_Descriptor ptr [si]).CSReloadValue,eax

	; set GTD's data buffer to GTD_Setup[0]-[7],
	;     DeviceAddress for device address in UsbHcIsr,
	;     GTD_Setup[0] for ProcessKeyboardData in PollingTdCallback
	lea	ax, (General_transfer_Descriptor ptr [si]).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 [si]).GTD_CURRENT_BUFFER_POINTER,eax
	add	eax, 7
	mov	(General_transfer_Descriptor ptr [si]).GTD_Buffer_End,eax
	mov	(General_transfer_Descriptor ptr [si]).GTD_Next_TD,TERMINATE
	mov	(General_Transfer_Descriptor ptr [si]).pCallback, offset cgroup:PollingTdCallback
	add	(General_Transfer_Descriptor ptr [si]).pCallback, orgbase
	mov	(General_Transfer_Descriptor ptr [si]).ActiveFlag, FALSE

	add	di, size Endpoint_Descriptor
	add	si, size General_Transfer_Descriptor
	inc	cl			;Inc ED counter(0-16 for device table entry 0-16)
	cmp	cl, MAX_DEVICES
	jbe	InitListNextEd		;Br if more EDs to init

; Setup EdRepeat and TdRepeat.  It will run a interrupt transaction to a
; nonexistant dummy device.  This will have the effect of generating a periodic
; interrupt used to generate keyboard repeat.  This ED/TD is normally inactive,
; and is only activated when a key is pressed.

	mov	di, offset EdRepeat	;DI = ptr to EdRepeat

	mov	(Endpoint_Descriptor ptr [di]).ED_Control, DUMMY_DEVICE_ADDR or ED_IN_PACKET or (DEFAULT_PACKET_LENGTH shl 16) or SKIP_TDQ
	mov	(Endpoint_Descriptor ptr [di]).Next_ED, TERMINATE
	mov	eax, HcdDataArea
	add	eax, offset TdRepeat
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Head_Pointer, eax
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Tail_Pointer, TERMINATE

	mov	si, offset TdRepeat	;SI = ptr to TdRepeat
	mov	eax, BUFFER_ROUNDING or IN_PACKET or IntD or (NOT_ACCESSED shl 28) or ONE_ERROR
	mov	(General_Transfer_Descriptor ptr [si]).GTD_CONTROL, eax
	mov	(General_Transfer_Descriptor ptr [si]).CSReloadValue, eax

	lea	ax, (General_transfer_Descriptor ptr [si]).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 [si]).GTD_CURRENT_BUFFER_POINTER, eax
	mov	(General_transfer_Descriptor ptr [si]).GTD_Buffer_End, eax
	mov	(General_transfer_Descriptor ptr [si]).GTD_Next_TD, TERMINATE
	mov	(General_Transfer_Descriptor ptr [si]).pCallback, offset cgroup:RepeatTdCallback
	add	(General_Transfer_Descriptor ptr [si]).pCallback, orgbase
	mov	(General_Transfer_Descriptor ptr [si]).ActiveFlag, TRUE

; Set the  periodic start time=2e67h(10% off from HcFmInterval)

	mov	dx, OHCI_PERIODIC_START
	mov	eax, 2e67h
	call	WriteUsbOperRegDword

; Read the HC's Root Hub Descriptor A register.  The lower 8 bits of this
; register indicate how many ports are on the HC's root hub.  Save this
; information for later use.

	mov 	dx, OHCI_RH_DESCRIPTOR_A
	call	ReadUsbOperRegDword	;EAX[7:0] = number of root hub ports
	mov	RootHubPortCount, al	;Save port count for later

; Hook the interrupt that has been assigned to the host controller.

ifdef DOS_DEBUG
	mov	bx, UsbHcBusDevFuncNum	;BX = HC's PCI bus/dev/function number
	mov	di, USB_IRQ_LEVEL
	mov	si, PCI_REG_ADDRESS_BYTE
	call	smi_pci_read_cfg	;Returns CL = IRQ level assigned to HC
	or	cl, cl
	jz	UsbInitDone		;Br if HC did not get an IRQ
	mov	HC_Interrupt_Level, cl

	add	cl, 8			;IRQ 0/1/../7 -> INT 8/9/../F
	cmp	cl, 10h
	jb	InitVector		;Br if IRQ 0..7
	add	cl, 70h - 10h		;Add offset of second 8259's vectors
InitVector:
	movzx	bx, cl			;BX = HC's interrupt vector
	shl	bx, 2			;BX = addr of interrupt vector to hook

	mov	ax, cs			;AX = CS
	shl	eax, 16 		;Put CS in upper half of EAX
	mov	ax, offset cgroup:UsbHcIsr ;EAX = CS:Offset of USB's ISR
	push	ds
	push	0			;Set DS = 0
	pop	ds
	mov	dword ptr [bx], eax	;Hook interrupt
	pop	ds
else

; Enable the HC's SMI generation on port 60/64 read/write and USB interrupt.
	mov	bx, UsbHcBusDevFuncNum
        call	EnableKBCTraps		;Returns CL[3:0] = 60/64 r/w trap flags
	or	cl, 10h			;Always enable SMI on USB interrupt
	call	UsbHcChipsetInit

endif

; Unmask the host controller's IRQ level in the 8259

ifdef DOS_DEBUG
	mov	cl, HC_Interrupt_Level	;CL = IRQ used by the HC (0..15)
	mov	bx, 1
	shl	bx, cl			;BX = bit map with one bit set
	not	bx			;BX = bit map with one bit clear

	in	al, 21h 		;AL = First 8259's mask reg
	and	al, bl			;Adjust mask
	out	21h, al 		;Write mask back

	in	al, 0A1h		;AL = Second 8259's mask reg
	and	al, bh			;Adjust mask
	out	0A1h, al		;Write mask back
endif

; Set the operational bit in the host controller so that power can be applied
; to the ports.

ifdef DOS_DEBUG
	mov	eax, USBOPERATIONAL
else
	mov	eax, USBOPERATIONAL or INTERRUPT_ROUTING
endif
	mov	dx, OHCI_CONTROL_REG
	call	WriteUsbOperRegDword	;Start the host controller running

; Enable global port power so that new devices can be detected.

	mov	dx, OHCI_RH_STATUS	;First enable global power
	mov	eax, SET_GLOBAL_POWER
	call	WriteUsbOperRegDword

	mov	cl, 1			;CL will count through port numbers
	mov 	dx, OHCI_RH_PORT1_STATUS;DX will count through port regs

EnablePowerNextPort:
	mov	eax, SET_PORT_POWER
	call	WriteUsbOperRegDword	;Enable individual port's power

ifdef HC_PATCH_NAT_OHCI
	push	cx
	mov	cx, 29Ah		;10ms / 15us
	call	pm_fixed_delay		;Delay 10ms
	pop	cx
endif

	add	dx, 4			;DX = next root hub status port
	inc	cl			;CL = next port number
	cmp	cl, RootHubPortCount
	jbe	EnablePowerNextPort	;Br if still more ports to check

	mov	cx, 29Ah		;10ms / 15us
	call	pm_fixed_delay		;Delay 10ms

; Set the HcFrameInterval register

	mov	dx, OHCI_FRAME_REMAINING
	call	ReadUsbOperRegDword	;EAX = HcFmRemaining register
	xor	eax, 80000000h		;Toggle FRT bit
	and	eax, 80000000h		;Save only FRT bit
	or	eax, 7FF82EDFh		;Set FSMPS to 7FFFh bits or 4095.7 bytes
	mov	dx, OHCI_FRAME_INTERVAL ;restore the HcFmInterval reg
	call	WriteUsbOperRegDword

; Start the host controller for control list only (no periodic list)

ifdef DOS_DEBUG
;        mov	eax, PERIODIC_LIST_ENABLE or CONTROL_LIST_ENABLE or USBOPERATIONAL
        mov	eax, CONTROL_LIST_ENABLE or USBOPERATIONAL
else
;        mov	eax, PERIODIC_LIST_ENABLE or CONTROL_LIST_ENABLE or USBOPERATIONAL or INTERRUPT_ROUTING
        mov	eax, CONTROL_LIST_ENABLE or USBOPERATIONAL or INTERRUPT_ROUTING
endif
	mov	dx, OHCI_CONTROL_REG
	call	WriteUsbOperRegDword	;Start the host controller running

; Check the root hub ports to see if a device is connected.  If so, then
; call UsbHubPortChange to handle the attachment of a new device.

	mov	cl, 1			;CL will count through port numbers
	mov 	dx, OHCI_RH_PORT1_STATUS;DX will count through port regs

InitRootHubNextPort:
	test	InitializationFlags, INIT_FLAG_ENUM_DISABLE
	jnz	@f			;Br if USB enum is disabled

	mov	al, 0FFh
	mov 	ah, cl			;AH = port number
	call	UsbGetRootHubPortStatus	;Returns BL,CF (ignore CF and BL bit 2)
	test	bl, 00000001b		;Test device connected bit
	jz	@f			;Br if no device connected

	call	UsbHubPortChange	;Process the connection/disconnection
@@:
	call	ReadUsbOperRegDword	;EAX = value from port 1 status reg
	and	eax, 0FFFF0000h		;Keep only the change indicator bits
	call	WriteUsbOperRegDword	;Write back to clear the change bits

	add	dx, 4			;DX = next root hub status port
	inc	cl			;CL = next port number
	cmp	cl, RootHubPortCount
	jbe	InitRootHubNextPort	;Br if still more ports to check

; Initialize the flag StatusChangeInProgress to indicate that a root hub status
; change is not in progress.

	mov	StatusChangeInProgress, FALSE

;Enable interrupts from the host controller

	mov	eax, MASTER_INTERRUPT_ENABLE or WRITEBACK_DONEHEAD_ENABLE or RH_STATUS_CHANGE_ENABLE or OWNERSHIP_CHANGE_ENABLE
	mov	dx, OHCI_INTERRUPT_ENABLE
	call	WriteUsbOperRegDword	;Enable SOF, WDH, RHSC interrupts

; Start the host controller for periodic list and control list.

ifdef DOS_DEBUG
        mov	eax, PERIODIC_LIST_ENABLE or CONTROL_LIST_ENABLE or USBOPERATIONAL
else
        mov	eax, PERIODIC_LIST_ENABLE or CONTROL_LIST_ENABLE or USBOPERATIONAL or INTERRUPT_ROUTING
endif
	mov	dx, OHCI_CONTROL_REG
	call	WriteUsbOperRegDword	;Start the host controller running

UsbInitDone:
ifdef DOS_DEBUG
	pop	es
	pop	ds
endif
	popad
	ret
_UsbHcInit	endp


;---------------------------------------;
; UsbHcClose                            ;
;---------------------------------------;--------------------------------------;
; This function shuts down and disables the USB host controller.               ;
;                                                                              ;
; Input:  Nothing                                                              ;
;                                                                              ;
; Output: Nothing                                                              ;
;                                                                              ;
; Destroys: Nothing                                                            ;
;------------------------------------------------------------------------------;
_UsbHcClose	proc near
	pusha

ifdef DOS_DEBUG
	push	ds
	push	es
	push	DOS_DEBUG_DATA_AREA
	push	DOS_DEBUG_DATA_AREA
	pop	ds
	pop	es
endif

	push	edx
	call	GetUsbHcBusDevFunc	;Returns BX = b/d/f, destroys AX,ECX,EDX
	pop	edx
	jc	@f			;Br if USB HC not found

	mov	UsbHcBusDevFuncNum,bx

	mov	di, PCI_REG_VENDID 
	mov	si, PCI_REG_ADDRESS_DWORD
	call	smi_pci_read_cfg	;Returns ECX = Vendor/Device ID
	inc	ecx
	jz	UsbHcCloseDone		;Br if HC is disabled

	mov	di, USB_BASE_ADDRESS
	mov	si, PCI_REG_ADDRESS_DWORD
	call	smi_pci_read_cfg	;Returns ECX = memory base of HC
	and	cl, 0F0h		;Clear reserved bits
	mov	Oper_Reg_Base_Address, ecx
@@:

; Stop the host controller

	mov     eax, USBRESET
	mov 	dx, OHCI_CONTROL_REG
	call	WriteUsbOperRegDword	;Write to HC control reg

; Disable interrupts from the host controller

	mov     eax, 0ffffffffh
	mov 	dx,  OHCI_INTERRUPT_DISABLE
	call	WriteUsbOperRegDword	;Disable all HC interrupts

; Disable the HC's SMI generation on port 60/64 read/write and USB interrupt.
	mov	bx, UsbHcBusDevFuncNum
	call	UsbHcChipsetShutdown

; Mask the host controller's IRQ level in the 8259

ifdef DOS_DEBUG
	mov 	cl, HC_Interrupt_Level	;CL = IRQ used by the HC (0..15)
	mov 	bx, 1
	shl 	bx, cl			;BX = bit map with one bit set

	in  	al, 21h			;AL = First 8259's mask reg
	or  	al, bl			;Adjust mask
	out 	21h, al			;Write mask back

	in  	al, 0A1h		;AL = Second 8259's mask reg
	or  	al, bh			;Adjust mask
	out 	0A1h, al		;Write mask back
endif

UsbHcCloseDone:
ifdef DOS_DEBUG
	pop	es
	pop	ds
endif
	popa
	ret
_UsbHcClose	endp


;---------------------------------------;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -