📄 usb.asm
字号:
; DH - Sub class
; DL - Protocol
call (USB_DEV_HDR PTR cs:[si]).pChkDevType
cmp al, 0FFh
je UIACD_TryNextDriver
; Set the device type in the device info structure
mov (DeviceInfo PTR [bx]).bDeviceType, al
; Device identified. Issue common configure call
; Call a common routine to handle the remaining initialization that is done
; for all devices.
; BX - DeviceInfo, DI - Descriptor pointer, CX - End offset of desc ptr
call USB_ConfigureDevice
jz UIACD_DriverInitDone ; Error in configuring the device
; Updated new device info in the BX
mov wRetValue, bx
; Issue device specific initialization
; BX - DeviceInfo, DI - Descriptor pointer, CX - End offset of desc ptr
call (USB_DEV_HDR PTR cs:[si]).pCfgDevice
; On error reset the temporary device info structure indicating the
; device is not configured correctly
jnz UIACD_DriverInitDone
mov (DeviceInfo PTR [bx]).bDeviceType, 0
jmp SHORT UIACD_DriverInitDone
UIACD_TryNextDriver:
pop si
add si, 2
jmp SHORT UIACD_CheckNextDriver
UIACD_DriverInitDone:
pop si
UIACD_Exit:
mov ax, wRetValue
ret
USBIdentifyAndConfigureDevice ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: USB_DetectNewDevice
;
; Description: This function is called when a new device is plugged
; into a port on a hub. The hub may be a normal USB hub
; or the root hub.
;
; Input: DH USB device address of the hub whose status
; has changed
; bit 7 : 1 - Root hub, 0 for other hubs
; bit 6-0 : Device address of the hub
; DL Port number
; AL Port status flags (See USB_PORT_STAT_XX equ)
; SI HCStruc of the host controller
;
; Output: AX Pointer to the DevInfo structure for the newly
; added device
;
; Modified: AX
;
; Referrals: DeviceInfo, HCStruc
; DeviceDescriptor, ConfigDescriptor, InterfaceDescriptor
; USB_GetDescriptor, USBEnableHubPort, USBDisableHubPort
;
; Notes: This function does the following:
; 1. Set the DeviceInfo entry for device 0 to be
; the same speed as the new device
; 2. Find a free entry in the DeviceInfo (the position
; in the DeviceInfo array is the same as the new
; device address for the device)
; 3. Enable the port on the hub
; 4. Send a GetDescriptor (Device Descriptor) command
; to the device using an assumed MaxPacket size
; of 128 bytes, and make note of the actual MaxPacket
; size returned in the descriptor data
; 5. Reset the hub port to handle any noncompliant devices
; 6. Send a SetAddress command to the device to set it
; to its new address
; 7. Send a GetDescriptor command to the device to get
; its Device descriptor
; 8. Use GetConfiguration commands to search for
; a configuration that includes an interface type
; that the BIOS can use (keyboard, mouse, or hub)
; 9. Use the data returned in the Device descriptor to
; fill in the DeviceInfo entry
; 10. Configure the device using SetConfiguration,
; SetInterface, and
; 11. SetProtocol commands
; 12. Call device specific initializer to start polling
; 13. Done
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
USB_DetectNewDevice PROC NEAR SYSCALL PUBLIC USES BX CX DX SI DI
LOCAL wDescLength:WORD, pBuffer:NEAR, wConfigLevel:WORD
; First set the speed of entry 0 in the DeviceInfo to run at the same speed
; as the new device. This is necessary because we will initially communicate
; with the device at address 0 before assigning it a unique device address.
mov di, OFFSET DeviceInfoTable ; DI - DeviceInfo[0]
mov (DeviceInfo PTR [di]).bFlag, DEV_INFO_VALID_STRUC
mov (DeviceInfo PTR [di]).bDeviceAddress, 0
mov (DeviceInfo PTR [di]).wEndp0MaxPacket, 40h
mov (DeviceInfo PTR [di]).bDeviceType, 00h
mov (DeviceInfo PTR [di]).wIncompatFlags, 0
; Fill the speed of the device
and al, USB_PORT_STAT_DEV_SPEED_MASK
shr al, USB_PORT_STAT_DEV_SPEED_MASK_SHIFT
mov (DeviceInfo PTR [di]).bEndpointSpeed, al
; Fill hub address byte
mov (DeviceInfo PTR [di]).bHubDeviceNumber, dh
; Fill port number in the hub
mov (DeviceInfo PTR [di]).bHubPortNumber, dl
mov (DeviceInfo PTR [di]).pHCStrucPtr, si
; Next enable the port on the hub where the device is connected.
test dh, BIT7
jz UDND_SkipPortEnable
; DH Hub/HC number
; DL Port number
; SI HCStruc pointer
call USBEnableHubPort
UDND_SkipPortEnable:
; Set BX to DeviceInfo pointer
mov bx, di
; Set config level
mov wConfigLevel, USB_ERR_DEV_INIT_MEM_ALLOC
; Allocate a block of memory for device request buffer
mov pBuffer, 0
mov al, (MAX_CONTROL_DATA_SIZE / USB_MEM_BLK_SIZE)
call USBMem_Alloc
jz UDND_Error
; Save the pBuffer value in the Control Transfer temp area in the
; device info structure
mov WORD PTR (DeviceInfo PTR [bx]).CntrlXfer.fpBuffer, ax
mov pBuffer, ax
mov di, ax
; Set config level
mov wConfigLevel, USB_ERR_DEV_INIT_GET_DESC_8
; Next send a GetDescriptor command to the device to get its Device
; Descriptor. Assume a MaxPacket size of 64 bytes (the device will use 8,
; 16, 32, or 64). Regardless of the packet size used by te device we can
; always get the real MaxPacket size that the device is using, because
; this piece of information is at offset 7 in the device descriptor.
mov cx, 8
mov (DeviceInfo PTR [bx]).CntrlXfer.wValue, (DESC_TYPE_DEVICE SHL 8)
; SI - HCStruc, BX - pDevInfo, CX - Length
call USB_GetDescriptor
jz UDND_Error
; Set config level
mov wConfigLevel, USB_ERR_DEV_INIT_SET_ADDR
; Get and store the endpoint 0 max packet size
movzx ax, (DeviceDescriptor PTR [di]).bEndp0MaxPacket
mov (DeviceInfo PTR [bx]).wEndp0MaxPacket, ax
; Give some delay
mov ax, ((10 * 1000) / 15) ; 10ms delay
call USBMisc_FixedDelay
; Now send a GetDescriptor command to the device to get its device descriptor.
mov cx, 18
; SI - HCStruc, BX - pDevInfo, CX - Length
call USB_GetDescriptor
jz UDND_Error
; Set config level
mov wConfigLevel, USB_ERR_DEV_INIT_GET_DESC_200
; Get the relevant information from the descriptor and store it in
; device information struture
mov ax, (DeviceDescriptor PTR [di]).wVendorId
mov (DeviceInfo PTR [bx]).wVendorId, ax
mov ax, (DeviceDescriptor PTR [di]).wDeviceId
mov (DeviceInfo PTR [bx]).wDeviceId, ax
; Look at each of the device's ConfigDescriptors and InterfaceDescriptors
; until an InterfaceDescriptor is found with BaseClass, SubClass, and
; Protocol fields indicating boot keyboard, mouse, hub or storage support.
mov al, (DeviceDescriptor PTR [di]).bNumConfigs
mov (DeviceInfo PTR [bx]).bNumConfigs, al
mov (DeviceInfo PTR [bx]).bConfigNum, 0
UDND_NextConfig:
;;;;;; Save DI if needed (for iteration)
mov cx, (MAX_CONTROL_DATA_SIZE - 1)
mov ah, DESC_TYPE_CONFIG
mov al, (DeviceInfo PTR [bx]).bConfigNum
mov (DeviceInfo PTR [bx]).CntrlXfer.wValue, ax
; SI - HCStruc, BX - pDevInfo, CX - Length
call USB_GetDescriptor ; Output DI - Descriptor read
jz UDND_Error
;DI should now point to a ConfigDescriptor. Verify this and
;then get some fields out of it. Then point to the next descriptor.
cmp (ConfigDescriptor PTR [di]).bDescType, DESC_TYPE_CONFIG
jne UDND_SkipConfig ;Br if device did not return config desc
mov al, (ConfigDescriptor PTR [di]).bConfigValue ;AL = Config value
mov (DeviceInfo PTR [bx]).bConfigNum, al
mov cx, (ConfigDescriptor PTR [di]).wTotalLength
cmp cx, MAX_CONTROL_DATA_SIZE - 1 ;BP = size of all data returned
jb UDND_NotOverFlowed
mov cx, MAX_CONTROL_DATA_SIZE - 1 ;Limit size of data to what we can handle
UDND_NotOverFlowed:
;; mov wDescLength, ax
; Convert size to end offset
add cx, di
movzx ax, (ConfigDescriptor PTR [di]).bDescLength
add di, ax
; DI should now point to an InterfaceDescriptor. Verify this
; and then check its BaseClass, SubClass, and Protocol fields for
; usable devices.
UDND_NextInterface:
cmp (InterfaceDescriptor PTR [di]).bDescType, DESC_TYPE_INTERFACE
jne UDND_SkipInterface ;Br if not on an interface desc
mov al, (InterfaceDescriptor PTR [di]).bInterfaceNum
mov (DeviceInfo PTR [bx]).bInterfaceNum, al
mov al, (InterfaceDescriptor PTR [di]).bAltSettingNum
mov (DeviceInfo PTR [bx]).bAltSettingNum, al
; SI - HCStruc, BX - DevInfo, DI - Pointer to InterfaceDescriptor,
; CX - Pointer to descriptor end
call USBIdentifyAndConfigureDevice
or ax, ax
jz UDND_SkipInterface
; Successfully configured
; Returns new device info structure in AX
mov bx, ax
UDND_SkipInterface:
movzx ax, (ConfigDescriptor PTR [di]).bDescLength ;AX = next desc
or ax, ax
jz UDND_SkipConfig ;Br if 0 length desc (should never happen, but...)
add di, ax ;BX = ptr to next desc
cmp di, cx
jae UDND_SkipConfig ; End of data
; There is one more config. Set device info structure entry 0 for it
mov bx, OFFSET DeviceInfoTable ; BX - DeviceInfo[0]
; Multi-interface device. Set the bit appropriately
or (DeviceInfo PTR [bx]).bFlag, DEV_INFO_MULTI_IF
jmp SHORT UDND_NextInterface
UDND_SkipConfig:
cmp (DeviceInfo PTR [bx]).bDeviceType, 00h
jne UDND_Success ;Br if at least on usable interface was found already
inc (DeviceInfo PTR [bx]).bConfigNum
mov al, (DeviceInfo PTR [bx]).bConfigNum
cmp al, (DeviceInfo PTR [bx]).bNumConfigs
jb UDND_NextConfig ;Br if more configs to look at
; No configuration could be found which supports a device which can be used
; by the BIOS. Beep politely and disable the hub port.
push bx
mov bl, 8
mov cx, 1000h
call USBMisc_SpeakerBeep
pop bx
; Log device configuration not found error
IF MKF_DISPLAY_DEV_DISABLE_ERROR
mov ax, ERRUSB_DEVICE_DISABLED
call USBLogError
ENDIF
jmp SHORT UDND_DisablePort
UDND_Success:
mov bl, 4
mov cx, 400h
call USBMisc_SpeakerBeep
mov ax, si ; Valid device info structure
jmp short UDND_Done
UDND_Error:
mov ax, wConfigLevel
; Log configuration level
call USBLogError
;;; Log device configuration error
;; mov ax, ERRUSB_DEVICE_INIT
;; call USBLogError
mov ax, wConfigLevel
UDND_DisablePort:
; If error is during getdescriptor_8 call then skip device
; disabling
cmp wConfigLevel, USB_ERR_DEV_INIT_GET_DESC_8
je UDND_Done
; Disable the hub port
mov dh, (DeviceInfo PTR [bx]).bHubDeviceNumber
mov dl, (DeviceInfo PTR [bx]).bHubPortNumber
mov si, (DeviceInfo PTR [bx]).pHCStrucPtr
call USBDisableHubPort
xor ax, ax ; Invalid device info
UDND_Done:
push ax
mov si, OFFSET DeviceInfoTable ;SI = ptr to DeviceInfo[0]
mov (DeviceInfo PTR [si]).bDeviceAddress, 0
; Free the memory allocated for device request buffer
mov al, (MAX_CONTROL_DATA_SIZE / USB_MEM_BLK_SIZE)
mov bx, pBuffer
call USBMem_Free
pop ax
ret
USB_DetectNewDevice ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: USBDisconnectDevice
;
; Description: This function is called when a device disconnect is
; detected. This routine disables the hub port and stops the
; device and its children by calling another routine.
;
; Input: DH USB device address of the hub whose status
; has changed
; bit 7 : 1 - Root hub, 0 for other hubs
; bit 6-0 : Device address of the hub
; DL Port number
; SI HCStruc of the host controller
;
; Output: Nothing
;
; Modified: Nothing
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
USBDisconnectDevice PROC NEAR SYSCALL PUBLIC USES BX CX
; A device has been disconnected from the USB. First disable the hub port
; that the device was plugged into. Then free up the device's entry in the
; DeviceTable. If there an error occurs while disabling the port, assume
; that the device is still present an leave its DeviceTable entry in place.
; DH Hub/HC number
; DL Port number
; SI HCStruc pointer
call USBDisableHubPort
; DH Hub/HC number
; DL Port number
; SI HCStruc pointer
call USBStopDevice
ret
USBDisconnectDevice ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: USBStopDevice
;
; Description: This function is called when a device disconnect is
; detected. This routine stops polling on the device, frees
; its DeviceInfo entry, and notifies the keyboard/mouse code
; that the device is disconnected. This routine also
; recursively processes any child devices if a hub is
; disconnected.
;
; Input: DH USB device address of the hub whose status
; has changed
; bit 7 : 1 - Root hub, 0 for other hubs
; bit 6-0 : Device address of the hub
; DL Port number
; SI HCStruc of the host controller
;
; Output: Nothing
;
; Modified: Nothing
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
USBStopDevice PROC NEAR SYSCALL PUBLIC
push bx
push dx
push di
; Find the device info entry for this device.
mov bx, OFFSET DeviceInfoTable ; SI = Ptr to DeviceInfoTable
add bx, SIZE DeviceInfo ; Skip first entry
xchg dh, dl
UDD_CheckNextEntry:
test (DeviceInfo PTR [bx]).bFlag, DEV_INFO_VALID_STRUC
jz UDD_SkipEntry ; Entry not used
cmp WORD PTR ((DeviceInfo PTR [bx]).bHubDeviceNumber), dx
jne UDD_SkipEntry ; Hub/port number not matched
; Issue disconnect call for the device
mov di, (DeviceInfo PTR [bx]).pDevDriverPtr
or di, di
jz UDD_SkipDisConnect
cmp (USB_DEV_HDR PTR cs:[di]).pDisconDevice, 0
je UDD_SkipDisConnect
pushf
call (USB_DEV_HDR PTR cs:[di]).pDisconDevice
popf
UDD_SkipDisConnect:
; Some device driver may not have a disconnect routine. For those drivers
; reset the device info structure validity flag
jnz UDD_SkipUpdatingFlag ; Device driver has disconnect routine
; Device driver does not have disconnect routine
and (DeviceInfo PTR [bx]).bFlag, NOT (DEV_INFO_VALID_STRUC OR DEV_INFO_DEV_PRESENT)
UDD_SkipUpdatingFlag:
; Stop polling the device's interrupt endpoint.
; Get the HC device driver address in DI
mov di, (HCStruc PTR [si]).pHCDPointer
; SI HCStruc
; BX DeviceInfo
call (HCDHEADER PTR cs:[di]).pHCDDeactivatePolling
UDD_SkipEntry:
add bx, SIZE DeviceInfo ; Point to next DeviceInfo
cmp bx, OFFSET DeviceInfoTableEnd
jb UDD_CheckNextEntry ; More entries in DeviceInfo
UDD_Exit:
pop di
pop dx
pop bx
ret
USBStopDevice ENDP
;<AMI_PHDR_START>
;----------------------------------------------------------------------------
; Procedure: USBGetProperDeviceInfoStructure
;
; Description: This routine searches for a device info structure that
; matches the vendor and device id, and LUN of the device
; found. If such a device info structure not found, then it
; will return a free device info structure
;
; Input: EAX Vendor and Device ID (Device ID in EAX+)
; DL Current LUN
;
; Output: SI Pointer to new device info. struc. 0 on error
;
; Modified: SI
;
; Referrals: DeviceInfo
;
;----------------------------------------------------------------------------
;<AMI_PHDR_END>
USBGetProperDeviceInfoStructure PROC NEAR PUBLIC
push bx
xor bx, bx
; Scan through the device info table for a free entry. Also if the device
; connected is a mass storage device look for a device info structure whose
; device is disconnected and its vendor & device id matches the one of
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -