USB Gadget
+ -

USB Gadget UAC1实现分析

2025-09-16 0 0

对于USB Gdaget驱动,有两个结构体,分别代表实例usb_function_instance(模板)和实例本身usb_function。
其中包含了usb_function_instance的结构体中包含了通过fsconfig可配置的参数,而包含了usb_function的结构体包含了设备的相关回调函数。

根通UAC1代码的f_audio_bind可知,由于UAC1通过gadget创建一个UAC扬声器,对于收到的PCM数据,其通过ALSA的playback设置即/dev/snd/pcmCoD0p来最终输出

而在f_audio_bind函数中调用gaudio_setup根据/dev/snd/pcmCoD0p设备信息初始化gadget设备信息。

uac playback ——> usb gadget ——->板载/dev/snd/pcmCoD0p

f_uac1_opts

f_uac1_opt由f_audio_alloc_inst函数实现,发生于:

mkdir -p functions/uac1.usb0

在 UAC1驱动中,usb_function_instance对应的结体为f_uac1_opts

struct f_uac1_opts {
    struct usb_function_instance    func_inst;
    int                req_buf_size; //48000
    int                req_count;//256
    int                audio_buf_size;//200
    char                *fn_play;// /dev/snd/pcmC0D0p
    char                *fn_cap;// /dev/snd/pcmC0D0c
    char                *fn_cntl;// /dev/snd/pcmC0D0p
    unsigned            bound:1;
    unsigned            fn_play_alloc:1;
    unsigned            fn_cap_alloc:1;
    unsigned            fn_cntl_alloc:1;
    struct mutex            lock;
    int                refcnt;
};

其可配置参数为

root@ATK-IMX6U:/sys/kernel/config/usb_gadget/g1/functions/uac1.usb0# ls
audio_buf_size  fn_cap  fn_cntl  fn_play  req_buf_size  req_count

对应于f_uac1_opts相应的成员。

f_audio

f_audio是实例,其创建发生于

mkdir -p configs/c.1
ln -s functions/uac1.usb0 configs/c.1/

其主要功能是初始化初始化gaudio的usb_function回调函数。

struct gaudio_snd_dev {
    struct gaudio            *card;
    struct file            *filp;
    struct snd_pcm_substream    *substream;
    int                access;
    int                format;
    int                channels;
    int                rate;
};

struct gaudio {
    struct usb_function        func;
    struct usb_gadget        *gadget;

    /* ALSA sound device interfaces */
    struct gaudio_snd_dev        control;
    struct gaudio_snd_dev        playback;
    struct gaudio_snd_dev        capture;
};

struct f_audio {
    struct gaudio            card;

    /* endpoints handle full and/or high speeds */
    struct usb_ep            *out_ep;

    spinlock_t            lock;
    struct f_audio_buf *copy_buf;
    struct work_struct playback_work;
    struct list_head play_queue;

    /* Control Set command */
    struct list_head cs;
    u8 set_cmd;
    struct usb_audio_control *set_con;
};

对usb_function回调的函数初始化还是老三样:

    audio->card.func.bind = f_audio_bind;  //启用UDC时连接回调
    audio->card.func.set_alt = f_audio_set_alt;//选择接口
    audio->card.func.setup = f_audio_setup;//控制请求

    audio->card.func.disable = f_audio_disable;
    audio->card.func.unbind = f_audio_unbind;//禁用UDC
    audio->card.func.free_func = f_audio_free;//释内实例

f_audio_bind

启用UDC时,先执行f_audio_bind函数。
f_audio_bind调用gaudio_setup初始化与linux设备端的uac设备信息,并建立文件打开链接。这些设备默认如下:

playback:/dev/snd/pcmC0D0p
capture:/dev/snd/pcmC0D0p
control:/dev/snd/pcmC0D0c

然后根据上面playback打开的设备实际参数信息修改gadget uac设备的相关描述符信息,这些参数包括:通道数、采样率
然后根调用usb_interface_id给uac控制和数据流接口描述符分析接口描述符的id.

