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_uac1之间的联系。由于我们在前面一切并未再展开结构体来讲,所以从草较来看struct f_uac1_opts和struct f_uac1好像没有关系。不过我们在看f_audio_bind函数时,有这么一句话:
static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
{
struct f_uac1_opts* audio_opts;
...
audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst)= container_of(f->fi, struct f_uac1_opts, func_inst);
}
可以看到,实现了从usb_function(struct f_uac1)到struct f_uac1_opts之间的转换。它们之间的联系竟然是struct usb_function func,所以我们需要深入地分析,并再次完善这个草图。
先看struct usb_function结构体。
struct usb_function {
const char *name;
struct usb_gadget_strings **strings;
struct usb_descriptor_header **fs_descriptors;
struct usb_descriptor_header **hs_descriptors;
struct usb_descriptor_header **ss_descriptors;
struct usb_descriptor_header **ssp_descriptors;
struct usb_configuration *config;
struct usb_os_desc_table *os_desc_table;
unsigned os_desc_n;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
* we can't restructure things to avoid mismatching.
* Related: unbind() may kfree() but bind() won't...
*/
/* configuration management: bind/unbind */
int (*bind)(struct usb_configuration *,
struct usb_function *);
void (*unbind)(struct usb_configuration *,
struct usb_function *);
void (*free_func)(struct usb_function *f);
struct module *mod;
/* runtime state management */
int (*set_alt)(struct usb_function *,
unsigned interface, unsigned alt);
int (*get_alt)(struct usb_function *,
unsigned interface);
void (*disable)(struct usb_function *);
int (*setup)(struct usb_function *,
const struct usb_ctrlrequest *);
bool (*req_match)(struct usb_function *,
const struct usb_ctrlrequest *,
bool config0);
void (*suspend)(struct usb_function *);
void (*resume)(struct usb_function *);
/* USB 3.0 additions */
int (*get_status)(struct usb_function *);
int (*func_suspend)(struct usb_function *,
u8 suspend_opt);
/* private: */
/* internals */
struct list_head list;
DECLARE_BITMAP(endpoints, 32);
const struct usb_function_instance *fi;
unsigned int bind_deactivated:1;
};
注意倒数第二个成员:
const struct usb_function_instance *fi;
可以看到,里面有了指示usb_function_instance的指针。
所以我们完善后的图如下:
图片,可以右键在新窗口打开放大。
所以对于任何的入口函数,由于传入的指针为struct usb_function *f
,故:
- 当知道了
struct usb_function *f
,其也就是struct g_audio的指针,也是struct f_uac1的指针。 - 同样当我们需要获取
struct f_uac1_opts
指针时,只需要先通过usb_function的成员fi获取struct usb_function_instance的指针,而该指针其实也是struct f_uac1_opts的提针。
所以上面从struct usb_function指针指化为struct f_uac1_opts指针时,代码就很简单:audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
而至于它们之间的关联,是通过usb_get_function函数实现的。
struct usb_function *usb_get_function(struct usb_function_instance *fi)
{
struct usb_function *f;
f = fi->fd->alloc_func(fi);
if (IS_ERR(f))
return f;
f->fi = fi;
return f;
}
EXPORT_SYMBOL_GPL(usb_get_function);
这里先调用alloc_func指针,也就是我们在驱动入口指针的函数指针f_audio_alloc,该返回返回usb_function的指针,这时将其成员fi与usb_function_instance关联。
题外话,LINUX复杂的数据结构指针会让人头晕,不过我们在看代码时,需要梳理出它们之间的数据结构关系,再结合各函数调用流程来理解LINUX驱动源代码。这也帮助我们理解LINUX内核数据结构的组保方式,同时也能提高我们自己代码数据的设计能力。