usb_submit_urb
Posted 善咏兄弟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了usb_submit_urb相关的知识,希望对你有一定的参考价值。
hub_irq() --> usb_submit_urb() usb_start_wait_urb() --> usb_submit_urb()
一旦urb被USB驱动程序正确地创建和初始化后,就可以递交到USB核心以发送到USB设备了。如果函数调用成功,当urb被HC处理结束的时候,urb的结束处理例程(urb->complete)正好被调用一次,当该结束处理函数被调用时,USB核心就结束了对urb的处理,此刻对urb的控制器权就返回给设备驱动程序了。
函数usb_submit_urb()用来递交URB,它在对URB进行设置后,调用主机控制器函数usb_hcd_submit_urb()来完成递交操作。
错误代码:
-ENOMEM 内存不足
-ENODEV 没有设备可用
-EPIPE 端点停止
-EAGAIN 排队等候同步传输的太多
-EFBIG 请求ISO frame的太多
-EINVAL 无效的中断间隔
函数usb_submit_urb递交URB后,urb->status为-EINPROGRESS.
--------------------------------------------------------
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;
pipe = urb->pipe;
temp = usb_pipetype(pipe);
is_out = usb_pipeout(pipe);
if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
//获取usb设备dev所能传输的数据包的最大值(单位是字节)
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;
}
处理“负责实时传输的urb”
|---------------------------------------------------------|
| if (temp == PIPE_ISOCHRONOUS) { |
| int n, len; |
| 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; |
| } |
| } |
|---------------------------------------------------------|
if (urb->transfer_buffer_length < 0)
return -EMSGSIZE;
--------------------------------------------------------
#ifdef DEBUG
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
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;
case PIPE_CONTROL:
allowed |= URB_NO_FSBR;
default:
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
case PIPE_ISOCHRONOUS:
allowed |= URB_ISO_ASAP;
break;
}
urb->transfer_flags &= allowed;
if (urb->transfer_flags != orig_flags) {
err("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
}
#endif
--------------------------------------------------------
设置urb的interval域
********************************************************
switch (temp) {
case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
if (urb->interval <= 0)
return -EINVAL;
switch (dev->speed) {
case USB_SPEED_HIGH:
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
temp = 1024 * 8;
break;
case USB_SPEED_FULL:
case USB_SPEED_LOW:
if (temp == PIPE_INTERRUPT) {
if (urb->interval > 255)
return -EINVAL;
temp = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
temp = 1024;
}
break;
default:
return -EINVAL;
}
while (temp > urb->interval)
temp >>= 1;
urb->interval = temp;
}
********************************************************
return usb_hcd_submit_urb(urb, mem_flags);
}
urb参数是指向urb的指针,mem_flags参数与传递给kmalloc()函数参数的意义相同,它用于告知USB核心如何在此时分配内存缓冲区。
在提交urb到USB核心后,直到完成函数被调用之前,不要访问urb中的任何成员。
usb_submit_urb()在原子上下文和进程上下文中都可以被调用,mem_flags变量需根据调用环境进行相应的设置,如下所示。
l GFP_ATOMIC:在中断处理函数、底半部、tasklet、定时器处理函数以及urb完成函数中,在调用者持有自旋锁或者读写锁时以及当驱动将current->state修改为非 TASK_ RUNNING时,应使用此标志。
l GFP_NOIO:在存储设备的块I/O和错误处理路径中,应使用此标志;
l GFP_KERNEL:如果没有任何理由使用GFP_ATOMIC和GFP_NOIO,就使用GFP_ KERNEL。
如果usb_submit_urb()调用成功,即urb的控制权被移交给USB核心,该函数返回0;否则,返回错误号。
以上是关于usb_submit_urb的主要内容,如果未能解决你的问题,请参考以下文章