1. 编写程序
1.1 编程思路
涉及的程序如下图所示:
PC 端基于 libusb 编写应用程序,开发板端直接使用 Linux 自带的 USB Gadget 驱动 zero.c【/drivers/usb/gadget/legacy/zero.c】。
应用程序编程框架如下:
- 找到设备
- 选择配置:zero.c 提供了两种配置,loopback、sourcesink
- 得到端点:找到 interface 进而得到 endpoint
- 读写数据:操作 endpoint
1.2 zero 设备的描述符
在 Ubuntu 里执行如下命令,根据 VID:PID 获取设备信息:
$ 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 个配置:
- 第 1 个配置(bConfigurationValue = 2)对应 loopback 功能:里面有 1 个接口,接口有 1 个 setting,下面有 2 个 endpoint
- 第 2 个配置(bConfigurationValue = 3)对应 SourceSink 功能:里面有 1 个接口,接口有 2 个 setting
- 第 1 个 setting 下面有 2 个 endpoint:都是 bulk 端点
- 第 2 个 setting 下面有 4 个 endpoint:2 个是 bulk 端点,另外 2 个是 Isochronous 端点
1.3 编程
参考 libusb 示例:libusbexamplesxusb.c
#include < errno.h >
#include < signal.h >
#include < stdio.h >
#include < stdlib.h >
#include < string.h >
#include < libusb-1.0/libusb.h >
#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 configsn", name);
printf("%s -s , name);
printf("%s -wstr < string > : write stringn", name);
printf("%s -rstr : read stringn", name);
printf("%s -w < val1 val2 .... > : write bytesn", name);
printf("%s -r : read 32 bytesn", 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 - %sn", 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 devicen");
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 descriptorn");
break;
}
printf("config %d: bConfigurationValue = %dn", 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 = %dn", i, err);
return -1;
}
return 0;
}
err = libusb_get_configuration(dev_handle, &i);
fprintf(stdout, "current config: %dn", i);
/* 想读写数据需要得到 endpoint */
err = get_bulk_endpoint(dev, &in_ep, &out_ep, &in_ep_maxlen);
if (err) {
fprintf(stderr, "could not get bulk endpointsn");
goto exit;
}
fprintf(stdout, "in_ep = 0x%x, out_ep = 0x%xn", 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_interfacen");
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 = %dn", err);
goto exit;
}
if (transferred != 32)
{
fprintf(stderr, "transferred != 32n");
}
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 = %dn", err);
goto exit;
}
if (transferred != 32)
{
fprintf(stderr, "transferred != 32n");
}
printf("Read string: %sn", 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 = %dn", err);
goto exit;
}
if (transferred != argc - 2)
{
fprintf(stderr, "transferred != %dn", 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 = %dn", err);
goto exit;
}
if (transferred != in_ep_maxlen)
{
fprintf(stderr, "transferred != in_ep_maxlenn");
}
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;
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
嵌入式
+关注
关注
5082文章
19107浏览量
304830 -
Linux
+关注
关注
87文章
11294浏览量
209341 -
程序
+关注
关注
117文章
3785浏览量
81005
发布评论请先 登录
相关推荐
读写24LCxx系列的EEPROM的实例程序
读写24LCxx系列的EEPROM的实例程序
;******************************************************** ;* &nbs
发表于 01-16 11:30
•2254次阅读
[嵌入式linux]将linux板卡虚拟为USB网卡设备(Ethernet Gadget)
kernel menuconfig-> Device Drivers ->USB support -> USB Gadget Support 建议最好选成M,作为内核驱动模块,便于
发表于 11-02 11:36
•12次下载
AMD Xilinx Linux 2022.1 USB Gadget使用
有客户使用Linux中的USB Gadget功能,把MPSoC器件做USB从设备
USB Gadget serial应用实例(上)
的 USB 口。 然后在板子加载驱动程序后,可以看到新的设备节点 /dev/ttyGS0: # modprobe g_serial g_serial gadget: Gadget S
USB Gadget zero应用上机实验
2. 上机实验 实验步骤: 先安装 g_zero 驱动程序:在开发板上执行 modprobe g_zero 然后连接 OTG 线到 PC 在 Ubuntu 中识别出设备 执行测试程序
评论