USB Gadget zero应用实例程序

描述

1. 编写程序

1.1 编程思路

涉及的程序如下图所示:

Linux

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

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分