小知識:
sudo insmod /lib/modules/2.6.22-14-generic/kernel/drivers/usb/serial/usbserial.ko vendor=0x8086 product=0xd001
同時插上ttyUSB0和ttyUSB1(ch341),obm可以將dkb下載下去,但是自動重起之后,就不能下載接下來的東西了,所以應(yīng)該,需要close(ttyUSB0_handle);
然后進行接下來的下載,分別調(diào)用兩次不過應(yīng)該自動關(guān)閉了,所以可能還是不能同時插上ttyUSB0和ttyUSB1
lsusb 顯示usb設(shè)備的vendor和product
比如:
luther@gliethttp:~$ lsusb
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 116: ID 8086:d001 Intel Corp.
Bus 001 Device 003: ID 413c:2105 Dell Computer Corp.
Bus 001 Device 002: ID 0461:4d15 Primax Electronics, Ltd
Bus 001 Device 001: ID 0000:0000
其中Bus 001 Device 116: ID 8086:d001 Intel Corp. 就是vendor=0x8086和product=0xd001
可以使用dmesg來查看具體的是ttyUSB0還是ttyUSB1了
pidof hello.exe
pidof bash
顯示進程的pid值
波特率:
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#define EXTA B19200
#define EXTB B38400
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define PARENB 0000400
#define PARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
#define B460800 0010004 //有些CDMA使用該波特率
#define B500000 0010005
#define B576000 0010006
#define B921600 0010007
#define B1000000 0010010
#define B1152000 0010011
#define B1500000 0010012
#define B2000000 0010013
#define B2500000 0010014
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
Developing Linux Device Drivers using Libusb API
Written by vikram_cvk - 2004-07-16 18:05
Introduction
We often come across a situation where a USB device which runs perfectly on Windows platform does not even get detected on Linux. Lack of support for USB devices is one of the reason why some people don't embrace Linux. Now there is a new API by name Libusb which helps the developers to develop USB device drivers on the fly!
What is Libusb
Libusb is a high-level language API which conceals low-level kernel interactions with the USB modules. It provides a set of function which are adequate to develop a device driver for a USB device from the Userspace.
Libusb is not complex
For any wannabe Linux Kernel programmers developing device driver as a Kernel module is a herculean task. Developing kernel modules requires fair degree of proficiency in 'C' language and also good idea of kernel subsystems, data structures etc. All these are enough to put-off a developer from venturing into Device Driver programming.Libusb has been designed to address this shortcoming. Simplified interface allows developers to develop USB drivers from the userspace . Libusb library functions provide high level abstraction to the Kernel structures and allows the developers to have access to these structures through the USBFS(USBfilesystem).
Its Cross-platform
Beauty of Libusb lies in its cross platform functionality. Driver written for one platform could be easily ported onto another platform with little or no changes, currently following operating systems are supported by Libusb.
Linux
FreeBSD
Darwin
OS X
This HOWTO focuses on how Libusb can be used on Linux platform. For information about other platforms goto http://http://libusb.sourceforge.net/.
LIBUSB ON LINUX
Linux is the most popular platform for the Libusb API,the reason being growing popularity of Linux as a stable OS. On Linux Libusb makes of the USBFS file system. by default USBFS is automatically mounted when the system is booted.
What is USBFS
USBFS is a filesystem specifically designed for USB devices, by default this filesystem gets mounted when the system is booted and it can be found at /proc/bus/usb/. This filesystem consists of information about all the USB devices that are connected to the computer.Libusb makes use of this filesystem to interact with the USB devices.
Following C program can be a stepping stone into the world of Libusb.This program can be used to gather all the technical/hardware details of a USB device connected to the computer ,ensure that some USB device is connected into the USB port.
Details like Vendor-Id , Product-Id ,Endpoint addresses of a USB device is of paramount importance for a device driver developer.
/* testlibusb.c */
#include
#include
void print_endpoint(struct usb_endpoint_descriptor *endpoint)
{
printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
printf(" bmAttributes: %02xh\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);
}
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);
}
void print_interface(struct usb_interface *interface)
{
int i;
for (i = 0; i < interface->num_altsetting; i++)
print_altsetting(&interface->altsetting);
}
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: %02xh\n", config->bmAttributes);
printf(" MaxPower: %d\n", config->MaxPower);
for (i = 0; i < config->bNumInterfaces; i++)
print_interface(&config->interface);
}
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) {
for (dev = bus->devices; dev; dev = dev->next) {
int ret, i;
char string[256];
usb_dev_handle *udev;
printf("%s/%s %04X/%04X\n", bus->dirname, dev->filename,
dev->descriptor.idVendor, dev->descriptor.idProduct);
udev = usb_open(dev);
if (udev) {
if (dev->descriptor.iManufacturer) {
ret = usb_get_string_simple(udev, dev->descriptor.iManufacturer, string, sizeof(string));
if (ret > 0)
printf("- Manufacturer : %s\n", string);
else
printf("- Unable to fetch manufacturer string\n");
}
if (dev->descriptor.iProduct) {
ret = usb_get_string_simple(udev, dev->descriptor.iProduct, string, sizeof(string));
if (ret > 0)
printf("- Product : %s\n", string);
else
printf("- Unable to fetch product string\n");
}
if (dev->descriptor.iSerialNumber) {
ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber, string, sizeof(string));
if (ret > 0)
printf("- Serial Number: %s\n", string);
else
printf("- Unable to fetch serial number string\n");
}
usb_close (udev);
}
if (!dev->config) {
printf(" Couldn't retrieve descriptors\n");
continue;
}
for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
print_configuration(&dev->config);
}
}
return 0;
}
The above program should be compiled as
(root$)gcc -o usbdevice_details testlibusb.c -I/usr/local/include -L. -lnsl -lm -lc -L/usr/local/lib -lusb
(root$)./usbdevice_details (enter)
Following is the output of the above command ,its the listing of a USB pen drive connected to my system.
The first line displays the bus-name/device-name & device-id/product-id and rest of the listing is self-descriptive.
001/004 0EA0/2168
- Manufacturer : USB
- Product : Flash Disk
- Serial Number: 4CE45C4E403EE53D
wTotalLength: 39
bNumInterfaces: 1
bConfigurationValue: 1
iConfiguration: 0
bmAttributes: 80h
MaxPower: 100
bInterfaceNumber: 0
bAlternateSetting: 0
bNumEndpoints: 3
bInterfaceClass: 8
bInterfaceSubClass: 6
bInterfaceProtocol: 80
iInterface: 0
bEndpointAddress: 81h
bmAttributes: 02h
wMaxPacketSize: 64
bInterval: 0
bRefresh: 0
bSynchAddress: 0
bEndpointAddress: 02h
bmAttributes: 02h
wMaxPacketSize: 64
bInterval: 0
bRefresh: 0
bSynchAddress: 0
bEndpointAddress: 83h
bmAttributes: 03h
wMaxPacketSize: 2
bInterval: 1
bRefresh: 0
bSynchAddress: 0
Before executing the above program download the current version of Libusb library from, http://http://libusb.sourceforge.net/. The above program can also be found under the tests directory of Libusb directory (after u install it)
Now I will explain in brief some of the functions and attributes dealt in the above program.
usb_init() - Used to initialize Libusb and establish connection with kernel structures .
usb_find_busses() - Looks for all the USB busses on the computer.
usb_find_devices() - Looks for all the USB devices connected to the computer.
usb_open(dev) - Opens the device 'dev' which is given as argument to this function.
usb_get_string_simple() - Used to extract the string descriptor of the device taken argument.
Important attributes of USB devices useful in device driver coding
Configuration and Endpoints are one of the two important descriptors of any USB device. These descriptors are defined using the ?struct usb_config_descriptor? and ?struct_usb_endpoint_descriptor? respectively .
dev->descriptor.idVendor ? Reveals the Vendor-Id of the USB device connected to the system.
dev->descriptor.idProduct - Reveals the Product-Id of the USB device connected to the system.
dev->descriptor.iManufacturer - Reveals the name of the Manufacturer USB device connected to the system.
EndpointAddress:Combination of endpoint address and endpoint direction on a USB device.
InterfaceNumber : One of the several interfaces that is allocated to the connected USB device.
AlternateSetting:This is part of the a single interface allocated to the USB device.
Prerequisites for Libusb programming
Linux system with Kernel 2.4 above series.
Proficiency in C language.
Good understanding of USB device internals.
Idea about USBFS.
Hope this HOWTO has enlightened you about Libusb API and I expect this HOWTO will give you a head start in your device driver programming endeavor .This HOWTO is just an introduction to Libusb ,for complete documentation please goto http://http://libusb.sourceforge.net/
About Myself
My name is Vikram C , I'm a linux freak and currently working as Linux developer in the city of Hyderabad India.You can reach me at vikram_147@hotmail.com / vikram@asrttechnologies.com
//================================================
2008年03月19日 星期三 10:31
驅(qū)動開發(fā)向來是內(nèi)核開發(fā)中工作量最多的一塊,隨著USB設(shè)備的普及,大量的USB設(shè)備的驅(qū)動開發(fā)也成為驅(qū)動開發(fā)者手頭上做的最多的事情。本文主要介紹 Linux平臺下基于libusb的驅(qū)動開發(fā),希望能夠給從事Linux驅(qū)動開發(fā)的朋友帶來些幫助,更希望能夠給其他平臺上的無驅(qū)設(shè)計帶來些幫助。文章是我在工作中使用libusb的一些總結(jié),難免有錯誤,如有不當(dāng)?shù)牡胤?,還請指正。
Linux 平臺上的usb驅(qū)動開發(fā),主要有內(nèi)核驅(qū)動的開發(fā)和基于libusb的無驅(qū)設(shè)計。
對于內(nèi)核驅(qū)動的大部分設(shè)備,諸如帶usb接口的hid設(shè)備,linux本身已經(jīng)自帶了相關(guān)的驅(qū)動,我們只要操作設(shè)備文件便可以完成對設(shè)備大部分的操作,而另外一些設(shè)備,諸如自己設(shè)計的硬件產(chǎn)品,這些驅(qū)動就需要我們驅(qū)動工程師開發(fā)出相關(guān)的驅(qū)動了。內(nèi)核驅(qū)動有它的優(yōu)點,然而內(nèi)核驅(qū)動在某些情況下會遇到如下的一些問題:
1 當(dāng)使用我們產(chǎn)品的客戶有2.4內(nèi)核的平臺,同時也有2.6內(nèi)核的平臺,我們要設(shè)計的驅(qū)動是要兼容兩個平臺的,就連makefile 我們都要寫兩個。
2 當(dāng)我們要把linux移植到嵌入平臺上,你會發(fā)現(xiàn)原先linux自帶的驅(qū)動移過去還挺大的,我的內(nèi)核當(dāng)然是越小越好拉,這樣有必要么。這還不是最郁悶的地方,如果嵌入平臺是客戶的,客戶要購買你的產(chǎn)品,你突然發(fā)現(xiàn)客戶設(shè)備里的系統(tǒng)和你的環(huán)境不一樣,它沒有你要的驅(qū)動了,你的程序運行不了,你會先想:“沒關(guān)系,我寫個內(nèi)核驅(qū)動加載一下不就行了“。卻發(fā)現(xiàn)客戶連insmod加載模塊的工具都沒移植,那時你就看看老天,說聲我怎么那么倒霉啊,客戶可不想你動他花了n時間移植的內(nèi)核哦
3 花了些功夫?qū)懥藗€新產(chǎn)品的驅(qū)動,挺有成就感啊,代碼質(zhì)量也是相當(dāng)?shù)挠兴疁?zhǔn)啊。正當(dāng)你沉醉在你的代碼中時,客服不斷的郵件來了,“客戶需要2.6.5內(nèi)核的驅(qū)動,config文件我已經(jīng)發(fā)你了” “客戶需要雙核的 2.6.18-smp 的驅(qū)動” “客戶的平臺是自己定制的是2.6.12-xxx “ 你恨不得把驅(qū)動的源代碼給客戶,這樣省得編譯了。你的一部分工作時間編譯內(nèi)核,定制驅(qū)動
有問題產(chǎn)生必然會有想辦法解決問題的人, libusb的出現(xiàn)給我們帶來了某些方便,即節(jié)約了我們的時間,也降低了公司的成本。 所以在一些情況下,就可以考慮使用libusb的無驅(qū)設(shè)計了。
下面我們就來詳細討論一下libusb, 并以寫一個hid設(shè)備的驅(qū)動來講解如何運用libusb,至于文章中涉及的usb協(xié)議的知識,限于篇幅,就不詳細講解了,相關(guān)的可自行查看usb相關(guān)協(xié)議。
一 libusb 介紹
libusb 設(shè)計了一系列的外部API 為應(yīng)用程序所調(diào)用,通過這些API應(yīng)用程序可以操作硬件,從libusb的源代碼可以看出,這些API 調(diào)用了內(nèi)核的底層接口,和kernel driver中所用到的函數(shù)所實現(xiàn)的功能差不多,只是libusb更加接近USB 規(guī)范。使得libusb的使用也比開發(fā)內(nèi)核驅(qū)動相對容易的多。
Libusb 的編譯安裝請查看Readme,這里不做詳解
二 libusb 的外部接口
2.1 初始化設(shè)備接口
這些接口也可以稱為核心函數(shù),它們主要用來初始化并尋找相關(guān)設(shè)備。
usb_init
函數(shù)定義: void usb_init(void);
從函數(shù)名稱可以看出這個函數(shù)是用來初始化相關(guān)數(shù)據(jù)的,這個函數(shù)大家只要記住必須調(diào)用就行了,而且是一開始就要調(diào)用的.
usb_find_busses
函數(shù)定義: int usb_find_busses(void);
尋找系統(tǒng)上的usb總線,任何usb設(shè)備都通過usb總線和計算機總線通信。進而和其他設(shè)備通信。此函數(shù)返回總線數(shù)。
usb_find_devices
函數(shù)定義: int usb_find_devices(void);
尋找總線上的usb設(shè)備,這個函數(shù)必要在調(diào)用usb_find_busses()后使用。以上的三個函數(shù)都是一開始就要用到的,此函數(shù)返回設(shè)備數(shù)量。
usb_get_busses
函數(shù)定義: struct usb_bus *usb_get_busses(void);
這個函數(shù)返回總線的列表,在高一些的版本中已經(jīng)用不到了,這在下面的實例中會有講解
2.2 操作設(shè)備接口
usb_open
函數(shù)定義: usb_dev_handle *usb_open(struct *usb_device dev);
打開要使用的設(shè)備,在對硬件進行操作前必須要調(diào)用usb_open 來打開設(shè)備,這里大家看到有兩個結(jié)構(gòu)體 usb_dev_handle 和 usb_device 是我們在開發(fā)中經(jīng)常碰到的,有必要把它們的結(jié)構(gòu)看一看。在libusb 中的usb.h和usbi.h中有定義。
這里我們不妨理解為返回的 usb_dev_handle 指針是指向設(shè)備的句柄,而行參里輸入就是需要打開的設(shè)備。
usb_close
函數(shù)定義: int usb_close(usb_dev_handle *dev);
與usb_open相對應(yīng),關(guān)閉設(shè)備,是必須調(diào)用的, 返回0成功,<0 失敗。
usb_set_configuration
函數(shù)定義: int usb_set_configuration(usb_dev_handle *dev, int configuration);
設(shè)置當(dāng)前設(shè)備使用的configuration,參數(shù)configuration 是你要使用的configurtation descriptoes中的bConfigurationValue, 返回0成功,<0失敗( 一個設(shè)備可能包含多個configuration,比如同時支持高速和低速的設(shè)備就有對應(yīng)的兩個configuration,詳細可查看usb標(biāo)準(zhǔn))
usb_set_altinterface
函數(shù)定義: int usb_set_altinterface(usb_dev_handle *dev, int alternate);
和名字的意思一樣,此函數(shù)設(shè)置當(dāng)前設(shè)備配置的interface descriptor,參數(shù)alternate是指interface descriptor中的bAlternateSetting。返回0成功,<0失敗
usb_resetep
函數(shù)定義: int usb_resetep(usb_dev_handle *dev, unsigned int ep);
復(fù)位指定的endpoint,參數(shù)ep 是指bEndpointAddress,。這個函數(shù)不經(jīng)常用,被下面介紹的usb_clear_halt函數(shù)所替代。
usb_clear_halt
函數(shù)定義: int usb_clear_halt (usb_dev_handle *dev, unsigned int ep);
復(fù)位指定的endpoint,參數(shù)ep 是指bEndpointAddress。這個函數(shù)用來替代usb_resetep
usb_reset
函數(shù)定義: int usb_reset(usb_dev_handle *dev);
這個函數(shù)現(xiàn)在基本不怎么用,不過這里我也講一下,和名字所起的意思一樣,這個函數(shù)reset設(shè)備,因為重啟設(shè)備后還是要重新打開設(shè)備,所以用usb_close就已經(jīng)可以滿足要求了。
usb_claim_interface
函數(shù)定義: int usb_claim_interface(usb_dev_handle *dev, int interface);
注冊與操作系統(tǒng)通信的接口,這個函數(shù)必須被調(diào)用,因為只有注冊接口,才能做相應(yīng)的操作。
Interface 指 bInterfaceNumber. (下面介紹的usb_release_interface 與之相對應(yīng),也是必須調(diào)用的函數(shù))
usb_release_interface
函數(shù)定義: int usb_release_interface(usb_dev_handle *dev, int interface);
注銷被usb_claim_interface函數(shù)調(diào)用后的接口,釋放資源,和usb_claim_interface對應(yīng)使用。
2.3 控制傳輸接口
usb_control_msg
函數(shù)定義:int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
從默認的管道發(fā)送和接受控制數(shù)據(jù)
usb_get_string
函數(shù)定義: int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, size_t buflen);
usb_get_string_simple
函數(shù)定義: int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen);
usb_get_descriptor
函數(shù)定義: int usb_get_descriptor(usb_dev_handle *dev, unsigned char type, unsigned char index, void *buf, int size);
usb_get_descriptor_by_endpoint
函數(shù)定義: 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
函數(shù)定義: int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
usb_interrupt_read
函數(shù)定義: int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
2.5 中斷傳輸接口
usb_bulk_write
函數(shù)定義: int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
usb_interrupt_read
函數(shù)定義: int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
基本上libusb所經(jīng)常用到的函數(shù)就有這些了,和usb協(xié)議確實很接近吧。下面我們實例在介紹一個應(yīng)用。
//----------------===================================
Libusb庫的使用
使用libusb之前你的linux系統(tǒng)必須裝有usb文件系統(tǒng),這里還介紹了使用hiddev設(shè)備文件來訪問設(shè)備,目的在于不僅可以比較出usb的易用性,還提供了一個轉(zhuǎn)化成libusb驅(qū)動的案例。
任何驅(qū)動第一步首先是尋找到要操作的設(shè)備,我們先來看看HID驅(qū)動是怎樣尋找到設(shè)備的。我們假設(shè)尋找設(shè)備的函數(shù)Device_Find(注:代碼只是為了方便解說,不保證代碼的健全)
/* 我們簡單看一下使用hid驅(qū)動尋找設(shè)備的實現(xiàn),然后在看一下libusb是如何尋找設(shè)備的 */
int Device_Find()
{
char dir_str[100]; /* 這個變量我們用來保存設(shè)備文件的目錄路徑 */
char hiddev[100]; /* 這個變量用來保存設(shè)備文件的全路徑 */
DIR dir;
/* 申請的字符串?dāng)?shù)組清空,這個編程習(xí)慣要養(yǎng)成 */
memset (dir_str, 0 , sizeof(dir_str));
memset (hiddev, 0 , sizeof(hiddev));
/* hiddev 的設(shè)備描述符不在/dev/usb/hid下面,就在/dev/usb 下面
這里我們使用opendir函數(shù)來檢驗?zāi)夸浀挠行?/font>
打開目錄返回的值保存在變量dir里,dir前面有聲明
*/
dir=opendir("/dev/usb/hid");
if(dir){
/* 程序運行到這里,說明存在 /dev/usb/hid 路徑的目錄 */
sprintf(dir_str,"/dev/usb/hid/");
closedir(dir);
}else{
/* 如果不存在hid目錄,那么設(shè)備文件就在/dev/usb下 */
sprintf(dir_str,"/dev/usb/");
}
/* DEVICE_MINOR 是指設(shè)備數(shù),HID一般是16個 */
for(i = 0; i < DEVICE_MINOR; i++) {
/* 獲得全路徑的設(shè)備文件名,一般hid設(shè)備文件名是hiddev0 到 hiddev16 */
sprintf(hiddev, "%shiddev%d", dir_str,i);
/* 打開設(shè)備文件,獲得文件句柄 */
fd = open(hiddev, O_RDWR);
if(fd > 0) {
/* 操作設(shè)備獲得設(shè)備信息 */
ioctl(fd, HIDIOCGDEVINFO, &info);
/* VENDOR_ID 和 PRODUCT_ID 是標(biāo)識usb設(shè)備廠家和產(chǎn)品ID,驅(qū)動都需要這兩個參數(shù)來尋找設(shè)備,到此我們尋找到了設(shè)備 */
if(info.vendor== VENDOR_ID && info.product== PRODUCT_ID) {
/* 這里添加設(shè)備的初始化代碼 */
device_num++; /* 找到的設(shè)備數(shù) */
}
close(fd);
}
}
return device_num; /* 返回尋找的設(shè)備數(shù)量 */
}
我們再來看libusb是如何來尋找和初始化設(shè)備
int Device_Find()
{
struct usb_bus *busses;
int device_num = 0;
device_num = 0; /* 記錄設(shè)備數(shù)量 */
usb_init(); /* 初始化 */
usb_find_busses(); /* 尋找系統(tǒng)上的usb總線 */
usb_find_devices(); /* 尋找usb總線上的usb設(shè)備 */
/* 獲得系統(tǒng)總線鏈表的句柄 */
busses = usb_get_busses();
struct usb_bus *bus;
/* 遍歷總線 */
for (bus = busses; bus; bus = bus->next) {
struct usb_device *dev;
/* 遍歷總線上的設(shè)備 */
for (dev = bus->devices; dev; dev = dev->next) {
/* 尋找到相關(guān)設(shè)備, */
if(dev->descriptor.idVendor==VENDOR_ID&& dev->descriptor.idProduct == PRODUCT_ID) {
/* 這里添加設(shè)備的初始化代碼 */
device_num++; /* 找到的設(shè)備數(shù) */
}
}
}
return device_num; /* 返回設(shè)備數(shù)量 */
}
注:在新版本的libusb中,usb_get_busses就可以不用了 ,這個函數(shù)是返回系統(tǒng)上的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) {
/* 這里添加設(shè)備的初始化代碼 */
}
}
假設(shè)我們定義的打開設(shè)備的函數(shù)名是device_open,
/* 使用hid驅(qū)動打開設(shè)備 */
int Device_Open()
{
int handle;
/* 傳統(tǒng)HID驅(qū)動調(diào)用,通過open打開設(shè)備文件就可 */
handle = open(“hiddev0”, O_RDONLY);
}
/* 使用libusb打開驅(qū)動 */
int Device_Open()
{
/* LIBUSB 驅(qū)動打開設(shè)備,這里寫的是偽代碼,不保證代碼有用 */
struct usb_device* udev;
usb_dev_handle* device_handle;
/* 當(dāng)找到設(shè)備后,通過usb_open打開設(shè)備,這里的函數(shù)就相當(dāng)open 函數(shù) */
device_handle = usb_open(udev);
}
假設(shè)我們的設(shè)備使用控制傳輸方式,至于批處理傳輸和中斷傳輸限于篇幅這里不介紹
我們這里定義三個函數(shù),Device_Write, Device_Read, Device_Report
Device_Report 功能發(fā)送接收函數(shù)
Device_Write 功能寫數(shù)據(jù)
Device_Read 功能讀數(shù)據(jù)
Device_Write和Device_Read調(diào)用Device_Report發(fā)送寫的信息和讀的信息,開發(fā)者根據(jù)發(fā)送的命令協(xié)議來設(shè)計,我們這里只簡單實現(xiàn)發(fā)送數(shù)據(jù)的函數(shù)。
假設(shè)我們要給設(shè)備發(fā)送72字節(jié)的數(shù)據(jù),頭8個字節(jié)是報告頭,是我們定義的和設(shè)備相關(guān)的規(guī)則,后64位是數(shù)據(jù)。
HID驅(qū)動的實現(xiàn)(這里只是用代碼來有助理解,代碼是偽代碼)
int Device_Report(int fd, unsigned char *buffer72)
{
int ret; /* 保存ioctl函數(shù)的返回值 */
int index;
unsigned char send_data[72]; /* 發(fā)送的數(shù)據(jù) */
unsigned char recv_data[72]; /* 接收的數(shù)據(jù) */
struct hiddev_usage_ref uref; /* hid驅(qū)動定義的數(shù)據(jù)包 */
struct hiddev_report_info rinfo; /* hid驅(qū)動定義的
memset(send_data, 0, sizeof(send_data));
memset(recv_data, 0, sizeof(recv_data));
memcpy(send_data, buffer72, 72);
/* 這在發(fā)送數(shù)據(jù)之前必須調(diào)用的,初始化設(shè)備 */
ret = ioctl(fd, HIDIOCINITREPORT, 0);
if( ret !=0) {
return NOT_OPENED_DEVICE;/* NOT_OPENED_DEVICE 屬于自己定義宏 */
}
/* HID設(shè)備每次傳輸一個字節(jié)的數(shù)據(jù)包 */
for(index = 0; index < 72; index++) {
/* 設(shè)置發(fā)送數(shù)據(jù)的狀態(tài) */
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;
}
}
/* 發(fā)送數(shù)據(jù) */
rinfo.report_type = HID_REPORT_TYPE_FEATURE;
rinfo.report_id = HID_REPORT_ID_FIRST;
rinfo.num_fields = 1;
ret=ioctl(fd, HIDIOCSREPORT, &rinfo); /* 發(fā)送數(shù)據(jù) */
if(ret != 0) {
return WRITE_REPORT;
}
/* 接受數(shù)據(jù) */
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驅(qū)動的實現(xiàn)
int Device_Report(int fd, unsigned char *buffer72)
{
/* 定義設(shè)備句柄 */
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;
/* 數(shù)據(jù)置空 */
memset(send_data, 0 , sizeof(send_data));
memset(recv_data, 0 , sizeof(recv_data));
/* 這里的g_list是全局的數(shù)據(jù)變量,里面可以存儲相關(guān)設(shè)備的所需信息,當(dāng)然我們 也可以從函數(shù)形參中傳輸進來,設(shè)備的信息在打開設(shè)備時初始化,我們將在后面的總結(jié)中詳細描述一下 */
Device_handle = (usb_dev_handle*)(g_list[fd].device_handle);
if (Device_handle == NULL) {
return NOT_OPENED_DEVICE;
}
/* 這個函數(shù)前面已經(jīng)說過,在操作設(shè)備前是必須調(diào)用的, 0是指用默認的設(shè)備 */
usb_claim_interface(Device_handle, 0);
/* 發(fā)送數(shù)據(jù),所用到的宏定義在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);
/* 發(fā)送數(shù)據(jù)有錯誤 */
if (send_len < 0) {
return WRITE_REPORT;
}
if (send_len != 72) {
return send_len;
}
/* 接受數(shù)據(jù)
#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對應(yīng) */
usb_release_interface(RY2_handle, 0);
memcpy(buffer72, recv_data, 72);
return SUCCESS;
}
假設(shè)我們定義的關(guān)閉設(shè)備的函數(shù)名是Device_Close()
/* 使用hid驅(qū)動關(guān)閉設(shè)備 */
int Device_Close()
{
int handle;
handle = open(“hiddev0”, O_RDONLY);
/* 傳統(tǒng)HID驅(qū)動調(diào)用,通過close()設(shè)備文件就可 */
close( handle );
}
/* 使用libusb關(guān)閉驅(qū)動 */
int Device_Close()
{
/* LIBUSB 驅(qū)動打開設(shè)備,這里寫的是偽代碼,不保證代碼有用 */
struct usb_device* udev;
usb_dev_handle* device_handle;
device_handle = usb_open(udev);
/* libusb庫使用usb_close關(guān)閉程序 */
usb_close(device_handle);
}
前面我們看了些主要的libusb函數(shù)的使用,這里我們把前面的內(nèi)容歸納下:
一般的驅(qū)動應(yīng)該都包含如下接口:
Device_Find(); /* 尋找設(shè)備接口 */
Device_Open(); /* 打開設(shè)備接口 */
Device_Write(); /* 寫設(shè)備接口 */
Device_Read(); /* 讀設(shè)備接口 */
Device_Close(); /* 關(guān)閉設(shè)備接口 */
具體代碼如下:
#include <usb.h>
/* usb.h
這個頭文件是要包括的,里面包含了必須要用到的數(shù)據(jù)結(jié)構(gòu)
*/
/*
我們將一個設(shè)備的屬性用一個結(jié)構(gòu)體來概括
*/
typedef struct
{
struct usb_device* udev;
usb_dev_handle* device_handle;
/*
這里可以添加設(shè)備的其他屬性,這里只列出每個設(shè)備要用到的屬性
*/
} device_descript;
/*
用來設(shè)置傳輸數(shù)據(jù)的時間延遲
*/
#define USB_TIMEOUT 10000
/*
廠家
ID
和產(chǎn)品
ID */
#define VENDOR_ID 0xffff
#define PRODUCT_ID 0xffff
/*
這里定義數(shù)組來保存設(shè)備的相關(guān)屬性,
DEVICE_MINOR
可以設(shè)置能夠同時操作的設(shè)備數(shù)量,用全局變量的目的在于方便保存屬性
*/
#define DEVICE_MINOR 16
int g_num;
device_descript g_list[ DEVICE_MINOR ];
/*
我們寫個設(shè)備先找到設(shè)備,并把相關(guān)信息保存在
g_list
中
*/
int Device_Find()
{
struct usb_bus *bus;
struct usb_device *dev;
g_num = 0;
usb_find_busses();
usb_find_devices();
/*
尋找設(shè)備
*/
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) {
/*
保存設(shè)備信息
*/
if (g_num < DEVICE_MINOR) {
g_list[g_num].udev = dev;
g_num ++;
}
}
}
}
return g_num;
}
/*
找到設(shè)備后,我們根據(jù)信息打開設(shè)備
*/
int Device_Open()
{
/*
根據(jù)情況打開你所需要操作的設(shè)備,這里我們僅列出偽代碼
*/
if(g_list[g_num].udev != NULL) {
g_list[g_num].device_handle = usb_open(g_list[g_num].udev);
}
}
/*
下面就是操作設(shè)備的函數(shù)了,我們就不列出來拉,大家可以參考上面的介紹
*/
int DeviceWite(int handle)
{
/*
填寫相關(guān)代碼,具體查看設(shè)備協(xié)議
*/
}
int DeviceOpen(int handle)
{
/*
填寫相關(guān)代碼,具體查看設(shè)備協(xié)議
*/
}
/*
最后不要忘記關(guān)閉設(shè)備
*/
void Device_close(int handle)
{
/*
調(diào)用
usb_close */
}
到此,使用libusb進行驅(qū)動開發(fā)介紹完了,通過對庫所提供的API的使用可以體會到libusb的易用性。