usb_submit_urb


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


取消 urb
        使用以下函數停止一個已經提交給 USB 核心的 urb: 
[cpp]  view plain copy
 
  1. void usb_kill_urb(struct urb *urb);  
  2. int usb_unlink_urb(struct urb *urb);   
        如果調用usb_kill_urb函數,則 urb 的生命周期將被終止. 這通常在設備從系統移除時,在斷開回調函數(disconnect callback)中調用.  對一些驅動, 應當調用 usb_unlink_urb 函數來使 USB 核心停止 urb. 這個函數不會等待 urb 完全停止才返回. 這對於在中斷處理例程中或者持有一個自旋鎖時去停止 urb 是很有用的, 因為等待一個 urb 完全停止需要 USB 核心有使調用進程休眠的能力(wait_event()函數).


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM