google / gousb

gousb provides low-level interface for accessing USB devices
Apache License 2.0
845 stars 124 forks source link

Error claiming interface #128

Closed michealroberts closed 2 months ago

michealroberts commented 5 months ago

I'm perhaps looking more for advice on what is going wrong, but I am seeing this error:

Error claiming interface: descriptor of interface (1, 1) in vid=1278,pid=0525,bus=3,addr=36,config=1: alternate setting 1 not found for Interface 1 (1 alternate settings), available alt settings: [0]

This is my Connect functionality:

func (d *Driver) Connect(vendorId gousb.ID, productId gousb.ID, configuration DeviceConfiguration) error {
    ctx := gousb.NewContext()

    ctx.Debug(4)

    defer ctx.Close()

    device, err := ctx.OpenDeviceWithVIDPID(vendorId, productId)
    if err != nil {
        return err
    }
    if device == nil {
        return fmt.Errorf("device not found")
    }
    defer device.Close()

    if len(device.Desc.Configs) < 1 {
        log.Fatalf("Device does not have any configurations")
    }

    d.device = &Device{ctx: ctx, handle: device}

    cfg, err := device.Config(configuration.Number)

    if err != nil {
        log.Printf("Error getting device config: %s", err.Error())
        return err
    }

    defer cfg.Close()

    for _, intf := range cfg.Desc.Interfaces {
        if len(intf.AltSettings) == 0 {
            log.Printf("No alternate settings available for interface %d", intf.Number)
            return fmt.Errorf("no alternate settings available for interface %d", intf.Number)
        }

        alt := intf.AltSettings[0]

        log.Printf("Processing interface %d alternate setting %d", intf.Number, alt.Number)

        iface, err := cfg.Interface(intf.Number, alt.Number)

        if err != nil {
            log.Printf("Error claiming interface: %s", err.Error())
            return err
        }

        defer iface.Close()

        for _, ep := range alt.Endpoints {
            if ep.Direction == gousb.EndpointDirectionOut {
                outEp, err := iface.OutEndpoint(ep.Number)
                if err != nil {
                    log.Printf("Error getting device out endpoint: %s", err.Error())
                    return err
                }
                d.device.outEndpoint = outEp
                fmt.Printf("Found OUT endpoint: %d\n", ep.Number)
            } else if ep.Direction == gousb.EndpointDirectionIn {
                inEp, err := iface.InEndpoint(ep.Number)
                if err != nil {
                    log.Printf("Error getting device in endpoint: %s", err.Error())
                    return err
                }
                d.device.inEndpoint = inEp
                fmt.Printf("Found IN endpoint: %d\n", ep.Number)
            }
            fmt.Println("Endpoint: ", ep)
        }
    }

    if d.device.outEndpoint == nil {
        return fmt.Errorf("out endpoint not found")
    }
    if d.device.inEndpoint == nil {
        return fmt.Errorf("in endpoint not found")
    }

    log.Println("Connected to the device")
    return nil
}

But I am somehow not getting the correct interface numbers from the discovery connection to the device, here is the full debug output:

