linux / libusb get usb device path
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.
How to get a USB device path by its idVendor and idProduct?
You can use libusbp, a USB abstraction library, to do that. See the port_name example that comes with libusbp. This will definitely work for USB CDC ACM devices (e.g. /dev/ttyACM0
) but I'm not sure if it will work for devices that use a different driver. If you try it, please post a comment here about whether it worked.
Get device path based on USB VID:PID in Linux
libusb can't get it actually. So look at this file instead: /proc/bus/input/devices
Example line from the file:
I: Bus=0003 Vendor=1a2c Product=0c23 Version=0110
N: Name="USB USB Keyboard"
P: Phys=usb-0000:00:14.0-3/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/0003:1A2C:0C23.0015/input/input30
U: Uniq=
H: Handlers=sysrq kbd event10 leds
B: PROP=0
B: EV=120013
B: KEY=1000000000007 ff800000000007ff febeffdff3cfffff fffffffffffffffe
B: MSC=10
B: LED=7
This function gets the event number from the device with the matching VID:PID:
#include <string>
#include <iostream>
#include <fstream>
void open_device (std::string device_vid, std::string device_pid)
{
try
{
std::ifstream file_input;
std::size_t pos;
std::string device_path, current_line, search_str, event_str;
std::string device_list_file = "/proc/bus/input/devices";
bool vid_pid_found = false;
int fd = 0;
bool debug = true;
// 1. open device list file
file_input.open(device_list_file.c_str());
if (!file_input.is_open())
{
std::cerr << "file_input.open >> " << std::strerror(errno) << std::endl;
throw -2;
}
// 2. search for first VID:PID and get event number
search_str = "Vendor=" + device_vid + " Product=" + device_pid;
while (getline(file_input, current_line))
{
if (!vid_pid_found)
{
pos = current_line.find(search_str, 0);
if (pos != std::string::npos)
{
vid_pid_found = true;
search_str = "event";
}
}
else
{
pos = current_line.find(search_str, 0);
if (pos != std::string::npos)
{
event_str = current_line.substr(pos);
// find space and substring event##
pos = event_str.find(' ', 0);
event_str = event_str.substr(0, pos);
break;
}
}
}
// 3. build device path
device_path = "/dev/input/" + event_str;
if (debug) std::cout << "device_path = " << device_path << std::endl;
// 4. connect to device
fd = open (device_path.c_str(), O_RDONLY);
if (fd < 0)
{
std::cerr << "open >> errno = " << std::strerror(errno) << std::endl;
throw -3;
}
}
catch (const std::exception &e)
{
std::cerr << "e.what() = " << e.what() << std::endl;
throw -1;
}
return;
}
Determine USB device file Path
So which device file is used for USB? How can i indentify it?
What you see behind /sys/
is mainly configuration/information about devices. /dev/bus/usb
is what you are looking for. I think that the following article can help you
http://www.linuxjournal.com/article/7466?page=0,0
Is quite old, but still it can help you. (In the article they speak about /proc/bus/usb
, today we have /dev/bus/usb
)
Further more, could you explain to me the number 1-1:1.0? What does it mean?
The generic form is
X-Y.Z:A.B
Each field identify the connection point of your device. The first two field are mandatory:
- X is the USB bus of your motherboard where is connected the USB system.
- Y is the port in use on the bus system
So the USB device identified with the string 3-3
is the device connected on the port 3 of the bus 3.
If you connect an USB hub, you are extending the connection capability of a single USB port. The Linux kernel identify this situation by appending the Z field.
- Z is the port is use on an hub
So, the USB device identified with the string 1-2.5
is the device connected on the port 5 of the hub connected on the port 2 of the bus 1.
USB specification allow you to connect in cascade more then one USB hub, so the Linux kernel continue to append the port in use on the different hubs. So, the USB device identified with the string 1-2.1.1
is the device connected on the port 1 of the hub connected on the port 1 of the hub connected to the port 2 of the bus 1.
A fast way to retrieve these information is to read the kernel messages (if you can).
$ dmesg | grep usb
[... snip ...]
[ 2.047950] usb 4-1: new full-speed USB device number 2 using ohci_hcd
[ 2.202628] usb 4-1: New USB device found, idVendor=046d, idProduct=c318
[ 2.202638] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 2.202643] usb 4-1: Product: Logitech Illuminated Keyboard
[ 2.202648] usb 4-1: Manufacturer: Logitech
[... snip ...]
Then, the last two fields of the pattern (after colon) identify an internal section of an USB device :
- A is the configuration number of the device
- B is the interface number of a configuration
So, the string 4-1:1.1
means: the interface 1, on configuration 1 that is connected on the port 1 of the bus 4.
You can retrieve these information with the command lsusb
.
Need to find and open a USB serial device on linux
I suggest using libusbp. It is a C library with a C++ wrapper, and there is example code showing how to get the name of a serial port based on the vendor ID and product ID of the USB device:
https://github.com/pololu/libusbp/blob/master/examples/port_name/port_name.cpp
Related Topics
How to Open Multiple Instances of a Program in Linux
Inotify Fd - Why Is The Limit Per User Id and Not Per Process
Count Number of Column in a Pipe Delimited File
Kate Text Editor Cannot Handle Lines Longer Than 1024
How to Type "Cargo Run" Without Needing to Set The Ld_Library_Path Shell Variable
Shared Library Symbol Conflicts and Static Linking (On Linux)
Finding Directories with Find in Bash Using a Exclude List
Docker Run Groupadd && Useradd Directives Have No Effect
How to Set Environment Variable in Linux Permanently
Docker - Eacces: Permission Denied, Mkdir '/App/Node_Modules/.Cache'
Adding a Shell Command Inside/Inline of a Systemd Service File
Bash: Start Remote Python Application Through Ssh and Get Its Pid
Copying an Image to The Clipboard from Command Line
What's The Advantage of 3G/1G Vm Split ? 32Bit Linux Kernel
Specify CPU Frequency as a Kernel Cmd_Line Parameter of Linux on Boot