📄 ohci.asm
字号:
;
; 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 + -