mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-14 10:28:54 +00:00
573 lines
36 KiB
HTML
573 lines
36 KiB
HTML
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-cn" lang="zh-cn" data-whc_version="26.0">
|
||
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="description" content="Gadget Device 支撑了核心 Gadget Api 的实现,而 Function Layer 又需要使用这些 Api。怎么样将两者适配起来?Gadget Driver 就是用来完成这项工作的。 目前存在两种风格的 Gadget Driver,其中包括: Legacy。这是早期风格的 Gadget Driver,只能通过静态编译的方式指定使用哪些 Function。 ..."/><meta name="DC.rights.owner" content="(C) 版权 2025"/><meta name="copyright" content="(C) 版权 2025"/><meta name="generator" content="DITA-OT"/><meta name="DC.type" content="concept"/><meta name="DC.contributor" content="yan.wang"/><meta name="DC.date.modified" content="2024-01-31"/><meta name="DC.format" content="HTML5"/><meta name="DC.identifier" content="usb_gadget_driver_configfs"/><meta name="DC.language" content="zh-CN"/><title>Gadget Driver (Configfs)</title><!-- Build number 2023110923. --><meta name="wh-path2root" content="../../../"/><meta name="wh-toc-id" content=""/><meta name="wh-source-relpath" content="topics/sdk/usb/usb-gadget_driver_configfs.dita"/><meta name="wh-out-relpath" content="topics/sdk/usb/usb-gadget_driver_configfs.html"/>
|
||
|
||
<link rel="stylesheet" type="text/css" href="../../../webhelp/app/commons.css?buildId=2023110923"/>
|
||
<link rel="stylesheet" type="text/css" href="../../../webhelp/app/topic.css?buildId=2023110923"/>
|
||
|
||
<script src="../../../webhelp/app/options/properties.js?buildId=20250121171154"></script>
|
||
<script src="../../../webhelp/app/localization/strings.js?buildId=2023110923"></script>
|
||
<script src="../../../webhelp/app/search/index/keywords.js?buildId=20250121171154"></script>
|
||
<script defer="defer" src="../../../webhelp/app/commons.js?buildId=2023110923"></script>
|
||
<script defer="defer" src="../../../webhelp/app/topic.js?buildId=2023110923"></script>
|
||
<link rel="stylesheet" type="text/css" href="../../../webhelp/template/aic-styles-web.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/notes.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/aic-common.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/aic-images.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/footnote.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/aic-web-watermark.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/topic-body-list.css?buildId=2023110923"/></head>
|
||
|
||
<body id="usb_gadget_driver_configfs" class="wh_topic_page frmBody">
|
||
<a href="#wh_topic_body" class="sr-only sr-only-focusable">
|
||
跳转到主要内容
|
||
</a>
|
||
|
||
|
||
|
||
|
||
<header class="navbar navbar-default wh_header">
|
||
<div class="container-fluid">
|
||
<div class="wh_header_flex_container navbar-nav navbar-expand-md navbar-dark">
|
||
<div class="wh_logo_and_publication_title_container">
|
||
<div class="wh_logo_and_publication_title">
|
||
|
||
<a href="http://www.artinchip.com" class=" wh_logo d-none d-sm-block "><img src="../../../company-logo-white.png" alt="RTOS SDK 使用指南SDK 指南文件"/></a>
|
||
<div class=" wh_publication_title "><a href="../../../index.html"><span class="booktitle"><span class="ph mainbooktitle">RTOS SDK 使用指南</span><span class="ph booktitlealt">SDK 指南文件</span></span></a></div>
|
||
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
<div class="wh_top_menu_and_indexterms_link collapse navbar-collapse" id="wh_top_menu_and_indexterms_link">
|
||
|
||
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
|
||
|
||
|
||
<div class=" wh_search_input navbar-form wh_topic_page_search search " role="form">
|
||
|
||
|
||
|
||
<form id="searchForm" method="get" role="search" action="../../../search.html"><div><input type="search" placeholder="搜索 " class="wh_search_textfield" id="textToSearch" name="searchQuery" aria-label="搜索查询" required="required"/><button type="submit" class="wh_search_button" aria-label="搜索"><span class="search_input_text">搜索</span></button></div></form>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
<div class="container-fluid" id="wh_topic_container">
|
||
<div class="row">
|
||
|
||
<nav class="wh_tools d-print-none navbar-expand-md" aria-label="Tools">
|
||
|
||
<div data-tooltip-position="bottom" class=" wh_breadcrumb "></div>
|
||
|
||
|
||
|
||
<div class="wh_right_tools">
|
||
<button class="wh_hide_highlight" aria-label="切换搜索突出显示" title="切换搜索突出显示"></button>
|
||
<button class="webhelp_expand_collapse_sections" data-next-state="collapsed" aria-label="折叠截面" title="折叠截面"></button>
|
||
|
||
|
||
|
||
|
||
<div class=" wh_print_link print d-none d-md-inline-block "><button onClick="window.print()" title="打印此页" aria-label="打印此页"></button></div>
|
||
|
||
|
||
</div>
|
||
|
||
</nav>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<div class="wh_content_area">
|
||
<div class="row">
|
||
|
||
|
||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12" id="wh_topic_body">
|
||
|
||
<button id="wh_close_topic_toc_button" class="close-toc-button d-none" aria-label="Toggle topic table of content" aria-controls="wh_topic_toc" aria-expanded="true">
|
||
<span class="close-toc-icon-container">
|
||
<span class="close-toc-icon"></span>
|
||
</span>
|
||
</button>
|
||
|
||
<div class=" wh_topic_content body "><main role="main"><article class="- topic/topic concept/concept topic concept" role="article" aria-labelledby="ariaid-title1"><span class="edit-link" style="font-size:12px; opacity:0.6; text-align:right; vertical-align:middle"><a target="_blank" href="http://172.16.35.88/tasks/jdssno1uvvbf2mltu9kb9v3if05d5gopuakboe8hlud18rma/edit/F:/aicdita/aicdita-cn/topics/sdk/usb/usb-gadget_driver_configfs.dita">Edit online</a></span><h1 class="- topic/title title topictitle1" id="ariaid-title1">Gadget Driver (Configfs)</h1><div class="date inPage">31 Jan 2024</div><div style="color: gray;">
|
||
Read time: 10 minute(s)
|
||
</div><div class="- topic/body concept/conbody body conbody"><p class="- topic/p p" data-ofbid="d348127e22__20250121172123">Gadget Device 支撑了核心 Gadget Api 的实现,而 Function Layer 又需要使用这些 Api。怎么样将两者适配起来?Gadget Driver
|
||
就是用来完成这项工作的。</p><p class="- topic/p p" data-ofbid="d348127e24__20250121172123">目前存在两种风格的 Gadget Driver,其中包括:</p><ul class="- topic/ul ul" id="usb_gadget_driver_configfs__ul_gzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__ul_gzn_drz_21c"><li class="- topic/li li" data-ofbid="d348127e27__20250121172123">
|
||
<p class="- topic/p p" data-ofbid="d348127e29__20250121172123">Legacy。这是早期风格的 Gadget Driver,只能通过静态编译的方式指定使用哪些 Function。</p>
|
||
</li><li class="- topic/li li" data-ofbid="d348127e32__20250121172123">
|
||
<p class="- topic/p p" data-ofbid="d348127e34__20250121172123">Configfs。这是目前流行的 Gadget Driver,可以通过 configfs 文件系统,不用重新编译内核,动态的配置需要使用的
|
||
Function。</p>
|
||
</li></ul><p class="- topic/p p" data-ofbid="d348127e37__20250121172123">我们首先介绍 configfs 风格的 Gadget Driver。</p><section class="- topic/section section" id="usb_gadget_driver_configfs__section_hzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__section_hzn_drz_21c"><h2 class="- topic/title title sectiontitle">Configfs 使用</h2>
|
||
|
||
<p class="- topic/p p" data-ofbid="d348127e44__20250121172123">首先从使用上体验一下 configfs 的便捷。例如创建一个 ACM Function:</p>
|
||
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__pre_izn_drz_21c" data-ofbid="usb_gadget_driver_configfs__pre_izn_drz_21c"><em class="hl-comment">// 1、挂载 configfs 文件系统。</em>
|
||
mount -t configfs none /sys/kernel/config
|
||
cd /sys/kernel/config/usb_gadget
|
||
|
||
<em class="hl-comment">// 2、创建 g1 目录,实例化一个新的 gadget 模板 (composite device)。</em>
|
||
mkdir g1
|
||
cd g1
|
||
|
||
<em class="hl-comment">// 3.1、定义 USB 产品的 VID 和 PID。</em>
|
||
echo <span class="hl-string">"0x1d6b"</span> > idVendor
|
||
echo <span class="hl-string">"0x0104"</span> > idProduct
|
||
|
||
<em class="hl-comment">// 3.2、实例化英语语言 ID。(0x409 是 ID 美国英语,不是任意的,可以在 USBIF 网站上下载文档查询。)</em>
|
||
mkdir strings/<span class="hl-number">0x409</span>
|
||
ls strings/<span class="hl-number">0x409</span>/
|
||
<em class="hl-comment">// 3.3、将开发商、产品和序列号字符串写入内核。</em>
|
||
echo <span class="hl-string">"0123456789"</span> > strings/<span class="hl-number">0x409</span>/serialnumber
|
||
echo <span class="hl-string">"AAAA Inc."</span> > strings/<span class="hl-number">0x409</span>/manufacturer
|
||
echo <span class="hl-string">"Bar Gadget"</span> > strings/<span class="hl-number">0x409</span>/product
|
||
|
||
<em class="hl-comment">// 4、创建 `Function` 功能实例,需要注意的是,一个功能如果有多个实例的话,扩展名必须用数字编号。</em>
|
||
mkdir functions/acm.GS0
|
||
|
||
<em class="hl-comment">// 5.1、创建一个 USB `Configuration` 配置实例:</em>
|
||
mkdir configs/c.<span class="hl-number">1</span>
|
||
ls configs/c.<span class="hl-number">1</span>
|
||
<em class="hl-comment">// 5.2、定义配置描述符使用的字符串</em>
|
||
mkdir configs/c.<span class="hl-number">1</span>/strings/<span class="hl-number">0x409</span>
|
||
ls configs/c.<span class="hl-number">1</span>/strings/<span class="hl-number">0x409</span>/
|
||
echo <span class="hl-string">"ACM"</span> > configs/c.<span class="hl-number">1</span>/strings/<span class="hl-number">0x409</span>/configuration
|
||
|
||
<em class="hl-comment">// 6、捆绑功能 `Function` 实例到 `Configuration` 配置 c.1</em>
|
||
ln -s functions/acm.GS0 configs/c.<span class="hl-number">1</span>
|
||
|
||
<em class="hl-comment">// 7.1、查找本机可获得的 UDC 实例 (即 gadget device)</em>
|
||
# ls /sys/class/udc/
|
||
<span class="hl-number">10200000.u</span>sb
|
||
<em class="hl-comment">// 7.2、将 gadget 驱动注册到 UDC 上,插上 USB 线到电脑上,电脑就会枚举 USB 设备。</em>
|
||
echo <span class="hl-string">"10200000.usb"</span> > UDC
|
||
</pre>
|
||
</section><section class="- topic/section section" id="usb_gadget_driver_configfs__section_jzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__section_jzn_drz_21c"><h2 class="- topic/title title sectiontitle">Configfs 层次结构</h2>
|
||
|
||
<p class="- topic/p p" data-ofbid="d348127e55__20250121172123">configfs 并不是 gadget 专用的,它是一个通用文件系统,方便用户通过文件系统创建文件夹、文件的方式来创建内核对象。</p>
|
||
<p class="- topic/p p" data-ofbid="d348127e58__20250121172123">configfs 是很好理解的, <code class="+ topic/ph pr-d/codeph ph codeph">struct config_group</code> 相当于一个文件夹, <code class="+ topic/ph pr-d/codeph ph codeph">struct
|
||
config_item_type</code> 是这个文件夹的属性集。其中
|
||
<code class="+ topic/ph pr-d/codeph ph codeph">config_item_type->ct_group_ops->make_group()/drop_item()</code>
|
||
定义了创建/销毁下一层子文件夹的方法, <code class="+ topic/ph pr-d/codeph ph codeph">config_item_type->ct_attrs</code> 定义了子文件和相关操作函数。</p>
|
||
<p class="- topic/p p" data-ofbid="d348127e73__20250121172123">我们通过解析 <code class="+ topic/ph pr-d/codeph ph codeph">drivers\usb\gadget\configfs.c</code> 文件来深入理解
|
||
<code class="+ topic/ph pr-d/codeph ph codeph">configfs</code> 的使用方法:</p>
|
||
<ul class="- topic/ul ul" id="usb_gadget_driver_configfs__ul_kzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__ul_kzn_drz_21c"><li class="- topic/li li" data-ofbid="d348127e83__20250121172123">
|
||
<div class="- topic/p p" data-ofbid="d348127e85__20250121172123">首先创建首层文件夹 <code class="+ topic/ph pr-d/codeph ph codeph">/sys/kernel/config/usb_gadget</code>
|
||
:<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__codeblock_anw_frz_21c" data-ofbid="usb_gadget_driver_configfs__codeblock_anw_frz_21c"><strong class="hl-keyword">static</strong> <strong class="hl-keyword">struct</strong> configfs_group_operations gadgets_ops = {
|
||
.make_group = &gadgets_make,
|
||
.drop_item = &gadgets_drop,
|
||
};
|
||
|
||
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">const</strong> <strong class="hl-keyword">struct</strong> config_item_type gadgets_type = {
|
||
.ct_group_ops = &gadgets_ops,
|
||
.ct_owner = THIS_MODULE,
|
||
};
|
||
|
||
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">struct</strong> configfs_subsystem gadget_subsys = {
|
||
.su_group = {
|
||
.cg_item = {
|
||
.ci_namebuf = <span class="hl-string">"usb_gadget"</span>,
|
||
.ci_type = &gadgets_type,
|
||
},
|
||
},
|
||
.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
|
||
};
|
||
|
||
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">int</strong> __init gadget_cfs_init(<strong class="hl-keyword">void</strong>)
|
||
{
|
||
<strong class="hl-keyword">int</strong> ret;
|
||
|
||
config_group_init(&gadget_subsys.su_group);
|
||
|
||
ret = configfs_register_subsystem(&gadget_subsys);
|
||
<strong class="hl-keyword">return</strong> ret;
|
||
}
|
||
module_init(gadget_cfs_init);
|
||
</pre></div>
|
||
</li><li class="- topic/li li" data-ofbid="d348127e93__20250121172123">
|
||
<div class="- topic/p p" data-ofbid="d348127e95__20250121172123">创建 <code class="+ topic/ph pr-d/codeph ph codeph">/sys/kernel/config/usb_gadget/g1</code> ,相当于创建一个全新的
|
||
<code class="+ topic/ph pr-d/codeph ph codeph">composite device</code>。会调用顶层 <code class="+ topic/ph pr-d/codeph ph codeph">struct
|
||
config_group</code> 的
|
||
<code class="+ topic/ph pr-d/codeph ph codeph">config_item_type->ct_group_ops->make_group()</code> 函数,即
|
||
<code class="+ topic/ph pr-d/codeph ph codeph">gadgets_make()</code>
|
||
:<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__pre_nzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__pre_nzn_drz_21c"><strong class="hl-keyword">static</strong> <strong class="hl-keyword">struct</strong> config_group *gadgets_make(
|
||
<strong class="hl-keyword">struct</strong> config_group *group,
|
||
<strong class="hl-keyword">const</strong> <strong class="hl-keyword">char</strong> *name)
|
||
{
|
||
<strong class="hl-keyword">struct</strong> gadget_info *gi;
|
||
|
||
gi = kzalloc(<strong class="hl-keyword">sizeof</strong>(*gi), GFP_KERNEL);
|
||
<strong class="hl-keyword">if</strong> (!gi)
|
||
<strong class="hl-keyword">return</strong> ERR_PTR(-ENOMEM);
|
||
|
||
<em class="hl-comment">/* (1) 创建顶层文件夹 `/sys/kernel/config/usb_gadget/g1` 对应的 `struct config_group` 结构
|
||
`/sys/kernel/config/usb_gadget/g1` 下对应不少子文件,在 gadget_root_type.ct_attrs 中定义,即 `gadget_root_attrs`:
|
||
static struct configfs_attribute *gadget_root_attrs[] = {
|
||
&gadget_dev_desc_attr_bDeviceClass,
|
||
&gadget_dev_desc_attr_bDeviceSubClass,
|
||
&gadget_dev_desc_attr_bDeviceProtocol,
|
||
&gadget_dev_desc_attr_bMaxPacketSize0,
|
||
&gadget_dev_desc_attr_idVendor,
|
||
&gadget_dev_desc_attr_idProduct,
|
||
&gadget_dev_desc_attr_bcdDevice,
|
||
&gadget_dev_desc_attr_bcdUSB,
|
||
&gadget_dev_desc_attr_UDC,
|
||
&gadget_dev_desc_attr_max_speed,
|
||
NULL,
|
||
};
|
||
*/</em>
|
||
config_group_init_type_name(&gi->group, name, &gadget_root_type);
|
||
|
||
<em class="hl-comment">/* (2) 创建子文件夹 `/sys/kernel/config/usb_gadget/g1/functions`
|
||
`functions_type` 中定义了进一步创建子文件夹的操作函数
|
||
*/</em>
|
||
config_group_init_type_name(&gi->functions_group, <span class="hl-string">"functions"</span>,
|
||
&functions_type);
|
||
configfs_add_default_group(&gi->functions_group, &gi->group);
|
||
|
||
<em class="hl-comment">/* (3) 创建子文件夹 `/sys/kernel/config/usb_gadget/g1/configs`
|
||
`config_desc_type` 中定义了进一步创建子文件夹的操作函数
|
||
*/</em>
|
||
config_group_init_type_name(&gi->configs_group, <span class="hl-string">"configs"</span>,
|
||
&config_desc_type);
|
||
configfs_add_default_group(&gi->configs_group, &gi->group);
|
||
|
||
<em class="hl-comment">/* (4) 创建子文件夹 `/sys/kernel/config/usb_gadget/g1/strings`
|
||
`gadget_strings_strings_type` 中定义了进一步创建子文件夹的操作函数
|
||
*/</em>
|
||
config_group_init_type_name(&gi->strings_group, <span class="hl-string">"strings"</span>,
|
||
&gadget_strings_strings_type);
|
||
configfs_add_default_group(&gi->strings_group, &gi->group);
|
||
|
||
<em class="hl-comment">/* (5) 创建子文件夹 `/sys/kernel/config/usb_gadget/g1/os_desc`
|
||
`os_desc_type` 中定义了进一步创建哪些子文件
|
||
*/</em>
|
||
config_group_init_type_name(&gi->os_desc_group, <span class="hl-string">"os_desc"</span>,
|
||
&os_desc_type);
|
||
configfs_add_default_group(&gi->os_desc_group, &gi->group);
|
||
|
||
<em class="hl-comment">/* (6) `configfs.c` 的目的很明确就是创建一个 `composite device`
|
||
由用户添加和配置这个 `device` 当中的多个 `interface` 即 `function`
|
||
*/</em>
|
||
gi->composite.bind = configfs_do_nothing;
|
||
gi->composite.unbind = configfs_do_nothing;
|
||
gi->composite.suspend = NULL;
|
||
gi->composite.resume = NULL;
|
||
gi->composite.max_speed = USB_SPEED_SUPER_PLUS;
|
||
|
||
spin_lock_init(&gi->spinlock);
|
||
mutex_init(&gi->lock);
|
||
INIT_LIST_HEAD(&gi->string_list);
|
||
INIT_LIST_HEAD(&gi->available_func);
|
||
|
||
composite_init_dev(&gi->cdev);
|
||
gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
|
||
gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
|
||
gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());
|
||
|
||
gi->composite.gadget_driver = configfs_driver_template;
|
||
|
||
gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
|
||
gi->composite.name = gi->composite.gadget_driver.function;
|
||
|
||
<strong class="hl-keyword">if</strong> (!gi->composite.gadget_driver.function)
|
||
<strong class="hl-keyword">goto</strong> err;
|
||
|
||
<strong class="hl-keyword">return</strong> &gi->group;
|
||
err:
|
||
kfree(gi);
|
||
<strong class="hl-keyword">return</strong> ERR_PTR(-ENOMEM);
|
||
}
|
||
</pre></div>
|
||
</li><li class="- topic/li li" data-ofbid="d348127e116__20250121172123">
|
||
<div class="- topic/p p" data-ofbid="d348127e118__20250121172123">创建 <code class="+ topic/ph pr-d/codeph ph codeph">/sys/kernel/config/usb_gadget/g1/functions/acm.GS0</code>。会调用
|
||
<code class="+ topic/ph pr-d/codeph ph codeph">functions_type</code> 中定义的 function_make()
|
||
函数:<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__pre_pzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__pre_pzn_drz_21c"><strong class="hl-keyword">static</strong> <strong class="hl-keyword">struct</strong> config_group *function_make(
|
||
<strong class="hl-keyword">struct</strong> config_group *group,
|
||
<strong class="hl-keyword">const</strong> <strong class="hl-keyword">char</strong> *name)
|
||
{
|
||
<strong class="hl-keyword">struct</strong> gadget_info *gi;
|
||
<strong class="hl-keyword">struct</strong> usb_function_instance *fi;
|
||
<strong class="hl-keyword">char</strong> buf[MAX_NAME_LEN];
|
||
<strong class="hl-keyword">char</strong> *func_name;
|
||
<strong class="hl-keyword">char</strong> *instance_name;
|
||
<strong class="hl-keyword">int</strong> ret;
|
||
|
||
ret = snprintf(buf, MAX_NAME_LEN, <span class="hl-string">"%s"</span>, name);
|
||
<strong class="hl-keyword">if</strong> (ret ≥ MAX_NAME_LEN)
|
||
<strong class="hl-keyword">return</strong> ERR_PTR(-ENAMETOOLONG);
|
||
|
||
<em class="hl-comment">/* (1) 把 `acm.GS0` 分割成两部分:
|
||
func_name = `acm`
|
||
instance_name = `GS0`
|
||
*/</em>
|
||
func_name = buf;
|
||
instance_name = strchr(func_name, <span class="hl-string">'.'</span>);
|
||
<strong class="hl-keyword">if</strong> (!instance_name) {
|
||
pr_err(<span class="hl-string">"Unable to locate . in FUNC.INSTANCE\n"</span>);
|
||
<strong class="hl-keyword">return</strong> ERR_PTR(-EINVAL);
|
||
}
|
||
*instance_name = <span class="hl-string">'\0'</span>;
|
||
instance_name++;
|
||
|
||
<em class="hl-comment">/* (2) 根据 func_name 在全局链表中查找对应 function
|
||
usb_get_function_instance() → try_get_usb_function_instance() → fd->alloc_inst() → acm_alloc_instance():
|
||
并调用 usb_function_driver->alloc_inst() 分配一个 function 实例
|
||
*/</em>
|
||
fi = usb_get_function_instance(func_name);
|
||
<strong class="hl-keyword">if</strong> (IS_ERR(fi))
|
||
<strong class="hl-keyword">return</strong> ERR_CAST(fi);
|
||
|
||
<em class="hl-comment">/* (3) 初始化 function 实例 */</em>
|
||
ret = config_item_set_name(&fi->group.cg_item, <span class="hl-string">"%s"</span>, name);
|
||
<strong class="hl-keyword">if</strong> (ret) {
|
||
usb_put_function_instance(fi);
|
||
<strong class="hl-keyword">return</strong> ERR_PTR(ret);
|
||
}
|
||
<strong class="hl-keyword">if</strong> (fi->set_inst_name) {
|
||
ret = fi->set_inst_name(fi, instance_name);
|
||
<strong class="hl-keyword">if</strong> (ret) {
|
||
usb_put_function_instance(fi);
|
||
<strong class="hl-keyword">return</strong> ERR_PTR(ret);
|
||
}
|
||
}
|
||
|
||
gi = container_of(group, <strong class="hl-keyword">struct</strong> gadget_info, functions_group);
|
||
|
||
mutex_lock(&gi->lock);
|
||
<em class="hl-comment">/* (4) 将 function 实例挂载到 composite device 的 function 链表当中去 */</em>
|
||
list_add_tail(&fi->cfs_list, &gi->available_func);
|
||
mutex_unlock(&gi->lock);
|
||
<strong class="hl-keyword">return</strong> &fi->group;
|
||
}
|
||
</pre></div>
|
||
<p class="- topic/p p" data-ofbid="d348127e129__20250121172123">在 <code class="+ topic/ph pr-d/codeph ph codeph">ln -s functions/acm.GS0 configs/c.1</code> 时给 function
|
||
实例安装实际的函数:</p>
|
||
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__pre_qzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__pre_qzn_drz_21c">config_usb_cfg_link() → usb_get_function() → fi->fd->alloc_func() → acm_alloc_func():
|
||
|
||
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">struct</strong> usb_function *acm_alloc_func(<strong class="hl-keyword">struct</strong> usb_function_instance *fi)
|
||
{
|
||
<strong class="hl-keyword">struct</strong> f_serial_opts *opts;
|
||
<strong class="hl-keyword">struct</strong> f_acm *acm;
|
||
|
||
<em class="hl-comment">/* (2.1) 对应分配一个 func 实例 */</em>
|
||
acm = kzalloc(<strong class="hl-keyword">sizeof</strong>(*acm), GFP_KERNEL);
|
||
<strong class="hl-keyword">if</strong> (!acm)
|
||
<strong class="hl-keyword">return</strong> ERR_PTR(-ENOMEM);
|
||
|
||
spin_lock_init(&acm->lock);
|
||
|
||
<em class="hl-comment">/* (2.2) 初始化 func 实例的成员函数 */</em>
|
||
acm->port.connect = acm_connect;
|
||
acm->port.disconnect = acm_disconnect;
|
||
acm->port.send_break = acm_send_break;
|
||
|
||
acm->port.func.name = <span class="hl-string">"acm"</span>;
|
||
acm->port.func.strings = acm_strings;
|
||
<em class="hl-comment">/* descriptors are per-instance copies */</em>
|
||
acm->port.func.bind = acm_bind;
|
||
acm->port.func.set_alt = acm_set_alt;
|
||
acm->port.func.setup = acm_setup;
|
||
acm->port.func.disable = acm_disable;
|
||
|
||
opts = container_of(fi, <strong class="hl-keyword">struct</strong> f_serial_opts, func_inst);
|
||
acm->port_num = opts->port_num;
|
||
acm->port.func.unbind = acm_unbind;
|
||
acm->port.func.free_func = acm_free_func;
|
||
acm->port.func.resume = acm_resume;
|
||
acm->port.func.suspend = acm_suspend;
|
||
|
||
<strong class="hl-keyword">return</strong> &acm->port.func;
|
||
}
|
||
</pre>
|
||
</li></ul>
|
||
</section><section class="- topic/section section" id="usb_gadget_driver_configfs__section_rzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__section_rzn_drz_21c"><h2 class="- topic/title title sectiontitle">Gadget Driver</h2>
|
||
|
||
<p class="- topic/p p" data-ofbid="d348127e144__20250121172123">Configfs 风格的 gadget driver 的定义:</p>
|
||
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__pre_szn_drz_21c" data-ofbid="usb_gadget_driver_configfs__pre_szn_drz_21c">drivers\usb\gadget\configfs.c:
|
||
|
||
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">const</strong> <strong class="hl-keyword">struct</strong> usb_gadget_driver configfs_driver_template = {
|
||
.bind = configfs_composite_bind,
|
||
.unbind = configfs_composite_unbind,
|
||
|
||
.setup = configfs_composite_setup,
|
||
.reset = configfs_composite_disconnect,
|
||
.disconnect = configfs_composite_disconnect,
|
||
|
||
.suspend = configfs_composite_suspend,
|
||
.resume = configfs_composite_resume,
|
||
|
||
.max_speed = USB_SPEED_SUPER_PLUS,
|
||
.driver = {
|
||
.owner = THIS_MODULE,
|
||
.name = <span class="hl-string">"configfs-gadget"</span>,
|
||
},
|
||
.match_existing_only = <span class="hl-number">1</span>,
|
||
};
|
||
</pre>
|
||
<p class="- topic/p p" data-ofbid="d348127e150__20250121172123">在调用 <code class="+ topic/ph pr-d/codeph ph codeph">echo "/sys/class/udc/10200000.usb" >
|
||
/sys/kernel/config/usb_gadget/g1/UDC</code> 时,将上述 <code class="+ topic/ph pr-d/codeph ph codeph">gadget
|
||
driver</code> 进行注册,和 UDC 已经注册好的 <code class="+ topic/ph pr-d/codeph ph codeph">gadget device</code> 进行动态适配。</p>
|
||
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__pre_tzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__pre_tzn_drz_21c">gadget_dev_desc_UDC_store() → usb_gadget_probe_driver(&gi->composite.gadget_driver) → udc_bind_to_driver()
|
||
</pre>
|
||
<p class="- topic/p p" data-ofbid="d348127e166__20250121172123">本质上是 使用 configfs 创建好的 <code class="+ topic/ph pr-d/codeph ph codeph">composite device</code> 和 <code class="+ topic/ph pr-d/codeph ph codeph">gadget
|
||
device</code> 进行绑定:</p>
|
||
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__pre_uzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__pre_uzn_drz_21c">gadget_dev_desc_UDC_store() → usb_gadget_probe_driver() → udc_bind_to_driver() → configfs_composite_bind() → usb_add_function() → function->bind() → acm_bind():
|
||
|
||
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">int</strong>
|
||
acm_bind(<strong class="hl-keyword">struct</strong> usb_configuration *c, <strong class="hl-keyword">struct</strong> usb_function *f)
|
||
{
|
||
<em class="hl-comment">/* (1) 这样 function 实例和 gadget device 进行了绑定 */</em>
|
||
<strong class="hl-keyword">struct</strong> usb_composite_dev *cdev = c->cdev;
|
||
<strong class="hl-keyword">struct</strong> f_acm *acm = func_to_acm(f);
|
||
|
||
<em class="hl-comment">/* allocate instance-specific endpoints */</em>
|
||
<em class="hl-comment">/* (2) function 实例可以从 gadget device 中分配得到 endpoint */</em>
|
||
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
|
||
<strong class="hl-keyword">if</strong> (!ep)
|
||
<strong class="hl-keyword">goto</strong> fail;
|
||
acm->port.in = ep;
|
||
|
||
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
|
||
<strong class="hl-keyword">if</strong> (!ep)
|
||
<strong class="hl-keyword">goto</strong> fail;
|
||
acm->port.out = ep;
|
||
|
||
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
|
||
<strong class="hl-keyword">if</strong> (!ep)
|
||
<strong class="hl-keyword">goto</strong> fail;
|
||
acm->notify = ep;
|
||
|
||
}
|
||
</pre>
|
||
<p class="- topic/p p" data-ofbid="d348127e178__20250121172123">但是 bind() 以后 function 实例只是分配了 endpoint 资源还没有被启动,因为 Device 是被动状态,只有连上 Host,被 Host
|
||
<code class="+ topic/ph pr-d/codeph ph codeph">Set Configuration</code> 操作以后。某一组 <code class="+ topic/ph pr-d/codeph ph codeph">Configuration</code>
|
||
被配置,相应的 <code class="+ topic/ph pr-d/codeph ph codeph">Function 实例</code> 才会被启用:</p>
|
||
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_gadget_driver_configfs__pre_vzn_drz_21c" data-ofbid="usb_gadget_driver_configfs__pre_vzn_drz_21c">dwc2_hsotg_complete_setup() → dwc2_hsotg_process_control() → hsotg->driver->setup() → configfs_composite_setup() → composite_setup() → set_config() → f->set_alt() → acm_set_alt():
|
||
|
||
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">int</strong> acm_set_alt(<strong class="hl-keyword">struct</strong> usb_function *f, <strong class="hl-keyword">unsigned</strong> intf, <strong class="hl-keyword">unsigned</strong> alt)
|
||
{
|
||
<strong class="hl-keyword">struct</strong> f_acm *acm = func_to_acm(f);
|
||
<strong class="hl-keyword">struct</strong> usb_composite_dev *cdev = f->config->cdev;
|
||
|
||
<em class="hl-comment">/* we know alt == 0, so this is an activation or a reset */</em>
|
||
|
||
<em class="hl-comment">/* (1) 使能 endpoint,并且提交 `struct usb_request` 请求 */</em>
|
||
<strong class="hl-keyword">if</strong> (intf == acm->ctrl_id) {
|
||
<strong class="hl-keyword">if</strong> (acm->notify->enabled) {
|
||
dev_vdbg(&cdev->gadget->dev,
|
||
<span class="hl-string">"reset acm control interface %d\n"</span>, intf);
|
||
usb_ep_disable(acm->notify);
|
||
}
|
||
|
||
<strong class="hl-keyword">if</strong> (!acm->notify->desc)
|
||
<strong class="hl-keyword">if</strong> (config_ep_by_speed(cdev->gadget, f, acm->notify))
|
||
<strong class="hl-keyword">return</strong> -EINVAL;
|
||
|
||
usb_ep_enable(acm->notify);
|
||
|
||
} <strong class="hl-keyword">else</strong> <strong class="hl-keyword">if</strong> (intf == acm->data_id) {
|
||
<strong class="hl-keyword">if</strong> (acm->notify->enabled) {
|
||
dev_dbg(&cdev->gadget->dev,
|
||
<span class="hl-string">"reset acm ttyGS%d\n"</span>, acm->port_num);
|
||
gserial_disconnect(&acm->port);
|
||
}
|
||
<strong class="hl-keyword">if</strong> (!acm->port.in->desc || !acm->port.out->desc) {
|
||
dev_dbg(&cdev->gadget->dev,
|
||
<span class="hl-string">"activate acm ttyGS%d\n"</span>, acm->port_num);
|
||
<strong class="hl-keyword">if</strong> (config_ep_by_speed(cdev->gadget, f,
|
||
acm->port.in) ||
|
||
config_ep_by_speed(cdev->gadget, f,
|
||
acm->port.out)) {
|
||
acm->port.in->desc = NULL;
|
||
acm->port.out->desc = NULL;
|
||
<strong class="hl-keyword">return</strong> -EINVAL;
|
||
}
|
||
}
|
||
gserial_connect(&acm->port, acm->port_num);
|
||
|
||
} <strong class="hl-keyword">else</strong>
|
||
<strong class="hl-keyword">return</strong> -EINVAL;
|
||
|
||
<strong class="hl-keyword">return</strong> <span class="hl-number">0</span>;
|
||
}</pre>
|
||
</section></div></article></main></div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
|
||
<nav role="navigation" id="wh_topic_toc" aria-label="On this page" class="col-lg-2 d-none d-lg-block navbar d-print-none">
|
||
<div id="wh_topic_toc_content">
|
||
|
||
<div class=" wh_topic_toc "><div class="wh_topic_label">在本页上</div><ul><li class="section-item"><div class="section-title"><a href="#usb_gadget_driver_configfs__section_hzn_drz_21c" data-tocid="usb_gadget_driver_configfs__section_hzn_drz_21c">Configfs 使用</a></div></li><li class="section-item"><div class="section-title"><a href="#usb_gadget_driver_configfs__section_jzn_drz_21c" data-tocid="usb_gadget_driver_configfs__section_jzn_drz_21c">Configfs 层次结构</a></div></li><li class="section-item"><div class="section-title"><a href="#usb_gadget_driver_configfs__section_rzn_drz_21c" data-tocid="usb_gadget_driver_configfs__section_rzn_drz_21c">Gadget Driver</a></div></li></ul></div>
|
||
|
||
</div>
|
||
</nav>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
<footer class="navbar navbar-default wh_footer">
|
||
<div class=" footer-container mx-auto ">
|
||
<title>footer def</title>
|
||
<style><!--
|
||
|
||
.p1 {
|
||
font-family: FangZhengShuSong, Times, serif;
|
||
}
|
||
.p2 {
|
||
font-family: Arial, Helvetica, sans-serif;
|
||
}
|
||
.p3 {
|
||
font-family: "Lucida Console", "Courier New", monospace;
|
||
}
|
||
|
||
--></style>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="webhelp.fragment.footer">
|
||
<p class="p1">Copyright © 2019-2024 广东匠芯创科技有限公司. All rights reserved.</p>
|
||
</div><div>
|
||
<div class="generation_time">
|
||
Update Time: 2025-01-21
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<div id="go2top" class="d-print-none">
|
||
<span class="oxy-icon oxy-icon-up"></span>
|
||
</div>
|
||
|
||
<div id="modal_img_large" class="modal">
|
||
<span class="close oxy-icon oxy-icon-remove"></span>
|
||
<div id="modal_img_container"></div>
|
||
<div id="caption"></div>
|
||
</div>
|
||
|
||
|
||
<script src="${pd}/publishing/publishing-styles-AIC-template/js/custom.js" defer="defer"></script>
|
||
|
||
|
||
</body>
|
||
</html> |