直接看代码吧。


/*-------------------------------------------------------------------*/

/**
* usb_submit_urb - issue an asynchronous transfer request for an endpoint
* @urb: pointer to the urb describing the request
* @mem_flags: the type of memory to allocate, see kmalloc() for a list
* of valid options for this.
*
* This submits a transfer request, and transfers control of the URB
* describing that request to the USB subsystem. Request completion will
* be indicated later, asynchronously, by calling the completion handler.
* The three types of completion are success, error, and unlink
* (a software-induced fault, also called "request cancellation").
*
* URBs may be submitted in interrupt context.
*
* The caller must have correctly initialized the URB before submitting
* it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
* available to ensure that most fields are correctly initialized, for
* the particular kind of transfer, although they will not initialize
* any transfer flags.
*
* Successful submissions return 0; otherwise this routine returns a
* negative error number. If the submission is successful, the complete()
* callback from the URB will be called exactly once, when the USB core and
* Host Controller Driver (HCD) are finished with the URB. When the completion
* function is called, control of the URB is returned to the device
* driver which issued the request. The completion handler may then
* immediately free or reuse that URB.
*
* With few exceptions, USB device drivers should never access URB fields
* provided by usbcore or the HCD until its complete() is called.
* The exceptions relate to periodic transfer scheduling. For both
* interrupt and isochronous urbs, as part of successful URB submission
* urb->interval is modified to reflect the actual transfer period used
* (normally some power of two units). And for isochronous urbs,
* urb->start_frame is modified to reflect when the URB's transfers were
* scheduled to start. Not all isochronous transfer scheduling policies
* will work, but most host controller drivers should easily handle ISO
* queues going from now until 10-200 msec into the future.
*
* For control endpoints, the synchronous usb_control_msg() call is
* often used (in non-interrupt context) instead of this call.
* That is often used through convenience wrappers, for the requests
* that are standardized in the USB 2.0 specification. For bulk
* endpoints, a synchronous usb_bulk_msg() call is available.
*
* Request Queuing:
*
* URBs may be submitted to endpoints before previous ones complete, to
* minimize the impact of interrupt latencies and system overhead on data
* throughput. With that queuing policy, an endpoint's queue would never
* be empty. This is required for continuous isochronous data streams,
* and may also be required for some kinds of interrupt transfers. Such
* queuing also maximizes bandwidth utilization by letting USB controllers
* start work on later requests before driver software has finished the
* completion processing for earlier (successful) requests.
*
* As of Linux 2.6, all USB endpoint transfer queues support depths greater
* than one. This was previously a HCD-specific behavior, except for ISO
* transfers. Non-isochronous endpoint queues are inactive during cleanup
* after faults (transfer errors or cancellation).
*
* Reserved Bandwidth Transfers:
*
* Periodic transfers (interrupt or isochronous) are performed repeatedly,
* using the interval specified in the urb. Submitting the first urb to
* the endpoint reserves the bandwidth necessary to make those transfers.
* If the USB subsystem can't allocate sufficient bandwidth to perform
* the periodic request, submitting such a periodic request should fail.
*
* Device drivers must explicitly request that repetition, by ensuring that
* some URB is always on the endpoint's queue (except possibly for short
* periods during completion callacks). When there is no longer an urb
* queued, the endpoint's bandwidth reservation is canceled. This means
* drivers can use their completion handlers to ensure they keep bandwidth
* they need, by reinitializing and resubmitting the just-completed urb
* until the driver longer needs that periodic bandwidth.
*
* Memory Flags:
*
* The general rules for how to decide which mem_flags to use
* are the same as for kmalloc. There are four
* different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
* GFP_ATOMIC.
*
* GFP_NOFS is not ever used, as it has not been implemented yet.
*
* GFP_ATOMIC is used when
* (a) you are inside a completion handler, an interrupt, bottom half,
* tasklet or timer, or
* (b) you are holding a spinlock or rwlock (does not apply to
* semaphores), or
* (c) current->state != TASK_RUNNING, this is the case only after
* you've changed it.
*
* GFP_NOIO is used in the block io path and error handling of storage
* devices.
*
* All other situations use GFP_KERNEL.
*
* Some more specific rules for mem_flags can be inferred, such as
* (1) start_xmit, timeout, and receive methods of network drivers must
* use GFP_ATOMIC (they are called with a spinlock held);
* (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also
* called with a spinlock held);
* (3) If you use a kernel thread with a network driver you must use
* GFP_NOIO, unless (b) or (c) apply;
* (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)
* apply or your are in a storage driver's block io path;
* (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and
* (6) changing firmware on a running storage or net device uses
* GFP_NOIO, unless b) or c) apply
*
*/
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int pipe, temp, max;
struct usb_device *dev;
int is_out; if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
if (!(dev = urb->dev) ||
(dev->state < USB_STATE_DEFAULT) ||
(!dev->bus) || (dev->devnum <= 0))
return -ENODEV;
if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
|| dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH; urb->status = -EINPROGRESS;
urb->actual_length = 0; /* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
pipe = urb->pipe;
temp = usb_pipetype(pipe);
is_out = usb_pipeout(pipe); if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
return -ENODEV; /* FIXME there should be a sharable lock protecting us against
* config/altsetting changes and disconnects, kicking in here.
* (here == before maxpacket, and eventually endpoint type,
* checks get made.)
*/ max = usb_maxpacket(dev, pipe, is_out);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_pipeendpoint(pipe), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
} /* periodic transfers limit size per frame/uframe,
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
if (temp == PIPE_ISOCHRONOUS) {
int n, len; /* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH) {
int mult = 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;
}
} /* the I/O buffer must be mapped/unmapped, except when length=0 */
if (urb->transfer_buffer_length < 0)
return -EMSGSIZE; #ifdef DEBUG
/* stuff that drivers shouldn't do, but which shouldn't
* cause problems in HCDs if they get it wrong.
*/
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed; /* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
URB_NO_INTERRUPT);
switch (temp) {
case PIPE_BULK:
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
case PIPE_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
case PIPE_ISOCHRONOUS:
allowed |= URB_ISO_ASAP;
break;
}
urb->transfer_flags &= allowed; /* fail if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) {
err("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
}
#endif
/*
* Force periodic transfer intervals to be legal values that are
* a power of two (so HCDs don't need to).
*
* FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
switch (temp) {
case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
/* too big? */
switch (dev->speed) {
case USB_SPEED_HIGH: /* units are microframes */
// NOTE usb handles 2^15
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
temp = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
if (temp == PIPE_INTERRUPT) {
if (urb->interval > 255)
return -EINVAL;
// NOTE ohci only handles up to 32
temp = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15
temp = 1024;
}
break;
default:
return -EINVAL;
}
/* power of two? */
while (temp > urb->interval)
temp >>= 1;
urb->interval = temp;
} return usb_hcd_submit_urb(urb, mem_flags);
}

这个函数的开头儿就要履行一下常规的检验,判断urb为空? Hcpriv是留给HCD用的, complete,每个urb结束了都必须的调用一次complete代表的函数。完成对urb本身的检验,接着对urb的目的地usb设备的检验。设备所属于的那条总线不存在,或者设备本身不存在,或者设备甚至还没进入USB_STATE_DEFAULT状态,管道的另一端还都是堵着的怎么过去,早先强调多少回了,要想让设备回应你,它起码得达到Default状态。设备编号devnum肯定是不能为负的了,那0为什么也不行那?你应该还记得Token包的地址域里有7位是表示设备地址的,也就是说总共可以有128个地址来分配给设备,但是其中0号地址是被保留作为缺省地址用的,任何一个设备处于Default状态还没有进入Address状态的时候都需要通过这个缺省地址来响应主机的请求,所以0号地址不能分配给任何一个设备,hub为设备选择一个地址的时候,只有选择到一个大于0的地址,设备的生命线才会继续,才会走到这里,因此说这里的devnum是不可能也不应该为0的。咱们看到这里是因为要设置设备的地址,让设备进入Address状态,所以针对SET_ADDRESS请求再看看这个devnum。主机向设备发送SET_ADDRESS请求时,如果设备处于Default状态,就是它现在处的状态,指定一个非0值时,设备将进入Adress状态,指定0值时,设备仍然会处于Default状态,所以说即使从这个角度看,这里的devnum也是不能为0的。如果设备已经处于Adress状态,指定一个非0值时,设备仍然会处于Address状态,只是将使用新分配的地址,一个设备只能占用一个地址。如果指定了一个0值,则设备将离开Address状态退回到Default状态。

power,power_state,event,还有PM_EVENT_ON都是电源管理核心里的东西,这里的目的是判断设备所在的那条总线的主机控制器有没有挂起,然后再判断设备本身是不是处于Suspended状态。

常规检查完,core和HCD已经认同了这个urb,就将它的状态设置为-EINPROGRESS,表示从现在开始urb的控制权就在core和HCD手里边儿了,驱动那里是看不到这个状态的。

actual_length这时还没开始传输,实际传输的数据长度当然为0了,这里初始化这么一下,也是为了防止以后哪里出错返回了,驱动里好检查。

接下来这几行获得管道的类型还有方向。

usb_pipecontrol函数,在设备进入Configured状态之前,主机只能使用控制传输,通过缺省管道,也就是管道0来和设备进行交流。

usb_maxpacket函数用来获得端点的wMaxPacketSize,这个函数不管从理论上还是实际上都是很简单的。咱们可以先问下自己,根据现有的信息如何获得一个端点的wMaxPacketSize?当然是必须得获得该端点的描述符,我们知道每个struct usb_device结构体里都有两个数组ep_out和ep_in保存了各个端点对应的struct usb_host_endpoint结构体,只要知道该端点对应了这两个数组里的哪个元素就可以获得它的描述符了,这就需要知道该端点的端点号和方向,而端点的方向就管道的方向,端点号也在pipe里保存有。你是不是会担心ep_out或ep_in数组都还空着,或者说没有保存对应的端点信息?倒不用担心它还是空的,即使是现在设备还刚从Powered走到Default,但是在使用usb_alloc_dev构造这个设备的struct usb_device的时候就把它里面端点0的struct usb_host_endpoint结构体ep0指定给ep_out[0]和ep_in[0]了,而且后来还对ep0的wMaxPacketSize指定了值。不过如果真的没有从它们里面找到想要的那个端点的信息,那肯定就是哪里出错了,指定了错误的端点号,或其它什么原因,也就不用再继续走了。

然而等时传输要做一些特别的处理,接下几行涉及到高速、高带宽端点(high speed,high bandwidth endpoint)。前面提到interval的时候,说过每一帧或微帧最多只能有一次等时传输,完成一次等时transaction,那时这么说主要是因为还没遇到高速高带宽的等时端点。高速高带宽等时端点每个微帧可以进行2到3次等时transaction,它和一般等时端点的主要区别也就在这儿,没必要专门为它搞个描述符类型,端点描述符wMaxPacketSize字段的bit 11~12就是用来指定可以额外有几次等时transaction的,00表示没有额外的transaction,01表示额外有1次,10表示额外有两次,11被保留。wMaxPacketSize字段的前10位就是实际的端点每次能够处理的最大字节数。所以这几行意思就是如果是高速等时端点,获得它允许的额外的等时transaction次数,和每次能够处理的最大字节数,再将它们相乘就得出了该等时端点每个微帧的所能传输的最大字节数。number_of_packets不大于0就表示这个等时urb没有指定任何一次等时传输,可以直接返回了。然后对等时urb里指定的各次等时传输分别做处理。如果它们预期传输的数据长度比上面算出来的max还要大,就return,同时将它们实际传输的数据长度先置为0,状态都先初始化为-EXDEV,表示这次等时传输仅仅部分完成了,实际到这里数据传输还没真正的开始。

判断transfer_buffer_length长度不能小于0。

#ifdef DEBUG,给人调试时用的。

跳过debug内容继续向下看。temp是上面计算出来的管道类型,那下面的各个case肯定是针对四种传输类型的了。不过我们可以发现,这里只case了等时传输和中断传输两种周期性的传输类型,原因很简单,我们需要对interval进行处理,所以就没控制传输和批量传输什么事儿了。必须保证等时和中断urb的interval是大于0的,然后代码中switch根据目的设备的速度去case三种。我们前面已经说过,不同的速度,urb->interval可以取不同的范围,不过你可能会发现那时说的最大值要比这里的限制要大一些,这是因为协议归协议,实现归实现,比如,对于UHCI来说,中断传输的interval不能比128更大,而协议规定的最大值为255。那么现在的问题是,这里的temp又做什么用?要注意urb->interval的单位是帧或者微帧,temp只是为了调整它的值为2的次幂,这点从下面的处理可以看出来。

while (temp > urb->interval)

temp >>= 1;

usb_hcd_submit_urb函数将urb扔给HCD,然后就进入HCD的片儿区了。

本来usb_submit_urb函数到此应该结束了,但是它对于写驱动的来说太重要了,驱动里做的所有铺垫就是为了使用usb_submit_urb提交一个合适的urb给设备,然后满怀期待的等待着设备回馈你需要的信息,再然后才有你接下来的处理,不然你的usb驱动只是一纸空谈毫无用处。

首先还是要再次强调一下,在调用usb_submit_urb提交你的urb之前,一定必须不得不要对它正确的初始化,对于控制/中断/批量传输,core都提供了usb_fill_control_urb的几个孪生兄弟供你初始化使用,对于等时传输要自己手工一步一步小心翼翼的对urb的相关元素逐个赋值。下层基础决定上层建筑,你的urb决定了你的整个usb驱动能否顺利运转。

第二,对于驱动来说,usb_submit_urb是异步的,也就是说不用等传输完全完成就返回了,只要usb_submit_urb的返回值表示为0,就表示已经提交成功了,你的urb已经被core和HCD认可了,接下来core和HCD怎么处理就是它们的事了。只要你提交成功了,不管是中间出了差错还是顺利完成,你指定的结束处理函数总是会调用,只有到这个时候,你才能够重新拿到urb的控制权,检查它是不是出错了,需要不需要释放或者是重新提交。

第三,什么时候需要在结束处理函数里重新提交这个urb?其实,我更想问的是对于中断/等时传输,是怎么实现让主机按一定周期去访问端点的?端点的描述符里已经指定了这个间隔时间是没错儿,urb里也有interval描述了这个间隔周期,更没错儿,可是咱们的urb一次只完成一次传输,即使等时传输也只完成有限次的传输,然后就在结束处理函数里返回了,urb的控制权就完全属于驱动了,接下来的周期访问是怎么做到的?难道脱离urb主机自己就去智能化的自动的与端点通信了?OK,即使是这样了,那通信的数据又在哪里,你又怎么去得到这些数据?事实上,你第一次提交一个中断或等时的urb的时候,HCD会根据interval判断一下自己是否能够满足你的需要,如果不能够安排足够的带宽来完成这种周期性的传输,它是不可能会批准你的请求的,如果它估量一下觉得自己可以满足,就会为你保留足够的带宽。HCD是为你保留带宽了,可是驱动得保证在对应端点要处理的那个urb队列里总是有urb,不能是空的,否则这个保留的带宽就会被cancel掉。那么问题就变成,对于中断/等时传输,如何保证对应端点的urb队列里总是会有urb?这就回到最开始的问题了,驱动需要在结束处理函数里重新初始化和提交刚刚完成的urb,友情提醒一下,这个时候你是不能够修改interval的值的,否则等待你的只能是错误。中断传输的例子可以去看看触摸屏驱动,等时传输的可以去看看摄像头驱动,看看它们在结束处理函数里都做了些什么,你就悟道了。

第四,对于控制/批量/中断传输,实际上很多时候你可以不用创建urb,不用对它初始化,不用调用usb_submit_urb来提交,core将这个过程分别封装在了usb_control_msg、usb_bulk_msg和usb_interrupt_msg这三个函数里,不同的是它们的实现是同步的,会去等待传输的完全结束

还记得咱们就是从usb_control_msg走过来的吗?有空可以去看看另外两个usb_bulk_msg和usb_interrupt_msg,它们都定义在drivers/usb/core/message.c

usb驱动开发14之设备生命线的更多相关文章

  1. usb驱动开发17之设备生命线

    拜会完了山头的几位大哥,还记得我们从哪里来要到哪里去吗?时刻不能忘记自身的使命啊.我们是从usb_submit_urb()最后的那个遗留问题usb_hcd_submit_urb()函数一路走来,现在就 ...

  2. usb驱动开发16之设备生命线

    回到struct usb_hcd,继续努力的往下看. kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看hcd.c文件. static void hcd_ ...

  3. usb驱动开发12之设备生命线

    函数usb_control_msg完成一些初始化后调用了usb_internal_control_msg之后就free urb.剩下的活,全部留给usb_internal_control_msg去做了 ...

  4. usb驱动开发15之设备生命线

    总算是进入了HCD的片儿区,既然来到一个片区,怎么都要去拜会一下山头几个大哥吧.,先回忆一些我们怎么到这里的?给你列举一个调用函数过程usb_control_msg->usb_internal_ ...

  5. usb驱动开发18之设备生命线

    现在已经使用GET_DESCRIPTOR请求取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw的,即原始的,所有数据不管是配置描述符.接口描述符还是端点描述符都挤在一起,所以得想办法将 ...

  6. usb驱动开发13之设备生命线

    上一节勉勉强强把struct urb这个中心给说完,接着看那三个基本点. 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/ ...

  7. usb驱动开发11之设备生命线

    暂时先告别媒人,我们去分析各自的生命旅程,最后还会回到usb_device_match函数. 首先当你将usb设备连接在hub的某个端口上,hub检测到有设备连接了进来,它会为设备分配一个struct ...

  8. HarmonyOS USB DDK助你轻松实现USB驱动开发

    HDF(Hardware Driver Foundation)驱动框架是HarmonyOS硬件生态开放的基础,为开发者提供了驱动加载.驱动服务管理和驱动消息机制等驱动能力,让开发者能精准且高效地开发驱 ...

  9. usb驱动开发22之驱动生命线

    我们总是很喜欢高潮,不是吗?那就好好对待她哦.我们来看一下linux中的高潮部分设备是怎么从Address进入Configured的. usb_set_configuration函数的代码就不贴了,可 ...

随机推荐

  1. Caliburn.Micro 关闭父窗体打开子窗体

    比如我们在做登录的时候需要关闭父窗体打开子窗体.使用Caliburn.Micro它的时候我们关闭登录窗口的时候主页面也会关闭. 解决方法就是在登录页面的CS里面写 IndexView iv = new ...

  2. iOS 远程推送通知

    1.什么是推送通知 在某些特殊情况下,应用程序被动收到的以不同种界面形式出现的提醒信息 推送通知的作用:可以让不在前台运行的app通知app发生了改变 iOS中得推送通知种类 远程推送通知(Remot ...

  3. zend studio 使用总结

    1 修改中文字体打开zend studio -> Window -> Preferences -> General -> Apperance -> Colors and ...

  4. JavaScript Lib Interface (JavaScript系统定义的接口一览表)

    function Object(){}; Object.prototype.toString = function(){return "";}; Object.prototype. ...

  5. 关于update set from where

    http://blog.csdn.net/xcbsdu/article/details/6736503 下面是这样一个例子: 两个表a.b,想使b中的memo字段值等于a表中对应id的name值    ...

  6. 编写Java应用程序。首先定义一个描述银行账户的Account类,包括成员变 量“账号”和“存款余额”,成员方法有“存款”、“取款”和“余额查询”。其次, 编写一个主类,在主类中测试Account类的功能

    package com.hanqi.test; //银行账号 public class account { private String zhanghao;//账号 //私有余额 private do ...

  7. SQL Server调优系列基础篇(索引运算总结)

    前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方 ...

  8. shell脚本的执行

    shell脚本有两种执行方式,一种是直接执行,一种是使用$source 或.命令执行 直接执行 直接执行shell脚本,bash会在当前bash下新建一个子bash进程用来执行shell脚本,此时脚本 ...

  9. (转)android.intent.action.MAIN与android.intent.category.LAUNCHER

    android.intent.action.MAIN决定应用程序最先启动的Activity android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里 在网上看到 ...

  10. java 重载、重写、构造函数详解

    方法重写 1.重写只能出现在继承关系之中.当一个类继承它的父类方法时,都有机会重写该父类的方法.一个特例是父类的方法被标识为final.重写的主要优点是能够定义某个子类型特有的行为. class An ...