linux对usb已有了比较完善的支撑,但是看了一下原理还有代码,仍是觉得一头雾水!有人引荐libusb,在网上搜了一下材料,嗯,感觉的确简略多了!
下面先介绍一下libusb:
Linux 渠道上的usb驱动开发,首要有内核驱动的开发和根据libusb的无驱规划。
1、为什么要开发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的无驱规划了。
2、怎么运用libusb进行开发
libusb是根据用户空间的usb库。libusb 规划了一系列的外部API 为应用程序所调用,经过这些API应用程序可以操作硬件,从libusb的源代码可以看出,这些API 调用了内核的底层接口,和kernel driver中所用到的函数所完成的功用差不多,仅仅libusb愈加挨近USB 规范。使得libusb的运用也比开发内核驱动相对简单的多。
2.0 一些重要的数据结构
struct usb_dev_handle {
int fd;
struct usb_bus *bus;
struct usb_device *device;
int config;
int interface;
int altsetting;
void *impl_info;
};
struct usb_device {
struct usb_device *next, *prev;
char filename[PATH_MAX + 1];
struct usb_bus *bus;
struct usb_device_descriptor descriptor;
struct usb_config_descriptor *config;
void *dev; /* Darwin support */
};
struct usb_bus {
struct usb_bus *next, *prev;
char dirname[PATH_MAX + 1];
struct usb_device *devices;
};
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);
3 移植
到网站http://sourceforge.net/project/showfiles.php?group_id=1674下载最新的libusb版别
现在是0.1.12
解压到/usr/local/libusb,分红两个版别一个是libusb-arm 一个是libusb-pc。
pc版别直接configure ;make就可以了。(其实本来的操作体系/usr/lib中都会自带有libusb的库文件,版别或许和咱们的会有不同,有爱好可以看看)
穿插编译arm版别
#./configure –host=arm-linux
#make
make时或许会呈现“treat warning as error”之类的过错信息。在Makefile里,去掉-Werror的编译选项就可以了。别的在一个tests文件夹的也会报uppercase的过错,无关紧要,把它注释掉就可以了。
在 .libs这个躲藏文件夹中,有编译好的libusb库文件
libusb-0.1.so.4.4.4 libusb.a libusbpp.a libusbpp-0.1.so.4.4.4
把libusb-arm整个目录复制到/usr/nfs (这是我的arm板nfs挂载的目录)
咱们在编程时,记住要在编译选项里参加libusb的头文件和库文件
LIBUSB=/usr/local/libusb/libusb-arm
-I$(LIBUSB) -L$(LIBUSB)/.libs -lusb
我写了一个小的测验程序,后边附上。
程序编译好后,就可以下载到arm板上了。
arm开发板的内核首先要可以支撑USB,usb-core、hub、usbdevfs、OHCI等等
设置好环境变量,修正/etc/profile文件添加
export LD_LIBRARY_PATH=/mnt/libusb-arm/.libs:$LD_LIBRARY_PATH
运转测验程序
# usbtest-arm
bus/device idVendor/idProduct
*****************************
见 鬼了。不可!在测验程序第一层for循环都没运转。应该是bus没有找到。从头检查libusb的源代码。发现在linux.c文件中的 usb_os_init(void)是经过环境变量USB_DEVFS_PATH,目录/dev/bus/usb和/proc/bus/usb开端搜索 usb-bus的。而我的开发板上没有/dev/bus,有/proc/bus/usb但是里边没有任何文件。再检查PC上的体系,运用2.4内核的 Redhat9.0 ,也是没有/dev/bus,但是/proc/bus/usb下有001/ 002/ devices drivers四个文件;运用2.6内核的FC6,
-bash-3.1$ ls -l /dev/bus/usb/
total 0
drwxr-xr-x 2 root root 60 Feb 27 20:09 001
drwxr-xr-x 2 root root 60 Feb 27 20:09 002
drwxr-xr-x 2 root root 60 Feb 27 20:09 003
drwxr-xr-x 2 root root 80 Feb 27 20:09 004
-bash-3.1$ ls -l /proc/bus/usb/
total 0
dr-xr-xr-x 2 root root 0 Feb 28 04:09 001
dr-xr-xr-x 2 root root 0 Feb 28 04:09 002
dr-xr-xr-x 2 root root 0 Feb 28 04:09 003
dr-xr-xr-x 2 root root 0 Feb 28 04:09 004
-r–r–r– 1 root root 0 Feb 28 04:09 devices
看来是和我的arm板上的内核装备或是环境设置有关,libusb应该没问题。
本来想试着设置USB_DEVFS_PATH,但是usb设备都不清楚在哪里找。我试着刺进u盘,usb鼠标,它们在/dev中的方位都不同的,设置一个一致的查找途径USB_DEVFS_PATH行不通。
后来,持续在libusb的maillist,linux-usb的官网上找头绪。总算看到一个文档中说:
/*************************************************************************************************/
The USB device filesystem is a dynamically generated filesystem, similar to the /proc filesystem. This filesystem can be mounted just about anywhere, however it is customarily mounted on /proc/bus/usb, which is an entry node created by the USB code, intended to be used as a mount point for this system. Mounting in other locations may break user space utilities, but should not affect the kernel support.
You need to select “Preliminary USB Device Filesystem” to make this work. You also need to enable general /proc support, and to have it mounted (normally automatic).
To mount the filesystem, you need to be root. Use the mount command: mount -t usbdevfs none /proc/bus/usb. Note that the nonekeyword is arbitrary – you can use anything, and some people prefer to use usbdevfs, as it makes the mount output look better.
If you do not want to have to mount the filesystem each time you reboot the system, you can add the following to /etc/fstab after the /proc entry:
none /proc/bus/usb usbdevfs defaults 0 0This has the same effect as the mount command.
After you have mounted the filesystem, the contents of /proc/bus/usb should look something like:
dr-xr-xr-x 1 root root 0 Jan 26 10:40 001 -r–r–r– 1 root root 0 Jan 26 10:40 devices -r–r–r– 1 root root 0 Jan 26 10:40 drivers. You may have more than one numbered directory entry if your machine has more than one universal serial bus controller.
/*************************************************************************************************/
试着挂载了usbdevfs文件体系,刺进u盘
# usbtest-arm
bus/device idVendor/idProduct
hello,dell 1 !
hello,dell 2 !
001/001 0000/0000
hello,dell 2 !
001/002 0471/0000
*****************************
OK!成功了!尽管绕了不小的弯子,但最终仍是搞定。看来,我的常识仍是太不厚实了,今后还需求多多尽力啊!
/*************************************************************************************************/
附1:
/* testlibusb.c */
#include
#include
#include
int main(void)
{
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
printf(“bus/device idVendor/idProduct\n”);
for (bus = usb_busses; bus; bus = bus->next) {
printf(“hello,dell 1 !\n”);
for (dev = bus->devices; dev; dev = dev->next) {
printf(“hello,dell 2 !\n”);
printf(“%s/%s %04X/%04X\n”,
bus->dirname,
dev->filename,
dev->descriptor.idVendor,
dev->descriptor.idProduct);
if (!dev->config) {
printf(” Couldn't retrieve descriptors\n”);
continue;
}
}
}
printf(“*****************************\n”);
}
/*************************************************************************************************/