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

📄 ohci.asm

📁 <BIOS研发技术剖析>书的源代码,包括完整的BIOS汇编语言源程序.
💻 ASM
📖 第 1 页 / 共 5 页
字号:
;
;	mov	di, USB_BASE_ADDRESS
;	mov	si, PCI_REG_ADDRESS_WORD
;	call	smi_pci_read_cfg	;Returns CX = I/O base of HC
;	and	cl, 0FCh		;Mask out 2 reserved bits
;
;	mov	dx, USB_COMMAND_REG	;DX = command reg
;	add	dx, cx			;DX = command reg + USB HC base addr
;	in	ax, dx
;	test	ax, HOST_CONTROLLER_RUN
;	jz	CheckActiveNo		;Br if HC is not running

CheckActiveYes:
	popad
	mov	cl, 00000101b		;Indicate USB BIOS is in control and running
	ret				;   and HC has two root hub ports

CheckActiveNo:
	popad
	mov	cl, 00000100b		;Indicate USB BIOS is not in control or not running
	ret				;   and HC has two root hub ports
UsbHcCheckActive	endp


;---------------------------------------;
; GetUsbHcBusDevFunc                    ;
;---------------------------------------;--------------------------------------;
; This function returns the PCI bus, device, and function number of the USB    ;
; host controller.                                                             ;
;                                                                              ;
; Input: Nothing                                                               ;
;                                                                              ;
; Output: BH = PCI Bus number                                                  ;
;         BL = Device / Function number                                        ;
;              Bits 7-3: PCI device number                                     ;
;              Bits 2-0: Function number within the device                     ;
;         CF = Clear if USB host controller was found, set if not found        ;
;                                                                              ;
; Destroys: AX, ECX, EDX                                                       ;
;------------------------------------------------------------------------------;
GetUsbHcBusDevFunc	proc near

; Find the PCI bus/device/function number of the USB host controller by calling
; a chipset hook to get the Device/Vendor ID of the USB HC and then search for
; that HC on the PCI bus.

ifdef DOS_DEBUG
	mov	ecx, USB_HC_CLASS_CODE	;Defined by UHCI.EQU or OHCI.EQU
	xor	si, si
	mov	ax, 0B103h		;PCI Find Class function
	int	1Ah			;Returns CF, BX=bus/dev/func of USB HC
else
	call	UsbGetHostControllerId	;Returns EDX = Vendor/Device ID
	or	edx, edx
	clc
	jz	UsbFindDone		;Br if hook returned bus/dev/func #
	call	smi_pci_find_device	;Returns CF, BX=bus/dev/func of USB HC
endif

UsbFindDone:
	ret
GetUsbHcBusDevFunc	endp


;---------------------------------------;
; UsbHcInit                             ;
;---------------------------------------;--------------------------------------;
; This function initializes the host controller, its schedule, and all other   ;
; associated data structures, and then starts the host controller.             ;
;                                                                              ;
; Input:  DS = ES = Usb Data Area                                              ;
;                                                                              ;
; Output: Nothing                                                              ;
;                                                                              ;
; Destroys: Nothing                                                            ;
;------------------------------------------------------------------------------;
_UsbHcInit	proc near
	pushad

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

	mov	InitializationFlags, 0	;Set to auto enum, beep
endif

	call	UsbDataInit		;Initialize any data structures

; Set the TdPoolPtr and EdPoolPtr fields in the DeviceTable array to each
; point to TD and ED in the TdPool / EdPool.

	mov	si, offset DeviceTable	;SI = ptr to entry for device address 0
	mov	di, offset TdPool	;DI = ptr to first entry in TdPool (TdDummy)
	mov	bx, offset EdPool	;BX = ptr to first entry in EdPool (EdDummy)
@@:
	mov	(DeviceTableEntry ptr [si]).TdPoolPtr, di
	mov	(DeviceTableEntry ptr [si]).EdPoolPtr, bx
	add	si, size DeviceTableEntry ;SI = ptr to next DeviceTableEntry
	add	di, size General_Transfer_Descriptor ;DI = ptr to next TD in TdPool
	add	bx, size Endpoint_Descriptor ;BX = ptr to next ED in EdPool
	cmp	si, offset DeviceTableEnd
	jb	@b			;Br if more DeviceTableEntries

; Initialize the flag StatusChangeInProgress to indicate that a root hub status
; change is in progress so that we will not try to process a root hub status
; change interrupt during initialization.

	mov	StatusChangeInProgress, TRUE

; Find the PCI bus/device/function number of the USB host controller and
; store it for later use.

	call	GetUsbHcBusDevFunc	;Returns BX = b/d/f, destroys AX,ECX,ESI
	jc	UsbInitDone		;Br if USB HC not found
	mov	UsbHcBusDevFuncNum, bx	;Save bus/dev/func for later

; Move OHCI memory mapped registers to C800:0 for debugging. - TEMPORARY

