Find bus number and device number with device file symlink

北慕城南 提交于 2019-12-01 06:40:20
Charles Pehlivanian

I think libudev will give you that:

#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>

int main(int argc, char **argv)
{

    struct udev *udev;
    struct udev_enumerate *enumerate;
    struct udev_list_entry *devices, *dev_list_entry;
    struct udev_device *dev;

    udev = udev_new();

    enumerate = udev_enumerate_new(udev);
    udev_enumerate_add_match_subsystem(enumerate, "CDMAModem");
    udev_enumerate_scan_devices(enumerate);
    devices = udev_enumerate_get_list_entry(enumerate);

    udev_list_entry_foreach(dev_list_entry, devices) {
        const char *path;

        path = udev_list_entry_get_name(dev_list_entry);
        dev = udev_device_new_from_syspath(udev, path);

        fprintf(stderr, "devnum: %s\n",
            udev_device_get_sysattr_value(dev, "devnum"));
        fprintf(stderr, "busnum: %s\n",
            udev_device_get_sysattr_value(dev, 'busnum:));
        udev_device_unref(dev);
    }

    udev_enumerate_unref(enumerate);
    udev_unref(udev);

    return 0;
}

You can then use this information with ioctl(), I think, as in:

[charles@localhost 2-1]$ cd /sys/class/mem/random
[charles@localhost 2-1]$echo $PWD
/sys/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-1

You can perform an ioctl on the file represented by the symlink /dev/CDMAModem as you would on the file under the /dev/bus/ structure.

#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>

int f = open("/dev/CDMAModem", O_RDWR);
ioctl(f, USBDEVFS_RESET);

If you actually want to find where this link is pointing, the file command will tell you.

> file /dev/CDMAModem
/dev/CDMAModem: symbolic link to `bus/usb/BUS/DEV'

I think the stat() library call would be a good place to start... Along with libusb.

If all you want to do is resolve the link, you can use readlink and parse the information later with string functions.

Function: ssize_t readlink (const char *filename, char *buffer, size_t size)

The readlink function gets the value of the symbolic link filename. The file name that the link points to is copied into buffer. This file name string is not null-terminated; readlink normally returns the number of characters copied. The size argument specifies the maximum number of characters to copy, usually the allocation size of buffer.

~$ sudo udevadm info -a -p $(sudo udevadm info -q path -n /dev/CDMAModem)
[sudo] password for gowtham:

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/ttyUSB0/tty/ttyUSB0':
    KERNEL=="ttyUSB0"
    SUBSYSTEM=="tty"
    DRIVER==""

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/ttyUSB0':
    KERNELS=="ttyUSB0"
    SUBSYSTEMS=="usb-serial"
    DRIVERS=="zte_ev"
    ATTRS{port_number}=="0"

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0':
    KERNELS=="2-1.2:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="zte_ev"
    ATTRS{bInterfaceClass}=="ff"
    ATTRS{bInterfaceSubClass}=="ff"
    ATTRS{bInterfaceProtocol}=="ff"
    ATTRS{bNumEndpoints}=="03"
    ATTRS{supports_autosuspend}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{interface}=="Data Interface"

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2':
    KERNELS=="2-1.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{devpath}=="1.2"
    ATTRS{idVendor}=="19d2"
    ATTRS{speed}=="12"
    ATTRS{bNumInterfaces}==" 6"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{busnum}=="2"
    ATTRS{devnum}=="8"
  ATTRS{busnum}=="2"
  ATTRS{devnum}=="8"

Though this is ugly but works. From C++ program call udevadm and filter for busnum and devnum attributes from the output. I hope some developer who involved in libudev development shall help and may be udev mailing-list will help.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!