//audo control
    status = usb_interface_id(c, f);//allocate an unused interface ID
    ac_interface_desc.bInterfaceNumber = status;
//audo streaming
    status = usb_interface_id(c, f);
    as_interface_alt_0_desc.bInterfaceNumber = status;
    as_interface_alt_1_desc.bInterfaceNumber = status;

分配端点信息

    ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
    audio->out_ep = ep;
    audio->out_ep->desc = &as_out_ep_desc;
    ep->driver_data = cdev;    /* claim */

最后是调用usb_assign_descriptors构建配置描述符,这里只有全速高速的,没有超高速的。

    status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL);

描述符数组如下:

static struct usb_descriptor_header *f_audio_desc[] = {
    (struct usb_descriptor_header *)&ac_interface_desc,//音频控制接口描述符
    (struct usb_descriptor_header *)&ac_header_desc,//Audio Control Interface Header Descriptor

    (struct usb_descriptor_header *)&input_terminal_desc,// Audio Control Input Terminal Descriptor 
    (struct usb_descriptor_header *)&output_terminal_desc,//   Audio Control Feature Unit Descriptor
    (struct usb_descriptor_header *)&feature_unit_desc,//Audio Control Output Terminal Descriptor

    (struct usb_descriptor_header *)&as_interface_alt_0_desc,//音频流接口描述符
    (struct usb_descriptor_header *)&as_interface_alt_1_desc,//音频流接口描述符(备用接口描述符)
    (struct usb_descriptor_header *)&as_header_desc, // Audio Streaming Interface Descriptor 

    (struct usb_descriptor_header *)&as_type_i_desc,//Audio Streaming Format Type Descriptor

    (struct usb_descriptor_header *)&as_out_ep_desc,//Endpoint Descriptor
    (struct usb_descriptor_header *)&as_iso_out_desc,//Audio Data Endpoint Descriptor
    NULL,
};

通过分析其配置描述符,确实只有一个UAC扬声器设备,没有麦克风。如果需要,需要自行修改源代码。

0 篇笔记 写笔记

UAC1.0和UAC2.0区别
传统3.5mm模拟耳机逐步被USB数字耳机代替。采用USB协议进行音频播放使用USB Audio Class协议(简称UAC).UAC2.0由于支持USB High Speed,从而天生带有高带宽、低延时的优势。这些优势转化为对于Hi-Resolution Auido的支持。UAC1.0最高只支持到......
UAC1.0麦克风端点描述符wMaxPacketSize的问题分析
同事搞了一个UAC麦克风,将输入端点设置如下: ----------------- Endpoint Descriptor -----------------bLength : 0x09 (9 bytes)bDescriptorType ......
ALSA框架UAC1驱动程序入口宏DECLARE_USB_FUNCTION分析
题外话:为了学习看LINUX驱动,我也是拼了。对于LINUX源代码,虽然以前了解过LINUX的字符串驱动,不过突然跳到一个复杂的LINUX设备驱动,还是有点迷茫,自己什么不会。不过还是要狠下心来,像看了7天的UVC规范一样,强行让自己翻译。自己看的Linux UAC源代码位于https://eli......
ALSA框架UAC1函数f_audio_alloc_inst和f_audio_alloc
前面大概分析到了UAC1的系统级的入口函数f_audio_alloc_inst和f_audio_alloc。从代码上来看,会先调用usb_function_instance,再是f_audio_alloc。这是因为f_audio_alloc函数中引用了usb_function_instance申请......
UAC1数据结构关系由f_audio_bind函数引出的struct f_uac1_opts和struct f_uac1之间的联系解读
前面看到了分别通过f_audio_alloc_inst和f_audio_alloc函数申请struct f_uac1_opts和struct f_uac1结构体,而我们在看UAC1源代码的时候,就需要这些结构体之间进行转换。首先我们先看struct f_uac1_opts和struct f_uac......
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......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • CDC
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

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

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