简体   繁体   中英

C/C++ How to get the usb subsystem path for a USB libudev hidraw device?

I'm using libudev in C/C++ with the hidraw subsystem to enumerate and communicate with custom HID devices - working well. My devices are assigned specific usb plugs and they are "hot swappable" - I need to know which plug is connected to each hidraw device. Is there a correspondence between the usb and the hidraw subsystems and how to get the usb path which details the interface route ( like: /dev/bus/usb/002/001 and not the hidraw path) for each device from its hidraw device pointer?

i think with hidraw device pointer you mean the device nodes like /dev/hidraw0 or similar

Hidraw uses a dynamic major number, meaning that udev should be relied on to create hidraw device nodes. Udev will typically create the device nodes directly under /dev (eg: /dev/hidraw0). As this location is distribution- and udev rule-dependent, applications should use libudev to locate hidraw devices attached to the system. There is a tutorial on libudev with a working example at: http://www.signal11.us/oss/udev/

linux has two species of device nodes, one created by device drivers ie /dev/sdb for a mass storage device and raw device nodes like /dev/bus/usb/BBB/DDD where BBB is the bus number and DDD is the device number, that are created by the kernel directly :

USB Device Issues

USB devices usually have two kinds of device nodes associated with them.

The first kind is created by device-specific drivers (eg, usb_storage/sd_mod or usblp) in the kernel. For example, a USB mass storage device would be /dev/sdb, and a USB printer would be /dev/usb/lp0. These device nodes exist only when the device-specific driver is loaded.

The second kind of device nodes (/dev/bus/usb/BBB/DDD, where BBB is the bus number and DDD is the device number) are created even if the device doesn't have a kernel driver. By using these "raw" USB device nodes , an application can exchange arbitrary USB packets with the device, ie, bypass the possibly-existing kernel driver.

source : http://www.linuxfromscratch.org/blfs/view/7.10/postlfs/devices.html

you want to establish a link between the kernel module device node ( ie /dev/hidraw0 ) and the corresponding raw device node ( ie /dev/bus/usb/BBB/DDD )

you can get the bus address ( BBB and DDD ) from the device node using sudo udevadm info -a -p $(sudo udevadm info -q path -n /dev/hidraw0) ( ATTRS{busnum}=="BBB" and ATTRS{devnum}=="DDD" in the output ) however this is a bit ugly

in Find bus number and device number with device file symlink is code using libudev to get bus number BBB and device number DDD for a specific device node in /dev/ ie /dev/hidraw0 it uses udev_device_get_sysattr_value(dev, "devnum")); to get DDD in /dev/bus/usb/BBB/DDD and udev_device_get_sysattr_value(dev, busnum")); to get BBB

you can also get BBB and DDD from sysfs ( /sys/devices/ ... ) :

/sys/devices/pci0000:00/0000:00:12.2/usb2/2-5/2-5.4$ ls 2-5.4:1.0
bDeviceSubClass configuration idProduct remove authorized
bmAttributes descriptors idVendor serial avoid_reset_quirk bMaxPacketSize0 dev manufacturer
speed bcdDevice bMaxPower devnum
maxchild subsystem bConfigurationValue bNumConfigurations devpath
power uevent bDeviceClass bNumInterfaces driver
product urbnum bDeviceProtocol busnum
ep_00

quirks version

source : http://www.signal11.us/oss/udev/

to get the sysfs path of your device ( the /sys/devices/pci0000:00/0000:00:12.2/usb2/2-5/2-5.4 above ) use sudo udevadm info -q path -n /dev/hidraw0

( https://unix.stackexchange.com/questions/344784/how-to-map-sys-bus-usb-devices-to-dev-video )

Hope it's helpful but IIRC, you cannot reliably (with port# being same between insert events) enumerate individual ports on hubs that are connected downstream from a main USB controller point. I think that was one of the reasons we started seeing lots and lots of USB controllers on MB's after USB came out; because when chaining everything off downstream hubs, besides negatively affecting bandwidth, also caused problems with persistent software numbering issues.

I believe when a device is plugged into a USB port directly connected to a USB controller, you can reliably get the same exact port# it's connected to. But when doing that from a downstream multi-port USB hub connected upstream to a USB port from a USB controller, the actual port# on the USB hub does not get passed upstream or even if it does, it is not a predictable port# between insertions/power-resets in the same hub port.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM