四联光电智能照明论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 17422|回复: 7
打印 上一主题 下一主题

Linux+libusb开发用户USB驱动程序

[复制链接]
  • TA的每日心情
    开心
    2018-11-9 08:52
  • 241

    主题

    691

    帖子

    7652

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    7652
    跳转到指定楼层
    楼主
    发表于 2016-11-18 15:17:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    前几天心血来潮,在网上买了游戏摇杆和按键,他们通过usb口与电脑连接,于是乎我就想针对此手柄与按键开发自己的usb驱动,目的是为了以后玩的happy,哈哈。
        libusb是用户端驱动程序封装库,是USB主机对USB设备进行操作的函数集合,有了它我们针对某型号USB设备就不用去修改比较繁琐的linux内核驱动了,方便了对设备的使用与调试。我电脑的编程环境是ubuntu12.04+geany(一款linux下的集成开发工具,个人感觉挺好用的)。接下来分享一下代码:
    #include <stdio.h>
    #include <string.h>
    #include <usb.h>

    #define IdVendor 0x0079       //这是我设备的厂商号
    #define IdProduct 0x0006      //这是我设备的产品号,当你的usb设备接入电脑时,使用lsusb -v命令来查看设备信息,请看下面第三张图片中的0079:0006
    //#define PrintDev

    char enp_num[8],buf8[8],is_change=0;

    //端点描述符
    static void print_endpoint(struct usb_endpoint_descriptor *endpoint)
    {
      printf("      bEndpointAddress: xh\n", endpoint->bEndpointAddress);
      printf("      bmAttributes:     xh\n", endpoint->bmAttributes);
      printf("      wMaxPacketSize:   %d\n", endpoint->wMaxPacketSize);
      printf("      bInterval:        %d\n", endpoint->bInterval);
      printf("      bRefresh:         %d\n", endpoint->bRefresh);
      printf("      bSynchAddress:    %d\n", endpoint->bSynchAddress);
    }

    static void print_altsetting(struct usb_interface_descriptor *interface)
    {
      int i;

      printf("    bInterfaceNumber:   %d\n", interface->bInterfaceNumber);
      printf("    bAlternateSetting:  %d\n", interface->bAlternateSetting);
      printf("    bNumEndpoints:      %d\n", interface->bNumEndpoints);
      printf("    bInterfaceClass:    %d\n", interface->bInterfaceClass);
      printf("    bInterfaceSubClass: %d\n", interface->bInterfaceSubClass);
      printf("    bInterfaceProtocol: %d\n", interface->bInterfaceProtocol);
      printf("    iInterface:         %d\n", interface->iInterface);

      for (i = 0; i < interface->bNumEndpoints; i++)
        print_endpoint(&interface->endpoint[i]);
    }

    //显示设备所拥有的所有接口的描述符
    static void print_interface(struct usb_interface *interface)
    {
      int i;

      for (i = 0; i < interface->num_altsetting; i++)
        print_altsetting(&interface->altsetting[i]);
    }

    //配置描述符
    static void print_configuration(struct usb_config_descriptor *config)
    {
      int i;

      printf("  wTotalLength:         %d\n", config->wTotalLength);
      printf("  bNumInterfaces:       %d\n", config->bNumInterfaces);
      printf("  bConfigurationValue:  %d\n", config->bConfigurationValue);
      printf("  iConfiguration:       %d\n", config->iConfiguration);
      printf("  bmAttributes:         xh\n", config->bmAttributes);
      printf("  MaxPower:             %d\n", config->MaxPower);

      for (i = 0; i < config->bNumInterfaces; i++)
        print_interface(&config->interface[i]);
    }

    static void print_device(struct usb_device *dev)
    {
        //读取描述符
        int i;
        char description[256];
        snprintf(description, sizeof(description), "X-X",dev->descriptor.idVendor, dev->descriptor.idProduct);
        printf("Dev #%d: %s\n", dev->devnum,description);
        for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
          print_configuration(&dev->config[i]);

    }

    //因为我的游戏设备属于HID类型,所以他与电脑通过中断端点进行数据传输。当摇杆位置变化或者按键按下时,读取设备中断端点值
    static int read_interupt(struct usb_device *dev)
    {
        usb_dev_handle *udev;
       
        char buf[256];
        int ret,i;
        udev=usb_open(dev);
       
        //#ifdef PrintDev
            //print_device(dev);
        //#endif

        //使用libusb驱动前必须使接口脱离linux内核驱动
        usb_detach_kernel_driver_np(udev,0);
        //操作libusb接口函数时需要声明接口
        usb_claim_interface(udev,0);
        //读中断端点1
        ret=usb_interrupt_read(udev,1,buf8,8,0x0a);
        //printf("%d\n",ret);
        usb_release_interface(udev,0);
        for(i=0;i<8;i++)
        {
            if(i==2)    //为了消除第二项不稳定因素
                continue;
            if(enp_num[i]!=buf8[i])
            {
                is_change=1;
                break;
            }
        }
       
        if(is_change==1)
        {
            is_change=0;
            for(i=0;i<8;i++)
            {
                enp_num[i]=buf8[i];
                printf("%d ",enp_num[i]);
                           
            }
            printf("\n");
        }
        if (udev)
            usb_close(udev);
        return 0;
    }

    int main(int argc, char *argv[])
    {
        struct usb_bus *bus;
        struct usb_device *dev;
       
        usb_init();
        usb_find_busses();
        usb_find_devices();
       
        memset(enp_num,0,sizeof(enp_num));
        memset(buf8,0,sizeof(buf8));
        for (bus = usb_busses; bus; bus = bus->next) {      
           for (dev = bus->devices; dev; dev = dev->next)     
               {
                   if((dev->descriptor.idVendor==IdVendor)&&(dev->descriptor.idProduct==IdProduct))
                   {                                             
                        while(1)
                        {
                            read_interupt(dev);
                        }              
                   }
               }
           }
       printf("*****************************\n");
      
       return 0;
    }

    //控制传输命令,通过控制端点(端点0)进行数据传输  
    //renum=usb_control_msg(udev,0x80,USB_REQ_GET_DESCRIPTOR,
                    //0x0100,0,description,USB_DT_DEVICE_SIZE,0);
  • TA的每日心情
    开心
    2018-11-9 08:52
  • 241

    主题

    691

    帖子

    7652

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    7652
    沙发
     楼主| 发表于 2016-11-18 15:40:42 | 只看该作者

    1   介绍


    1.1   概览

    本文档描述libusb-0.1的API和USB相关内容。


    1.2   当前OS支持

    Linux 2.2或以上

    FreeBSD/NetBSD/OpenBSD

    Darwin/MacOSX


    2   API


    2.1   设备与接口

    一个设备可能有多个接口,所以一个句柄可以返回多个接口实例。不要忘记调用 usb_claim_interface() 。


    2.2   超时

    总是以毫秒为单位。


    2.3   数据类型

    同时使用有抽象结构和非抽象结构来保持可移植性。


    2.4   同步

    所有libusb v0.1的函数都是同步的,这意味着操作完成或超时前不会返回。异步操作从libusb v1.0开始支持。


    2.5   返回值

    libusb v0.1有两种返回值。一种是 usb_open() 返回的句柄,另一种是整数int,返回负数表示错误。


    3   函数


    3.1   核心函数

    void usb_init(void);

    初始化libusb。

    int usb_find_busses(void);

    查找所有总线,返回上次调用以后改变的数量(包括新增的和移除的总线)。

    int usb_find_devices(void);

    寻找每个总线上的所有设备。应该在 usb_find_busses() 之后调用。返回上次调用后改变的数量(包括新增和移除的设备)。

    struct usb_bus *usb_get_busses(void);

    简单的返回全局变量 usb_busses 。这仅对支持C调用规范和可以使用共享库的语言,但是不支持C全局变量的(例如Delphi)。


    3.2   设备操作

    这组函数用于操作设备。允许你打开关闭设备,设置配置、轮换设置、干净的关闭和重置设备。它也提供OS级别的操作,如认领(claim)和释放接 口。

    usb_dev_handle *usb_open(struct *usb_device dev);

    打开设备以供使用,返回设备句柄。

    int usb_close(usb_dev_handle *dev);

    关闭设备,返回0成功,负数失败。

    int usb_set_configuration(usb_dev_handle *dev, int configuration);

    设置活跃配置。configuration参数是描述符bConfigurationValue字段的值。返回0成功,负数失败。

    int usb_set_altinterface(usb_dev_handle *dev, int alternate);

    设置当前接口的活跃轮换设置。alternate参数是描述符bAlternateSetting字段的值。返回0成功,负数失败。

    int usb_resetep(usb_dev_handle *dev, unsigned int ep);

    重置指定端点的所有状态。ep参数是描述符的bEndpointAddress字段的值。返回0称公,负数失败。

    该接口不建议使用,你可能需要的是 usb_clear_halt() 。

    int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);

    清理端点所有停止状态,ep是描述符bEndpointAddress字段的值。返回0成功,负数失败。

    int usb_reset(usb_dev_handle *dev);

    重置指定设备,通过发送RESET指令过去。返回0成功,负数失败。

    在执行该函数之后,需要重新列举,找到设备。当前的句柄无法再工作了。

    int usb_claim_interface(usb_dev_handle *dev, int interface);

    通过OS认领一个接口。interface参数是描述符的bInterfaceNumber字段。返回0成功,负数失败。

    必须在任何接口相关操作(如 usb_set_altinterface() 、 usb_bulk_write() 等)之前调用。

    返回码:

    1.EBUSY :接口无效,无法被认领
    2.ENOMEM :内存不足

    int usb_release_interface(usb_dev_handle *dev, int interface);

    释放之前认领的接口。interface参数是描述符的bInterfaceNumber字段。返回0成功,负数失败。


    3.3   控制传输

    发送消息到缺省控制管道。

    int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);

    发送控制请求到设备的缺省控制管道。参数对应USB规范中的同名类型。返回读写字节数,负数失败。

    int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, size_t buflen);

    获取设备的字符串描述,通过index和langdi索引。返回Unicode字符串到buf中。返回实际写入buf的字节数,负数失败。

    int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen);

    包装了 usb_get_string() 函数,返回第一种语言指定index索引的字符串描述,并转换到C风格的ASCII。返回写入buf字节数,负数失败。

    int usb_get_descriptor(usb_dev_handle *dev, unsigned char type, unsigned char index, void *buf, int size);

    获取设备缺省控制管道的描述符,通过type和index索引。返回实际写入buf的字节数,负数失败。

    参考 usb_get_descriptor_by_endpoint() 了解允许指定控制端点的。

    int usb_get_descriptor_by_endpoint(usb_dev_handle *dev, int ep, unsigned char type, unsigned char index, void *buf, int size);

    从设备获取描述符,以type和index索引,以ep标志的控制管道。返回读取字节数,负数失败。


    3.4   块传输

    这部分允许应用从数据块管道发送和接收数据。

    int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);

    写入一块数据到端点ep,返回写入成功字节数,负数失败。

    int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);

    读取一块数据,从端点ep,返回读取成功字节数,负数失败。


    3.5   中断传输

    这组函数允许应用发送和接收数据通过中断管道。

    int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);

    执行对端点ep的中断写入,返回实际写入字节数,负数失败。

    int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);

    执行对中断端点ep的读取,返回实际读取字节数,负数失败。


    3.6   不可移植

    这些函数是不可移植的。有些是暴露了OS USB API之类的。他们都回加上函数名后缀 _np 。

    一个C预处理器宏会定义实现的函数。形式是 LIBUSB_HAS_ 加上函数名,没有 usb_ 前缀。例如, usb_get_driver_np() 实现了,就会定义LIBUSB_HAS_GET_DRIVER_NP 。

    int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name, int namelen);

    这个函数获取接口驱动的名字。成功返回0,失败负数。

    只在Linux有实现。

    int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);

    这个函数从接口剥离内核驱动。使用了libusb的应用可以随即重新认领接口。返回0成功,负数失败。

    只在Linux有实现。


    4   例子


    4.1   简单例子

    与设备通信前要先找到它。需要先找到所有总线(busses),然后找到所有设备:
    struct usb_bus *busses;

    usb_init();
    usb_find_busses();
    usb_find_devices();

    busses=usb_get_busses();


    在这之后,应用应该手动轮询所有总线和设备,匹配其所要的:
    struct usb_bus *bus;
    int c,i,a;

    for (bus=busses; bus; bus=bus->next) {
        struct usb_device *dev;
        for (dev=bus->devices; dev; dev=dev->next) {
            if (dev->descriptor.bDeviceClass==7) {
                /*打开设备,认领接口,然后操作*/
            }
            /*循环遍历所有配置*/
            for (c=0; c< dev->descriptor.bNumConfigurations; c++) {
                /*循环遍历所有接口*/
                for (i=0; i< dev->config[c].bNumInterfaces; i++) {
                    /*循环遍历所有轮换设置*/
                    for (a=0; a< dev->config[c].interface[i].num_altsetting; a++) {
                        /*检查接口是否是打印机*/
                        if (dev->config[c].interface[i].altsetting[a].bInterfaceClass==7) {
                            /*打开设备,设置轮换配置,认领接口,然后操作*/
                        }
                    }
                }
            }
        }
    }



    4.2   源码包的例子

    tests目录有个程序叫 testlibusb.c 。它简单的调用libusb寻找所有设备,然后遍历并打印描述符。其结果很简单,不过用处有限。倒是可以作为很好的入门。


    4.3   其他应用

    其他应用就参考其他的项目吧:
    1.gPhoto :使用libusb与相机通信
    2.rio500 :使用libusb与SONICblue Rio 500播放器
  • TA的每日心情
    开心
    2018-11-9 08:52
  • 241

    主题

    691

    帖子

    7652

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    7652
    板凳
     楼主| 发表于 2016-11-18 15:43:48 | 只看该作者
    驱动开发向来是内核开发中工作量最多的一块,随着USB设备的普及,大量的USB设备的驱动开发也成为驱动开发者手头上做的最多的事情。本文主要介绍 Linux平台下基于libusb的驱动开发,希望能够给从事Linux驱动开发的朋友带来些帮助,更希望能够给其他平台上的无驱设计带来些帮助。文章是我在工作中使用libusb的一些总结,难免有错误,如有不当的地方,还请指正。

        Linux 平台上的usb驱动开发,主要有内核驱动的开发和基于libusb的无驱设计。



    对于内核驱动的大部分设备,诸如带usb接口的hid设备,linux本身已经自带了相关的驱动,我们只要操作设备文件便可以完成对设备大部分的操作,而另外一些设备,诸如自己设计的硬件产品,这些驱动就需要我们驱动工程师开发出相关的驱动了。内核驱动有它的优点,然而内核驱动在某些情况下会遇到如下的一些问题:



    1 当使用我们产品的客户有2.4内核的平台,同时也有2.6内核的平台,我们要设计的驱动是要兼容两个平台的,就连makefile 我们都要写两个。



    2 当我们要把linux移植到嵌入平台上,你会发现原先linux自带的驱动移过去还挺大的,我的内核当然是越小越好拉,这样有必要么。这还不是最郁闷的地方,如果嵌入平台是客户的,客户要购买你的产品,你突然发现客户设备里的系统和你的环境不一样,它没有你要的驱动了,你的程序运行不了,你会先想:“没关系,我写个内核驱动加载一下不就行了“。却发现客户连insmod加载模块的工具都没移植,那时你就看看老天,说声我怎么那么倒霉啊,客户可不想你动他花了n时间移植的内核哦



    3 花了些功夫写了个新产品的驱动,挺有成就感啊,代码质量也是相当的有水准啊。正当你沉醉在你的代码中时,客服不断的邮件来了,“客户需要2.6.5内核的驱动,config文件我已经发你了” “客户需要双核的 2.6.18-smp 的驱动” “客户的平台是自己定制的是2.6.12-xxx “   你恨不得把驱动的源代码给客户,这样省得编译了。你的一部分工作时间编译内核,定制驱动



    有问题产生必然会有想办法解决问题的人, libusb的出现给我们带来了某些方便,即节约了我们的时间,也降低了公司的成本。 所以在一些情况下,就可以考虑使用libusb的无驱设计了。



        下面我们就来详细讨论一下libusb, 并以写一个hid设备的驱动来讲解如何运用libusb,至于文章中涉及的usb协议的知识,限于篇幅,就不详细讲解了,相关的可自行查看usb相关协议。





    一 libusb 介绍



       libusb 设计了一系列的外部API 为应用程序所调用,通过这些API应用程序可以操作硬件,从libusb的源代码可以看出,这些API 调用了内核的底层接口,和kernel driver中所用到的函数所实现的功能差不多,只是libusb更加接近USB 规范。使得libusb的使用也比开发内核驱动相对容易的多。

    Libusb 的编译安装请查看Readme,这里不做详解



    二 libusb 的外部接口



    2.1 初始化设备接口



    这些接口也可以称为核心函数,它们主要用来初始化并寻找相关设备。



    usb_init

    函数定义: void usb_init(void);

    从函数名称可以看出这个函数是用来初始化相关数据的,这个函数大家只要记住必须调用就行了,而且是一开始就要调用的.



    usb_find_busses

    函数定义: int usb_find_busses(void);

    寻找系统上的usb总线,任何usb设备都通过usb总线和计算机总线通信。进而和其他设备通信。此函数返回总线数。



    usb_find_devices

    函数定义: int usb_find_devices(void);

    寻找总线上的usb设备,这个函数必要在调用usb_find_busses()后使用。以上的三个函数都是一开始就要用到的,此函数返回设备数量。



    usb_get_busses

    函数定义: struct usb_bus *usb_get_busses(void);

    这个函数返回总线的列表,在高一些的版本中已经用不到了,这在下面的实例中会有讲解





    2.2 操作设备接口



        usb_open

    函数定义: usb_dev_handle *usb_open(struct *usb_device dev);

    打开要使用的设备,在对硬件进行操作前必须要调用usb_open 来打开设备,这里大家看到有两个结构体 usb_dev_handle 和 usb_device 是我们在开发中经常碰到的,有必要把它们的结构看一看。在libusb 中的usb.h和usbi.h中有定义。

    这里我们不妨理解为返回的 usb_dev_handle 指针是指向设备的句柄,而行参里输入就是需要打开的设备。



       usb_close

       函数定义: int usb_close(usb_dev_handle *dev);

       与usb_open相对应,关闭设备,是必须调用的, 返回0成功,<0 失败。



       usb_set_configuration

       函数定义: int usb_set_configuration(usb_dev_handle *dev, int configuration);

       设置当前设备使用的configuration,参数configuration 是你要使用的configurtation descriptoes中的bConfigurationValue, 返回0成功,<0失败( 一个设备可能包含多个configuration,比如同时支持高速和低速的设备就有对应的两个configuration,详细可查看usb标准)



       usb_set_altinterface

       函数定义: int usb_set_altinterface(usb_dev_handle *dev, int alternate);

       和名字的意思一样,此函数设置当前设备配置的interface descriptor,参数alternate是指interface descriptor中的bAlternateSetting。返回0成功,<0失败



       usb_resetep

       函数定义: int usb_resetep(usb_dev_handle *dev, unsigned int ep);

       复位指定的endpoint,参数ep 是指bEndpointAddress,。这个函数不经常用,被下面介绍的usb_clear_halt函数所替代。



       usb_clear_halt

       函数定义: int usb_clear_halt (usb_dev_handle *dev, unsigned int ep);

       复位指定的endpoint,参数ep 是指bEndpointAddress。这个函数用来替代usb_resetep



       usb_reset

       函数定义: int usb_reset(usb_dev_handle *dev);

       这个函数现在基本不怎么用,不过这里我也讲一下,和名字所起的意思一样,这个函数reset设备,因为重启设备后还是要重新打开设备,所以用usb_close就已经可以满足要求了。



       usb_claim_interface

       函数定义: int usb_claim_interface(usb_dev_handle *dev, int interface);

       注册与操作系统通信的接口,这个函数必须被调用,因为只有注册接口,才能做相应的操作。

    Interface 指 bInterfaceNumber. (下面介绍的usb_release_interface 与之相对应,也是必须调用的函数)



       usb_release_interface

       函数定义: int usb_release_interface(usb_dev_handle *dev, int interface);

       注销被usb_claim_interface函数调用后的接口,释放资源,和usb_claim_interface对应使用。



       2.3 控制传输接口



       usb_control_msg

       函数定义:int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);

       从默认的管道发送和接受控制数据



       usb_get_string

       函数定义: int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, size_t buflen);



       usb_get_string_simple

    函数定义: int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen);





       usb_get_descriptor

       函数定义: int usb_get_descriptor(usb_dev_handle *dev, unsigned char type, unsigned char index, void *buf, int size);



       usb_get_descriptor_by_endpoint

       函数定义: int usb_get_descriptor_by_endpoint(usb_dev_handle *dev, int ep, unsigned char type, unsigned char index, void *buf, int size);





       2.4 批传输接口



       usb_bulk_write

       函数定义: int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);



        usb_interrupt_read

    函数定义: int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);





    2.5 中断传输接口

    usb_bulk_write

    函数定义: int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);



    usb_interrupt_read

    函数定义: int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);





    基本上libusb所经常用到的函数就有这些了,和usb协议确实很接近吧。下面我们实例在介绍一个应用。

    //----------------===================================

    Libusb库的使用


    使用libusb之前你的linux系统必须装有usb文件系统,这里还介绍了使用hiddev设备文件来访问设备,目的在于不仅可以比较出usb的易用性,还提供了一个转化成libusb驱动的案例。

    3.1 find设备


    任何驱动第一步首先是寻找到要操作的设备,我们先来看看HID驱动是怎样寻找到设备的。我们假设寻找设备的函数Device_Find(注:代码只是为了方便解说,不保证代码的健全)


    /* 我们简单看一下使用hid驱动寻找设备的实现,然后在看一下libusb是如何寻找设备的 */

    int Device_Find()

    {

        char dir_str[100];   /* 这个变量我们用来保存设备文件的目录路径 */

        char hiddev[100];    /* 这个变量用来保存设备文件的全路径 */

    DIR dir;              


    /* 申请的字符串数组清空,这个编程习惯要养成 */

    memset (dir_str, 0 , sizeof(dir_str));

    memset (hiddev, 0 , sizeof(hiddev));


        /* hiddev 的设备描述符不在/dev/usb/hid下面,就在/dev/usb 下面

    这里我们使用opendir函数来检验目录的有效性

    打开目录返回的值保存在变量dir里,dir前面有声明

    */

    dir=opendir("/dev/usb/hid");

        if(dir){

            /* 程序运行到这里,说明存在 /dev/usb/hid 路径的目录 */

            sprintf(dir_str,"/dev/usb/hid/");

            closedir(dir);

        }else{

            /* 如果不存在hid目录,那么设备文件就在/dev/usb下 */

            sprintf(dir_str,"/dev/usb/");

        }


        /* DEVICE_MINOR 是指设备数,HID一般是16个 */

    for(i = 0; i < DEVICE_MINOR; i++) {

        /* 获得全路径的设备文件名,一般hid设备文件名是hiddev0 到 hiddev16 */

            sprintf(hiddev, "%shiddev%d", dir_str,i);


           /* 打开设备文件,获得文件句柄 */

           fd = open(hiddev, O_RDWR);

           if(fd > 0) {


               /* 操作设备获得设备信息 */

              ioctl(fd, HIDIOCGDEVINFO, &info);

       

                  /* VENDOR_ID 和 PRODUCT_ID 是标识usb设备厂家和产品ID,驱动都需要这两个参数来寻找设备,到此我们寻找到了设备 */

               if(info.vendor== VENDOR_ID && info.product== PRODUCT_ID) {

                    /* 这里添加设备的初始化代码 */

                      


                   device_num++;   /* 找到的设备数 */

               }

               close(fd);

           }

        }

        return device_num;         /* 返回寻找的设备数量 */

    }


    我们再来看libusb是如何来寻找和初始化设备


    int Device_Find()

    {

    struct usb_bus             *busses;


        int                           device_num = 0;


        device_num = 0;       /* 记录设备数量 */

       

        usb_init();            /* 初始化 */

        usb_find_busses();   /* 寻找系统上的usb总线 */

        usb_find_devices(); /* 寻找usb总线上的usb设备 */

       

        /* 获得系统总线链表的句柄 */

    busses = usb_get_busses();


        struct usb_bus       *bus;

        /* 遍历总线 */

        for (bus = busses; bus; bus = bus->next) {

            struct usb_device *dev;

            /* 遍历总线上的设备 */

            for (dev = bus->devices; dev; dev = dev->next) {


               /* 寻找到相关设备, */

    if(dev->descriptor.idVendor==VENDOR_ID&& dev->descriptor.idProduct == PRODUCT_ID) {

                    /* 这里添加设备的初始化代码 */

                      

                   device_num++;   /* 找到的设备数 */

    }              

            }      

        }

        return device_num;        /* 返回设备数量 */

    }


    注:在新版本的libusb中,usb_get_busses就可以不用了 ,这个函数是返回系统上的usb总线链表句柄

    这里我们直接用usb_busses变量,这个变量在usb.h中被定义为外部变量

    所以可以直接写成这样:

    struct usb_bus    *bus;

            for (bus = usb_busses; bus; bus = bus->next) {

                   struct usb_device *dev;

            for (dev = bus->devices; dev; dev = dev->next) {

               /* 这里添加设备的初始化代码 */


            }

    }


    3.2 打开设备


    假设我们定义的打开设备的函数名是device_open,


    /* 使用hid驱动打开设备 */

    int Device_Open()

    {

        int handle;

        /* 传统HID驱动调用,通过open打开设备文件就可 */

    handle = open(“hiddev0”, O_RDONLY);

    }


    /* 使用libusb打开驱动 */


    int Device_Open()

    {

    /* LIBUSB 驱动打开设备,这里写的是伪代码,不保证代码有用 */

    struct usb_device*    udev;

    usb_dev_handle*        device_handle;


    /* 当找到设备后,通过usb_open打开设备,这里的函数就相当open 函数 */

    device_handle = usb_open(udev);

    }


    3.3 读写设备和操作设备

    假设我们的设备使用控制传输方式,至于批处理传输和中断传输限于篇幅这里不介绍

    我们这里定义三个函数,Device_Write, Device_Read, Device_Report

    Device_Report 功能发送接收函数

    Device_Write 功能写数据

    Device_Read   功能读数据


    Device_Write和Device_Read调用Device_Report发送写的信息和读的信息,开发者根据发送的命令协议来设计,我们这里只简单实现发送数据的函数。


    假设我们要给设备发送72字节的数据,头8个字节是报告头,是我们定义的和设备相关的规则,后64位是数据。


    HID驱动的实现(这里只是用代码来有助理解,代码是伪代码)


    int Device_Report(int fd, unsigned char *buffer72)

    {

    int       ret; /* 保存ioctl函数的返回值 */

    int      index;


        unsigned char send_data[72]; /* 发送的数据 */

    unsigned char recv_data[72]; /* 接收的数据 */

        struct hiddev_usage_ref uref; /* hid驱动定义的数据包 */

        struct hiddev_report_info rinfo; /* hid驱动定义的


        memset(send_data, 0, sizeof(send_data));

    memset(recv_data, 0, sizeof(recv_data));


        memcpy(send_data, buffer72, 72);

       /* 这在发送数据之前必须调用的,初始化设备 */

        ret = ioctl(fd, HIDIOCINITREPORT, 0);

        if( ret !=0) {

            return NOT_OPENED_DEVICE;/* NOT_OPENED_DEVICE 属于自己定义宏 */

        }

        /* HID设备每次传输一个字节的数据包 */

        for(index = 0; index < 72; index++) {

            /* 设置发送数据的状态 */

        uref.report_type = HID_REPORT_TYPE_FEATURE;

        uref.report_id = HID_REPORT_ID_FIRST;

        uref.usage_index = index;

        uref.field_index = 0;

        uref.value = send_data[index];

        ioctl(fd, HIDIOCGUCODE, &uref);

        ret=ioctl(fd, HIDIOCSUSAGE, &uref);

        if(ret != 0 ){

               return UNKNOWN_ERROR;

        }

    }

    /* 发送数据 */

    rinfo.report_type = HID_REPORT_TYPE_FEATURE;

    rinfo.report_id = HID_REPORT_ID_FIRST;

    rinfo.num_fields = 1;

    ret=ioctl(fd, HIDIOCSREPORT, &rinfo);   /* 发送数据 */

    if(ret != 0) {

            return WRITE_REPORT;

    }


    /* 接受数据 */

    ret = ioctl(fd, HIDIOCINITREPORT, 0);

    for(index = 0; index < 72; index++) {

        uref.report_type = HID_REPORT_TYPE_FEATURE;

        uref.report_id = HID_REPORT_ID_FIRST;

        uref.usage_index = index;

        uref.field_index = 0;

        ioctl(fd, HIDIOCGUCODE, &uref);

        ret = ioctl(fd, HIDIOCGUSAGE, &uref);

        if(ret != 0 ) {

            return UNKNOWN_ERROR;

        }

        recv_data[index] = uref.value;

    }


    memcpy(buffer72, recv_data, 72);


    return SUCCESS;

    }


    libusb驱动的实现


    int Device_Report(int fd, unsigned char *buffer72)

    {

        /* 定义设备句柄 */

        usb_dev_handle* Device_handle;

       

        /* save the data of send and receive */

        unsigned char   send_data[72];

        unsigned char   recv_data[72];

       

        int              send_len;

        int             recv_len;

       

        /* 数据置空 */

        memset(send_data, 0 , sizeof(send_data));

        memset(recv_data, 0 , sizeof(recv_data));

       

        /* 这里的g_list是全局的数据变量,里面可以存储相关设备的所需信息,当然我们 也可以从函数形参中传输进来,设备的信息在打开设备时初始化,我们将在后面的总结中详细描述一下 */

        Device_handle = (usb_dev_handle*)(g_list[fd].device_handle);

        if (Device_handle == NULL) {

            return NOT_OPENED_DEVICE;

    }


    /* 这个函数前面已经说过,在操作设备前是必须调用的, 0是指用默认的设备 */

    usb_claim_interface(Device_handle, 0);


    /* 发送数据,所用到的宏定义在usb.h可以找到,我列出来大家看一下

            #define USB_ENDPOINT_OUT       0x00

           #define USB_TYPE_CLASS     (0x01 << 5)

           #define USB_RECIP_INTERFACE 0x01

          

           #define HID_REPORT_SET       0x09 */

    send_len = usb_control_msg(Device_handle,

    USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE,

                                   HID_REPORT_SET,

                                   0x300,

                                   0,

                                   send_data, 72, USB_TIMEOUT);


    /* 发送数据有错误 */

    if (send_len < 0) {

            return WRITE_REPORT;

    }


    if (send_len != 72) {

            return send_len;

    }


    /* 接受数据

           #define USB_ENDPOINT_IN         0x80

           #define USB_TYPE_CLASS          (0x01 << 5)

           #define USB_RECIP_INTERFACE        0x01

           #define HID_REPORT_GET          0x01

        */

    recv_len = usb_control_msg(Device_handle,

    USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE,

                                   HID_REPORT_GET,

                                   0x300,

                                     0,

                                   recv_data, 72, USB_TIMEOUT);

                                                       

        if (recv_len < 0) {

            printf("failed to retrieve report from USB device!\n");

            return READ_REPORT;

        }

       

        if (recv_len != 72) {

            return recv_len;

        }

       

       

        /* 和usb_claim_interface对应 */

        usb_release_interface(RY2_handle, 0);

        memcpy(buffer72, recv_data, 72);


    return SUCCESS;

    }


    3.4 关闭设备

    假设我们定义的关闭设备的函数名是Device_Close()


    /* 使用hid驱动关闭设备 */

    int Device_Close()

    {

        int handle;

       

    handle = open(“hiddev0”, O_RDONLY);

    /* 传统HID驱动调用,通过close()设备文件就可 */


    close( handle );

    }


    /* 使用libusb关闭驱动 */

    int Device_Close()

    {

    /* LIBUSB 驱动打开设备,这里写的是伪代码,不保证代码有用 */

    struct usb_device*    udev;

    usb_dev_handle*        device_handle;


    device_handle = usb_open(udev);


    /* libusb库使用usb_close关闭程序 */

    usb_close(device_handle);

    }


    libusb的驱动框架

    前面我们看了些主要的libusb函数的使用,这里我们把前面的内容归纳下:

    一般的驱动应该都包含如下接口:

    Device_Find(); /* 寻找设备接口 */

    Device_Open(); /* 打开设备接口 */

    Device_Write(); /* 写设备接口 */

    Device_Read(); /* 读设备接口 */

    Device_Close(); /* 关闭设备接口 */


    具体代码如下:


    #include <usb.h>

    /* usb.h这个头文件是要包括的,里面包含了必须要用到的数据结构 */


    /* 我们将一个设备的属性用一个结构体来概括 */

    typedef struct

    {

        struct usb_device*    udev;

        usb_dev_handle*        device_handle;

        /* 这里可以添加设备的其他属性,这里只列出每个设备要用到的属性 */

    } device_descript;


    /* 用来设置传输数据的时间延迟 */

    #define USB_TIMEOUT     10000


    /* 厂家ID 和产品 ID */

    #define VENDOR_ID    0xffff   

    #define PRODUCT_ID   0xffff


    /* 这里定义数组来保存设备的相关属性,DEVICE_MINOR可以设置能够同时操作的设备数量,用全局变量的目的在于方便保存属性 */

    #define DEVICE_MINOR 16

    int     g_num;

    device_descript g_list[ DEVICE_MINOR ];


    /* 我们写个设备先找到设备,并把相关信息保存在 g_list 中 */

    int Device_Find()

    {

        struct usb_bus       *bus;

        struct usb_device *dev;


        g_num = 0;

        usb_find_busses();

        usb_find_devices();

       

        /* 寻找设备 */

        for (bus = usb_busses; bus; bus = bus->next) {

            for (dev = bus->devices; dev; dev = dev->next) {

    if(dev->descriptor.idVendor==VENDOR_ID&& dev->descriptor.idProduct == PRODUCT_ID) {

                        /* 保存设备信息 */

                        if (g_num < DEVICE_MINOR) {

                         g_list[g_num].udev = dev;  

                         g_num ++;

                         }              

                }      

            }

        }

       

        return g_num;

    }


    /* 找到设备后,我们根据信息打开设备 */

    int Device_Open()

    {

        /* 根据情况打开你所需要操作的设备,这里我们仅列出伪代码 */

        if(g_list[g_num].udev != NULL) {
            g_list[g_num].device_handle = usb_open(g_list[g_num].udev);

    }

    }


    /* 下面就是操作设备的函数了,我们就不列出来拉,大家可以参考上面的介绍 */

    int DeviceWite(int handle)

    {

        /* 填写相关代码,具体查看设备协议*/

    }


    int DeviceOpen(int handle)

    {

        /* 填写相关代码,具体查看设备协议 */

    }


    /* 最后不要忘记关闭设备 */

    void Device_close(int handle)

    {

        /* 调用usb_close */

    }
  • TA的每日心情
    开心
    2018-11-9 08:52
  • 241

    主题

    691

    帖子

    7652

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    7652
    地板
     楼主| 发表于 2016-11-18 15:44:32 | 只看该作者
    USB描述符

    主机是通过标准的USB请求命令中的GET_DESCRIPTOR获得一个USB设备属性的描述符的。关于Descriptor即描述符,是一个完整的数据结构,可以通过C语言等编程实现,并存储在USB设备中,用于描述一个USB设备的所有属性。它的作用就是通过响应主机的请求命令操作来给主机传递信息,从而让主机知道设备具有什么功能、属于哪一类设备、要占用多少带宽、使用哪类传输方式及数据量的大小,只有主机确定了这些信息,并为设备分配资源后,设备才能真正开始工作。标准的描述符有5种,USB为这些描述符定义了编号:

    1——设备描述符

    2——配置描述符

    3——字符描述符

    4——接口描述符

    5——端点描述符

    一个设备只有一个设备描述符,而一个设备描述符可以包含多个配置描述符,而一个配置描述符可以包含多个接口描述符,一个接口使用了几个端点,就有几个端点描述符。这些描述符是用一定的字段构成的,分别如下说明:
    1.设备描述符

    struct_DEVICE_DEscriptOR_STRUCT
    {
    BYTE bLength;
    BYTE bDescriptorType;
    WORD bcdUSB;
    BYTE bDeviceClass;
    BYTE bDeviceSubClass;
    BYTE bDeviceProtocl;
    BYTE bMaxPacketSize0;
    WORD idVendor;
    WORD idProduct;
    WORD bcdDevice;
    BYTE iManufacturer;
    BYTE iProduct;
    BYTE iSeialNumber;
    BYTE bNumConfiguration;
    }

    2.配置描述符

    struct_CONFIGURATION_DEscriptOR_STRUCT
    {
    BYTE bLength;
    BYTE bDescriptorType;
    WORD wTotalLength;
    BYTE bNumlnterface;
    BYTE bConfigurationValue;
    BYTE iConfiguration:
    BYTE bmAttribute;
    BYTE MaxPower;
    }

    3.字符描述符

    struct_STRING_DEscriptOR_STRUCT
    {
    BYTE bLength;
    BYTE bDescriptorType;
    BYTE SomeDes criptor[36];
    }


    4.接口描述符

    struct_INTERFACE_DEscriptOR_STRUCT
    {
    BYTE bLength;
    BYTE bDescriptorType;
    BYTE bInterfaceNumber;
    BYTE bAlternateSetting;
    BYTE bNumEndpoints:
    BYTE bInterfaceSubClass;
    BYTE bInterfaceProtocol;
    BYTE iInterface;
    }

    5.端点描述符

    struct_ENDPOINT_DescriptOR_STRUCT
    {
    BYTE bLength;
    BYTE bDescriptorType;
    BYTE bEndpointAddress;
    BYTE bmAttribute;
    WORD wMaxPacketSize;
    BYTE bInterval;
    }
  • TA的每日心情
    开心
    2018-11-9 08:52
  • 241

    主题

    691

    帖子

    7652

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    7652
    5#
     楼主| 发表于 2016-11-18 15:49:53 | 只看该作者
  • TA的每日心情
    开心
    2018-11-9 08:52
  • 241

    主题

    691

    帖子

    7652

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    7652
    6#
     楼主| 发表于 2016-11-18 15:50:54 | 只看该作者
  • TA的每日心情
    开心
    2018-11-9 08:52
  • 241

    主题

    691

    帖子

    7652

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    7652
    7#
     楼主| 发表于 2016-11-18 16:02:01 | 只看该作者
    linux下libusb的安装与测试

    0.libusb的介绍:参考[1]
    1.环境:vmware_fedora_10(Linux-2.6.x)
    2.获取源代码:http://sourceforge.net/projects/libusb/  (最好选择libusb-1.0.9版本,下载次数最多,自是有它的道理)
    3.解压源码tar xjvf libusb-1.0.9.tar.bz2 按照INSTALL文件给出的提示进行安装:主要分为./configure ->make -> make install
    4.安装过程如下:
    configure略去......(看不懂......)
    /* make的动作主要是编译libusb的源代码 */
    [root@zx libusb-1.0.9]# make
    make  all-recursive
    make[1]: Entering directory `/share/libusb-1.0.9'
    Making all in libusb
    make[2]: Entering directory `/share/libusb-1.0.9/libusb'
      CC     libusb_1_0_la-core.lo
      CC     libusb_1_0_la-descriptor.lo
      CC     libusb_1_0_la-io.lo
      CC     libusb_1_0_la-sync.lo
      CC     libusb_1_0_la-linux_usbfs.lo
      CC     libusb_1_0_la-threads_posix.lo
      CCLD   libusb-1.0.la
    make[2]: Leaving directory `/share/libusb-1.0.9/libusb'
    Making all in doc
    make[2]: Entering directory `/share/libusb-1.0.9/doc'
    make[2]: Nothing to be done for `all'.
    make[2]: Leaving directory `/share/libusb-1.0.9/doc'
    make[2]: Entering directory `/share/libusb-1.0.9'
    make[2]: Nothing to be done for `all-am'.
    make[2]: Leaving directory `/share/libusb-1.0.9'
    make[1]: Leaving directory `/share/libusb-1.0.9'
    /* make install的动作主要是编译出libusb库并加入到系统文件夹下 */
    [root@zx libusb-1.0.9]# make install
    Making install in libusb
    make[1]: Entering directory `/share/libusb-1.0.9/libusb'
    make[2]: Entering directory `/share/libusb-1.0.9/libusb'
    test -z "/usr/local/lib" || /bin/mkdir -p "/usr/local/lib"
    /bin/sh ../libtool   --mode=install /usr/bin/install -c   libusb-1.0.la '/usr/local/lib'
    libtool: install: /usr/bin/install -c .libs/libusb-1.0.so.0.1.0 /usr/local/lib/libusb-1.0.so.0.1.0
    libtool: install: (cd /usr/local/lib && { ln -s -f libusb-1.0.so.0.1.0 libusb-1.0.so.0 || { rm -f libusb-1.0.so.0 && ln -s libusb-1.0.so.0.1.0 libusb-1.0.so.0; }; })
    libtool: install: (cd /usr/local/lib && { ln -s -f libusb-1.0.so.0.1.0 libusb-1.0.so || { rm -f libusb-1.0.so && ln -s libusb-1.0.so.0.1.0 libusb-1.0.so; }; })
    libtool: install: /usr/bin/install -c .libs/libusb-1.0.lai /usr/local/lib/libusb-1.0.la
    libtool: install: /usr/bin/install -c .libs/libusb-1.0.a /usr/local/lib/libusb-1.0.a
    libtool: install: chmod 644 /usr/local/lib/libusb-1.0.a
    libtool: install: ranlib /usr/local/lib/libusb-1.0.a
    libtool: finish: PATH="/usr/lib/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/lib/ccache:/opt/EmbedSky/4.3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/sbin" ldconfig -n /usr/local/lib
    ----------------------------------------------------------------------
    Libraries have been installed in:
       /usr/local/lib /* 这里提示已经将库加入到/usr/local/lib目录,所以我们基于libusb编程的时候,需要包含这个库 */
    If you ever happen to want to link against installed libraries
    in a given directory, LIBDIR, you must either use libtool, and
    specify the full pathname of the library, or use the `-LLIBDIR'
    flag during linking and do at least one of the following:
       - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
         during execution
       - add LIBDIR to the `LD_RUN_PATH' environment variable
         during linking
       - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
       - have your system administrator add LIBDIR to `/etc/ld.so.conf'
    See any operating system documentation about shared libraries for
    more information, such as the ld(1) and ld.so(8) manual pages.
    ----------------------------------------------------------------------
    test -z "/usr/local/include/libusb-1.0" || /bin/mkdir -p "/usr/local/include/libusb-1.0"
    /usr/bin/install -c -m 644 libusb.h '/usr/local/include/libusb-1.0'
    make[2]: Leaving directory `/share/libusb-1.0.9/libusb'
    make[1]: Leaving directory `/share/libusb-1.0.9/libusb'
    Making install in doc
    make[1]: Entering directory `/share/libusb-1.0.9/doc'
    make[2]: Entering directory `/share/libusb-1.0.9/doc'
    make[2]: Nothing to be done for `install-exec-am'.
    make[2]: Nothing to be done for `install-data-am'.
    make[2]: Leaving directory `/share/libusb-1.0.9/doc'
    make[1]: Leaving directory `/share/libusb-1.0.9/doc'
    make[1]: Entering directory `/share/libusb-1.0.9'
    make[2]: Entering directory `/share/libusb-1.0.9'
    make[2]: Nothing to be done for `install-exec-am'.
    test -z "/usr/local/lib/pkgconfig" || /bin/mkdir -p "/usr/local/lib/pkgconfig"
    /usr/bin/install -c -m 644 libusb-1.0.pc '/usr/local/lib/pkgconfig'
    make[2]: Leaving directory `/share/libusb-1.0.9'
    make[1]: Leaving directory `/share/libusb-1.0.9'
    5.源码目录下有example目录,是libusb提供的测试程序listdev.c (列出usb设备)
    [java] view plain copy print?
    #include <stdio.h>  
    #include <sys/types.h>  
    #include <libusb.h>  
      
    static void print_devs(libusb_device **devs)  
    {  
        libusb_device *dev;  
        int i = 0;  
      
        while ((dev = devs[i++]) != NULL) {  
            struct libusb_device_descriptor desc;  
            int r = libusb_get_device_descriptor(dev, &desc);  
            if (r < 0) {  
                fprintf(stderr, "failed to get device descriptor");  
                return;  
            }  
      
            printf("%04x:%04x (bus %d, device %d)\n",  
                desc.idVendor, desc.idProduct,  
                libusb_get_bus_number(dev), libusb_get_device_address(dev));  
        }  
    }  
      
    int main(void)  
    {  
        libusb_device **devs;  
        int r;  
        ssize_t cnt;  
      
        r = libusb_init(NULL);  
        if (r < 0)  
            return r;  
      
        cnt = libusb_get_device_list(NULL, &devs);  
        if (cnt < 0)  
            return (int) cnt;  
      
        print_devs(devs);  
        libusb_free_device_list(devs, 1);  
      
        libusb_exit(NULL);  
        return 0;  
    }  
    编译的时候我们可以用自带的makefile生成可执行文件,也可以用如下操作进行:(参考[2])
    [root@zx examples]# gcc -I/usr/local/include/libusb-1.0 listdevs.c -L/usr/local/lib -lusb-1.0
    -I包含头文件 ;-L链接库
    6.listdev的运行结果如下:
    [root@zx examples]# gcc -I/usr/local/include/libusb-1.0 listdevs.c -L/usr/local/lib -lusb-1.0
    [root@zx examples]# ./a.out
    1d6b:0002 (bus 1, device 1)
    1d6b:0001 (bus 2, device 1)
    0e0f:0003 (bus 2, device 2)
    0e0f:0002 (bus 2, device 3)
    0cf3:1006 (bus 1, device 3)
    [root@zx examples]# lsusb  /* 与lsusb命令得出的是一致 */
    Bus 001 Device 003: ID 0cf3:1006 Atheros Communications, Inc.
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 002 Device 003: ID 0e0f:0002  
    Bus 002 Device 002: ID 0e0f:0003  
    Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hubReference:
    7.若想打开调试开关,看出libusb内部的运行情况
    在libusb/libusbi.h中有如下代码
    [java] view plain copy print?
    #ifdef ENABLE_DEBUG_LOGGING  
    #define usbi_dbg(...) _usbi_log(NULL, LOG_LEVEL_DEBUG, __VA_ARGS__)  
    #else  
    #define usbi_dbg(...) do {} while(0)  
    #endif  
    所以说在makefile加上-DENABLE_DEBUG_LOGGING=1这个编译选项即可.
    在libusb的目录下找到makefile(configure之后才会生成),找到CFLAGS = -g -O2,替换为CFLAGS = -g -O2 -DENABLE_DEBUG_LOGGING=1
    再次make和make install,切换到之前的listdev程序,可以看见已经打出libusb内部的调用顺序:
    [root@zx examples]# ./listdevs
    libusb: 0.000000 debug [libusb_init] libusb-1.0.9
    libusb: 0.003326 debug [find_usbfs_path] found usbfs at /dev/bus/usb
    libusb: 0.004064 debug [op_init] found usb devices in sysfs
    libusb: 0.004939 debug [usbi_add_pollfd] add fd 3 events 1
    libusb: 0.005519 debug [usbi_io_init] using timerfd for timeouts
    libusb: 0.006147 debug [usbi_add_pollfd] add fd 5 events 1
    libusb: 0.006710 debug [libusb_init] created default context
    libusb: 0.007273 debug [libusb_get_device_list]
    libusb: 0.011264 debug [sysfs_scan_device] scan usb1
    libusb: 0.012133 debug [sysfs_scan_device] bus=1 dev=1
    libusb: 0.012681 debug [enumerate_device] busnum 1 devaddr 1 session_id 257
    libusb: 0.013244 debug [enumerate_device] allocating new device for 1/1 (session 257)
    libusb: 0.013956 debug [sysfs_scan_device] scan usb2
    libusb: 0.014740 debug [sysfs_scan_device] bus=2 dev=1
    libusb: 0.015685 debug [enumerate_device] busnum 2 devaddr 1 session_id 513
    libusb: 0.016251 debug [enumerate_device] allocating new device for 2/1 (session 513)
    libusb: 0.016984 debug [sysfs_scan_device] scan 2-1
    libusb: 0.017761 debug [sysfs_scan_device] bus=2 dev=2
    libusb: 0.018467 debug [enumerate_device] busnum 2 devaddr 2 session_id 514
    libusb: 0.018988 debug [enumerate_device] allocating new device for 2/2 (session 514)
    libusb: 0.019789 debug [sysfs_scan_device] scan 2-2
    libusb: 0.020473 debug [sysfs_scan_device] bus=2 dev=3
    libusb: 0.021145 debug [enumerate_device] busnum 2 devaddr 3 session_id 515
    libusb: 0.021742 debug [enumerate_device] allocating new device for 2/3 (session 515)
    libusb: 0.022440 debug [sysfs_scan_device] scan 1-1
    libusb: 0.023203 debug [sysfs_scan_device] bus=1 dev=3
    libusb: 0.023986 debug [enumerate_device] busnum 1 devaddr 3 session_id 259
    libusb: 0.024548 debug [enumerate_device] allocating new device for 1/3 (session 259)
    libusb: 0.025266 debug [libusb_get_device_descriptor]
    1d6b:0002 (bus 1, device 1)
    libusb: 0.026017 debug [libusb_get_device_descriptor]
    1d6b:0001 (bus 2, device 1)
    libusb: 0.026479 debug [libusb_get_device_descriptor]
    0e0f:0003 (bus 2, device 2)
    libusb: 0.026516 debug [libusb_get_device_descriptor]
    0e0f:0002 (bus 2, device 3)
    libusb: 0.026576 debug [libusb_get_device_descriptor]
    0cf3:1006 (bus 1, device 3)
    libusb: 0.026616 debug [libusb_unref_device] destroy device 1.1
    libusb: 0.026636 debug [libusb_unref_device] destroy device 2.1
    libusb: 0.026652 debug [libusb_unref_device] destroy device 2.2
    libusb: 0.026667 debug [libusb_unref_device] destroy device 2.3
    libusb: 0.026682 debug [libusb_unref_device] destroy device 1.3
    libusb: 0.026698 debug [libusb_exit]
    libusb: 0.026731 debug [libusb_exit] destroying default context
    libusb: 0.026747 debug [usbi_remove_pollfd] remove fd 3
    libusb: 0.026778 debug [usbi_remove_pollfd] remove fd 5
    PS:这里还有一个问题:
    [root@zx test]# ./a.out
    ./a.out: error while loading shared libraries: libusb-1.0.so.0: cannot open shared object file: No such file or directory
    [root@zx test]# /* 运行的时候若出现这个错误,只要先运行下面一句话即可 */
    [root@zx test]# export LD_LIBRARY_PATH=/usr/local/lib

    Reference:
    [1].libusb介绍:http://baike.baidu.com/view/4598042.htm
    [2].解决编译问题:http://libusb.6.n5.nabble.com/Compile-my-program-td2645564.html
  • TA的每日心情
    开心
    2018-11-9 08:52
  • 241

    主题

    691

    帖子

    7652

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    7652
    8#
     楼主| 发表于 2016-11-18 16:31:30 | 只看该作者
    编译应用程序出现如下错误:
    /tmp/ccEM4ZMg.o: In function `main':
    testlibusb.c.text+0xc): undefined reference to `usb_init'
    testlibusb.c.text+0x11): undefined reference to `usb_find_busses'
    testlibusb.c.text+0x16): undefined reference to `usb_find_devices'
    testlibusb.c.text+0x1b): undefined reference to `usb_get_busses'
    collect2: ld returned 1 exit status

    英这样编译:
    gcc testlibusb.c -o testusb -lusb
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|Silian Lighting+ ( 蜀ICP备14004521号-1 )

    GMT+8, 2024-5-15 18:45 , Processed in 1.093750 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表