USB Gadget
+ -

USB Gadget总结

2025-09-25 本文链接为:http://www.usbzh.com/article/detail-1589.html ,欢迎转载,转载请附上本文链接。

USB Gadget 流程

USB Gadget设备一般是通过SHELL脚本通过configfs文件系统来创建的。其大致分为三部:

  • 第一步:创建function目录下的USB设备模板,例如mkdir functions/Loopback.0,就会调用其对应的loopback_alloc_instance。
  • 第二步:将创建的实例与配置目录下进行“链接”,例如:ln -s functions/Loopback.0 configs/c.1,则会调用loopback_alloc,即以loopback_alloc_instance的实例usb_function_instance创建usb_function。
  • 第三步:就是启用UDC.这时会硬件触发设备的枚举。会执行 function.bind,function.set_alt函数。

以上的操作详细可见https://www.usbzh.com/article/detail-1579.html

function.bind

在function.bind函数为设备枚举前的数据准备,即根据提供的USB设备描述符信息:

  • 分配相应的接口描述符id,函数 usb_interface_id
  • 从硬件中选择相应的端点,并修改端点描述符地址,函数usb_ep_autoconfig
      ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
      if (!ep)
          goto fail;
      audio->out_ep = ep;
      audio->out_ep->desc = &as_out_ep_desc;
    

这是我们在gadget function中提交的软件信息与硬件信息绑定适配的过程,即UDC控制器硬件根据软件提交的接口和端点信息,分配相应的硬件信息。

当然,做了这么多的分配信息,其主要还是生成配置描述符,这里根据linux版本和UDC控制器的情况,分有USB3.0超高速配置描述符,USB2.0高速配置描述符全速配置描述符。

所以function.bind的功能就是硬件根据软件提交的需求信息,确定配置描述符的过程。

关于usb_interface_id中设置是最大USB_MAXINTERFACES,最小从0开始

#define USB_MAXINTERFACES 32

表明这个数值是一个人为设定的上限,并非USB协议本身的强制规定。之所以这样设定,是因为在实际应用中,极少有USB设备的一个配置会包含超过32个接口,这个值被认定为足以满足几乎所有情况。

usb_assign_descriptors实质是对指定的描述符进行复制备份

int usb_assign_descriptors(struct usb_function *f,
        struct usb_descriptor_header **fs,
        struct usb_descriptor_header **hs,
        struct usb_descriptor_header **ss,
        struct usb_descriptor_header **ssp)
{
    struct usb_gadget *g = f->config->cdev->gadget;
    if (fs) {
        f->fs_descriptors = usb_copy_descriptors(fs);
        if (!f->fs_descriptors)
            goto err;
    }
    if (hs && gadget_is_dualspeed(g)) {
        f->hs_descriptors = usb_copy_descriptors(hs);
        if (!f->hs_descriptors)
            goto err;
    }
    if (ss && gadget_is_superspeed(g)) {
        f->ss_descriptors = usb_copy_descriptors(ss);
        if (!f->ss_descriptors)
            goto err;
    }
    if (ssp && gadget_is_superspeed_plus(g)) {
        f->ssp_descriptors = usb_copy_descriptors(ssp);
        if (!f->ssp_descriptors)
            goto err;
    }
    return 0;
err:
    usb_free_all_descriptors(f);
    return -ENOMEM;
}

function.set_alt

set_alt对应的USB标准请求应是SET_INTERFACESET_INTERFACE应启用其接口描述符下的各个端点。所以这里主要涉及的是对端点进行数据传输前的配置和启用,当然,对于OUT端点,需要准备UDC端的接收队列。

  1. config_ep_by_speed:对usb_ep_autoconfig选择出的端点的maxpacket等参数进行配置。

2.usb_ep_enable 使能端点.这里在看相关的参考代码时发现很奇怪,详见https://www.usbzh.com/article/detail-1587.html 一文中的疑惑。

static inline int usb_ep_enable(struct usb_ep *ep)
{
    return ep->ops->enable(ep, ep->desc);
}

关于使能与禁用端点,我们后面再议。

3.分端点分配请求。对于IN端点,按需分配,对于OUT端点,提前分配好并加入到其端点队列中,这样就可以随时接收数据了。

struct usb_request *req = usb_ep_alloc_request(out_ep, GFP_ATOMIC);
    if (req) {
        req->buf = kzalloc(req_buf_size,GFP_ATOMIC);
        if (req->buf) {
            req->length = req_buf_size;
            req->context = audio;
            req->complete =    f_audio_complete;
            err = usb_ep_queue(out_ep,    req, GFP_ATOMIC);
        }
    }
