当驱动有数据发送到 USB 设备(如同在驱动的 write 函数中发生的), 一个 urb 必须被 分配来传送数据到设备.

urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb)

{

retval = -ENOMEM; goto error;

}

在 urb 被成功分配后, 一个 DMA 缓冲也应当被创建来发送数据到设备以最有效的方式, 并且被传递到驱动的数据应当被拷贝到缓冲:

buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); if (!buf)

{

retval = -ENOMEM; goto error;

}

if (copy_from_user(buf, user_buffer, count))

{

retval = -EFAULT; goto error;

}

应当数据被正确地从用户空间拷贝到本地缓冲, urb 在它可被提交给 USB 核心之前必须 被正确初始化:

/* initialize the urb properly */ usb_fill_bulk_urb(urb, dev->udev,

usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),

buf, count,
skel_write_bulk_callback, dev); urb->transfer_flags |=
URB_NO_TRANSFER_DMA_MAP;

现在 urb 被正确分配, 数据被正确拷贝, 并且 urb 被正确初始化, 它可被提交给 USB 核心来传递给设备.

/*
send the data out the bulk port */ retval = usb_submit_urb(urb, GFP_KERNEL); if
(retval)

{

err("%s
- failed submitting write urb, error %d", FUNCTION , retval); goto error;

}


urb 被成功传递到 USB 设备(或者在传输中发生了什么), urb 回调被 USB 核心调用. 在我们的例子中, 我们初始化 urb 来指向函数
skel_write_bulk_callback, 并且那就是 被调用的函数:

static
void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)

{

/*
sync/async unlink faults aren't errors */ if (urb->status &&

!(urb->status
== -ENOENT ||

urb->status ==
-ECONNRESET || urb->status == -ESHUTDOWN)){

dbg("%s - nonzero write
bulk status received: %d",

FUNCTION  , urb->status);

}

/*
free up our allocated buffer */

usb_buffer_free(urb->dev,
urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma);

}

回调函数做的第一件事是检查 urb 的状态来决定是否这个 urb 成功完成或没有. 错误值,

-ENOENT, -ECONNRESET, 和 -ESHUTDOWN 不是真正的传送错误, 只是报告伴随成功传送的 情况. (见
urb 的可能错误的列表, 在"结构 struct urb"一节中详细列出). 接着这个回 调释放安排给这个 urb 传送的已分配的缓冲.

在 urb 的回调函数在运行时另一个 urb 被提交给设备是普遍的. 当流数据到设备时是有 用的. 记住 urb 回调是在中断上下文运行,
因此它不应当做任何内存分配, 持有任何旗 标, 或者任何可导致进程睡眠的事情. 当从回调中提交 urb, 使用
GFP_ATOMIC 标志来告 知 USB 核心不要睡眠, 如果它需要分配新内存块在提交过程中.

Linux 内核提交和控制一个 urb的更多相关文章

  1. Linux 内核提交 urb

    一旦 urb 被正确地创建,并且被 USB 驱动初始化, 它已准备好被提交给 USB 核心来发送 出到 USB 设备. 这通过调用函数 usb_submit_urb 实现: int usb_submi ...

  2. Linux内核装载和启动一个可执行程序

    “平安的祝福 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 理解编 ...

  3. 理解Linux内核之中断控制

    乍一看下边的Linux内核代码,貌似L3389有bug,于是我就绕有兴趣地阅读了一下local_irq_save/local_irq_restore的源代码. /* linux-4.14.12/mm/ ...

  4. linux内核学习之二 一个精简内核的分析(基于时间片轮转)

    一   实验过程及效果 1.准备好相关的代码,分别是mymain.c,mypcb.h,myinterrupt.c ,如下图,make make成功: 在qemu创建的虚拟环境下的运行效果:(使用的命令 ...

  5. Linux内核分析:完成一个简单的时间片轮转多道程序内核代码

    PS.贺邦   原创作品转载请注明出处  <Linux内核分析>MOOC课程    http://mooc.study.163.com/course/USTC-1000029000 1.m ...

  6. Linux内核是如何创建一个新进程的?

    进程描述 进程描述符(task_struct) 用来描述进程的数据结构,可以理解为进程的属性.比如进程的状态.进程的标识(PID)等,都被封装在了进程描述符这个数据结构中,该数据结构被定义为task_ ...

  7. 实验七:Linux内核如何装载和启动一个可执行程序

    原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 题目自拟,内容围绕对Linu ...

  8. 作业七:Linux内核如何装载和启动一个可执行程序

    作业七:Linux内核如何装载和启动一个可执行程序 一.编译链接的过程和ELF可执行文件格式 可执行文件的创建——预处理.编译和链接 在object文件中有三种主要的类型. 一个可重定位(reloca ...

  9. 20135323符运锦----第七周:Linux内核如何装载和启动一个可执行程序

    可执行程序的装载 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 ①编译器预处理 gcc -E -o XX.cpp XX.c (-m32)// 注:把include的文件包含进来, ...

随机推荐

  1. 微信公众号系统在Linux下的部署操作

    ps -ef | grep tomcat 查看tomcat进程

  2. SSM框架用JSON进行前后端数据传输

    一个根据用户id查找用户信息的简单功能,使用JSON进行数据的传输 前端代码 这里用bootstrap做简单的样式美化,中间留了个div用来异步的显示查询结果,ajax进行前端的数据传输(class内 ...

  3. oracle-ORA-01555错误

    Snapshot too old 原因:没有足够的撤销空间满足读一致性而需要撤销信息的长查询

  4. Ubuntu里node命令出错,找不到

    ubuntu里用sudo apt-get install nodejs安装Node.js后, 发现terminals里运行node命令(比如node –-version)时候会有No such fil ...

  5. js函数易犯的错误

    1.定义一个js函数时不能写在另一个函数里面. 2.定义一个打开网页自动执行的函数,一定要注意加载的顺序.如果是不是自动执行的,而是等页面加载完后事件触发的,那写在任何地方都没问题. 错误的:

  6. Python发送邮件1(带附件的)

    普通的发邮件(不使用类)

  7. 洛谷3067 BZOJ 2679题解(折半搜索)

    传送门 BZOJ传送门(权限题) 看到n小于20,就可以想到搜索 所有的数要么在集合a中,要么在集合b中,要么都不在 可是3^n复杂度会炸,我们考虑优化 可以利用折半搜索,将前面一半的所有可能情况与后 ...

  8. 《mysql必知必会》笔记3(插入、更新、删除、创建删除更新表、视图)

    十九:插入数据 1:insert语句用来将行插入数据表中,可以插入完整的行.行的一部分.插入多行.插入某些查询的结果. 2:不指定列名,可以这样插入: insert into customers va ...

  9. nodeJs学习-05 案例:http/fs/querystring/url

    const http = require('http'); const fs = require('fs'); const querystring = require('querystring'); ...

  10. C#判断文件是否被混淆

    可以使用混淆工具对一个DLL 和 exe 进行混淆. 但是如何知道一个文件是否已经混淆了. 在发布之前,需要知道是不是有文件忘了混淆. 要判断文件是否混淆,必须知道常用的混淆手法. 混淆就是因为编写的 ...