linux usb urb详解

谨以此文纪念过往的岁月

一.前言

在前文中看过了hub的驱动以及host的驱动还有usb设备的驱动,在把这些东西关联起来的东东中,一个很重要的urb(usb request blk),在本文中会详细来看urb的实现,以及具体的应用。

二.Urb

urb是什么东西,那先来看urb的定义吧。

1struct urb

2{

3/*私有的:只能由usb核心和主机控制器访问的字段*/

4struct kref kref; /*urb引用计数*/

5spinlock_t lock; /* urb锁*/

6void *hcpriv; /*主机控制器私有数据*/

7int bandwidth; /* int/iso请求的带宽*/

8atomic_t use_count; /*并发传输计数*/

9u8 reject; /*传输将失败*/

10

11/*公共的: 可以被驱动使用的字段*/

12struct list_head urb_list; /*链表头*/

13struct usb_device *dev; /*关联的usb设备*/

14unsigned int pipe; /*管道信息*/

15int status; /* urb的当前状态*/

16unsigned int transfer_flags; /* urb_short_not_ok | ...*/

17void *transfer_buffer; /*发送数据到设备或从设备接收数据的缓冲区*/

18dma_addr_t transfer_dma; /*用来以dma方式向设备传输数据的缓冲区*/

19int transfer_buffer_length;/*transfer_buffer或transfer_dma指向缓冲区的大小*/

20

21int actual_length; /* urb结束后,发送或接收数据的实际长度*/

22unsigned char *setup_packet; /*指向控制urb的设置数据包的指针*/

23dma_addr_t setup_dma; /*控制urb的设置数据包的dma缓冲区*/

24int start_frame; /*等时传输中用于设置或返回初始帧*/

25int number_of_packets; /*等时传输中等时缓冲区数据*/

26int interval; /* urb被轮询到的时间间隔(对中断和等时urb有效)*/

27int error_count;/*等时传输错误数量 */

28void *context; /* completion函数上下文*/

29usb_complete_t complete; /*当urb被完全传输或发生错误时,被调用*/

30struct usb_iso_packet_descriptor iso_frame_desc[0];

31/*单个urb一次可定义多个等时传输时,描述各个等时传输*/

32 };

2.1 urb申请

usb_alloc_urb开辟一个urb空间并对其部分的成员初始化。

iso_packets:等时传输的包数

mem_flags:开辟urb空间的mem旗标,一般为GFP_KERNEL

struct urb *usb_alloc_urb(int, gfp_t )

{

struct

urb *urb;

urb

= kmalloc(sizeof(struct urb) +iso_packets * sizeof(struct

usb_iso_packet_descriptor),

mem_flags);--开辟空间

if

(!urb) {

return

NULL;

}

usb_init_urb(urb);

--初始化部分成员

return

urb;

}

void usb_init_urb(struct urb *urb)

{

if

(urb) {

memset(urb,

0, sizeof(*urb));

kref_init(&urb->kref);--初始化urb计数器

INIT_LIST_HEAD(&urb->anchor_list);--初始化锁定链表

}

}

一般会在初始化之后,对urb的各个成员进行初始化。例如调用usb_fill_int_urb对urb进行成员的填充。在此不做讲述,这个还是比较简单的。

2.2 usb_submit_urb提交urb

int usb_submit_urb(struct urb *urb, gfp_t

mem_flags)

