使用设备文件符号链接查找总线编号和设备编号

时间:2013-11-27 17:42:18

标签: c++ c linux device

我有SYMLINK规则生成的设备文件(/dev/CDMAModemudev。我想找到实际设备的总线编号和设备编号。实际上我想在我的C ++程序中在设备USBDEVFS_RESET上执行/dev/bus/usb/BUS_NO/DEVICE_NO ioctl。

---- udev rule ----

SUBSYSTEMS=="usb", ACTION=="add", DRIVERS=="zte_ev", ATTRS{bNumEndpoints}=="03", SYMLINK+="CDMAModem"
SUBSYSTEMS=="usb", ACTION=="remove", DRIVERS=="zte_ev", ATTRS{bNumEndpoints}=="03", SYMLINK-="CDMAModem"

5 个答案:

答案 0 :(得分:4)

我认为libudev会给你:

#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;
}

我认为您可以将此信息与ioctl()一起使用,如:

[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

答案 1 :(得分:2)

您可以对符号链接ioctl所代表的文件执行/dev/CDMAModem,就像/dev/bus/结构下的文件一样。

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

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

如果您确实想查找此链接指向的位置,file命令会告诉您。

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

答案 2 :(得分:1)

我认为stat()库调用是一个很好的起点...与libusb一起。

答案 3 :(得分:1)

如果您只想解决链接问题,可以使用readlink并稍后使用字符串函数解析信息。

  

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

     

readlink函数获取符号链接文件名的值。链接指向的文件名被复制到缓冲区中。此文件名字符串不以空值终止; readlink通常返回复制的字符数。 size参数指定要复制的最大字符数,通常是缓冲区的分配大小。

答案 4 :(得分:1)

~$ 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"

虽然这很难看但有效。从C ++程序调用{​​{1}}并从输出中过滤udevadmbusnum属性。我希望参与devnum开发的一些开发人员可以提供帮助,并且可能libudev邮件列表会有所帮助。