ifdef DOS_DEBUG
	mov	bx, UsbHcBusDevFuncNum	;BX = HC's PCI bus/dev/function number
	mov	di, USB_BASE_ADDRESS
	mov	ecx, 0C8000h
	mov	si, PCI_REG_ADDRESS_DWORD
	call	smi_pci_write_cfg
endif

; Get I/O base address of the HC and store it in the variable
; Oper_Reg_Base_Address in the USB data segment.

	mov	bx, UsbHcBusDevFuncNum	;BX = HC's PCI bus/dev/function number
	mov	di, PCI_REG_VENDID 
	mov	si, PCI_REG_ADDRESS_DWORD
	call	smi_pci_read_cfg	;Returns ECX = Vendor/Device ID
	inc	ecx
	jz	UsbInitDone		;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

; Set ports 1 and 2 to Removable ;Need?.......................

	mov	dx, OHCI_RH_DESCRIPTOR_B ;set these ports removable
	call	ReadUsbOperRegDword
	and	ax, 0fff9h
	call	WriteUsbOperRegDword

; First stop the host controller if it is at all active
; 1.Software Reset the host controller -> USB Suspend state
;   This HC_RESET bit is cleaed by HC upon the completion of the reset operation
; 2.Then let HC go to UsbReset state to reset Root Hub and downstream ports,
;   and wait for the assertion of reset on the USB (P43).

	mov	dx, OHCI_COMMAND_STATUS	;Issue a software reset
	mov	eax, HC_RESET		;and HC go to UsbSuspend state
	call	WriteUsbOperRegDword

	mov	cx, 86h 		;wait for ensure HC stay in UsbSuspend > 2ms
	call	pm_fixed_delay		;134*15us = 2 ms, Delay 2ms (see p42)

	mov	dx, OHCI_CONTROL_REG	;let HC go to UsbReset state
	mov	eax, USBRESET		;for reset Root Hub and downstream ports
	call	WriteUsbOperRegDword	;(see p43)

	mov	cx, 029Ah		;wait 10ms for assertion of reset
	call	pm_fixed_delay		;Delay 10ms

; Set the HcHCCA register

	mov	eax, HcdDataArea	;EAX = absolute addr of HCCA
	mov	dx, OHCI_HCCA_REG
	call	WriteUsbOperRegDword	;Write addr of frame list into HC

;;;;; Pre initialize the periodic list to contain all TERMINATE entries.
;;;;; This will allow control transactions to take place, but will
;;;;; prevent any HID or Hub polling from taking place.  The HID and Hub polling
;;;;; TDs will be put into the schedule after the USB bus is initially enumerated.
;;;;
;;;;    mov     di, offset INTERRUPTLIST
;;;;PreInitInterruptListNextRepeat:
;;;;    mov     dword ptr [di], TERMINATE ;Set frame list entry to be idle
;;;;    add     di, 4                   ;DI = ptr to next frame list entry
;;;;    cmp     di, offset INTERRUPTLIST + (FRAME_LIST_SIZE * 4)
;;;;    jb      PreInitInterruptListNextRepeat  ;Br if entire frame list is not done

;Initial the periodic list
; Initialize the HccaInterruptTable's 32 entries

	mov	di, offset INTERRUPTLIST

InitInterruptListNextRepeat:
	mov	cx, ACTIVE_FRAMES	;CX = number of active frames
	mov	eax, HcdDataArea	;EAX = seg containing TD pool
	add	eax, offset EdPool	;EAX = addr of first ED in pool (EdDummy)
	add	eax, size Endpoint_Descriptor	;EAX = addr of next ED (EdHid[0])

InitInterruptListNextFrame:
	stosd				;Set frame list entry = ED[cx]
	add	eax, size Endpoint_Descriptor	;EAX = addr of next ED

	mov	bx, IDLE_FRAMES 	;BX = # of idle frames between actives
InitInterruptListNextIdle:
	mov	dword ptr [di], TERMINATE ;Set frame list entry to be idle
	add	di, 4			;DI = ptr to next frame list entry
	dec	bx			;Dec idle frame counter
	jnz	InitInterruptListNextIdle	;Br if more idle frames to insert

	loop	InitInterruptListNextFrame	;Loop for all active frames

	cmp	di, offset INTERRUPTLIST + (FRAME_LIST_SIZE * 4)
	jb	InitInterruptListNextRepeat	;Br if entire frame list is not done

; Now "hook" the first interrupt list entry and point it to the array of Hub
; EDs.  Then link the EDs in the EdHub array together in a linear linked list.

	mov	di, offset INTERRUPTLIST;DI = ptr to first interrupt list entry
	mov	ebx, dword ptr [di]	;Save contents of first interrupt list entry
	mov	eax, HcdDataArea	;EAX = seg containing EdPool
	add	eax, offset EdHub	;EAX = addr of first hub ED
	stosd				;Set frame list entry to point to root hub TD

	mov	di, offset EdHub	;DI = ptr to first ED in EdHub array
	movzx	eax, di
	add	eax, size Endpoint_Descriptor
	add	eax, HcdDataArea	;EAX = ptr to next ED
	mov	edx, offset TdHub	;EDX = offset within usbdseg of 1st Hub TD
	add	edx, HcdDataArea	;EDX = addr of 1st Hub TD
	mov	cx, HUB_DEVICE_LIMIT - 1

