ALSA
+ -

ALSA框架UAC1函数f_audio_alloc_inst和f_audio_alloc

2022-06-11 27 0

前面大概分析到了UAC1的系统级的入口函数f_audio_alloc_inst和f_audio_alloc。

从代码上来看,会先调用usb_function_instance,再是f_audio_alloc。这是因为f_audio_alloc函数中引用了usb_function_instance申请的f_uac1_opts结构体。

机智如我。。。

两个函数的源代码如下:

static struct usb_function_instance *f_audio_alloc_inst(void)
{
    struct f_uac1_opts *opts;

    opts = kzalloc(sizeof(*opts), GFP_KERNEL);
    if (!opts)
        return ERR_PTR(-ENOMEM);

    mutex_init(&opts->lock);
    opts->func_inst.free_func_inst = f_audio_free_inst;

    config_group_init_type_name(&opts->func_inst.group, "",
                    &f_uac1_func_type);

    opts->c_chmask = UAC1_DEF_CCHMASK;
    opts->c_srate = UAC1_DEF_CSRATE;
    opts->c_ssize = UAC1_DEF_CSSIZE;
    opts->p_chmask = UAC1_DEF_PCHMASK;
    opts->p_srate = UAC1_DEF_PSRATE;
    opts->p_ssize = UAC1_DEF_PSSIZE;
    opts->req_number = UAC1_DEF_REQ_NUM;
    return &opts->func_inst;
}
static struct usb_function *f_audio_alloc(struct usb_function_instance *fi)
{
    struct f_uac1 *uac1;
    struct f_uac1_opts *opts;

    /* allocate and initialize one new instance */
    uac1 = kzalloc(sizeof(*uac1), GFP_KERNEL);
    if (!uac1)
        return ERR_PTR(-ENOMEM);

    opts = container_of(fi, struct f_uac1_opts, func_inst);
    mutex_lock(&opts->lock);
    ++opts->refcnt;
    mutex_unlock(&opts->lock);

    uac1->g_audio.func.name = "uac1_func";
    uac1->g_audio.func.bind = f_audio_bind;
    uac1->g_audio.func.unbind = f_audio_unbind;
    uac1->g_audio.func.set_alt = f_audio_set_alt;
    uac1->g_audio.func.get_alt = f_audio_get_alt;
    uac1->g_audio.func.setup = f_audio_setup;
    uac1->g_audio.func.disable = f_audio_disable;
    uac1->g_audio.func.free_func = f_audio_free;

    return &uac1->g_audio.func;
}

可以看到,主要是分配两个关键的结构体和初始化一堆堆的回调函数。

所以这里我画了一张草图来表述它们之间的关系:
UAB结构体关系

从当前来看 f_uac1_opts结构体好像有用的就是这个引用计数和其锁,而这些掩码是用来对一些初始化参数用的。

另外f_uac1这个结构体通过继承USB通用框架结构体usb_function func和引用usb_gadget* gdaget的指针。这就体现了C++类的继承方面的思想,也和UAC规范的设计思想一致,其是建立在USB规范基础上的,而LINUX相关的USB框架又与gdaget相关,这与USB的设备相关。

另外,在结构体uac1中:

struct f_uac1 {
    struct g_audio g_audio;
    u8 ac_intf, as_in_intf, as_out_intf;
    u8 ac_alt, as_in_alt, as_out_alt;    /* needed for get_alt() */
};

这里有一些相关的整数型,分别为ac和as开头的,这其实对应的是Audio Control和Audio Stream的简单。所也有就是了输入,输入接口的一些参数。

  • ac_intf:音频控制接口
  • as_in_intf音频流输入接口
  • as_out_intf:音频输出流接口

而下面的alt对应的是alternat,即转换或者叫备用接口索引,用于音频设备打开时的数据端点。所以后面的函数get_alt与set_alt的功能就呼之欲出。
而bind和unbind就类似于windows中IRP_MN_START和IRP_MN_REMOVE。

f_audio_free函数从名称上来看是f_audio_alloc的逆向函数,f_audio_alloc类似DriverEntry,那么f_audio_free就是类似DriverUnload,不过f_audio_free中并未内存释放,而仅是引用计数减1,所以内存释放应该是modeinstall remove来实现调用f_audio_free吧。

f_audio_setup就是控制端点的控制命令,就是SET_CUR,GET_MAX,GET_CUR,GET_MIN等这些特定类请求

另外,我们在看LINUX关于UAC源代码时,发现大量函数的入口参数第一个参数为usb_function的指针类型,其实这个指针也就是我们的struct f_uac1,也是的指针struct g_audio指针。不过为了防止usb_function成员没有在第一个,也使用了宏func_to_g_audio来进行转换。这个宏的功能和windows的CONTANING_RECORD的功能一致。

#define CONTAINING_RECORD(address, type, field) ((type *)( \
                                                  (PCHAR)(address) - \
                                                  (ULONG_PTR)(&((type *)0)->field)))
#ifndef container_of
#define container_of(ptr, type, member) \
    (type *)((char *)(ptr) - (char *) &((type *)0)->member)
#endif

static inline struct g_audio *func_to_g_audio(struct usb_function *f)
{
    return container_of(f, struct g_audio, func);
}

所以,惊不惊喜,意不意外。其实仔细想想也是理所当然了,虽然linux和windows是两个不同的操作系统,不过其设计思路基本一致,只是实现细节不同而已。

0 篇笔记 写笔记

ALSA框架UAC1驱动程序入口宏DECLARE_USB_FUNCTION分析
题外话:为了学习看LINUX驱动,我也是拼了。对于LINUX源代码,虽然以前了解过LINUX的字符串驱动,不过突然跳到一个复杂的LINUX设备驱动,还是有点迷茫,自己什么不会。不过还是要狠下心来,像看了7天的UVC规范一样,强行让自己翻译。自己看的Linux UAC源代码位于https://eli......
ALSA框架UAC1函数f_audio_alloc_instf_audio_alloc
前面大概分析到了UAC1的系统级的入口函数f_audio_alloc_instf_audio_alloc。从代码上来看,会先调用usb_function_instance,再是f_audio_alloc。这是因为f_audio_alloc函数中引用了usb_function_instance申请......
作者信息
USB中文网
B站搜索 站长漫谈 看视频。
pnpon内核开网,USB中文网,
busrom硬核技术网站长
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

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

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