📄 uhci.asm
字号:
; The CSReloadValue field will contain 0 because this is a "one shot" packet.
; The pCallback will be set to point to the ControlTdCallback routine.
; The ActiveFlag field will be set to TRUE.
or si, si
jz DevReqSkipDataTds ;Br if no data transfer (data length=0)
cmp si, MAX_CONTROL_DATA_SIZE
jb @f ;Br if not more data than we can handle
mov si, MAX_CONTROL_DATA_SIZE ;Limit to amount of data that we can handle
@@:
mov di, offset TdControlData ;DI = ptr of TdControlData
mov dh, 1 ;Start with a data 1 token
DevReqNextDataTd:
movzx eax, di
add eax, size Transfer_Descriptor
add eax, HcdDataArea
mov (Transfer_Descriptor ptr [di]).TD_Link_Pointer, eax
movzx eax, (DeviceTableEntry ptr [bx]).LowSpeedFlag ;AL = 0/1 for hi/lo
shl eax, 26
or eax, INTERRUPT_ON_COMPLETE or THREE_ERRORS or ACTIVE
mov (Transfer_Descriptor ptr [di]).TD_Control_Status, eax
mov (Transfer_Descriptor ptr [di]).TD_Buffer_Pointer, ebp
movzx eax, si ;ESI = data length
cmp ax, (DeviceTableEntry ptr [bx]).Endp0MaxPacket
jbe @f ;Br if remaining data <= max packet size
mov ax, (DeviceTableEntry ptr [bx]).Endp0MaxPacket
@@: sub si, ax ;Subtract packet size from overall data length
add ebp, eax ;Update the buffer pointer
dec ax ;AX = packet data size - 1
shl eax, 21
or eax, ecx ;EAX[18:8] = Device address / endpoint
mov al, OUT_PACKET ;EAX[7:0] = OUT PID
test dl, 80h
jz @f ;Br if host sending data to device (OUT)
mov al, IN_PACKET ;EAX[7:0] = IN PID
@@:
test dh, 1
jz @f ;Br if this packet is a data 0 token
or eax, DATA_TOGGLE ;Make packet into a data 1
@@:
mov (Transfer_Descriptor ptr [di]).TD_Token, eax
mov (Transfer_Descriptor ptr [di]).CSReloadValue, 0
mov (Transfer_Descriptor ptr [di]).pCallback, offset cgroup:ControlTdCallback
add (Transfer_Descriptor ptr [di]).pCallback, orgbase
mov (Transfer_Descriptor ptr [di]).ActiveFlag, TRUE
add di, size Transfer_Descriptor ;Point to next data TD
xor dh, 1 ;Toggle between data 1 / data 0
or si, si
jnz DevReqNextDataTd ;Br if more data TDs must be built
sub di, size Transfer_Descriptor ;Point to last data TD
mov eax, HcdDataArea ;EAX = seg containing TDs
add eax, offset TdControlStatus ;EAX = abs addr of TdControlStatus
mov (Transfer_Descriptor ptr [di]).TD_Link_Pointer, eax
DevReqSkipDataTds:
; Fill in various fields in the TdControlStatus.
; The TD_Link_Pointer field will point to TERMINATE.
; The TD_Control_Status field will be set to active and interrupt on complete.
; The TD_Token field will contain the packet size (0), the device address,
; endpoint, and a setup PID with opposite data direction as that defined
; in the request type (DL).
; The TD_Buffer_Pointer field will point to the TD's DataArea buffer even
; though we are not expecting any data transfer.
; The CSReloadValue field will contain 0 because this is a "one shot" packet.
; The pCallback will be set to point to the ControlTdCallback routine.
; The ActiveFlag field will be set to TRUE.
mov di, offset TdControlStatus ;DI = ptr to TdControlStatus
mov (Transfer_Descriptor ptr [di]).TD_Link_Pointer, TERMINATE
movzx eax, (DeviceTableEntry ptr [bx]).LowSpeedFlag ;AL = 0/1 for hi/lo
shl eax, 26
or eax, INTERRUPT_ON_COMPLETE or THREE_ERRORS or ACTIVE
mov (Transfer_Descriptor ptr [di]).TD_Control_Status, eax
mov eax, ecx ;EAX[18:8] = Device address / endpoint
mov al, OUT_PACKET ;EAX[7:0] = OUT PID
test dl, 80h
jnz @f ;Br if device sending data to host (IN)
mov al, IN_PACKET ;EAX[7:0] = IN PID
@@: or eax, DATA_TOGGLE or (7FFh shl 21) ;Make packet into a data 1 and length 0
mov (Transfer_Descriptor ptr [di]).TD_Token, eax
lea ax, (Transfer_Descriptor ptr [di]).DataArea ;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 (Transfer_Descriptor ptr [di]).TD_Buffer_Pointer, eax
mov (Transfer_Descriptor ptr [di]).CSReloadValue, 0
mov (Transfer_Descriptor ptr [di]).pCallback, offset cgroup:ControlTdCallback
add (Transfer_Descriptor ptr [di]).pCallback, orgbase
mov (Transfer_Descriptor ptr [di]).ActiveFlag, TRUE
; Now put the TdControlSetup, TdControlData TDs, and TdControlStatus into the
; HC's schedule by pointing QhControl's link pointer to TdControlSetup.
; This will cause the HC to execute the transaction in the next active frame.
mov di, offset QhControl
mov eax, HcdDataArea ;EAX = seg containing TDs
add eax, offset TdControlSetup ;EAX = abs addr of TdControlSetup
mov (Q_Head ptr [di]).Q_Element_Link_Pointer, eax
; Now wait for the TdControlStatus to complete. When it has completed,
; the ControlTdCallback will its active flag to FALSE.
mov di, offset TdControlStatus ;DI = ptr of TdControlStatus
mov bx, 20000d ;Repeat this loop this number of times
; before giving up (~50us per iteration)
WaitForComplete:
mov dx, USB_STATUS_REG
call ReadUsbIoRegWord ;AX = value from status register
test al, USB_INTERRUPT
jz @f ;Br if HC is not asserting IRQ
ifdef DOS_DEBUG
pushf ;Simulate IRQ from the HC
push cs
cli
endif
call UsbHcIsr
@@:
cmp (Transfer_Descriptor ptr [di]).ActiveFlag, FALSE
je DevReqComplete ;Br if TdControlStatus completed
mov cx, 3
call pm_fixed_delay ;Delay 45us
dec bx ;Dec timeout counter
jnz WaitForComplete ;Br if not time to give up yet
or (Transfer_Descriptor ptr [di]).TD_Control_Status, CRC_TIMEOUT_ERROR
DevReqComplete:
; Remove the TdControlSetup, TdControlData TDs, and TdControlStatus from the
; HC's schedule by pointing QhControl's link pointer to TERMINATE.
mov di, offset QhControl
mov (Q_Head ptr [di]).Q_Element_Link_Pointer, TERMINATE
; Finally check for any error bits set in both the TdControlStatus.
; If the TD did not complete successfully, return STC.
test TdControlStatus.TD_Control_Status, BITSTUFF_ERROR or CRC_TIMEOUT_ERROR or NAK_RECEIVED or BABBLE_DETECTED or DATA_BUFFER_ERROR or STALLED
stc ;Indicate error
jnz DeviceRequestDone ;Br if any error bits set in status
clc ;Indicate success
DeviceRequestDone:
popad
ret
UsbDeviceRequest endp
;---------------------------------------;
; UsbGetRootHubPortStatus ;
;---------------------------------------;--------------------------------------;
; This function returns the status of one port on the root hub. ;
; ;
; Input: AH = Port number within hub ;
; ;
; Output: BL = Port status flags ;
; Bit 0: Connect status ;
; 0 = No device is connected to port ;
; 1 = A device is connected to port ;
; Bit 1: Device speed ;
; 0 = Full speed device attached ;
; 1 = Low speed device attached ;
; Bit 2: Connect status change ;
; 0 = Connect status has not changed ;
; 1 = Device has been attached/removed ;
; Bit 3-7: Reserved ;
; CF = Clear if the hub port's status was determined successfully ;
; Set if the hub port's status cannot be determined ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbGetRootHubPortStatus proc near
push ax
push dx
shl ah, 1 ;AH = 2/4 for port 1/2
mov dx, USB_PORT1_CONTROL - 2
add dl, ah ;DX = Port 1/2 control reg
call ReadUsbIoRegWord ;AX = value from port control reg
xor bl, bl ;Init the output values
test al, CONNECT_STATUS
jz @f ;Br if no device present
or bl, 00000001b ;Set connect status bit
@@:
test ax, LOW_SPEED_ATTACHED
jz @f ;Br if high speed device
or bl, 00000010b ;Set low speed bit
@@:
test ax, CONNECT_STATUS_CHANGE
jz @f ;Br if connect status not changed
or bl, 00000100b ;Set connect status change bit
@@:
pop dx
pop ax
clc
ret
UsbGetRootHubPortStatus endp
;---------------------------------------;
; UsbEnableRootHubPort ;
;---------------------------------------;--------------------------------------;
; This function powers, resets, and enables one port on the root hub. ;
; ;
; Input: AH = Port number within hub ;
; ;
; Output: CF = Clear if the hub port was enabled successfully ;
; Set if the hub port was not enabled ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbEnableRootHubPort proc near
pusha
shl ah, 1 ;AH = 2/4 for port 1/2
mov dx, USB_PORT1_CONTROL - 2
add dl, ah ;DX = Port 1/2 control reg
call ReadUsbIoRegWord ;AX = value from port control reg
or ax, PORT_ENABLE or PORT_RESET ;Set enable and reset bits
call WriteUsbIoRegWord
mov cx, 029Ah ;10ms / 15us
call pm_fixed_delay ;Delay 10ms
call ReadUsbIoRegWord ;AX = value from port control reg
and ax, not PORT_RESET ;Clear reset bit
or ax, PORT_ENABLE ;Set enable bit
call WriteUsbIoRegWord
mov cx, (1 * 1000) / 15 ;1ms / 15us
call pm_fixed_delay ;Delay 10ms
call ReadUsbIoRegWord ;AX = value from port control reg
or ax, PORT_ENABLE ;Set enable bit
call WriteUsbIoRegWord
mov cx, (100 * 1000) / 15 ;100ms / 15us
call pm_fixed_delay ;Delay 100ms
popa
clc
ret
UsbEnableRootHubPort endp
;---------------------------------------;
; UsbDisableRootHubPort ;
;---------------------------------------;--------------------------------------;
; This function disables one port on a USB hub or the root hub. ;
; ;
; Input: AH = Port number within hub ;
; ;
; Output: CF = Clear if the hub port was disabled successfully ;
; Set if the hub port was not disabled ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbDisableRootHubPort proc near
pusha
shl ah, 1 ;AH = 2/4 for port 1/2
mov dx, USB_PORT1_CONTROL - 2
add dl, ah ;DX = Port 1/2 control reg
call ReadUsbIoRegWord ;AX = value from port control reg
and ax, not PORT_ENABLE ;Clear enable bit
call WriteUsbIoRegWord
popa
clc
ret
UsbDisableRootHubPort endp
;---------------------------------------;
; UsbHcCheckActive ;
;---------------------------------------;--------------------------------------;
; This function returns a flag indicating if the USB host controller is ;
; currently active and under BIOS control. ;
; ;
; Input: Nothing (even DS and ES are undefined) ;
; ;
; Output: CL = Flags ;
; Bit[7:4] = Reserved ;
; Bit[3:1] = Number of ports on root hub of host controller ;
; Bit[0] = 1 if USB BIOS is running host controller ;
; 0 if USB BIOS is not running host controller ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbHcCheckActive proc near
pushad
call GetUsbHcBusDevFunc ;Returns BX = b/d/f, destroys AX,ECX,EDX
call UsbHcChipsetGetStatus ;Returns CL[4:0] = USB & 60/64 r/w trap flags
test cl, 00010000b ;Bit 4 enables SMI on HC IRQ if set
jz CheckActiveNo ;Br if HC int not routed to SMI
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -