QT - USB-driver - libusb

转载自http://blog.sina.com.cn/s/blog_40b3edd70100n3pi.html

 

  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( 注:代码只是为了方便解说,不保证代码的健全 )


int Device_Find()
{
     char dir_str[100];   
     char hiddev[100];     
DIR dir;                 


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

     
dir=opendir("/dev/usb/hid");
     if(dir){
         
          sprintf(dir_str,"/dev/usb/hid/");
          closedir(dir);
     }else{
         
          sprintf(dir_str,"/dev/usb/");
     }

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

        
        fd = open(hiddev, O_RDWR);
        if(fd > 0) {

            
            ioctl(fd, HIDIOCGDEVINFO, &info);
     
               
             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_find_devices();
     
     
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,


int Device_Open()
{
     int handle;
     
handle = open(“hiddev0”, O_RDONLY);
}



int Device_Open()
{

struct usb_device*     udev;
usb_dev_handle*          device_handle;



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;
int       index;


     unsigned char send_data[72];
unsigned char recv_data[72];
     struct hiddev_usage_ref uref;
     struct hiddev_report_info rinfo;
     ret = ioctl(fd, HIDIOCINITREPORT, 0);
     if( ret !=0) {
          return NOT_OPENED_DEVICE;
     }
     
     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;
     
     
     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));
     
     
     Device_handle = (usb_dev_handle*)(g_list[fd].device_handle);
     if (Device_handle == NULL) {
         return NOT_OPENED_DEVICE;
}


usb_claim_interface(Device_handle, 0);


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


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_release_interface(RY2_handle, 0);
     memcpy(buffer72, recv_data, 72);

return SUCCESS;
}


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


int Device_Close()
{
     int handle;
     
handle = open(“hiddev0”, O_RDONLY);


close( handle );
}


int Device_Close()
{

struct usb_device*     udev;
usb_dev_handle*          device_handle;

device_handle = usb_open(udev);


usb_close(device_handle);
}


libusb
的驱动框架
前面我们看了些主要的 libusb 函数的使用,这里我们把前面的内容归纳下:
一般的驱动应该都包含如下接口:
Device_Find();
Device_Open();
Device_Write();
Device_Read();
Device_Close();

具体代码如下:


#include



typedef struct
{
     struct usb_device*     udev;
     usb_dev_handle*          device_handle;
     
} device_descript;


#define USB_TIMEOUT      10000


#define VENDOR_ID     0xffff      
#define PRODUCT_ID    0xffff


#define DEVICE_MINOR 16
int      g_num;
device_descript g_list[ DEVICE_MINOR ];


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
                       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)
{
     
}


小结

   
  到此,使用 libusb 进行驱动开发介绍完了,通过对库所提供的 API 的使用可以体会到 libusb 的易用性。
 
 
 
 
 
 
 
 
request, requesttype, value, index, size加工成usb_ctrlrequest,然后调用usb_internal_control_msg()

dev
                       参数 dev 指向目标设备的 usb_device 数据结构
pipe                     pipe 是个 32 位无符号整数,其最高两位表示传输的类型 ( 实时 / 中断 / 控制 / 批量 ) ,其余各位包括对方的端口号以及设备号,以及设备是否为全速 ( 或者低度 )
requesttype              requesttype 其最高位表示传输的方向,最低 5 位则表明传输终极对象的类别 ( 设备 / 接口 / 端口 / 其他 )
index, request, value    index 则指明具体的单元,这就是终极的操作对象。针对这个操作对象, request 说明了需要进行的具体操作,而 value 则是参数
data, size                 如果有更多的数据需要传递 ( / ) ,则通过缓冲区 data 进行,其大小为 size 这些都是从用户空间传下来的参数,而传输的目的正是要把这些信息发送给目标设备
timeout                   参数 timeout 表示愿意睡眠等待传输完成的时间
------------------------------------------------------
int usb_control_msg(
    struct usb_device  
  *dev , unsigned int     pipe ,
      __u8 - request , __u8   requesttype , __u16    value ,     
   
  __u16   index ,   void   *data ,       __u16    size ,
    int  
  timeout )
{
    struct usb_ctrlrequest *
dr   = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
    int ret;
    if (!dr)
        return -ENOMEM;
    dr->bRequestType= requesttype;
    dr->bRequest = request;
    dr->wValue = cpu_to_le16p(&value);
    dr->wIndex = cpu_to_le16p(&index);
    dr->wLength = cpu_to_le16p(&size);
    ret =
  usb_internal_control_msg (dev, pipe,   dr ,   data , size, timeout);
    kfree(dr);
    return ret;
}

 

你可能感兴趣的:(QT - USB-driver - libusb)