c - linux下如何获取usb的urb信息

标签 c linux usb libusb

我正在尝试获取 U 盘的 urb 信息。我写如下:

#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <usb.h>
/* #include <stropts.h> */
/* #include <inttypes.h> */
#include <linux/usbdevice_fs.h>
/* #include <asm/byteorder.h> */
/* #include <linux/usb/ch9.h> */
#define USBDEVFS_REAPURB           _IOW('U', 12, void *)
int main(int argc, char *argv[])
{ 
  int fd;
  int result;
  int i;
  struct usbdevfs_urb * receive;
  receive = malloc(sizeof (struct usbdevfs_urb));

  bzero(receive, sizeof (struct usbdevfs_urb));

  char file[30];
  strncpy (file, argv[1], 30);

  if ((fd = open(file, O_RDWR)) < 0)
    {
      printf("failed to open device: %s, \n error: %s \n", file, strerror(errno));
    }
  else 
    {
      printf ("Open successed: Device: %s\n", file);
      for (i = 0; i < 1000; ++i)
        {
          printf ("polling...\n");
          result = ioctl(fd, USBDEVFS_REAPURB, receive);
            if (result < 0)
              {
                printf ("Error!  : ioctl returned : %d\n errno =%s\n", result, strerror(errno));
                break;
              }
          printf ("The %d th time ok.\n", i + 1);
          usleep(2000);
        }
    }
  close(fd);
  return 0;
}

我可以编译它。但当我运行它时,它说参数无效。 那么,我这是怎么了?

最佳答案

我最终遇到了类似的问题 - 所以这是我的笔记...除了评论中迄今为止指出的问题之外,我认为 OP 代码的主要问题是:

  1. 你不能只是“收获”URB;您首先必须“提交”(读取或写入)URB,然后“收获”它
  2. 你不能只是open一个file您从命令行参数 ( argv[1] ) 作为路径获得的字符串,并获取对 URB ioctl 有效的文件描述符。

至于1,也许参见c - User mode USB isochronous transfer from device-to-host

Also, once I have filled this structure am I right in thinking I need to call the following:
int retSubmit = ioctl( fd, USBDEVFS_SUBMITURB, &usbRequest );
and then once submitted I can wait for the request to complete using
USBDEVFS_REAPURBNDELAY

'[Linux-usb-users] usbfs urb reap problem.' - MARC

The routine, and the call to it, whidch I use to submit the URB are as follows:
...
Submitting the URB works fine. This is how I try to reap it:
...

linux.usb.devel - Re: usbdevfs questions (and others... ) - msg#00167

Yes, you submit a BULK type usbdevfs_urb to the interrupt endpoint. It gets one packet of data. You can submit multiple ones that will queue up. and I'm guessing 'reap' is REAd Pointer, not like the grim reaper (although maybe it is...:)

认为(但我不确定100%)“提交”和“收获”相当于Virtual USB Analyzer - Tutorial中所述的“提交”和“完成” 。

就 2. 而言 - 这取决于设备的类型。例如,如果您将带有 FT232 USB 串行芯片的 Arduino Duemillanove 连接到 Linux PC,则会自动加载 ftdi_sio内核驱动程序,依次加载 usbserial驱动程序,然后创建文件(设备节点)/dev/ttyUSB0 。因此,Linux 最多会将该文件视为一个普通的串行端口 - 不一定与 URB 请求相关(我猜 USB 闪存拇指驱动器也有类似的情况);当尝试使用 /dev/ttyUSB0 参数调用 OP 代码时,我遇到了与 OP 相同的错误。

获取这个文件描述符有点困难,因为很难追踪示例:

'Re: Accessing usb devices with USBDEVFS' - MARC

On Fri, May 05, 2006 at 04:45:30PM -0400, Danny Budik wrote:
> How do I use the "raw" usbfs? I tried reading from the /dev/bus/usb file
> and got a bind - address already in use error.