{

intxfertype, max;

struct

usb_device*dev;

struct

usb_host_endpoint*ep;

intis_out;

if

(!urb || urb->hcpriv || !urb->complete)

return

-EINVAL;

dev

= urb->dev;

if

((!dev) || (dev->state < USB_STATE_DEFAULT))

return

-ENODEV;

ep

= (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) [usb_pipeendpoint(urb->pipe)];

--查找设备端点

if

(!ep)

return

-ENOENT;

urb->ep

= ep;

urb->status

= -EINPROGRESS;

urb->actual_length

= 0;

xfertype

= usb_endpoint_type(&ep->desc);

if

(xfertype == USB_ENDPOINT_XFER_CONTROL) {--如果是控制类型

struct

usb_ctrlrequest *setup = (struct usb_ctrlrequest *) urb->setup_packet;

if

(!setup)

return

-ENOEXEC;

is_out

= !(setup->bRequestType & USB_DIR_IN) ||!setup->wLength;

}

else {

is_out

= usb_endpoint_dir_out(&ep->desc);

}

urb->transfer_flags

= (urb->transfer_flags & ~URB_DIR_MASK) | (is_out ? URB_DIR_OUT :

URB_DIR_IN);--缓存的方向留待后用

if

(xfertype != USB_ENDPOINT_XFER_CONTROL &&dev->state <

USB_STATE_CONFIGURED)--在设备没有配置前,传输的类型必为控制类型,唯有设备配置完成后才能传输其他类型的urb

return

-ENODEV;

max

= le16_to_cpu(ep->desc.wMaxPacketSize);

if

(max <= 0) {

return

-EMSGSIZE;

}

if

(xfertype == USB_ENDPOINT_XFER_ISOC) {--等时传输

intn, len;

if

(dev->speed == USB_SPEED_HIGH) {

intmult = 1 + ((max >> 11) & 0x03);

max

&= 0x07ff;

max

*= mult;

}

if

(urb->number_of_packets <= 0)

return

-EINVAL;

for

(n = 0; n < urb->number_of_packets; n++) {

len

= urb->iso_frame_desc[n].length;

if

(len < 0 || len > max)

return

-EMSGSIZE;

urb->iso_frame_desc[n].status

= -EXDEV;

urb->iso_frame_desc[n].actual_length

= 0;

}

}

if

(urb->transfer_buffer_length < 0)

return

-EMSGSIZE;

switch

(xfertype) {--对等时传输和中断传输的等待时间进行检测

case

USB_ENDPOINT_XFER_ISOC:

case

USB_ENDPOINT_XFER_INT:

if

(urb->interval <= 0)

return

-EINVAL;

switch

(dev->speed) {

case

USB_SPEED_HIGH:

/*

NOTE usb handles 2^15 */

if

(urb->interval > (1024 * 8))

urb->interval

= 1024 * 8;

max

= 1024 * 8;

break;

case

USB_SPEED_FULL:

case

USB_SPEED_LOW:

if

(xfertype == USB_ENDPOINT_XFER_INT) {

if

(urb->interval > 255)

return

-EINVAL;

max

= 128;

}

else {

if

(urb->interval > 1024)

urb->interval

= 1024;

max

= 1024;

}

break;

default:

return

-EINVAL;

}

urb->interval

= min(max, 1 << ilog2(urb->interval));

}

return

(urb,

mem_flags);

}

int usb_hcd_submit_urb (struct urb *urb,

gfp_t mem_flags)

{

intstatus;

struct

usb_hcd*hcd =

bus_to_hcd(urb->dev->bus);

usb_get_urb(urb);

atomic_inc(&urb->use_count);--增减urb计数

atomic_inc(&urb->dev->urbnum);--增加dev的urb计数

usbmon_urb_submit(&hcd->self,

urb);--退化为空函数

status

= map_urb_for_dma(hcd, urb, mem_flags);--将urb的缓冲区与dma的区间映射

if

(unlikely(status)) {

usbmon_urb_submit_error(&hcd->self,

urb, status);

goto

error;

}

if

(is_root_hub(urb->dev))

status

= rh_urb_enqueue(hcd, urb);

else

status

= hcd->driver->urb_enqueue(hcd, urb, mem_flags);--将urb入队

if

(unlikely(status)) {

usbmon_urb_submit_error(&hcd->self,

urb, status);

unmap_urb_for_dma(hcd,

urb);

error:

urb->hcpriv

= NULL;

INIT_LIST_HEAD(&urb->urb_list);

atomic_dec(&urb->use_count);

atomic_dec(&urb->dev->urbnum);

if

(atomic_read(&urb->reject))

wake_up(&usb_kill_urb_queue);

usb_put_urb(urb);

}

return

status;

}