InitHubListNext:
	mov	(Endpoint_Descriptor ptr [di]).Next_ED, eax
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Head_Pointer, edx
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Tail_Pointer, TERMINATE
	add	eax, size Endpoint_Descriptor
	add	edx, size General_Transfer_Descriptor
	add	di, size Endpoint_Descriptor
	loop	InitHubListNext		;Fill all TdHub EDs except last

	; Link last hub ED to the saved contents of the first frame list entry
	mov	(Endpoint_Descriptor ptr [di]).Next_ED, ebx
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Head_Pointer, edx
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Tail_Pointer, TERMINATE

; Initialize the Endpoint Descriptors into a two dimensional array.  The
; array has ACTIVE_FRAMES number of rows (each row is headed by one frame list
; entry).  The array has TDS_PER_FRAME number of columns.  The last TD in each
; row has its link pointer set to point to the PeriodicTd.

	mov	cl, 0			;CL will be row counter (0..ACTIVE_FRAMES-1)

InitEdArrayNextRow:
	mov	ch, 0			;CH will be column counter (0..EDS_PER_FRAME-1)

InitEdArrayNextCol:
	mov	al, ACTIVE_FRAMES	;AL = number of rows
	mul	ch			;AL = index of ED in row 0 of cur column
	add	al, cl			;AL = index of ED in cur row of cur column
	mov	bl, size Endpoint_Descriptor
	mul	bl			;AX = offset within EdHid array of current ED
	add	ax, offset EdHid	;AX = offset within usbdseg of current ED
	mov	di, ax			;DI = offset within usbdseg of current ED

	mov	eax, TERMINATE		;EAX = ptr to NULL
	cmp	ch, EDS_PER_FRAME - 1
	jae	InitEdLastCol		;Br if cur ED is last col in its row

	movzx	eax, di 		;EAX = offset within usbdseg of current TD
	add	eax, size Endpoint_Descriptor * ACTIVE_FRAMES
	add	eax, HcdDataArea
					;EAX = abs addr of next ED in row
InitEdLastCol:
	mov	(Endpoint_Descriptor ptr [di]).Next_ED, eax ;Link the ED list
	;Link each InterruptEd with one InterruptTd
	mov	al, ACTIVE_FRAMES	;AL = number of rows
	mul	ch			;AL = index of ED in row 0 of cur column
	add	al, cl			;AL = index of ED in cur row of cur column
	mov	bl, size General_Transfer_Descriptor
	mul	bl			;AX = offset within TdHid array of current TD
	add	ax, offset TdHid	;AX = offset within usbdseg of current TD
	movzx	eax, ax
	add	eax, HcdDataArea	;EAX = addr of current TD
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Head_Pointer, eax
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Tail_Pointer, TERMINATE

	inc	ch
	cmp	ch, EDS_PER_FRAME
	jb	InitEdArrayNextCol	;Br if more cols to do

	inc	cl
	cmp	cl, ACTIVE_FRAMES
	jb	InitEdArrayNextRow	;Br if more rows to do

; Now "hook" the last HID ED in the first row of the HID array and point it
; to EdRepeat.

	mov	al, HID_DEVICE_LIMIT - ACTIVE_FRAMES ;AL = array index of last HidEd in first row
	mov	ah, size Endpoint_Descriptor
	mul	ah			;AX = offset of ED within HID ED array
	mov	di, ax
	add	di, offset EdHid	;DI = offset of last EdHid in first row

	mov	eax, HcdDataArea	;EAX = seg containing TDs
	add	eax, offset EdRepeat	;EAX = addr of EdRepeat
	xchg	(Endpoint_Descriptor ptr [di]).Next_ED, eax
	mov	di, offset EdRepeat
	mov	(Endpoint_Descriptor ptr [di]).Next_ED, eax
	mov	eax, HcdDataArea	;EAX = seg containing TDs
	add	eax, offset TdRepeat	;EAX = addr of TdRepeat
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Head_Pointer, eax
	mov	(Endpoint_Descriptor ptr [di]).TDQ_Tail_Pointer, TERMINATE

; Initialize the body of each Endpoint Descriptor and its GTD in the HID/Hub
; list to perform an interrupt transaction on endpoint 0 of a device.  All EDs
; and GTDs in the list will initially be disabled (skip=true,ActiveFlag=FALSE).
; As devices are found that need to be polled, the ED/TD corresponding to the
; device's device table entry will be made active.

	mov	cl, 0			;CL will count EDs (0..MAX_DEVICES)
	mov	di, offset EdPool	;DI = offset of first ED in list
	mov	si, offset TdPool	;SI = offset of first TD in list

InitListNextEd:

	;Now nonactive,so skip ED, when device is connected then set to not skip

⌨️ 快捷键说明

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