USB Core五

 

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


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值