15
votes

I'm learning to use libusb v1.0.0 for the first time on Ubuntu 12.10. Here is some small test code I'm using to try and understand how to use this API:

#include <libusb-1.0/libusb.h>
...
libusb_device **list;
libusb_get_device_list(ctx, &list); // Returns 11 USB devices which is correct.
for (size_t idx = 0; list[idx] != NULL; idx ++)
{
    libusb_device *dev = list[idx];
    libusb_device_descriptor desc = {0};
    int rc = libusb_get_device_descriptor(dev, &desc);

At this point, rc == 0, meaning it should have completed successfully. Source: documentation for *libusb_get_device_descriptor()*.

But the structure desc is always empty. None of the fields ever get set. If I change the last two lines above to this:

    libusb_device_descriptor desc = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int rc = libusb_get_device_descriptor(dev, &desc);

...then when libusb_get_device_descriptor() returns, I see desc remains unchanged, confirming for me that I'm not getting what I expect from this API.

I've also tried to run a.out as root just in case this requires elevated privileges. Doing a Google search on libusb_get_device_descriptor hasn't gotten me anywhere.

Relevant commands I ran to try this code:

sudo apt-get install libusb-1.0.0-dev
g++ -ggdb test.cpp -lusb-1.0
./a.out 

Ah! Crazy user error! sharth's code helped me figure it out. Here is the code I was actually using -- see if you can spot the error:

std::cout << "rc == " << libusb_get_device_descriptor(dev, &desc) << std::endl
          << "vendor == " << desc.idVendor << std::endl;

I guess the way the compiler evaluates this, it is free to evaluate desc.idVendor before the call to libusb_get_device_descriptor() has actually been made. My bad.

3

3 Answers

31
votes

You didn't include a full, compilable test case. So I built one. This works for me on CentOS 6 x64. I'm also running this as a normal user account.

Source

#include <cassert>
#include <cstdio>
#include <libusb-1.0/libusb.h>

int main() {
    libusb_context *context = NULL;
    libusb_device **list = NULL;
    int rc = 0;
    ssize_t count = 0;

    rc = libusb_init(&context);
    assert(rc == 0);

    count = libusb_get_device_list(context, &list);
    assert(count > 0);

    for (size_t idx = 0; idx < count; ++idx) {
        libusb_device *device = list[idx];
        libusb_device_descriptor desc = {0};

        rc = libusb_get_device_descriptor(device, &desc);
        assert(rc == 0);

        printf("Vendor:Device = %04x:%04x\n", desc.idVendor, desc.idProduct);
    }

    libusb_free_device_list(list, count);
    libusb_exit(context);
}

Output

Vendor:Device = 1d6b:0002
Vendor:Device = 1d6b:0002
Vendor:Device = 8087:0020
Vendor:Device = 8087:0020
Vendor:Device = 0424:2514
Vendor:Device = 10c4:ea60
Vendor:Device = 051d:0002
Vendor:Device = 0624:0248
3
votes

This is not an standalone answer, it's more a comment to Bill Lynch's post. I'm not able to add a comment to Bill Lynch's post (missing reputation) so I decided to do it this way ;-).

There's a little detail missing in the code above:

you have to free the list you got filled from libusb_get_device_list by hand.

From the libusb docu:

You are expected to unreference all the devices when you are done with them, and then free the list with libusb_free_device_list(). Note that libusb_free_device_list() can unref all the devices for you. Be careful not to unreference a device you are about to open until after you have opened it.

3
votes

Just to add to Bill's answer, to avoid the multiple warnings you will likely recieve from this line

libusb_device_descriptor desc = {0};

Simply remove the assignment.

libusb_device_descriptor desc;

Not a huge deal, but these things bother me.