⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch13s03.html

📁 介绍Linux内核驱动编程的一本书 最主要的是有源代码,都是可用的 学习操作系统很好
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<p>结构 usb_iso_packet_descriptor 由下列成员组成:</p><div class="variablelist"><dl><dt><span class="term"><span>unsigned int offset</span></span></dt><dd><p>报文数据所在的传送缓冲中的偏移(第一个字节从 0 开始).</p></dd><dt><span class="term"><span>unsigned int length </span></span></dt><dd><p>这个报文的传送缓冲的长度.</p></dd><dt><span class="term"><span>unsigned int actual_length </span></span></dt><dd><p>接收到给这个同步报文的传送缓冲的数据长度.</p></dd><dt><span class="term"><span>unsigned int status </span></span></dt><dd><p>这个报文的单独同步传送的状态. 它可采用同样的返回值如同主 struct urb 结构的状态变量.</p></dd></dl></div></dd></dl></div></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="CreatingandDestroyingUrbs.sect2"></a>13.3.2.&#160;创建和销毁 urb</h3></div></div></div><p>struct urb 结构在驱动中必须不被静态创建, 或者在另一个结构中, 因为这可能破坏 USB 核心给 urb 使用的引用计数方法. 它必须使用对 usb_alloc_urb 函数的调用而被创建. 这个函数有这个原型:</p><pre class="programlisting">struct urb *usb_alloc_urb(int iso_packets, int mem_flags);</pre><p>第一个参数, iso_packet, 是这个 urb 应当包含的同步报文的数目. 如果你不想创建一个同步 urb, 这个变量应当被设置为 0. 第 2 个参数, mem_flags, 是和传递给 kmalloc 函数调用来从内核分配内存的相同的标志类型(见"flags 参数"一节, 第 8 章, 关于这些标志的细节). 如果这个函数在分配足够内存给这个 urb 成功, 一个指向 urb 的指针被返回给调用者. 如果返回值是 NULL, 某个错误在 USB 核心中发生了, 并且驱动需要正确地清理.</p><p>在创建了一个 urb 之后, 它必须被正确初始化在它可被 USB 核心使用之前. 如何初始化不同类型 urb 见下一节</p><p>为了告诉 USB 核心驱动用完这个 urb, 驱动必须调用 usb_free_urb 函数. 这个函数只有一个参数:</p><pre class="programlisting">void usb_free_urb(struct urb *urb);</pre><p>参数是一个指向你要释放的 struct urb 的指针. 在这个函数被调用之后, urb 结构消失, 驱动不能再存取它.</p><div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Interrupturbs.sect3"></a>13.3.2.1.&#160;中断 urb</h4></div></div></div><p>函数 usb_fill_int_urb 是一个帮忙函数, 来正确初始化一个urb 来发送给 USB 设备的一个中断端点:</p><pre class="programlisting">void usb_fill_int_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context, int interval);</pre><p>这个函数包含许多参数:</p><div class="variablelist"><dl><dt><span class="term"><span>struct urb *urb </span></span></dt><dd><p>指向要被初始化的 urb 的指针.</p></dd><dt><span class="term"><span>struct usb_device *dev </span></span></dt><dd><p>这个 urb 要发送到的 USB 设备.</p></dd><dt><span class="term"><span>unsigned int pipe </span></span></dt><dd><p>这个 urb 要被发送到的 USB 设备的特定端点. 这个值被创建, 使用前面提过的 usb_sndintpipe 或者 usb_rcvintpipe 函数.</p></dd><dt><span class="term"><span>void *transfer_buffer </span></span></dt><dd><p>指向缓冲的指针, 从那里外出的数据被获取或者进入数据被接受. 注意这不能是一个静态的缓冲并且必须使用 kmalloc 调用来创建.</p></dd><dt><span class="term"><span>int buffer_length</span></span></dt><dd><p>缓冲的长度, 被 transfer_buffer 指针指向. </p></dd><dt><span class="term"><span>usb_complete_t complete </span></span></dt><dd><p>指针, 指向当这个 urb 完成时被调用的完成处理者.</p></dd><dt><span class="term"><span>void *context </span></span></dt><dd><p>指向数据块的指针, 它被添加到这个 urb 结构为以后被完成处理者函数获取.</p></dd><dt><span class="term"><span>int interval </span></span></dt><dd><p>这个 urb 应当被调度的间隔. 见之前的 struct urb 结构的描述, 来找到这个值的正确单位.</p></dd></dl></div></div><div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Bulkurbs.sect3"></a>13.3.2.2.&#160;块 urb</h4></div></div></div><p>块 urb 被初始化非常象中断 urb. 做这个的函数是 usb_fill_bulk_urb, 它看来如此:</p><pre class="programlisting">void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context);</pre><p>这个函数参数和 usb_fill_int_urb 函数的都相同. 但是, 没有 interval 参数因为 bulk urb 没有间隔值. 请注意这个 unsiged int pipe 变量必须被初始化用对 usb_sndbulkpipe 或者 usb_rcvbulkpipe 函数的调用.</p><p>usb_fill_int_urb 函数不设置 urb 中的 transfer_flags 变量, 因此任何对这个成员的修改不得不由这个驱动自己完成.</p></div><div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Controlurbs.sect3"></a>13.3.2.3.&#160;控制 urb</h4></div></div></div><p>控制 urb 被初始化几乎和 块 urb 相同的方式, 使用对函数 usb_fill_control_urb 的调用:</p><pre class="programlisting">void usb_fill_control_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, unsigned char *setup_packet, void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context);</pre><p>函数参数和 usb_fill_bulk_urb 函数都相同, 除了有个新参数, unsigned char *setup_packet, 它必须指向要发送给端点的 setup 报文数据. 还有, unsigned int pipe 变量必须被初始化, 使用对 usb_sndctrlpipe 或者 usb_rcvictrlpipe 函数的调用.</p><p>usb_fill_control_urb 函数不设置 transfer_flags 变量在 urb 中, 因此任何对这个成员的修改必须游驱动自己完成. 大部分驱动不使用这个函数, 因为使用在"USB 传送不用 urb"一节中介绍的同步 API 调用更简单.</p></div><div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Isochronousurbs.sect3"></a>13.3.2.4.&#160;同步 urb</h4></div></div></div><p>不幸的是, 同步 urb 没有一个象中断, 控制, 和块 urb 的初始化函数. 因此它们必须在驱动中"手动"初始化, 在它们可被提交给 USB 核心之前. 下面是一个如何正确初始化这类 urb 的例子. 它是从 konicawc.c 内核驱动中取得的, 它位于主内核源码树的 drivers/usb/media 目录.</p><pre class="programlisting">urb-&gt;dev = dev;urb-&gt;context = uvd;urb-&gt;pipe = usb_rcvisocpipe(dev, uvd-&gt;video_endp-1);urb-&gt;interval = 1;urb-&gt;transfer_flags = URB_ISO_ASAP;urb-&gt;transfer_buffer = cam-&gt;sts_buf[i];urb-&gt;complete = konicawc_isoc_irq;urb-&gt;number_of_packets = FRAMES_PER_DESC;urb-&gt;transfer_buffer_length = FRAMES_PER_DESC;for (j=0; j &lt; FRAMES_PER_DESC; j++) { urb-&gt;iso_frame_desc[j].offset = j; urb-&gt;iso_frame_desc[j].length = 1;}</pre></div></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="SubmittingUrbs.sect2"></a>13.3.3.&#160;提交 urb</h3></div></div></div><p>一旦 urb 被正确地创建,并且被 USB 驱动初始化, 它已准备好被提交给 USB 核心来发送出到 USB 设备. 这通过调用函数 usb_submit_urb 实现:</p><pre class="programlisting">int usb_submit_urb(struct urb *urb, int mem_flags);</pre><p>urb 参数是一个指向 urb 的指针, 它要被发送到设备. mem_flags 参数等同于传递给 kmalloc 调用的同样的参数, 并且用来告诉 USB 核心如何及时分配任何内存缓冲在这个时间.</p><p>在 urb 被成功提交给 USB 核心之后, 应当从不试图存取 urb 结构的任何成员直到完成函数被调用.</p><p>因为函数 usb_submit_urb 可被在任何时候被调用(包括从一个中断上下文), mem_flags 变量的指定必须正确. 真正只有 3 个有效值可用, 根据何时 usb_submit_urb 被调用:</p><div class="variablelist"><dl><dt><span class="term"><span>GFP_ATOMIC </span></span></dt><dd><p>这个值应当被使用无论何时下面的是真:</p><div class="itemizedlist"><ul type="disc"><li><p>调用者处于一个 urb 完成处理者, 一个中断, 一个后半部, 一个 tasklet, 或者一个时钟回调.</p></li><li><p>调用者持有一个自旋锁或者读写锁. 注意如果正持有一个旗标, 这个值不必要.</p></li><li><p>current-&gt;state 不是 TASK_RUNNING. 状态一直是 TASK_RUNNING 除非驱动已自己改变 current 状态.</p></li></ul></div></dd><dt><span class="term"><span>GFP_NOIO </span></span></dt><dd><p>这个值应当被使用, 如果驱动在块 I/O 补丁中. 它还应当用在所有的存储类型的错误处理补丁中.</p></dd><dt><span class="term"><span>GFP_KERNEL </span></span></dt><dd><p>这应当用在所有其他的情况中, 不属于之前提到的类别.</p></dd></dl></div></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="CompletingUrbsTheCompletionCallbackHandler.sect2"></a>13.3.4.&#160;完成 urb: 完成回调处理者</h3></div></div></div><p>如果对 usb_submit_urb 的调用成功, 传递对 urb 的控制给 USB 核心, 这个函数返回 0; 否则, 一个负错误值被返回. 如果函数成功, urb 的完成处理者(如同被完成函数指针指定的)被确切地调用一次, 当 urb 被完成. 当这个函数被调用, USB 核心完成这个 urb, 并且对它的控制现在返回给设备驱动.</p><p>只有 3 个方法, 一个urb 可被结束并且使完成函数被调用:</p><div class="itemizedlist"><ul type="disc"><li><p>urb 被成功发送给设备, 并且设备返回正确的确认. 对于一个 OUT urb, 数据被成功发送, 对于一个 IN urb, 请求的数据被成功收到. 如果发生这个, urb 中的状态变量被设置为 0.</p></li><li><p>一些错误连续发生, 当发送或者接受数据从设备中. 被 urb 结构中的 status 变量中的错误值所记录.</p></li><li><p>这个 urb 被从 USB 核心去链. 这发生在要么当驱动告知 USB 核心取消一个已提交的 urb 通过调用 usb_unlink_urb 或者 usb_kill_urb, 要么当设备从系统中去除, 以及一个 urb 已经被提交给它.</p></li></ul></div><p>一个如何测试在一个 urb 完成调用中不同返回值的例子在本章稍后展示.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="CancelingUrbs.sect2"></a>13.3.5.&#160;取消 urb</h3></div></div></div><p>为停止一个已经提交给 USB 核心的 urb, 函数 usb_kill_urb 或者 usb_unlink_urb 应当被调用:</p><pre class="programlisting">int usb_kill_urb(struct urb *urb); int usb_unlink_urb(struct urb *urb);</pre>The urb parameter for both of these functions is a pointer to the urb that is to be canceled. <p></p><p>当函数是 usb_kill_urb, 这个 urb 的生命循环就停止了. 这个函数常常在设备从系统去除时被使用, 在去连接回调中.</p><p>对一些驱动, 应当用 usb_unlink_urb 函数来告知 USB 核心去停止 urb. 这个函数在返回到调用者之前不等待这个 urb 完全停止. 这对于在中断处理或者持有一个自旋锁时停止 urb 时是有用的, 因为等待一个 urb 完全停止需要 USB 核心有能力使调用进程睡眠. 为了正确工作这个函数要求 URB_ASYNC_UNLINK 标志值被设置在正被要求停止的 urb 中.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch13s02.html">上一页</a>&#160;</td><td width="20%" align="center"><a accesskey="u" href="ch13.html">上一级</a></td><td width="40%" align="right">&#160;<a accesskey="n" href="ch13s04.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">13.2.&#160;USB 和 sysfs&#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top">&#160;13.4.&#160;编写一个 USB 驱动</td></tr></table></div></body></html><div style="display:none"><script language="JavaScript" src="script.js"></script> </div>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -