10

I use libusb to enumerate over a few usb-devices. Now i like to get the "device-path". I think it's not called usb device-path, because i was not successful with google.

If i connect a usb-device with linux, i get a message in dmesg, here are a few examples for such a "device-path" with an usb temperature sensor (something like this):

Directly to a usb port: [68448.099682] generic-usb 0003:0C45:7401.0056: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:12.0-1/input0 => 12.0-1

Directly to another port: [68560.853108] generic-usb 0003:0C45:7401.0058: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:13.0-1/input0 => 13.0-1

To a usb hub on the first used port: [68600.245809] generic-usb 0003:0C45:7401.005A: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:12.2-1.4/input0 => 12.2-1.4

To another port on the same usb hub: [68647.925092] generic-usb 0003:0C45:7401.005C: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:12.2-1.3/input0 => 12.2-1.3

An now to a usb hub on the usb hub used before: [68740.715518] generic-usb 0003:0C45:7401.005E: input,hidraw1: USB HID v1.10 Keyboard [RDing TEMPer1V1.2] on usb-0000:00:12.2-1.4.4/input0 => 12.2-1.4.4

Long story short: The kernel message always contains a unique path for the physical usb device location (see the bold text before). Is it possible to get this "path" in the user space via libusb? I tried many things with struct usb_bus and struct usb_device, but i always was unsuccessfully.

I need this to identify multiple of these usb thermometers, because they don't have a unique serial number and sometimes they just "reconnect" at runtime, so they get different usb id's. So i think the only way to identify them is via the physical location.

Thanks for the help,

Best Regards Kevin M.

-edit-

Currently i use the following code to search my usb device:

usb_dev_handle *find_lvr_winusb() {

     struct usb_bus *bus;
        struct usb_device *dev;

        for (bus = usb_busses; bus; bus = bus->next) {
        for (dev = bus->devices; dev; dev = dev->next) {
                        if (dev->descriptor.idVendor == VENDOR_ID && 
                                dev->descriptor.idProduct == PRODUCT_ID ) {
                                usb_dev_handle *handle;
                                if(debug) {
                                  printf("lvr_winusb with Vendor Id: %x and Product Id: %x found.\n", VENDOR_ID, PRODUCT_ID);
                                    printf("INFO: %d\n", dev->bus->location);
                                    printf("INFO: %d %s\n", bus->location, bus->dirname);
                                }

                                if (!(handle = usb_open(dev))) {
                                        printf("Could not open USB device\n");
                                        return NULL;
                                }
                                return handle;
                        }
                }
        }
        return NULL;
}

But with this code i cannot get a unique physical position id. The bus->location returns an integer (bus->dirname contains the same, but as string), which is not unique. I know usb has a hierarchy and in the dmesg i can see this hierarchys path.

With libusb i only can get the bus-id (?) and some device id's. But they don't help me, because i need to identify two or more of these temperature sensors. The device-id always changes when the temperature sensor reset's the connection (every 5 to 60 seconds) and the bus id is not unique. Unfortunately the temperature sensor has no unique serial id.

So i think the physical path is the only way to identify the device.

Best regards Kevin M.

Kevin Meier
  • 2,339
  • 3
  • 25
  • 52

3 Answers3

7

Since libusb 1.0.12, they have introduced libusb_get_port_path(), and in 1.0.16 replaced it with libusb_get_port_numbers() which allows you to query the bus topology.

ndyer
  • 952
  • 2
  • 11
  • 15
  • 1
    Use `libusb_get_device_address` for `/dev/input/eventX` http://libusb.sourceforge.net/api-1.0/group__dev.html#gab6d4e39ac483ebaeb108f2954715305d – xinthose Jun 01 '16 at 03:12
3

Overall summery of the sysfs structure path:

1-1.3:1.0

|_usb root hub - bus number - 1
  |_ port number - 1 of root hub
    |_port number - 3 of intermediate hub
      |_current configuration number - 1
        |_ current interface number - 0

More information here

ebpa
  • 1,171
  • 1
  • 12
  • 31
premal
  • 163
  • 3
  • 1
    This is Linux specific. libusb_get_port_numbers() implemented in libusb 1.0.16 works on any plaftorm, even Windows. – mvp Sep 24 '15 at 23:58
  • @mvp: Do you mean any version of Windows? But it seems it won't work on XP sp3. This is my issue https://github.com/libusb/libusb/issues/113. Can you give me some suggestion? – diverger Oct 16 '15 at 11:13
-1

It's possible, like here.

Just scan all USB devices at all busses. When you find needed VID/PID — that's your device.

Or you can do simpler: write an udev-rule which would create symlink like /dev/thermoX when you attach you device. All you need after is to open needed /dev/thermoX.

Eddy_Em
  • 864
  • 6
  • 14
  • Yes, but i have 2 or more devices with the same VIP and PID. The devices are exactly the same. All id's are the same. The only difference is the port they are connected to. – Kevin Meier Jan 11 '13 at 15:57
  • Look to `/dev/bus/usb`: directories are hubs and files in them — devices. – Eddy_Em Jan 11 '13 at 16:05
  • Thanks. I tried, but there is another problem: The file names are the device id. The device id is always increased when a device is reconnected. Unfortunately the usb device reconnects all the time without doing anything. I don't know what the directory name is exactly, because if i connect a usb hub then i just get a new file in a sub directory and not a new directory. – Kevin Meier Jan 11 '13 at 16:10
  • 1
    It's really difficult to identify absolutely identical devices. – Eddy_Em Jan 11 '13 at 16:30
  • Unfortunately yes:-( I thoght it's easy to do this with the hardware path which is printed in `dmesg`, but i cannot find a way get this path for a `struct usb_device`. – Kevin Meier Jan 11 '13 at 16:39
  • In the example above this path is in fields `bus->dirname` and `dev->filename`. – Eddy_Em Jan 11 '13 at 16:55
  • Yes, with these two fields i can get the `/dev/bus/usb/*/*` file. But the filename changes after every reconnection. It doesn't depend on the physical location. So i can only identify the dev-file, but i still don't know which dev-file is which physical device, because the name is "random" and always changes. – Kevin Meier Jan 11 '13 at 17:06
  • I think developer of such device didn't think that somebody would use simultaneously more than one device. So my advice: plug devices to different hubs or find better devices. BTW 1-wire sensors works pretty good without any additional hardware (through serial port or USBserial). – Eddy_Em Jan 11 '13 at 17:12
  • Yes, i think you are right. Btw: If i use `lsusb -t` there is a device tree which shows the physical hierarchy. Maybe i check the source of this tool. Anyway. Thanks for help:-) – Kevin Meier Jan 11 '13 at 17:54
  • I think `lsusb -t` works similar like example in my answer: it just scan all busses & all ports on it. – Eddy_Em Jan 11 '13 at 17:59
  • Yes, it seems to parse the `/dev/bus/usb/*/*` file content (just a blob). With the information there it creates a hierarchical output of the current usb devices. This tree contains the physical path to the device. Thanks for help. – Kevin Meier Jan 12 '13 at 00:02