//将提交过来的urb 指派给合适的主机控制器驱动程序
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
/*
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{
return &hcd->self;
}
static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
{
return container_of(bus, struct usb_hcd, self);
}
*/
struct usb_host_endpoint *ep;
unsigned long flags;
if (!hcd)
return -ENODEV;
/*usbmon_urb_submit 就是与前面Greg 孕育出来的usb Monitor 有关的,如果你编译内核的时候没有配置上CONFIG_USB_MON,它就啥也不是,一个空函数,一具空壳。*/
usbmon_urb_submit(&hcd->self, urb);
/*
* Atomically queue the urb, first to our records, then to the HCD.
* Access to urb->status is controlled by urb->lock ... changes on
* i/o completion (normal or fault) or unlinking.
*/
// FIXME: verify that quiescing hc works right (RH cleans up)
spin_lock_irqsave (&hcd_data_lock, flags);
ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
[usb_pipeendpoint(urb->pipe)];
if (unlikely (!ep))
status = -ENOENT;
else if (unlikely (urb->reject))//目的端点为空的可能性太小了,所以加上了unlikely
status = -EPERM;
else switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
doit:
list_add_tail (&urb->urb_list, &ep->urb_list);
status = 0;
break;
case HC_STATE_SUSPENDED:
/* HC upstream links (register access, wakeup signaling) can work
* even when the downstream links (and DMA etc) are quiesced;let
* usbcore talk to the root hub.
*/
if (hcd->self.controller->power.power_state.event ==PM_EVENT_ON&& urb->dev->parent == NULL)
goto doit;
/* FALL THROUGH */
default:
status = -ESHUTDOWN;
break;
}
spin_unlock_irqrestore (&hcd_data_lock, flags);
if (status) {
INIT_LIST_HEAD (&urb->urb_list);
usbmon_urb_submit_error(&hcd->self, urb, status);
return status;
}
/* increment urb's reference count as part of giving it to the HCD
* (which now controls it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
urb = usb_get_urb (urb);//可以放心的增加urb 的引用计数了
atomic_inc (&urb->use_count);//将urb 的use_count 也增加1,表示urb 已经被HCD 接受了,正在被处理着。
if (urb->dev == hcd->self.root_hub) {
/* NOTE: requirement on hub callers (usbfs and the hub
* driver, for now) that URBs' urb->transfer_buffer be
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data.
*/
status = rh_urb_enqueue (hcd, urb);
goto done;
}
/* lower level hcd code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
/*
如果这个主机控制器支持DMA,可你却没有告诉它URB_NO_SETUP_DMA_MAP或URB_NO_TRANSFER_DMA_MAP 这两个标志,它就会认为你在urb 里没有提供DMA的缓冲区,就会调用dma_map_single将setup_packet 或transfer_buffer映射为DMA缓冲区。
*/
if (hcd->self.uses_dma) {
if (usb_pipecontrol (urb->pipe)&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (hcd->self.controller,urb->setup_packet,sizeof (struct usb_ctrlrequest),DMA_TO_DEVICE);
if (urb->transfer_buffer_length != 0&& !(urb->transfer_flags &URB_NO_TRANSFER_DMA_MAP))
urb->transfer_dma = dma_map_single (hcd->self.controller,urb->transfer_buffer,urb->transfer_buffer_length,usb_pipein (urb->pipe)? DMA_FROM_DEVICE: DMA_TO_DEVICE);
}
status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); //终于可以将urb 扔给具体的主机控制器驱动程序了
done:
if (unlikely (status)) {
urb_unlink (urb);
atomic_dec (&urb->use_count);
if (urb->reject)
wake_up (&usb_kill_urb_queue);
usbmon_urb_submit_error(&hcd->self, urb, status);
usb_put_urb (urb);
}
return status;
}