Files
luban-lite-t3e-pro/doc/topics/sdk/usb/usb-host-core.html
2025-01-23 16:37:00 +08:00

348 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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="Layer 由前几节可知 USB 将 Device 进一步细分成了 3 个层级: Configuration 配置、 Interface 接口、 Endpoint 端点。 USB Core 为其中两个层次提供了 Device + Driver 的设备驱动模型,这两个层次分别是 USB Device Layer 和 USB Interface Layer 层,一个 USB Device ..."/><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-02-04"/><meta name="DC.format" content="HTML5"/><meta name="DC.identifier" content="usb_host_core"/><meta name="DC.language" content="zh-CN"/><title>USB Core</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-host-core.dita"/><meta name="wh-out-relpath" content="topics/sdk/usb/usb-host-core.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_host_core" 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-host-core.dita">Edit online</a></span><h1 class="- topic/title title topictitle1" id="ariaid-title1">USB Core</h1><div class="date inPage">4 Feb 2024</div><div style="color: gray;">
Read time: 5 minute(s)
</div><div class="- topic/body concept/conbody body conbody"><section class="- topic/section section" id="usb_host_core__section_fvy_tnz_21c" data-ofbid="usb_host_core__section_fvy_tnz_21c"><h2 class="- topic/title title sectiontitle">Layer</h2>
<div class="- topic/p p" data-ofbid="d280064e27__20250121171751"><br/><div class="imagecenter"><img class="- topic/image image imagecenter" id="usb_host_core__image_gvy_tnz_21c" src="../../../images/usb/usb_host_drv_dev.png" alt="image1"/></div><br/></div>
<p class="- topic/p p" data-ofbid="d280064e32__20250121171751">由前几节可知 USB 将 <code class="+ topic/ph pr-d/codeph ph codeph">Device</code> 进一步细分成了 3 个层级: <code class="+ topic/ph pr-d/codeph ph codeph">Configuration</code> 配置、
<code class="+ topic/ph pr-d/codeph ph codeph">Interface</code> 接口、 <code class="+ topic/ph pr-d/codeph ph codeph">Endpoint</code> 端点。</p>
<p class="- topic/p p" data-ofbid="d280064e47__20250121171751">USB Core 为其中两个层次提供了 <code class="+ topic/ph pr-d/codeph ph codeph">Device + Driver</code> 的设备驱动模型,这两个层次分别是 <code class="+ topic/ph pr-d/codeph ph codeph">USB
Device Layer</code><code class="+ topic/ph pr-d/codeph ph codeph">USB Interface Layer</code> 层,一个 <code class="+ topic/ph pr-d/codeph ph codeph">USB
Device</code> 包含一个或多个 <code class="+ topic/ph pr-d/codeph ph codeph">USB Interface</code>。其中:</p>
<ul class="- topic/ul ul" id="usb_host_core__ul_hvy_tnz_21c" data-ofbid="usb_host_core__ul_hvy_tnz_21c"><li class="- topic/li li" data-ofbid="d280064e66__20250121171751">
<p class="- topic/p p" data-ofbid="d280064e68__20250121171751"><code class="+ topic/ph pr-d/codeph ph codeph">USB Device Layer</code> 层。这一层的 <code class="+ topic/ph pr-d/codeph ph codeph">Device</code>
<code class="+ topic/ph pr-d/codeph ph codeph">Hub</code> 创建, <code class="+ topic/ph pr-d/codeph ph codeph">Hub</code> 本身也是一种 <code class="+ topic/ph pr-d/codeph ph codeph">USB
Device</code> 。这一层的 <code class="+ topic/ph pr-d/codeph ph codeph">Driver</code> 完成的功能非常简单,基本就是帮
<code class="+ topic/ph pr-d/codeph ph codeph">USB Device</code> 创建其包含的所有子 <code class="+ topic/ph pr-d/codeph ph codeph">USB Interface</code>
<code class="+ topic/ph pr-d/codeph ph codeph">Device</code> ,大部分场景下都是使用
<code class="+ topic/ph pr-d/codeph ph codeph">usb_generic_driver</code></p>
</li><li class="- topic/li li" data-ofbid="d280064e101__20250121171751">
<p class="- topic/p p" data-ofbid="d280064e103__20250121171751"><code class="+ topic/ph pr-d/codeph ph codeph">USB Interface Layer</code> 层。这一层的 <code class="+ topic/ph pr-d/codeph ph codeph">Device</code> 由上一级
<code class="+ topic/ph pr-d/codeph ph codeph">USB Device</code> 在驱动 probe() 时创建。而这一层的
<code class="+ topic/ph pr-d/codeph ph codeph">Driver</code> 就是普通的业务 Usb 驱动,即 Usb 协议中所说的 <code class="+ topic/ph pr-d/codeph ph codeph">Client
Software</code></p>
</li></ul>
</section><section class="- topic/section section" id="usb_host_core__section_ivy_tnz_21c" data-ofbid="usb_host_core__section_ivy_tnz_21c"><h2 class="- topic/title title sectiontitle">URB (USB Request Block)</h2>
<div class="- topic/p p" data-ofbid="d280064e126__20250121171751"><br/><div class="imagecenter"><img class="- topic/image image imagecenter" id="usb_host_core__image_jvy_tnz_21c" src="../../../images/usb/usb_host_urb.png" alt="image2"/></div><br/></div>
<p class="- topic/p p" data-ofbid="d280064e131__20250121171751">USB Core 除了提供上一节描述的设备驱动模型以外,另一个重要的作用就是要给 <code class="+ topic/ph pr-d/codeph ph codeph">USB Interface</code> Driver 提供读写
USB 数据的 API这一任务是围绕着 <code class="+ topic/ph pr-d/codeph ph codeph">USB Request Block</code> 来完成的。</p>
<p class="- topic/p p" data-ofbid="d280064e140__20250121171751"><code class="+ topic/ph pr-d/codeph ph codeph">USB Interface</code> Driver 适配成功以后,会从配置信息中获取到当前 Interface 包含了多少个
<code class="+ topic/ph pr-d/codeph ph codeph">Endpoint</code> ,以及每个 <code class="+ topic/ph pr-d/codeph ph codeph">Endpoint</code> 的地址、传输类型、最大包长等其他信息。
<code class="+ topic/ph pr-d/codeph ph codeph">Endpoint</code> 是 USB 总线传输中最小的 <code class="+ topic/ph pr-d/codeph ph codeph">寻址单位</code> Interface Driver
利用对几个 <code class="+ topic/ph pr-d/codeph ph codeph">Endpoint</code> 的读写来驱动具体的设备功能。</p>
<p class="- topic/p p" data-ofbid="d280064e160__20250121171751">对某个 <code class="+ topic/ph pr-d/codeph ph codeph">Endpoint</code> 发起一次读写操作,具体工作使用 <code class="+ topic/ph pr-d/codeph ph codeph">struct urb</code>
数据结构来承担。</p>
<p class="- topic/p p" data-ofbid="d280064e170__20250121171751">以下是一个对 <code class="+ topic/ph pr-d/codeph ph codeph">Endpoint 0</code> 使用 urb 发起读写的一个简单实例:</p>
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_host_core__pre_kvy_tnz_21c" data-ofbid="usb_host_core__pre_kvy_tnz_21c"><strong class="hl-keyword">static</strong> <strong class="hl-keyword">int</strong> usb_internal_control_msg(<strong class="hl-keyword">struct</strong> usb_device *usb_dev,
<strong class="hl-keyword">unsigned</strong> <strong class="hl-keyword">int</strong> pipe,
<strong class="hl-keyword">struct</strong> usb_ctrlrequest *cmd,
<strong class="hl-keyword">void</strong> *data, <strong class="hl-keyword">int</strong> len, <strong class="hl-keyword">int</strong> timeout)
{
<strong class="hl-keyword">struct</strong> urb *urb;
<strong class="hl-keyword">int</strong> retv;
<strong class="hl-keyword">int</strong> length;
<em class="hl-comment">/* (1) 分配一个 urb 内存空间 */</em>
urb = usb_alloc_urb(<span class="hl-number">0</span>, GFP_NOIO);
<strong class="hl-keyword">if</strong> (!urb)
<strong class="hl-keyword">return</strong> -ENOMEM;
<em class="hl-comment">/* (2) 填充 urb 内容,最核心的有 3 方面:
1、总线地址Device Num + Endpoint Num
2、数据data + len
3、回调函数usb_api_blocking_completion
*/</em>
usb_fill_control_urb(urb, usb_dev, pipe, (<strong class="hl-keyword">unsigned</strong> <strong class="hl-keyword">char</strong> *)cmd, data,
len, usb_api_blocking_completion, NULL);
<em class="hl-comment">/* (3) 发送 urb 请求,并且等待请求完成 */</em>
retv = usb_start_wait_urb(urb, timeout, &amp;length);
<strong class="hl-keyword">if</strong> (retv &lt; <span class="hl-number">0</span>)
<strong class="hl-keyword">return</strong> retv;
<strong class="hl-keyword">else</strong>
<strong class="hl-keyword">return</strong> length;
}
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">int</strong> usb_start_wait_urb(<strong class="hl-keyword">struct</strong> urb *urb, <strong class="hl-keyword">int</strong> timeout, <strong class="hl-keyword">int</strong> *actual_length)
{
<strong class="hl-keyword">struct</strong> api_context ctx;
<strong class="hl-keyword">unsigned</strong> <strong class="hl-keyword">long</strong> expire;
<strong class="hl-keyword">int</strong> retval;
init_completion(&amp;ctx.done);
urb-&gt;context = &amp;ctx;
urb-&gt;actual_length = <span class="hl-number">0</span>;
<em class="hl-comment">/* (3.1) 把 urb 请求挂载到 hcd 的队列当中 */</em>
retval = usb_submit_urb(urb, GFP_NOIO);
<strong class="hl-keyword">if</strong> (unlikely(retval))
<strong class="hl-keyword">goto</strong> out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
<em class="hl-comment">/* (3.2) 当 urb 执行完成后,首先会调用 urb 的回调函数,然后会发送 completion 信号解除这里的阻塞 */</em>
<strong class="hl-keyword">if</strong> (!wait_for_completion_timeout(&amp;ctx.done, expire)) {
usb_kill_urb(urb);
retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
dev_dbg(&amp;urb-&gt;dev-&gt;dev,
<span class="hl-string">"%s timed out on ep%d%s len=%u/%u\n"</span>,
current-&gt;comm,
usb_endpoint_num(&amp;urb-&gt;ep-&gt;desc),
usb_urb_dir_in(urb) ? <span class="hl-string">"in"</span> : <span class="hl-string">"out"</span>,
urb-&gt;actual_length,
urb-&gt;transfer_buffer_length);
} <strong class="hl-keyword">else</strong>
retval = ctx.status;
out:
<strong class="hl-keyword">if</strong> (actual_length)
*actual_length = urb-&gt;actual_length;
usb_free_urb(urb);
<strong class="hl-keyword">return</strong> retval;
}
</pre>
</section><section class="- topic/section section" id="usb_host_core__section_lvy_tnz_21c" data-ofbid="usb_host_core__section_lvy_tnz_21c"><h2 class="- topic/title title sectiontitle">Normal Device urb_enqueue</h2>
<p class="- topic/p p" data-ofbid="d280064e184__20250121171751">对普通的 Usb device 来说urb 最后会提交到 Host Controller 的收发队列上面,由 HC 完成实际的 USB 传输:</p>
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_host_core__pre_mvy_tnz_21c" data-ofbid="usb_host_core__pre_mvy_tnz_21c">usb_submit_urb() → usb_hcd_submit_urb():
<strong class="hl-keyword">int</strong> usb_hcd_submit_urb (<strong class="hl-keyword">struct</strong> urb *urb, gfp_t mem_flags)
{
<em class="hl-comment">/* (1) 如果是 roothub 走特殊的路径 */</em>
<strong class="hl-keyword">if</strong> (is_root_hub(urb-&gt;dev)) {
status = rh_urb_enqueue(hcd, urb);
<em class="hl-comment">/* (2) 如果是普通 device 调用对应的 hcd 的 urb_enqueue() 函数 */</em>
} <strong class="hl-keyword">else</strong> {
status = map_urb_for_dma(hcd, urb, mem_flags);
<strong class="hl-keyword">if</strong> (likely(status == <span class="hl-number">0</span>)) {
status = hcd-&gt;driver-&gt;urb_enqueue(hcd, urb, mem_flags);
<strong class="hl-keyword">if</strong> (unlikely(status))
unmap_urb_for_dma(hcd, urb);
}
}
}
</pre>
</section><section class="- topic/section section" id="usb_host_core__section_nvy_tnz_21c" data-ofbid="usb_host_core__section_nvy_tnz_21c"><h2 class="- topic/title title sectiontitle">7.12.5.1.2.2. Roothub Device urb_enqueue</h2>
<p class="- topic/p p" data-ofbid="d280064e195__20250121171751">特别需要注意的是 roothub 它是一个虚拟的 usb device实际上它并不在 usb 总线上而是在 host 内部,所以相应的 urb 需要特殊处理,而不能使用
hcd 把数据发送到 Usb 总线上去。</p>
<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="usb_host_core__pre_ovy_tnz_21c" data-ofbid="usb_host_core__pre_ovy_tnz_21c">usb_submit_urb() → usb_hcd_submit_urb() → rh_urb_enqueue():
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">int</strong> rh_urb_enqueue (<strong class="hl-keyword">struct</strong> usb_hcd *hcd, <strong class="hl-keyword">struct</strong> urb *urb)
{
<em class="hl-comment">/* (1) 对于 int 类型的数据,被挂载到 hcd-&gt;status_urb 指针上面
通常 roothub 驱动用这个 urb 来查询 roothub 的端口状态
*/</em>
<strong class="hl-keyword">if</strong> (usb_endpoint_xfer_int(&amp;urb-&gt;ep-&gt;desc))
<strong class="hl-keyword">return</strong> rh_queue_status (hcd, urb);
<em class="hl-comment">/* (2) 对于 control 类型的数据,是想读取 roothub ep0 上的配置信息
使用软件来模拟这类操作的响应
*/</em>
<strong class="hl-keyword">if</strong> (usb_endpoint_xfer_control(&amp;urb-&gt;ep-&gt;desc))
<strong class="hl-keyword">return</strong> rh_call_control (hcd, urb);
<strong class="hl-keyword">return</strong> -EINVAL;
}
|→
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">int</strong> rh_queue_status (<strong class="hl-keyword">struct</strong> usb_hcd *hcd, <strong class="hl-keyword">struct</strong> urb *urb)
{
<em class="hl-comment">/* (1.1) 将 urb 挂载到对应的 ep 链表中 */</em>
retval = usb_hcd_link_urb_to_ep(hcd, urb);
<strong class="hl-keyword">if</strong> (retval)
<strong class="hl-keyword">goto</strong> done;
<em class="hl-comment">/* (1.2) 将 urb 赋值给 hcd-&gt;status_urb
在 hcd 驱动中,会通过这些接口来通知 roothub 的端口状态变化
*/</em>
hcd-&gt;status_urb = urb;
urb-&gt;hcpriv = hcd; <em class="hl-comment">/* indicate it's queued */</em>
<strong class="hl-keyword">if</strong> (!hcd-&gt;uses_new_polling)
mod_timer(&amp;hcd-&gt;rh_timer, (jiffies/(HZ/<span class="hl-number">4</span>) + <span class="hl-number">1</span>) * (HZ/<span class="hl-number">4</span>));
}
|→
<strong class="hl-keyword">static</strong> <strong class="hl-keyword">int</strong> rh_call_control (<strong class="hl-keyword">struct</strong> usb_hcd *hcd, <strong class="hl-keyword">struct</strong> urb *urb)
{
<em class="hl-comment">/* (2.1) 软件模拟对 roothub 配置读写的响应 */</em>
}</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_host_core__section_fvy_tnz_21c" data-tocid="usb_host_core__section_fvy_tnz_21c">Layer</a></div></li><li class="section-item"><div class="section-title"><a href="#usb_host_core__section_ivy_tnz_21c" data-tocid="usb_host_core__section_ivy_tnz_21c">URB (USB Request Block)</a></div></li><li class="section-item"><div class="section-title"><a href="#usb_host_core__section_lvy_tnz_21c" data-tocid="usb_host_core__section_lvy_tnz_21c">Normal Device urb_enqueue</a></div></li><li class="section-item"><div class="section-title"><a href="#usb_host_core__section_nvy_tnz_21c" data-tocid="usb_host_core__section_nvy_tnz_21c">7.12.5.1.2.2. Roothub Device urb_enqueue</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>