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;
/*如果是等时传输要做一些特别的处理,。前面提到interval 的时候,说过每一帧或微帧最多只能有一次等时传输,完成一次等时transaction,那时这么说主要是因为还没遇到高速高带宽的等时端点。高速高带宽等时端点每个微帧可以进行2 到3 次等时transaction*/
if (dev->speed == USB_SPEED_HIGH) {
int mult = 1 + ((max >> 11) & 0x03);
max &= 0x07ff;
max *= mult;
}
if (urb->number_of_packets <= 0)
return -EINVAL;
/*对等时urb 里指定的各次等时传输分别做处理。如果它们预期传输的数据长
度比上面算出来的max 还要大,对不起,要求太过分了,返回吧。然后将它们实际传输的
数据长度先置为0,状态都先初始化为-EXDEV,表示这次等时传输仅仅部分完成了
*/
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).
*/
//temp 是上面计算出来的管道类型
switch (temp) {
//这里只case 了等时传输和中断传输两种周期性
//的传输类型,因为是关于interval 的处理,所以就没控制传输和批量传输什么事儿了。
case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
/* too small? */
if (urb->interval <= 0)//这里保证等时和中断urb 的interval 必须是大于0 的
return -EINVAL;
/* 这里的switch 根据目的设备的速度去case,速度有三种,case 也有三个。不同的速度,urb->interval 可以取不同的范围,,不过你可能会发现那时说
的最大值要比这里的限制要大一些,这是因为协议归协议,实现归实现,比如,对于UHCI来说,中断传输的interval 不能比128 更大,而协议规定的最大值为255.*/
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 扔给HCD,然后就进入HCD 的片儿区了。
}
在调用usb_submit_urb提交你的urb之前,一定必须不得不要对它正确的初始化,对于控制/中断/批量传输,core都提供了usb_fill_control_urb的几个孪生兄弟供你初始化使用,对于等时传输要自己手工一步一步小心翼翼的对urb的相关元素逐个赋值.
第二,对于驱动来说,usb_submit_urb 是异步的,也就是说不用等传输完全完成就返回了,只要usb_submit_urb 的返回值表示为0,就表示已经提交成功了,你的urb 已经被
core 和HCD 认可了,接下来core 和HCD 怎么处理就是它们的事了.
第三个要说的是,对于控制/批量/中断传输,实际上很多时候你可以不用创建urb,不用对它初始化, 不用调用usb_submit_urb 来提交, core 将这个过程分别封装在了
usb_control_msg、usb_bulk_msg 和usb_interrupt_msg 这三个函数里,不同的是它们的实现是同步的,会去等待传输的完全结束。
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;
struct usb_host_endpoint *ep;
ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)
[usb_pipeendpoint(pipe)];
if (!ep || len < 0)
return -EINVAL;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT) {
pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
usb_fill_int_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL,
ep->desc.bInterval);
} else
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
return usb_start_wait_urb(urb, timeout, actual_length);
}
首先根据指定的pipe获得端点的方向和端点号,然后从设备struct usb_device结构体的ep_in或ep_out数组里得道端点对应的struct usb_host_endpoint结构体,接着调用usb_alloc_urb创建urb。因为这个函数可能是从usb_interrupt_msg 那里调用过来的, 所以接下来要根据端点描述符的bmAttributes字段获取传输的类型,判断究竟是中断传输还是批量传输,是中断传输的话还要修改pipe的类型。不管是中断传输还是批量传输,都要调用usb_fill_xxx_urb 来初始化, 最后, 和usb_control_msg 一样, 调用
usb_start_wait_urb函数。