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函数。