Linux USB 3.0驱动分析(九)——Gadget function驱动分析
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;
}