Private Sub Form_Load()

'   This subroutine runs as soon as the program starts  (ie as soon as this FORM is loaded)

'   Initialize my global variables

ConnectionStatus(0) = "No device"

ConnectionStatus(1) = "Device connected"

ConnectionStatus(2) = "Device FAILED enumeration"

ConnectionStatus(3) = "Device general FAILURE"

ConnectionStatus(4) = "Device caused overcurrent"

ConnectionStatus(5) = "Not enough power for device"



'   Initialize the display

For i& = 0 To 3: HCD(i&).BackColor = RGB(256, 0, 0): Next i& 'Red = start

StatusBox.Text = "Searching for Host Controllers"

Collect_Data.Height = 1725



'   Descriptors will be displayed in a different window, load it

Load Display_Descriptors



'   Look for Host Controllers.

'   I limit the search to 3. There may be more but this is unlikely.

'   The Host Controller Buttons are HCD(0) to HCD(3)

'   Try opening the controller using it's Symbollic Name

'

For ControllerIndex& = 0 To 3

    HostControllerName$ = "\\.\HCD" & ControllerIndex&

    HostControllerHandle& = CreateFile(HostControllerName$, &H40000000, 2, 0, 3, 0, 0)

    If HostControllerHandle& > 0 Then

        HCD(ControllerIndex&).Tag = HostControllerHandle&

        HCD(ControllerIndex&).BackColor = RGB(0, 256, 0) 'Green = GO

        HCD(ControllerIndex&).Enabled = True

        Else

        HCD(ControllerIndex&).BackColor = RGB(256, 128, 0) 'Amber = wait

        HCD(ControllerIndex&).Enabled = False

        End If

    Next ControllerIndex&

StatusBox.Text = "Select a Host Controller"

End Sub



Private Sub HCD_Click(Index%)

'   Can only click HCD buttons with a Host Controller behind them

'   Host controller handle is stored in the button's TAG field

'

'   Get the name of the host controller

HostController$ = GetNameOf("Host Controller", HCD(Index).Tag, &H220424)

StatusBox.Text = "Host Controller: " & HostController$ & " selected"

Device_Display.Clear

Collect_Data.Height = 6900

'

'   Get the name of the Root Hub and open a connection to it

RootHubName$ = GetNameOf("Root Hub", HCD(Index).Tag, &H220408)

RootHubHandle& = OpenConnection(RootHubName$)

'

'   Get the node connection information.

' **This is commented out, it should work but doesn't.  Assume Root Hub has a Device ID of 1

'Status& = DeviceIoControl(RootHubHandle&, &H22040C, RootHubNodeConnection.ConnectionIndex, 256, RootHubNodeConnection.ConnectionIndex, 256, BytesReturned&, 0)

'If Status& = 0 Then ErrorExit ("Could not get connection information from Root Hub")

'

Call GetNodeInformation(RootHubHandle&)

'

'   Save this information in our data table

DeviceData(0).DeviceHandle = RootHubHandle&

DeviceData(0).DeviceType = 1  'Root Hub

Device_Display.AddItem "001      : Root Hub"

'

'   Discover what is connected to the ports of this Root Hub

Level& = 0

Level& = GetPortData(RootHubHandle&, DeviceData(0).NodeData.NodeDescriptor.PortCount, Level& + 1)



StatusBox.Text = "Select a device, then choose a descriptor to display"

End Sub



Function GetPortData(Handle&, PortCount As Byte, HubDepth&) As Long

Dim ThisDevice As Byte



For PortIndex& = 1 To PortCount

    Call GetNodeConnectionData(Handle&, PortIndex&)

    

    ThisDevice = 0 ' default value, no device connected

    PortStatus& = DeviceData(DataIndex).ConnectionData.ThisConnectionStatus(0) ' save some typing!

    If PortStatus& = 1 Then

        ThisDevice = DeviceData(DataIndex).ConnectionData.DeviceAddress(0)

        DeviceData(DataIndex).DeviceHandle = Handle&

        End If

    ' Create an indented display so that Hubs and their connections are easily seen

    Indent$ = " ": For i& = 1 To HubDepth: Indent$ = Indent$ & ".": Next i&

    DeviceName$ = ThreeDecimalCharacters$(ThisDevice) & Indent$ & "       Port["

    Mid$(DeviceName$, 10) = ":"

    

    If PortStatus& <> 1 Then ' There is not a valid device on this port, tell user

        Device_Display.AddItem DeviceName$ & PortIndex & "] = " & ConnectionStatus$(PortStatus&)

        Else ' have a Device or a Hub connected to this port

        

        If DeviceData(DataIndex).ConnectionData.DeviceIsHub Then

'

'   Need to discover how many ports are supported on this hub.

'   Follow the same proceedure as we did for the root hub = get it's name, "open" it and get the node information

            ExternalHubName$ = GetExternalHubName(PortIndex&, Handle&)

            ExternalHubHandle& = OpenConnection(ExternalHubName$)

            Call GetNodeInformation(ExternalHubHandle&)

            DeviceData(DataIndex).DeviceType = 2 'Hub

'   LAST thing we do is update the display status of this device connection

            Device_Display.AddItem DeviceName$ & PortIndex & "] = Hub Connected"

'

