关于内核驱动的大多数设备,比方带usb接口的hid设备,linux自身现已自带了关联的驱动,咱们只需操作设备文件便能够结束对设备大多数的操作,而别的一些设备,比方自个描绘的硬件商品,这些驱动就需求咱们驱动工程师开宣告关联的驱动了。内核驱动有它的利益,可是内核驱动在某些状况下会遇到如下的一些疑问:
1 当运用咱们商品的客户有2.4内核的方法,一起也有2.6内核的方法,咱们要描绘的驱动是要兼容两个方法的,就连makefile 咱们都要写两个。
2 当咱们要把linux移植到嵌入方法上,你会发现原先linux自带的驱动移过去还挺大的,我的内核当然是越小越好拉,这样有必要么。这还不是最抑郁的当地,若是嵌入方法是客户的,客户要采办你的商品,你俄然发现客户设备里的体系和你的环境不相同,它没有你要的驱动了,你的兰蔻清脂酵素lankou.faxingge/程序作业不了,你会先想:“不要紧,我写个内核驱动加载一下不就行了“。却发现客户连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()后运用。以上的三发型格www.faxingge/个函数都是一开始就要用到的,此函数回来设备数量。
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);
这个函数如今根柢不怎么用,不过这里我也讲一下,和姓名所起的时代女人网www.times520/意思相同,这个函数reset设备,由于重启设备后仍是要从头翻开设备,所以用usb_close就现已能够满足要求了。
usb_claim_interface
函数界说:int usb_claim_interface(usb_dev_handle *dev, int interface);recv函数
注册与操作体系通讯的接口,这个函数有必要被调用,由于只需注册接口,才能做相应的操作。
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
2.5 连续传输接口
根柢上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 方法的目录*/
/* 若是不存在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是怎么来寻觅和初始化设备
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) {
return device_num; /* 回来设备数量*/
注:在新版别的libusb中,usb_get_busses就能够不用了,这个函数是回来体系上的usb总线链表句柄
这里咱们直接用usb_busses变量,这个变量在usb.h中被界说为外部变量
所以能够直接写成这样:
for (bus = usb_busses; bus; bus = bus->next) {
3.2 翻开设备
假定咱们界说的翻开设备的函数名是device_open,
/* 运用hid驱动翻开设备*/
int Device_Open()
int handle;
/
* 传统HID驱动调用,经过open翻开设备文件就可*/
handle = open(“hiddev0”, O_RDONLY);
/* 运用libusb翻开驱动*/
/* 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.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;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。