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;否則,返回錯誤號。