`

结构体声名为:

struct usb_request {
    void            *buf;//数据指针
    unsigned        length;//数据指针,buf长度
    dma_addr_t        dma;

    struct scatterlist    *sg;
    unsigned        num_sgs;
    unsigned        num_mapped_sgs;

    unsigned        stream_id:16;
    unsigned        no_interrupt:1;
    unsigned        zero:1;
    unsigned        short_not_ok:1;

    void            (*complete)(struct usb_ep *ep,struct usb_request *req);//完成例程
    void            *context; //端点自定义上下文
    struct list_head    list;

    int            status;
    unsigned        actual; //实际发送或者接收长度
};

当一个请求完成时,会返回其状态。

static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
{
    struct f_audio *audio = req->context;
    int status = req->status;
    u32 data = 0;
    struct usb_ep *out_ep = audio->out_ep;

    switch (status) {
    case 0:                /* normal completion? */
        if (ep == out_ep)
            f_audio_out_ep_complete(ep, req);
        else if (audio->set_con) {
            memcpy(&data, req->buf, req->length);
            audio->set_con->set(audio->set_con, audio->set_cmd,    le16_to_cpu(data));
            audio->set_con = NULL;
        }
        break;
    default:
        break;
    }
}
本文链接为:http://www.usbzh.com/article/detail-1589.html ,欢迎转载,转载请附上本文链接。

0 篇笔记 写笔记

USB Gadget CDC-ECM网卡实例
ECM和NCM网卡类似,也需要安装ECM驱动设备兼容ID为:USBClass_02&SubClass_06&Prot_00USBClass_02&SubClass_06USBClass_02创建脚本:#!/bin/bashmodprobe libcompos......
Linux Gadget驱动结构关系图
Linux Gadget驱动层级如下:Gadget Function驱动/gadget legacy驱动Gadget Compoiste驱动USB UDC驱动(USB Device Control)Gadget Function驱动/gadget legacy驱动function, 更加现......
gadget probe过程-以g_audio为例
g_audio中通过如下代码调用usb_composite_probe,其中入参为audio_driverstatic struct usb_composite_driver audio_driver = { .name = "g_audio", ......
configfs文件系统
Linux内核使用CONFIGFS配置项支持可以通过用户创建USB Compoiste Gadget。CONFIG_CONFIGFS_FS项用于支持配置文件系统。Menconfig -> FileSystems -> Psuedo File System -> {M}User......
Gadget legacy和Gadget Function的区别
在 Linux 的 USB Gadget 子系统中,Legacy GadgetGadget Function(FunctionFS 或 configfs) 是两种不同的实现方式,用于将 Linux 设备配置为 USB 外设(如 U 盘、网卡、串口等)。它们的区别主要体现在架构、使用方式和灵活性......
usb_gadget复合HID键盘和U盘实例
#!/bin/bash# 加载模块modprobe libcompositemodprobe usb_f_hidmodprobe usb_f_mass_storage.komount -t configfs none /sys/kernel/config# 创建 Gadgetcd......
usb gadget创建uvc相机脚本实例
#!/bin/bashmodprobe libcompositemodprobe usb_f_uvcmount -t configfs none /sys/kernel/configmkdir -p /sys/kernel/config/usb_gadget/g1cd /sys/kern......
USB Gadget CDC-ACM串口实例
符合USB ACM规范的设备由Windows提供其驱动程序usbser.sysuserser.infLinux Gadget对应的ACM驱动依赖为root@ATK-IMX6U:/sys/kernel/config/usb_gadget/g1# lsmodModule ......
USB Gadget CDC-NCM网卡实例
USG Gadget也提供了CDC-NCM网卡驱动程序,使用USB Gadget CDC-NCM驱动,这样在Windows主机端和Linux设备端都会创建一个USB网卡设备。root@ATK-IMX6U:/lib/modules/4.1.15# ifconfig -ausb0 Lin......
USB Gadget 打印机实例
打印机这一块应该要与实例相连,具体这一块没有研究过。生成的设备如下:设备模块如下:root@ATK-IMX6U:/lib/modules/4.1.15# lsmodModule Size Used byusb_f_printer 1137......
USB Gadget CDC-EEM网卡实例
从理论上来讲,EEM网卡Windows是应该支持的,实际上也确实不用像NCM、ECM需要手动安装驱动,系统会自动匹配兼容ID来进行安装驱动,但是驱动启动失败,这个Linux系统下就没有问题。#!/bin/bashmodprobe libcompositemodprobe usb_f_eemm......
USB Gadget LoopBack实例
Loopback Function 提供的功能简单,它分配了两个 bulk endpoint,所做的就是把 out_ep 接收到的数据转发到 in_ep。#!/bin/bashmodprobe libcompositemodprobe usb_f_ss_lbmount -t configfs......
USB Gadget RNDIS网络适配器实列
和NCM一样,由于兼容ID的问题,RNDIS网络适配器也需要手动安装驱动。其对应的驱动为:netrndis.infrndismp6.sys其创建脚本如下:#!/bin/bashmodprobe libcompositemodprobe usb_f_rndismount -t conf......
USB Gadget实例分析usb_function_instance和usb_function
linux usb gadtet的设备类驱动有两个很重要的概念:usb_function_instance和usb_function从名来上看,usb_function_instance像是usb_function的实例化,但实际是恰恰相反。这里以f_loopback为示例解释:USB设备信息执......
USB Gadget数据收发-批量传输
当执行命令ln -s functions/Loopback.0 configs/c.1之后,会调用loopback_alloc函数创建usb_functionstruct f_loopback { struct usb_function function; struct......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • CDC
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    您的支持,是我们前进的动力!