'   Discover what, if anything, is connected to the ports of this Root Hub

            Level& = GetPortData(ExternalHubHandle&, DeviceData(DataIndex - 1).NodeData.NodeDescriptor.PortCount, HubDepth& + 1)



        Else 'we have a device connected to this port

            DeviceData(DataIndex).DeviceType = 3 'IODevice

            Device_Display.AddItem DeviceName$ & PortIndex & "] = IO Device Connected"

            End If 'USBDeviceInfo.DeviceIsHub

        End If 'PortStatus& <> 1

    Next PortIndex&

End Function



Private Sub Device_Display_Click()

' User has selected a device

Selected& = Device_Display.ListIndex

Entry$ = Device_Display.List(Selected)

DeviceID& = Val(Left$(Entry$, 3))

If DeviceID& = 0 Then

    StatusBox.Text = "There is no device connected to this node, please choose another"

Else

    StatusBox.Text = "Fetching descriptors"

    Call CollectDescriptors(Selected&)

    Call Display_Descriptors.Initialize

    End If

End Sub



Private Sub CollectDescriptors(Selected&)

' Collect all of the descriptors from the selected device and store them in the DescriptorData byte array

' Start with the Device Descriptor

For i& = 1 To 18: DescriptorData(i&) = DeviceData(Selected&).ConnectionData.ThisDevice.Contents(i& - 1): Next i&

Nexti& = 18

' Now get local copies of some key variables

Dim Configuration As Byte: Dim StringIndex As Byte

Handle& = DeviceData(Selected&).DeviceHandle

ConnectionIndex& = DeviceData(Selected&).ConnectionData.ConnectionIndex

ConfigurationCount = DeviceData(Selected).ConnectionData.ThisDevice.Contents(17)

For Configuration = 1 To ConfigurationCount

    TotalLength& = GetConfigurationDescriptor(Handle&, ConnectionIndex&, Configuration - 1)

' Copy the Configuration Descriptor into the common data buffer

    For i& = 1 To TotalLength&: DescriptorData(Nexti& + i&) = PCHostRequest.ConfigurationDescriptor(i& - 1): Next i&

    Nexti& = Nexti& + TotalLength&: Next Configuration

' Check for Strings

StringIndex = 0

Do While TotalLength& <> 0

    TotalLength = GetStringDescriptor(Handle&, ConnectionIndex&, StringIndex)

    StringIndex = StringIndex + 1

    For i& = 1 To TotalLength&: DescriptorData(Nexti& + i&) = PCHostRequest.ConfigurationDescriptor(i& - 1): Next i&

    Nexti& = Nexti& + TotalLength&: Loop

End Sub



Private Function GetStringDescriptor&(Handle&, ConnectionIndex&, StringIndex As Byte)

PCHostRequest.ConnectionIndex = ConnectionIndex

PCHostRequest.PacketData.wValueLo = StringIndex: PCHostRequest.PacketData.wValueHi = 3 ' = type

If StringIndex = 0 Then

    PCHostRequest.PacketData.wIndex = 0

    Else: PCHostRequest.PacketData.wIndex = &H409: End If ' This SHOULD be read from String 0

PCHostRequest.PacketData.wLength = 254 ' = Max string length

Status& = DeviceIoControl(Handle&, &H220410, PCHostRequest.ConnectionIndex, 286, PCHostRequest.ConnectionIndex, 286, BytesReturned&, 0)

If Status = 0 Then BytesReturned = 12 ' No string, so return TotalLength = 0

GetStringDescriptor& = BytesReturned& - 12

End Function



Private Function GetConfigurationDescriptor&(Handle&, ConnectionIndex&, ConfigurationID As Byte)

PCHostRequest.ConnectionIndex = ConnectionIndex

PCHostRequest.PacketData.wValueLo = ConfigurationID: PCHostRequest.PacketData.wValueHi = 2 ' = type

PCHostRequest.PacketData.wIndex = 0: PCHostRequest.PacketData.wLength = 9

' First read just the Configuration Descriptor to discover 'Total Length'

' Note 21 = 13(Size of PCHostRequest) + 8(Size of PacketData)

Status& = DeviceIoControl(Handle&, &H220410, PCHostRequest.ConnectionIndex, 21, PCHostRequest.ConnectionIndex, 21, BytesReturned&, 0)

If Status = 0 Then ErrorExit ("Could not get initial Configuration Data")

' Now read Configuration+Interface+Endpoint+Class

TotalLength = 256 * PCHostRequest.ConfigurationDescriptor(3) + PCHostRequest.ConfigurationDescriptor(2)

PCHostRequest.ConnectionIndex = ConnectionIndex

PCHostRequest.PacketData.wValueLo = ConfigurationID: PCHostRequest.PacketData.wValueHi = 2 ' = type

PCHostRequest.PacketData.wIndex = 0: PCHostRequest.PacketData.wLength = TotalLength

Status& = DeviceIoControl(Handle&, &H220410, PCHostRequest.ConnectionIndex, TotalLength + 13, PCHostRequest.ConnectionIndex, TotalLength + 13, BytesReturned&, 0)

If Status = 0 Then ErrorExit ("Could not get complete Configuration Data")

If BytesReturned& > 2000 Then ErrorExit ("Buffer Overflow for Configuration Descriptor")

GetConfigurationDescriptor& = BytesReturned& - 12

End Function