function目錄匯集了很多功能層的功能接口(interface)的具體實現,

我們這里分析UAC2.
一.
UAC2 function驅動分析
代碼位置 drivers\usb\gadget\function\f
_uac2.c
里面實現usb設置中的接口和端點相關功能。
這里的DECLARE_USB_FUNCTION_INIT就是入口函數。
DECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc);
不過看起來好像有點不一樣啊,我們來帶入宏定義,后面就得到了熟悉的表達試。usb_function_register主要是把usb_function_driver放入func_list鏈表。
/* 這里是DECLARE_USB_FUNCTION的定義
#define DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc) \
static struct usb_function_driver _name ## usb_func = { \
.name = __stringify(_name), \
.mod = THIS_MODULE, \
.alloc_inst = _inst_alloc, \
.alloc_func = _func_alloc, \
}; \
MODULE_ALIAS("usbfunc:"__stringify(_name));
這里是DECLARE_USB_FUNCTION_INIT的定義
#define DECLARE_USB_FUNCTION_INIT(_name, _inst_alloc, _func_alloc) \
DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc) \
static int __init _name ## mod_init(void) \
{ \
return usb_function_register(&_name ## usb_func); \
} \
static void __exit _name ## mod_exit(void) \
{ \
usb_function_unregister(&_name ## usb_func); \
} \
module_init(_name ## mod_init); \
module_exit(_name ## mod_exit)
*/
//我們把宏定義化簡之后,注冊什么的都有了
static struct usb_function_driver uac2usb_func = { //這里定義的是一個usb_function_driver驅動
.name = __stringify(uac2),
.mod = THIS_MODULE,
.alloc_inst = afunc_alloc_inst,
.alloc_func = afunc_alloc,
};
MODULE_ALIAS("usbfunc:"__stringify(uac2));
static int __init uac2mod_init(void)
{
return usb_function_register(&uac2usb_func); //這里主要是把這個uac2usb_func這個usb_function_driver放入func_list鏈表
}
static void __exit uac2mod_exit(void)
{
usb_function_unregister(&uac2usb_func);
}
module_init(uac2mod_init);
module_exit(uac2mod_init)
我們再來看看afunc_alloc_inst里面主要是分配一個usb_function_instance實例結構體,並賦值一些默認參數
static struct usb_function_instance *afunc_alloc_inst(void)
{
struct f_uac2_opts *opts;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = afunc_free_inst;
config_group_init_type_name(&opts->func_inst.group, "",
&f_uac2_func_type); //這里是用來給用戶空間操作的節點,比如p_srate,播放的采樣率
opts->p_chmask = UAC2_DEF_PCHMASK;
opts->p_srate = UAC2_DEF_PSRATE;
opts->p_ssize = UAC2_DEF_PSSIZE;
opts->c_chmask = UAC2_DEF_CCHMASK;
opts->c_srate = UAC2_DEF_CSRATE;
opts->c_ssize = UAC2_DEF_CSSIZE;
opts->req_number = UAC2_DEF_REQ_NUM;
return &opts->func_inst;
}
我們再來看看afunc_alloc,主要是設置一些操作函數,初始化接口端點描述符,最后初始化一個虛擬ALSA聲卡
static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
{
struct f_uac2 *uac2;
struct f_uac2_opts *opts;
uac2 = kzalloc(sizeof(*uac2), GFP_KERNEL);
if (uac2 == NULL)
return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_uac2_opts, func_inst);
mutex_lock(&opts->lock);
++opts->refcnt;
mutex_unlock(&opts->lock);
uac2->g_audio.func.name = "uac2_func"; //這里是function的名字
uac2->g_audio.func.bind = afunc_bind; //用來綁定設備和function
uac2->g_audio.func.unbind = afunc_unbind;
uac2->g_audio.func.set_alt = afunc_set_alt;
uac2->g_audio.func.get_alt = afunc_get_alt;
uac2->g_audio.func.disable = afunc_disable;
uac2->g_audio.func.setup = afunc_setup;
uac2->g_audio.func.free_func = afunc_free;
return &uac2->g_audio.func;
}
我再看看afunc_bind
static struct usb_string strings_fn[] = { //字符串
[STR_ASSOC].s = "Source/Sink",
[STR_IF_CTRL].s = "Topology Control",
[STR_CLKSRC_IN].s = clksrc_in,
[STR_CLKSRC_OUT].s = clksrc_out,
[STR_USB_IT].s = "USBH Out",
[STR_IO_IT].s = "USBD Out",
[STR_USB_OT].s = "USBH In",
[STR_IO_OT].s = "USBD In",
[STR_AS_OUT_ALT0].s = "Playback Inactive",
[STR_AS_OUT_ALT1].s = "Playback Active",
[STR_AS_IN_ALT0].s = "Capture Inactive",
[STR_AS_IN_ALT1].s = "Capture Active",
{ },
};
static int
afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
{
us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); //獲取字符串描述符
if (IS_ERR(us))
return PTR_ERR(us);
//處理化function,ClockSource, Terminal,Interface,這里是從字符串里面獲得的值賦值
iad_desc.iFunction = us[STR_ASSOC].id;
std_ac_if_desc.iInterface = us[STR_IF_CTRL].id;
in_clk_src_desc.iClockSource = us[STR_CLKSRC_IN].id;
out_clk_src_desc.iClockSource = us[STR_CLKSRC_OUT].id;
usb_out_it_desc.iTerminal = us[STR_USB_IT].id;
io_in_it_desc.iTerminal = us[STR_IO_IT].id;
usb_in_ot_desc.iTerminal = us[STR_USB_OT].id;
io_out_ot_desc.iTerminal = us[STR_IO_OT].id;
std_as_out_if0_desc.iInterface = us[STR_AS_OUT_ALT0].id;
std_as_out_if1_desc.iInterface = us[STR_AS_OUT_ALT1].id;
std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id;
std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id;
/* Initialize the configurable parameters 初始化可配置參數*/
usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask);
usb_out_it_desc.bmChannelConfig = cpu_to_le32(uac2_opts->c_chmask);
io_in_it_desc.bNrChannels = num_channels(uac2_opts->p_chmask);
io_in_it_desc.bmChannelConfig = cpu_to_le32(uac2_opts->p_chmask);
as_out_hdr_desc.bNrChannels = num_channels(uac2_opts->c_chmask);
as_out_hdr_desc.bmChannelConfig = cpu_to_le32(uac2_opts->c_chmask);
as_in_hdr_desc.bNrChannels = num_channels(uac2_opts->p_chmask);
as_in_hdr_desc.bmChannelConfig = cpu_to_le32(uac2_opts->p_chmask);
as_out_fmt1_desc.bSubslotSize = uac2_opts->c_ssize;
as_out_fmt1_desc.bBitResolution = uac2_opts->c_ssize * 8;
as_in_fmt1_desc.bSubslotSize = uac2_opts->p_ssize;
as_in_fmt1_desc.bBitResolution = uac2_opts->p_ssize * 8;
snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate);
snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate);
ret = usb_interface_id(cfg, fn); //給這個function分配未使用的接口ID
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
iad_desc.bFirstInterface = ret; //控制接口
std_ac_if_desc.bInterfaceNumber = ret;
uac2->ac_intf = ret;
uac2->ac_alt = 0;
if (EPOUT_EN(uac2_opts)) {
ret = usb_interface_id(cfg, fn);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
std_as_out_if0_desc.bInterfaceNumber = ret; //音頻流輸出接口
std_as_out_if1_desc.bInterfaceNumber = ret;
uac2->as_out_intf = ret;
uac2->as_out_alt = 0;
}
if (EPIN_EN(uac2_opts)) {
ret = usb_interface_id(cfg, fn);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
std_as_in_if0_desc.bInterfaceNumber = ret; //音頻流輸入接口
std_as_in_if1_desc.bInterfaceNumber = ret;
uac2->as_in_intf = ret;
uac2->as_in_alt = 0;
}
/* Calculate wMaxPacketSize according to audio bandwidth 根據音頻的帶寬,計算最大包的大小*/
set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
if (EPOUT_EN(uac2_opts)) { //輸出端點
agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); //選擇與描述符匹配的端點
if (!agdev->out_ep) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return -ENODEV;
}
}
if (EPIN_EN(uac2_opts)) { //輸入端口
agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
if (!agdev->in_ep) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return -ENODEV;
}
}
agdev->in_ep_maxpsize = max_t(u16,
le16_to_cpu(fs_epin_desc.wMaxPacketSize),
le16_to_cpu(hs_epin_desc.wMaxPacketSize)); //最大包大小
agdev->out_ep_maxpsize = max_t(u16,
le16_to_cpu(fs_epout_desc.wMaxPacketSize),
le16_to_cpu(hs_epout_desc.wMaxPacketSize));
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; //高速輸出端點
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;//高速輸入端點
setup_descriptor(uac2_opts); //設置一些描述符
ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL,
NULL); //給全速和高速端點分配描述符
if (ret)
return ret;
agdev->gadget = gadget;
agdev->params.p_chmask = uac2_opts->p_chmask; //賦值一些參數
agdev->params.p_srate = uac2_opts->p_srate;
agdev->params.p_ssize = uac2_opts->p_ssize;
agdev->params.c_chmask = uac2_opts->c_chmask;
agdev->params.c_srate = uac2_opts->c_srate;
agdev->params.c_ssize = uac2_opts->c_ssize;
agdev->params.req_number = uac2_opts->req_number;
ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget"); //初始化一個虛擬ALSA聲卡
if (ret)
goto err_free_descs;
return 0;
}
我們再來分析g_audio_setup里面是如何初始化一個虛擬ALSA聲卡的,這樣應用層就可以讀寫了。
static const struct snd_pcm_ops uac_pcm_ops = { //uac的操作函數。
.open = uac_pcm_open,
.close = uac_pcm_null,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = uac_pcm_hw_params,
.hw_free = uac_pcm_hw_free,
.trigger = uac_pcm_trigger,
.pointer = uac_pcm_pointer,
.prepare = uac_pcm_null,
};
int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
const char *card_name)
{
/* Choose any slot, with no id */
err = snd_card_new(&g_audio->gadget->dev,
-1, NULL, THIS_MODULE, 0, &card); //創建並初始化一個聲卡結構
if (err < 0)
goto fail;
uac->card = card;
/*
* Create first PCM device
* Create a substream only for non-zero channel streams
*/
err = snd_pcm_new(uac->card, pcm_name, 0,
p_chmask ? 1 : 0, c_chmask ? 1 : 0, &pcm); //創建一個新的PCM實例
if (err < 0)
goto snd_fail;
strlcpy(pcm->name, pcm_name, sizeof(pcm->name));
pcm->private_data = uac;
uac->pcm = pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops); //設置PCM操作符
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops);
strlcpy(card->driver, card_name, sizeof(card->driver));
strlcpy(card->shortname, card_name, sizeof(card->shortname));
sprintf(card->longname, "%s %i", card_name, card->dev->id);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); //對於指定的DMA類型,對給定pcm的所有子流進行預先分配。
err = snd_card_register(card); //注冊聲卡,這樣應用層就可以讀寫了。
if (!err)
return 0;
}