Look at how libusb is implemented for a good example of how to do this.
The source code to 'lsusb' will also help you out here.

Linux Kernel Documentation/usb/proc_usb_info.txt

NOTE: The filesystem has been renamed from "usbdevfs" to
"usbfs", to reduce confusion with "devfs". You may
still see references to the older "usbdevfs" name.

我基本上是从[Discuss-gnuradio] New implementation for fusb_linux without allocs/frees中的代码开始的,并尝试修改 OP 代码,使其能够与 Arduino Duemillanove 配合使用。问题是它使用旧的 libusb-0.1代码,其中有一些不同名称的 header 和函数;例如libusb-0.1libusb/usbi.h ,而较新的 libusb-1.0libusb/libusbi.h 。本质上,libusb函数可用于获取正确的文件描述符。

修改后的OP代码如下,假设我们称之为 testu.c 。我已经在 Ubuntu Natty 上对其进行了测试 - 首先,连接 Arduino Duemillanove,它挂接 ftdi_sio驱动程序(可以在终端中使用 tail -f /var/log/syslog 检查)。因此,首先,删除自动 Hook 的驱动程序( libusb 不需要它与设备通信,并且它可能会干扰;请注意,删除后, /dev/ttyUSB0 文件不再存在):

sudo modprobe -r ftdi_sio   # this also removes usbserial 
lsmod | grep ftdi           # make sure ftdi_sio isn't listed by lsmod

然后,我们将使用 USB 供应商/产品 ID 通过 libusb 连接到设备;要找到它,请使用 lsusb :

$ lsusb | grep FT
Bus 002 Device 005: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC

视频ID:PID 0403:6001被硬编码在testu.c中;然后我们就可以构建并运行它。请注意 testu程序必须以 root 身份运行(通过 sudo ) - 否则 libusb将无法与设备通信:

$ gcc -o testu -Wall -g testu.c `pkg-config --libs --cflags libusb-1.0`
testu.c:23:1: warning: ‘fd_from_usb_dev_handle’ defined but not used

$ sudo ./testu
First
Second 0x8B4B4F0
Open successed: Device: 0403:6001 6
polling...
The 1 th time ok.
polling...
The 2 th time ok.
polling...
The 3 th time ok.
polling...
The 4 th time ok.
polling...
The 5 th time ok.
polling...
The 6 th time ok.
polling...
The 7 th time ok.
polling...
The 8 th time ok.
polling...
The 9 th time ok.
polling...
The 10 th time ok.

代码提交一个写入请求(在端点 0x02 上),然后获取它 - 我可以看到 Arduino 上的 RX LED 闪烁 - 这意味着一些数据确实如预期的那样到达了它。然而,并没有发生更多的事情 - 所以我不确定代码是否回答了“获取 USB 的 urb 信息”部分 :)但是,它确实显示了如何获取文件描述符,因此原始 ioctl可以工作 - 尽管通过 libusb (您可能必须深入挖掘 libusb 源代码,以便在没有 libusb 的情况下执行相同的操作)。

这里是testu.c (注意,安装 libusb-dev 包以便可以编译):

#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <usb.h>
/* #include <stropts.h> */
/* #include <inttypes.h> */
#include <linux/usbdevice_fs.h>
/* #include <asm/byteorder.h> */
/* #include <linux/usb/ch9.h> */
//~ #define USBDEVFS_REAPURB           _IOW('U', 12, void *)

#include <libusb.h>

struct libusb_device_handle *d_udh = NULL;


// [http://www.mail-archive.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aecac7ddcddbdddd83c9c0dbdccfcac7c1eec9c0db80c1dcc9" rel="noreferrer noopener nofollow">[email protected]</a>/msg17549.html [Discuss-gnuradio] New implementation for fusb_linux without allocs/frees]
static int
fd_from_usb_dev_handle (libusb_device_handle *udh) //(usb_dev_handle *udh)
{
  return *((int *) udh);
}