在函数usb_hcd_submit_urb调用该hcd的urb_enqueue,在ohci中将会调用ohci_urb_enqueue。其实到此我们需要放下urb的探索,重新来看ohci中关于ed,td的应用。在前文中对ohci的probe进行了讲述,但是对于其余的函数并没有仔细说明,那在后中仔细来看关于ohci的详情。

2.3usb_anchor_urb

当urb在处理的时候锁定。这个函数其实实现很简单就是将urb->anchor_list添加到anchor->urb_list中。关于该函数的具体实现我并不知道具体是做什么用的。

void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)

{

unsigned long flags;

spin_lock_irqsave(&anchor->lock,

flags);

usb_get_urb(urb);

list_add_tail(&,

&;

urb->anchor = anchor;

if

(unlikely(anchor->poisoned)) {

atomic_inc(&urb->reject);

}

spin_unlock_irqrestore(&anchor->lock,

flags);

}

2.4 usb_unanchor_urb

该函数与上面的函数刚好相反,解锁一个urb同时删除urb

void(struct urb *urb)

{

unsigned long flags;

struct usb_anchor

*anchor;

if (!urb)

return;

anchor =

urb->anchor;

if (!anchor)

return;

spin_lock_irqsave(&anchor->lock,

flags);

if (unlikely(anchor !=

urb->anchor)) {

spin_unlock_irqrestore(&anchor->lock,

flags);

return;

}

urb->anchor = NULL;

list_del(&urb->anchor_list);--将urb从anchor的链表中删除

spin_unlock_irqrestore(&anchor->lock,

flags);

usb_put_urb(urb);--减少urb计数同时删除urb == usb_free_urb

if

(list_empty(&anchor->urb_list))

(&anchor->wait);

}

void (struct urb *urb)

{

if (urb)

kref_put(&urb->kref,

urb_destroy);

}

在某一方面来讲anchor类似一个urb的守护链表,在urb被使用时是不能被删除的。在删除一个urb时需要调用usb_wait_anchor_empty_timeout来等待urb传输完全结束。下面的wait_event_timeout则与上面的wake_up相互对应。

int(struct

usb_anchor *anchor,unsigned int timeout)

{

return (anchor->wait,

list_empty(&anchor->urb_list),

msecs_to_jiffies(timeout));

}

三.总结

urb在某一方面来说是设备驱动与hcd的通信的东东,关于urb的处理其本质还是在ohci中。这个将会在后面的学习中好好学习。

linux usb声卡 submit urb,linux usb urb详解相关推荐

  1. Linux下boost库的编译、安装详解

    1.下载源文件 去官网下载:http://www.boost.org/ 这里下载最新版本 wget https://dl.bintray.com/boostorg/release/1.64.0/sou ...

  2. Linux下的tar归档及解压缩功能详解

    Linux下的tar归档及解压缩功能详解 一.Linux下解压缩工具 二.gzip工具的使用方法 三.其他解压缩工具 一.Linux下解压缩工具 二.gzip工具的使用方法 三.其他解压缩工具 一.L ...

  3. 【Linux】19.Linux环境变量名LD_LIBRARY_PATH 和 ldd命令详解

    Linux环境变量名LD_LIBRARY_PATH 和 ldd命令详解 参考链接: https://www.jianshu.com/p/a62e1d327023 LD_LIBRARY_PATH中的LD ...

  4. 【转载】Linux命令-自动挂载文件/etc/fstab功能详解[转]

    博客园 首页 新随笔 联系 订阅 管理 随笔 - 322  文章 - 0  评论 - 19 Linux命令-自动挂载文件/etc/fstab功能详解[转]     一./etc/fstab文件的作用 ...

  5. linux为什么用tar压缩,linux下tar压缩和解压命令用法详解

    linux下tar压缩和解压命令用法详解 2017-03-25 14:06 分享人:老牛 将/usr/local/test目录下所有文件仅打包,不压缩到 /usr/local/auto_bak/目下 ...

  6. 详解FTP服务完成Linux和WIN10之间的信息传输(实验详解)

    详解FTP服务完成Linux和WIN10之间的信息传输(实验详解) 一.FTP简介 1. FTP服务--用来传输文件的协议 2.端口 3.数据连接模式 二.相关配置 1.安装FTP服务 2.设置匿名用 ...

  7. linux mk创建文件,Linux运维知识之Linux mkkickstart建立安装的组态文件命令详解

    本文主要向大家介绍了Linux运维知识之Linux mkkickstart建立安装的组态文件命令详解,通过具体的内容向大家展现,希望对大家学习Linux运维知识有所帮助. 功能说明:建立安装的组态文件 ...

  8. linux 子域dns,linux下搭建DNS子域及相关授权详解

    linux下搭建DNS子域及相关授权详解forward功能是本地无法解析的域名,转发给指定DNS服务器 forward only; 所有无法解析的域名,都转发给指定DNS服务器,必须有解析结果 for ...

  9. linux添加nginx,linux下安装Nginx1.16.0的教程详解

    因为最近在倒腾linux,想安装新版本的nginx,找了一圈教程没有找到对应的教程,在稍微倒腾了一会之后终于成功的安装了最新版. 服务器环境为centos,接下来是详细步骤: 安装必要依赖插件 ? 创 ...

  10. Linux环境下怎么使用pip,linux下pip的安装步骤及使用详解

    linux下pip的安装步骤及使用详解 pip类似RedHat里面的yum,安装软件非常方便.下面话不多说,来看看详细的介绍: pip下载:# wget "https://pypi.pyth ...

最新文章

  1. sqlite DLL load failed
  2. Boost:BOOST_VERIFY扩展的用法测试程序
  3. sqlsession.selectlist 会返回null么_如何在Java代码中去掉烦人的“!=null”
  4. [Silverlight入门系列]用TransformToVisual和Transform取得元素绝对位置(Location)
  5. Python3 可变对象VS不可变对象、 对象的赋值、深拷贝VS浅拷贝
  6. 取消Win7驱动数字签名认证
  7. bzoj 3162: 独钓寒江雪 树形dphash
  8. 志存高远,少年当自强
  9. AOJ-AHU-OJ-670 Tyrion的矩阵
  10. Android O 自定义prop的问题小总结
  11. 如何在自己电脑上设php网站,怎么在自己电脑上建网站
  12. cbrt函数_cbrt()函数以及C ++中的示例
  13. 鲁班图片压缩实现仿微信九宫格选择图片效果
  14. 我的(此)电脑里面除了磁盘以外,多了一个CD驱动器,删除方法,亲测有效
  15. 计算机无法读取移动光驱,电脑检测不到光驱怎么办?
  16. [Erlang危机](3.1)常见过载情景
  17. js 捕获子元素的 focus 事件
  18. python自动买股票_用python可以做哪些有趣的事--我:选股票
  19. 教你文件名中文转英语并重命名的技巧
  20. AirFlow调度执行Talend ETL任务

热门文章

  1. 从浏览器端JavaScript代码进行服务器端日志记录
  2. 使用自定义断言丰富测试代码
  3. Spring Boot 1.0和Spring Boot 1.0.1错误修复版本
  4. Java 8:正在运行的CompletableFuture
  5. 谁在偷你的记忆? 应用服务器版
  6. Java对象如何实现比较规则
  7. 数据库 MySQL 如何设置表的主键自增起始值
  8. linux l文件共享,llinux服务器文件共享的一种简单的方法
  9. 解决postman请求乱码问题
  10. java当前4中引用_Java的四种引用