libusb使用

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 成功, 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
    /*
获得全路径的设备文件名,一般 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
      /*
设置发送数据的状态 */
    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
    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
       #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
      return WRITE_REPORT;
}

if (send_len != 72) {
      return send_len;
}

/*
接受数据
       #define USB_ENDPOINT_IN       0x80
       #define USB_TYPE_CLASS           (0x01
       #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
      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);
}

你可能感兴趣的:(struct,api,report,Class,buffer,interface)