Attempting to connecting to device with Vendor ID: 4728 and Product ID: 1317
[timestamp] [threadID] facility level [function call] <message>
--------------------------------------------------------------------------------
[ 0.002738] [00d6bdb4] libusb: debug [libusb_get_device_list]  
[ 0.002737] [00d6bdce] libusb: debug [libusb_get_next_timeout] no URBs, no timeout!
[ 0.002747] [00d6bdce] libusb: debug [libusb_handle_events_timeout_completed] doing our own event handling
[ 0.002749] [00d6bdce] libusb: debug [handle_events] event sources modified, reallocating event data
[ 0.002752] [00d6bdce] libusb: debug [usbi_wait_for_events] poll() 1 fds with timeout in 100ms
[ 0.002777] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.002860] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.002867] [00d6bdb4] libusb: debug [libusb_open] open 3.36
[ 0.002896] [00d6bdb4] libusb: debug [darwin_open] device open for access
[ 0.002901] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.002903] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.002905] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002907] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002908] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002909] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002911] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002912] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002914] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002915] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002916] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002917] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002919] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002920] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002921] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002922] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002923] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002925] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002926] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002927] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002928] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002929] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002930] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002931] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002933] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002934] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x25
[ 0.002949] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.002951] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.002956] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.002958] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.002961] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.002962] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.002964] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.002965] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.002967] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.002968] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.002969] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.002971] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 1
[ 0.002972] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.002973] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.002974] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.002976] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.002998] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.002999] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.003000] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.003002] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.003004] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.003005] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.003006] [00d6bdb4] libusb: debug [libusb_get_device_descriptor]  
[ 0.003008] [00d6bdb4] libusb: debug [libusb_get_config_descriptor] index 0
[ 0.003009] [00d6bdb4] libusb: debug [parse_endpoint] skipping descriptor 0x30
[ 0.003013] [00d6bdb4] libusb: debug [libusb_get_configuration]  
[ 0.003014] [00d6bdb4] libusb: debug [libusb_get_configuration] active config 1
2024/06/08 15:36:21 Processing interface 1 alternate setting 1
2024/06/08 15:36:21 Error claiming interface: descriptor of interface (1, 1) in vid=1278,pid=0525,bus=3,addr=36,config=1: alternate setting 1 not found for Interface 1 (1 alternate settings), available alt settings: [0]
[ 0.003176] [00d6bdb4] libusb: debug [libusb_close]  
[ 0.003184] [00d6bdce] libusb: debug [usbi_wait_for_events] poll() returned 1
[ 0.003187] [00d6bdce] libusb: debug [handle_event_trigger] event triggered
[ 0.003188] [00d6bdce] libusb: debug [handle_event_trigger] someone is closing a device
[ 0.003192] [00d6bdce] libusb: debug [libusb_get_next_timeout] no URBs, no timeout!
[ 0.003194] [00d6bdce] libusb: debug [libusb_try_lock_events] someone else is closing a device
[ 0.003195] [00d6bdce] libusb: debug [libusb_event_handler_active] someone else is closing a device
[ 0.003196] [00d6bdce] libusb: debug [libusb_handle_events_timeout_completed] another thread is doing event handling
[ 0.003222] [00d6bdce] libusb: debug [libusb_exit]  
[ 0.003223] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.36
[ 0.003225] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.32
[ 0.003226] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.31
[ 0.003227] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.30
[ 0.003229] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.29
[ 0.003230] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.9
[ 0.003231] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.5
[ 0.003232] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.4
[ 0.003233] [00d6bdce] libusb: debug [libusb_unref_device] destroy device 3.2
[ 0.003888] [00d6bdce] libusb: debug [usbi_remove_event_source] remove fd 3
2024/06/08 15:36:21 failed to connect to device: descriptor of interface (1, 1) in vid=1278,pid=0525,bus=3,addr=36,config=1: alternate setting 1 not found for Interface 1 (1 alternate settings), available alt settings: [0]
exit status 1

I think the device can be connected to, it's just that the alternative interface numbers are not matching up ...

When I manually change to this:

iface, err := cfg.Interface(1, 0)

I get an index out of range panic ...

I am stumped. Is this a firmware issue?

Let me know what other information is needed, if any ...

michealroberts commented 4 months ago

@krasin Is there a way to call libusb_detach_kernel_driver() to ensure that we can claim the target interface?

michealroberts commented 4 months ago

cc @kylelemons Not sure who to ping ...

krasin commented 4 months ago

@krasin Is there a way to call libusb_detach_kernel_driver() to ensure that we can claim the target interface?

@michealroberts it's being 11 years since I touched this codebase. Sorry, but my memory returns zero context about it...

michealroberts commented 4 months ago

@krasin No worries, trying to find the core maintainers for this ... if any are left? :(

zagrodzki commented 4 months ago

Before I review your PR #129, I'd like to see some data to confirm where the issue comes from. Post a result of lsusb -v for the device in question.

zagrodzki commented 2 months ago

For future reference, the discussion happened mostly in the comment threads of #129 .

The lsusb output of the problematic device:

002.001 1278:0525 Unknown (Starlight Xpress)
  Protocol: (Defined at Interface level)
  Configuration 1:
    --------------
    Interface 1 alternate setting 0 (available endpoints: [0x01(1,OUT) 0x82(2,IN)])
      Vendor Specific Class
      ep #2 IN (address 0x82) bulk [512 bytes]
      ep #1 OUT (address 0x01) bulk [512 bytes]
    --------------

and the problem was that the interface number here is not 0 (as expected by the USB for the first interface).

There was an additional problem with the code mentioned in https://github.com/google/gousb/issues/128#issue-2341686861 - that code used intf.Number as the interface number and alt.Number as the alternate setting number. This is a mistake, since alt.Number is always the same as the interface number - the alternate number in the example code should be alt.Alternate. This is why the code tried to claim Interface(1,1) rather than Interface(1,0) and this is why this failed - there was no alternate setting 1. This was as intended. Like reported, calling Interface(1,0) directly resulted in out of bounds access, as Config.Interfaces had only a single element (a single interface in the device above), but its Number was 1, not 0.