pci_utils代码走读之设备读写

   

目录

通用接口层注册

具体接口层实现

设备节点

读取或者写入


   在一个系统中,如何访问pcie外设?

   在linux 内核中已经封装了接口,不必关系具体实现,直接用即可;针对X86, 则可通过常用的寄存器进行访问。

通用接口层注册

  作为通用的pci设备扫描及读写工具,pci utils对此接口层进行了同一的封装,具体代码在 

lib/ init.c    中。 根据不同的编译宏,可以选择不同的底层访问接口。例如针对带有linux sysfs的,则通过sysfs接口进行访问。

static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
  NULL,
#ifdef PCI_HAVE_PM_LINUX_SYSFS
  &pm_linux_sysfs,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_LINUX_PROC
  &pm_linux_proc,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_INTEL_CONF
  &pm_intel_conf1,
  &pm_intel_conf2,
#else
  NULL,
  NULL,
#endif
#ifdef PCI_HAVE_PM_FBSD_DEVICE
  &pm_fbsd_device,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_AIX_DEVICE
  &pm_aix_device,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_NBSD_LIBPCI
  &pm_nbsd_libpci,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_OBSD_DEVICE
  &pm_obsd_device,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_DUMP
  &pm_dump,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_DARWIN_DEVICE
  &pm_darwin,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_SYLIXOS_DEVICE
  &pm_sylixos_device,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_HURD_CONF
  &pm_hurd,
#else
  NULL,
#endif
#ifdef PCI_HAVE_PM_WIN32_CFGMGR32
  &pm_win32_cfgmgr32,
#else
  NULL,
#endif
};

具体接口层实现

以通过 sysfs访问pcie为例,其代码在  lib/sysfs.c 

static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
{
  int fd = sysfs_setup(d, SETUP_READ_CONFIG);
  int res;

  if (fd < 0)
    return 0;
  res = do_read(d, fd, buf, len, pos);
  if (res < 0)
    {
      d->access->warning("sysfs_read: read failed: %s", strerror(errno));
      return 0;
    }
  else if (res != len)
    return 0;
  return 1;
}

设备节点

sysfs_setup(struct pci_dev *d, int intent)
{
  struct pci_access *a = d->access;
  char namebuf[OBJNAMELEN];

  if (a->cached_dev != d || (intent == SETUP_WRITE_CONFIG && !a->fd_rw))
    {
      sysfs_flush_cache(a);
      a->cached_dev = d;
    }

  if (intent == SETUP_READ_VPD)
    {
      if (a->fd_vpd < 0)
	{
	  sysfs_obj_name(d, "vpd", namebuf);
	  a->fd_vpd = open(namebuf, O_RDONLY);
	  /* No warning on error; vpd may be absent or accessible only to root */
	}
      return a->fd_vpd;
    }

  if (a->fd < 0)
    {
      sysfs_obj_name(d, "config", namebuf); //这个接口用于确定pcie设备sysfs config的节点位置
      a->fd_rw = a->writeable || intent == SETUP_WRITE_CONFIG;
      a->fd = open(namebuf, a->fd_rw ? O_RDWR : O_RDONLY);
      if (a->fd < 0)
	a->warning("Cannot open %s", namebuf);
      a->fd_pos = 0;
    }
  return a->fd;
}

即sysfs中通过此config文件来访问pcie配置空间。
/sys/bus/pci/devices/0000:00:01.0$ ll config
-rw-r--r-- 1 root root 256 May 16 00:12 config

sysfs_obj_name(struct pci_dev *d, char *object, char *buf)
{
  int n = snprintf(buf, OBJNAMELEN, "%s/devices/%04x:%02x:%02x.%d/%s",
		   sysfs_name(d->access), d->domain, d->bus, d->dev, d->func, object);
  if (n < 0 || n >= OBJNAMELEN)
    d->access->error("File name too long");
}

读取或者写入

通过在lib/pread.h 中的pread pwrite进行读写

/* glibc 2.1 or newer -> pread/pwrite supported automatically */

系统中glibc版本查询:

ldd --version
ldd (Ubuntu GLIBC 2.27-3ubuntu1.2) 2.27
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

参考

5. Accessing PCI device resources through sysfs — The Linux Kernel documentation 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

proware

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值