涉及的程序如下图所示:
PC 端基于 libusb 编写应用程序,开发板端直接使用 Linux 自带的 USB Gadget 驱动 zero.c【/drivers/usb/gadget/legacy/zero.c】。
应用程序编程框架如下:
在 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 个配置:
参考 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;
}
全部0条评论
快来发表一下你的评论吧 !