//~ ./libusb/os/linux_usbfs.c
struct linux_device_handle_priv {
  int fd;
};

//~ ./libusb/libusbi.h
#define usbi_mutex_t                    pthread_mutex_t
struct list_head {
        struct list_head *prev, *next;
};
struct libusb_device_handle {
        /* lock protects claimed_interfaces */
        usbi_mutex_t lock;
        unsigned long claimed_interfaces;

        struct list_head list;
        struct libusb_device *dev;
        unsigned char os_priv[0];
};

//~ ./libusb/os/linux_usbfs.c
struct linux_device_handle_priv* _device_handle_priv(
        struct libusb_device_handle *handle)
{
  struct linux_device_handle_priv* out;
  out =  (struct linux_device_handle_priv *) handle->os_priv;
  return out;
};



int main(int argc, char *argv[])
{
  int fd;
  int result;
  int i;
  struct usbdevfs_urb * receive;
  struct usbdevfs_urb * send;
  struct linux_device_handle_priv *hpriv;
  send = malloc(sizeof (struct usbdevfs_urb));
  memset(send, 0, sizeof (*send));
  send->buffer_length = 10;
  send->buffer = malloc(sizeof(unsigned char)*10);
  send->type = USBDEVFS_URB_TYPE_BULK;
  send->endpoint = 0x02;
  send->signr = 0;


  receive = malloc(sizeof (struct usbdevfs_urb));

  bzero(receive, sizeof (struct usbdevfs_urb));

  char file[30];
  if (argv[1]) strncpy (file, argv[1], 30);

  printf ("First\n");
  result = libusb_init(NULL);
  if (result < 0)
  {
    printf("failed to initialise libusb:\n");
  }
  d_udh = libusb_open_device_with_vid_pid(NULL, 0x0403, 0x6001);
  hpriv = _device_handle_priv(d_udh);
  printf ("Second 0x%X\n", (unsigned int)d_udh);
  result = d_udh ? 0 : -EIO;
  //~ if ((fd = open(file, O_RDWR)) < 0)
  if (result < 0)
    {
      printf("failed to open device: %s, \n error: %s \n", "0403:6001", strerror(errno)); //file
    }
  else
    {
      //~ fd = fd_from_usb_dev_handle(d_udh); // doesn't work
      fd = _device_handle_priv(d_udh)->fd;
      printf ("Open successed: Device: %s %d\n", "0403:6001", fd ); // file);
      for (i = 0; i < 10; ++i)
        {
          result = ioctl (fd, USBDEVFS_SUBMITURB, send);
            if (result < 0)
              {
                printf ("Error! USBDEVFS_SUBMITURB : ioctl returned : %d\n errno =%s\n", result, strerror(errno));
                break;
              }
          printf ("polling...\n");
          result = ioctl(fd, USBDEVFS_REAPURB, receive);
            if (result < 0)
              {
                printf ("Error! USBDEVFS_REAPURB : ioctl returned : %d\n errno =%s\n", result, strerror(errno));
                break;
              }
          printf ("The %d th time ok.\n", i + 1);
          usleep(2000);
        }
    }
  close(fd);
  return 0;
}

好吧,希望这对某人有帮助,
干杯!

关于c - linux下如何获取usb的urb信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11574418/

相关文章:

python - 如何从 python 执行用 C 编写的文件,同时传递字符串值并接受/存储它作为输出返回的字符串。(Linux)

c - 是否有将整数转换为十六进制或二进制的 C 库?

linux - 我如何编写一个命令来显示 mac 地址并且每个地址后跟一个换行符?

c++ - 如何在 Ubuntu 中构建 OpenSMILE?

c# - 释放未插入的虚拟串行端口

java - 如何与 USB 转并行适配器连接?

c - sizeof 运算符在以下代码片段中的行为如何?

linux - 我如何正确引用此 bash 管道以供观看?

linux - USB 键盘和 setxkbmap

c - 'add an index to an archive file' 是什么意思?