📄 usb.asm
字号:
; entry ;
; 10. Configure the device using SetConfiguration, SetInterface, and ;
; SetProtocol commands ;
; 11. Activate polling for the device by calling UsbActivatePolling ;
; 12. Done ;
; ;
; Input: AL = USB Device address of hub where new device has been plugged in ;
; 00 - 7F = Device address of hub on the USB ;
; 80 - FE = Reserved ;
; FF = Root hub ;
; AH = Port number within hub where new device has been plugged in ;
; 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-7: Reserved ;
; DS = ES = usbdseg ;
; ;
; Output: Nothing ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
UsbDetectNewDevice proc near
pusha
push es
; First set the speed of entry 0 in the DeviceTable 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 si, offset DeviceTable ;SI = ptr to DeviceTableEntry[0]
mov (DeviceTableEntry ptr [si]).DeviceAddress, 0
shr bl, 1 ;Full/Low speed bit in bit 0
and bl, 1 ;BL = 00/01 for Full/Low speed
mov (DeviceTableEntry ptr [si]).LowSpeedFlag, bl
mov (DeviceTableEntry ptr [si]).Endp0MaxPacket, 40h
mov word ptr ((DeviceTableEntry ptr [si]).HubDeviceNumber), ax
mov (DeviceTableEntry ptr [si]).BiosDeviceType, 00h
; Next enable the port on the hub where the device is connected.
; HubDeviceNumber is in AL and HubPortNumber is in AH.
; Full speed / low speed flag is in BL.
call UsbEnableHubPort ;Enables/resets the port and delays
; 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 learn the real
; MaxPacket size that the device is using, because this piece of information
; is at offset 7 in the device descriptor.
push si
mov al, 0 ;AL = default device address
mov ah, 0 ;Send command to endpoint 0 on device
mov ch, DESC_TYPE_DEVICE ;CH = Descriptor type
mov cl, 0 ;CL = Descriptor index
mov si, 8d ;SI = Size of descriptor
call _UsbGetDescriptor ;Returns ES:DI = descriptor data
pop si
jc NewDeviceAbort ;Br if error during command
movzx ax, es:(DeviceDescriptor ptr [di]).Endp0MaxPacket
mov (DeviceTableEntry ptr [si]).Endp0MaxPacket, ax
; Delay for 5 milliseconds after premature termination of the GetDescriptor
; command above. This was added to accomodate the Philips Infra-Red keyboard
; (Vid=0471, Pid=0601, Ver=1.00) which stops responding during the status
; phase of the SetAddress command below if SetAddress follows the
; GetDescriptor command by only 2ms.
mov cx, (5 * 1000) / 15 ;5ms
call pm_fixed_delay ;Delay
; Now find a free device address. This is done by searching through the array
; of DeviceTable entries, trying addresses until an unused one is found.
mov dl, 1 ;First device address to try
FindAddrNextAddr:
mov si, offset DeviceTable ;SI = ptr to DeviceTable[0]
FindAddrNextEntry:
cmp (DeviceTableEntry ptr [si]).Present, TRUE
jne FindAddrSkipEntry ;Br if found unused entry
cmp (DeviceTableEntry ptr [si]).DeviceAddress, dl
je FindAddrSkipAddr ;Br if addr DL is already used
FindAddrSkipEntry:
add si, size DeviceTableEntry
cmp si, offset DeviceTableEnd
jb FindAddrNextEntry ;Br if not to end of DeviceTable
jmp NewDeviceFoundAddr ;Made it all the way through the DeviceTable
; array wthout finding addr DL
FindAddrSkipAddr:
inc dl ;Inc address to try
cmp dl, MAX_DEVICE_ADDR
jbe FindAddrNextAddr ;Br if still more addresses to try
jmp NewDeviceDone ;No free address was found so abort
; A free device address is now in DL. Now send a SetAddress command to the
; device to set it to its new USB device address (in DL).
NewDeviceFoundAddr:
mov al, dl ;AL = new device address
call _UsbSetAddress
mov si, offset DeviceTable ;SI = ptr to DeviceTable[0]
jc NewDeviceAbort ;Br if error setting address
mov (DeviceTableEntry ptr [si]).DeviceAddress, dl
; Now send a GetDescriptor command to the device to get its device descriptor.
push si
mov al, dl ;AL = new device address
mov ah, 0 ;Send command to endpoint 0 on device
mov ch, DESC_TYPE_DEVICE ;CH = Descriptor type
mov cl, 0 ;CL = Descriptor index
mov si, 18d ;SI = Size of descriptor
call _UsbGetDescriptor ;Returns ES:DI = descriptor data
pop si
jc NewDeviceAbort ;Br if error during command
mov cx, es:(DeviceDescriptor ptr [di]).VendorId
mov (DeviceTableEntry ptr [si]).VendorId, cx
mov cx, es:(DeviceDescriptor ptr [di]).DeviceId
mov (DeviceTableEntry ptr [si]).DeviceId, cx
; 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, or hub support.
mov cl, es:(DeviceDescriptor ptr [di]).NumConfigs
mov (DeviceTableEntry ptr [si]).NumConfigs, cl
mov (DeviceTableEntry ptr [si]).ConfigNum, 0
NewDeviceNextConfig:
push si
mov al, dl ;AL = new device address
mov ah, 0 ;Send command to endpoint 0 on device
mov ch, DESC_TYPE_CONFIG ;CH = Descriptor type
mov cl, (DeviceTableEntry ptr [si]).ConfigNum ;CL = Desc index
mov si, MAX_CONTROL_DATA_SIZE - 1 ;SI = Max size of descriptor
call _UsbGetDescriptor ;Returns ES:DI = descriptor data
pop si
jc NewDeviceAbort ;Br if error during command
;ES:DI should now point to a ConfigDescriptor. Verify this and
;then get some fields out of it. Then point to the next descriptor.
cmp es:(ConfigDescriptor ptr [di]).DescType, DESC_TYPE_CONFIG
jne NewDeviceSkipConfig ;Br if device did not return config desc
mov al, es:(ConfigDescriptor ptr [di]).ConfigValue ;AL = Config value
mov (DeviceTableEntry ptr [si]).ConfigNum, al
mov bp, es:(ConfigDescriptor ptr [di]).TotalLength
cmp bp, MAX_CONTROL_DATA_SIZE - 1 ;BP = size of all data returned
jb @f ;Br if data did not overflow
mov bp, MAX_CONTROL_DATA_SIZE - 1 ;Limit size of data to what we can handle
@@:
movzx bx, es:(ConfigDescriptor ptr [di]).DescLength
;ES:DI+BX should now point to an InterfaceDescriptor. Verify this
;and then check its BaseClass, SubClass, and Protocol fields for
;usable devices.
NewDeviceNextInterface:
cmp es:(InterfaceDescriptor ptr [di+bx]).DescType, DESC_TYPE_INTERFACE
jne NewDeviceSkipInterface ;Br if not on an interface desc
mov al, es:(InterfaceDescriptor ptr [di+bx]).InterfaceNum
mov (DeviceTableEntry ptr [si]).InterfaceNum, al
mov al, es:(InterfaceDescriptor ptr [di+bx]).AltSettingNum
mov (DeviceTableEntry ptr [si]).AltSettingNum, al
call CheckForAndConfigureKeyboard
jnc NewDeviceSkipInterface ;Br if successful
call CheckForAndConfigureMouse
jnc NewDeviceSkipInterface ;Br if successful
call CheckForAndConfigureHub
NewDeviceSkipInterface:
movzx ax, es:(ConfigDescriptor ptr [di+bx]).DescLength ;BX = next desc
or ax, ax
jz NewDeviceSkipConfig ;Br if 0 length desc (should never happen, but...)
add bx, ax ;BX = ptr to next desc
cmp bx, bp
jb NewDeviceNextInterface ;Br if not past end of data
NewDeviceSkipConfig:
cmp (DeviceTableEntry ptr [si]).BiosDeviceType, 00h
jne NewDeviceSuccess ;Br if at least on usable interface was found already
inc (DeviceTableEntry ptr [si]).ConfigNum
mov al, (DeviceTableEntry ptr [si]).ConfigNum
cmp al, (DeviceTableEntry ptr [si]).NumConfigs
jb NewDeviceNextConfig ;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.
mov ah, 4 ;Issue connect beep (high & short)
mov cx, 1000h
call SpeakerBeep
jmp short NewDeviceDisablePort
NewDeviceAbort:
mov ah, 64 ;Issue error beep (low & long)
mov cx, 4000h
call SpeakerBeep
NewDeviceDisablePort:
mov ax, word ptr ((DeviceTableEntry ptr [si]).HubDeviceNumber)
call UsbDisableHubPort ;Disables the hub/port at AL/AH
NewDeviceDone:
mov si, offset DeviceTable ;SI = ptr to DeviceTableEntry[0]
mov (DeviceTableEntry ptr [si]).DeviceAddress, 0
pop es
popa
ret
NewDeviceSuccess:
mov ah, 4 ;Issue connect beep (high & short)
mov cx, 1000h
mov cx, 400h
call SpeakerBeep
jmp short NewDeviceDone
UsbDetectNewDevice endp
;---------------------------------------;
; CheckForAndConfigureKeyboard ;
;---------------------------------------;--------------------------------------;
; This function checks an interface descriptor of a device to see if it ;
; describes a HID/Boot/Keyboard device. If the device is a keyboard, then ;
; it is configured and initialized. ;
; ;
; Input: ES:DI+BX = Pointer to an interface descriptor supported by device ;
; ES:DI+BP = Limit of the data returned by device during the last ;
; Get Configuration Descriptor command ;
; DS:SI = Pointer to DeviceTableEntry[0] which contains some info ;
; from the device, config, and interface descriptors ;
; ;
; Output: CF = Set if keyboard was not found ;
; Clear if keyboard was found and initialized ;
; ;
; Destroys: Nothing ;
;------------------------------------------------------------------------------;
CheckForAndConfigureKeyboard proc near
pusha
; ES:DI+BX points to an InterfaceDescriptor. Check its BaseClass, SubClass,
; and Protocol fields for a HID/Boot/Keyboard device.
cmp es:(InterfaceDescriptor ptr [di+bx]).BaseClass, BASS_CLASS_HID
stc
jne CheckKbdDone ;Br if this interface is not a HID device
cmp es:(InterfaceDescriptor ptr [di+bx]).SubClass, SUB_CLASS_BOOT_DEVICE
stc
jne CheckKbdDone ;Br if this interface is not a boot device
cmp es:(InterfaceDescriptor ptr [di+bx]).Protocol, PROTOCOL_KEYBOARD
stc
jne CheckKbdDone ;Br if this interface is not a keyboard
; Set the BiosDeviceType field in DeviceTableEntry[0]. This serves as a flag
; that indicates a usable interface has been found in the current configuration.
; This is needed so we can check for other usable interfaces in the current
; configuration (i.e. composite device), but not try to search in other
; configurations.
mov (DeviceTableEntry ptr [si]).BiosDeviceType, BIOS_DEV_TYPE_KEYBOARD
mov (DeviceTableEntry ptr [si]).pDeviceCallback, offset cgroup:ProcessKeyboardData
add (DeviceTableEntry ptr [si]).pDeviceCallback, orgbase
; Call a common routine to handle the remaining initialization that is done
; for all devices.
call ConfigureNewDevice ;Finish init for new device
; Returns CF set/clear appropriately
CheckKbdDone:
popa
ret
CheckForAndConfigureKeyboard endp
;---------------------------------------;
; CheckForAndConfigureMouse ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -