1. 編寫程序
1.1 編程思路
涉及的程序如下圖所示:
PC 端基于 libusb 編寫應用程序,開發(fā)板端直接使用 Linux 自帶的 USB Gadget 驅動 zero.c【/drivers/usb/gadget/legacy/zero.c】。
應用程序編程框架如下:
- 找到設備
- 選擇配置:zero.c 提供了兩種配置,loopback、sourcesink
- 得到端點:找到 interface 進而得到 endpoint
- 讀寫數(shù)據(jù):操作 endpoint
1.2 zero 設備的描述符
在 Ubuntu 里執(zhí)行如下命令,根據(jù) 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);
/* 想讀寫數(shù)據(jù)需要得到 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字節(jié)的數(shù)據(jù) */
{
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;
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
嵌入式
+關注
關注
5086文章
19141瀏覽量
305925 -
Linux
+關注
關注
87文章
11314瀏覽量
209772 -
程序
+關注
關注
117文章
3789瀏覽量
81134
發(fā)布評論請先 登錄
相關推薦
讀寫24LCxx系列的EEPROM的實例程序
讀寫24LCxx系列的EEPROM的實例程序
;********************************************************? ;*???????????&nbs
發(fā)表于 01-16 11:30
?2262次閱讀
[嵌入式linux]將linux板卡虛擬為USB網(wǎng)卡設備(Ethernet Gadget)
kernel menuconfig-> Device Drivers ->USB support -> USB Gadget Support 建議最好選成M,作為內核驅動模塊,便于
發(fā)表于 11-02 11:36
?12次下載
AMD Xilinx Linux 2022.1 USB Gadget使用
有客戶使用Linux中的USB Gadget功能,把MPSoC器件做USB從設備
USB Gadget serial應用實例(上)
的 USB 口。 然后在板子加載驅動程序后,可以看到新的設備節(jié)點 /dev/ttyGS0: # modprobe g_serial g_serial gadget: Gadget S
USB Gadget zero應用上機實驗
2. 上機實驗 實驗步驟: 先安裝 g_zero 驅動程序:在開發(fā)板上執(zhí)行 modprobe g_zero 然后連接 OTG 線到 PC 在 Ubuntu 中識別出設備 執(zhí)行測試程序
評論