0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

USB Gadget zero应用实例程序

麦辣鸡腿堡 来源:嵌入式Linux系统开发 作者:嵌入式Linux系统开 2023-07-13 11:14 次阅读

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;
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    4983

    文章

    18295

    浏览量

    288610
  • Linux
    +关注

    关注

    87

    文章

    10992

    浏览量

    206745
  • 程序
    +关注

    关注

    114

    文章

    3631

    浏览量

    79555
收藏 人收藏

    评论

    相关推荐

    进销存管理实例程序源代码

    进销存管理实例程序
    发表于 07-19 11:14 926次下载

    c#高级技巧 (C#高级实例程序哦)

    c#高级技巧是很多高手写的一些C#高级实例程序及技巧,相信大家看了会明白很多东西。呵呵。。
    发表于 09-19 17:52 115次下载
    c#高级技巧 (C#高级<b class='flag-5'>实例程序</b>哦)

    simulink的实例程序

    simulink的实例程序:很多simulink的例程,对于初学者和高手都需要的东西。
    发表于 02-08 14:57 186次下载

    读写24LCxx系列的EEPROM的实例程序

    读写24LCxx系列的EEPROM的实例程序 ;********************************************************  ;*           &nbs
    发表于 01-16 11:30 2149次阅读

    C8051F41x实例程序

    一些很实用的c8051f410实例程序,包括寄存器、中断、延时等等
    发表于 10-27 14:26 66次下载

    精品verilog实例程序代码

    精品verilog实例程序代码,下来看看。
    发表于 05-24 10:03 46次下载

    LCD实例程序

    微雪电子 LCD实例程序 微雪电子 LCD实例程序
    发表于 07-12 11:54 33次下载

    AVR产生PWM波实例程序

    AVR单片机产生PWM波实例程序
    发表于 12-29 20:38 5次下载

    u盘读写模块实例程序

    本文分享了u盘读写模块的实例程序
    发表于 11-16 13:34 36次下载

    34461A的USB口驱动工程实例程序等资料免费下载

    本文档的主要内容详细介绍的是34461A的USB口驱动工程实例程序等资料免费下载。
    发表于 01-07 08:00 136次下载
    34461A的<b class='flag-5'>USB</b>口驱动工程<b class='flag-5'>实例程序</b>等资料免费下载

    微雪电子Zero/Zero W USB转接板简介

    树莓派Zero/Zero W/Zero WH USB转接板 micro USB转换Type A接口,方便接入计算机,无需连接其他线材或
    的头像 发表于 01-06 10:50 1476次阅读
    微雪电子<b class='flag-5'>Zero</b>/<b class='flag-5'>Zero</b> W <b class='flag-5'>USB</b>转接板简介

    [嵌入式linux]将linux板卡虚拟为USB网卡设备(Ethernet Gadget

    kernel menuconfig-> Device Drivers ->USB support -> USB Gadget Support 建议最好选成M,作为内核驱动模块,便于
    发表于 11-02 11:36 11次下载
    [嵌入式linux]将linux板卡虚拟为<b class='flag-5'>USB</b>网卡设备(Ethernet <b class='flag-5'>Gadget</b>)

    AMD Xilinx Linux 2022.1 USB Gadget使用

    有客户使用Linux中的USB Gadget功能,把MPSoC器件做USB从设备
    的头像 发表于 07-07 14:15 479次阅读

    USB Gadget serial应用实例(上)

    USB 口。 然后在板子加载驱动程序后,可以看到新的设备节点 /dev/ttyGS0: # modprobe g_serial g_serial gadget: Gadget S
    的头像 发表于 07-13 11:06 1264次阅读
    <b class='flag-5'>USB</b> <b class='flag-5'>Gadget</b> serial应用<b class='flag-5'>实例</b>(上)

    USB Gadget zero应用上机实验

    2. 上机实验 实验步骤: 先安装 g_zero 驱动程序:在开发板上执行 modprobe g_zero 然后连接 OTG 线到 PC 在 Ubuntu 中识别出设备 执行测试程序
    的头像 发表于 07-13 11:15 433次阅读