在Ubuntu里执行如下命令:
$ lsusb -v -d 0525:a4a0
可以列出zero设备的描述符:
Bus 001 Device 002: ID 0525:a4a0 Netchip Technology, Inc. Linux-USB "Gadget Zero"
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 255 Vendor Specific Class
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x0525 Netchip Technology, Inc.
idProduct 0xa4a0 Linux-USB "Gadget Zero"
bcdDevice 4.09
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 2
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 69
bNumInterfaces 1
bConfigurationValue 3
iConfiguration 4
bmAttributes 0xc0
Self Powered
MaxPower 2mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 1
bNumEndpoints 4
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 4
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 4
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 2
iConfiguration 5
bmAttributes 0xc0
Self Powered
MaxPower 2mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 6
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
它有2个配置:
参考libusb示例:libusb\examples\xusb.c
zero_app.c
#include
#include
#include
#include
#include
#include
#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
int get_bulk_endpoint(libusb_device *dev, int *in_ep, int *out_ep, int *in_ep_maxlen)
{
struct libusb_config_descriptor *config;
const struct libusb_endpoint_descriptor *ep;
int r;
int iface_idx;
int found = 0;
r = libusb_get_active_config_descriptor(dev, &config);
if (r < 0) {
printf("could not retrieve active config descriptor");
return LIBUSB_ERROR_OTHER;
}
{
const struct libusb_interface *iface = &config->interface[0];
int altsetting_idx = 0;
const struct libusb_interface_descriptor *altsetting
= &iface->altsetting[altsetting_idx];
int ep_idx;
for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints; ep_idx++) {
const struct libusb_endpoint_descriptor *ep =
&altsetting->endpoint[ep_idx];
if ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK)
{
if (ep->bEndpointAddress & LIBUSB_ENDPOINT_IN)
{
*in_ep = ep->bEndpointAddress;
*in_ep_maxlen = ep->wMaxPacketSize;
found++;
}
else
{
*out_ep = ep->bEndpointAddress;
found++;
}
}
}
}
libusb_free_config_descriptor(config);
return (found == 2) ? 0 : -1;
}
void PrintUsage(char *name)
{
printf("Usage:\n");
printf("%s -l : list bConfigurationValue of all configs\n", name);
printf("%s -s : select config\n" , name);
printf("%s -wstr : write string\n" , name);
printf("%s -rstr : read string\n", name);
printf("%s -w : write bytes\n" , name);
printf("%s -r : read 32 bytes\n", name);
}
int main(int argc, char **argv)
{
int err = 0;
libusb_device *dev, **devs;
int num_devices;
int endpoint;
int interface_num = 0;
int found = 0;
int transferred;
int count = 0;
unsigned char buffer[1024];
struct libusb_config_descriptor *config_desc;
struct libusb_device_handle *dev_handle = NULL;
int i;
int in_ep, out_ep;
int in_ep_maxlen;
if (argc == 1)
{
PrintUsage(argv[0]);
return 0;
}
/* libusb_init */
err = libusb_init(NULL);
if (err < 0) {
fprintf(stderr, "failed to initialise libusb %d - %s\n", err, libusb_strerror(err));
exit(1);
}
/* open device */
dev_handle = libusb_open_device_with_vid_pid(NULL, DRIVER_VENDOR_NUM, DRIVER_PRODUCT_NUM);
if (!dev_handle) {
printf("can not open zero device\n");
return -1;
}
dev = libusb_get_device(dev_handle);
/* 想选择某一个配置, 先知道它的bConfigurationValue */
if (!strcmp(argv[1], "-l"))
{
for (i = 0; i < 255; i++)
{
/* parse interface descriptor, find usb mouse */
err = libusb_get_config_descriptor(dev, i, &config_desc);
if (err) {
//fprintf(stderr, "could not get configuration descriptor\n");
break;
}
printf("config %d: bConfigurationValue = %d\n", i, config_desc->bConfigurationValue);
libusb_free_config_descriptor(config_desc);
}
return 0;
}
/* 想选择某一个配置 */
if (!strcmp(argv[1], "-s") && (argc == 3))
{
i = strtoul(argv[2], NULL, 0);
libusb_set_auto_detach_kernel_driver(dev_handle, 0);
libusb_detach_kernel_driver(dev_handle, 0);
//libusb_release_interface(dev_handle, 0);
err = libusb_set_configuration(dev_handle, i);
if (err) {
fprintf(stderr, "could not set configuration as %d, err = %d\n", i, err);
return -1;
}
return 0;
}
err = libusb_get_configuration(dev_handle, &i);
fprintf(stdout, "current config: %d\n", i);
/* 想读写数据需要得到endpoint */
err = get_bulk_endpoint(dev, &in_ep, &out_ep, &in_ep_maxlen);
if (err) {
fprintf(stderr, "could not get bulk endpoints\n");
goto exit;
}
fprintf(stdout, "in_ep = 0x%x, out_ep = 0x%x\n", in_ep, out_ep);
/* claim interface */
libusb_set_auto_detach_kernel_driver(dev_handle, 1);
err = libusb_claim_interface(dev_handle, interface_num);
if (err)
{
fprintf(stderr, "failed to libusb_claim_interface\n");
goto exit;
}
/* write string */
if (!strcmp(argv[1], "-wstr") && (argc == 3))
{
memset(buffer, 0, 32);
strncpy(buffer, argv[2], 32);
err = libusb_bulk_transfer(dev_handle, out_ep,
buffer, 32, &transferred, 1000);
if (err) {
fprintf(stderr, "libusb_bulk_transfer err = %d\n", err);
goto exit;
}
if (transferred != 32)
{
fprintf(stderr, "transferred != 32\n");
}
goto exit;
}
/* read string */
if (!strcmp(argv[1], "-rstr"))
{
memset(buffer, 0, 32);
err = libusb_bulk_transfer(dev_handle, in_ep,
buffer, 32, &transferred, 1000);
if (err) {
fprintf(stderr, "libusb_bulk_transfer err = %d\n", err);
goto exit;
}
if (transferred != 32)
{
fprintf(stderr, "transferred != 32\n");
}
printf("Read string: %s\n", buffer);
goto exit;
}
/* write datas */
if (!strcmp(argv[1], "-w") && (argc >= 3))
{
memset(buffer, 0, 32);
/* argv[2],... */
for (i = 2; i < argc; i++)
buffer[i-2] = strtoul(argv[i], NULL, 0);
err = libusb_bulk_transfer(dev_handle, out_ep,
buffer, argc - 2, &transferred, 1000);
if (err) {
fprintf(stderr, "libusb_bulk_transfer err = %d\n", err);
goto exit;
}
if (transferred != argc - 2)
{
fprintf(stderr, "transferred != %d\n", argc - 2);
}
goto exit;
}
/* read datas */
if (!strcmp(argv[1], "-r")) /* 读Source/Sink这个配置里的端点时, 它一次性返回512字节的数据 */
{
memset(buffer, 0, 1024);
err = libusb_bulk_transfer(dev_handle, in_ep,
buffer, in_ep_maxlen, &transferred, 1000);
if (err) {
fprintf(stderr, "libusb_bulk_transfer err = %d\n", err);
goto exit;
}
if (transferred != in_ep_maxlen)
{
fprintf(stderr, "transferred != in_ep_maxlen\n");
}
printf("Read datas: \n");
for (i = 0; i < transferred; i++)
{
printf("%02x ", buffer[i]);
if ((i+1) % 16 == 0)
printf("\n");
}
printf("\n");
goto exit;
}
exit:
/* libusb_close */
libusb_release_interface(dev_handle, interface_num);
libusb_close(dev_handle);
libusb_exit(NULL);
return err;
}
实验步骤:
先安装g_zero驱动程序:在开发板上执行modprobe g_zero
然后连接OTG线到PC
在Ubuntu中识别出设备
执行测试程序
先编译:在Ubuntu里执行如下命令
apt-cache search libusb # 查找libusb开发包
sudo apt install libusb-1.0-0-dev # 安装libusb开发包
gcc -o zero_app zero_app.c -lusb-1.0 # 编译
测试:在Ubuntu里执行如下命令
$ sudo ./zero_app -l # 列出设备的配置值
config 0: bConfigurationValue = 3
config 1: bConfigurationValue = 2
# 测试loopback功能
$ sudo ./zero_app -s 2 # 选择loopback的配置
$ sudo ./zero_app -wstr www.100ask.net # 写入字符串
current config: 2
in_ep = 0x81, out_ep = 0x1
$ sudo ./zero_app -rstr # 读出字符串
current config: 2
in_ep = 0x81, out_ep = 0x1
Read string: www.100ask.net
$ sudo ./zero_app -w 1 2 3 4 5 6 7 8 # 写入8个字节
current config: 2
in_ep = 0x81, out_ep = 0x1
sudo ./zero_app -r # 读到8个字节
current config: 2
in_ep = 0x81, out_ep = 0x1
transferred != in_ep_maxlen
Read datas:
01 02 03 04 05 06 07 08
#测试Source/Sink功能
$ sudo ./zero_app -s 3 # 选择source/sink的配置
[email protected]:/work/nfs_rootfs/libusb_zero$ sudo ./zero_app -r # 读数据
current config: 3
in_ep = 0x81, out_ep = 0x1
Read datas:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
sudo ./zero_app -w 0 0 0 # 写数据, 只能写入0,
# 写入其他值将会导致开发板上的驱动认为是错误然后halt out端点
# 然后只能重新执行 ”sudo ./zero_app -s 3“ 才能恢复
以上笔记源自
韦东山
老师的视频课程,感谢韦老师,韦老师是嵌入式培训界一股清流,为嵌入式linux开发点起的星星之火,也愿韦老师桃李满园。聚是一团火,散是满天星!
在这样一个速食的时代,坚持做自己,慢下来,潜心琢磨,心怀敬畏,领悟知识,才能向下扎到根,向上捅破天,背着世界往前行!
仅此向嵌入行业里的每一个认真做技术的从业者致敬!