zoukankan      html  css  js  c++  java
  • 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) ",
                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 plaincopy
     
    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()函数).
  • 相关阅读:
    Java8基础学习之Object类
    Java8基础之equals方法和==的区别
    Spring集成ElasticSearch
    ElasticSearch常用的查询过滤语句
    数据库查看SQL执行计划
    数据库优化总结
    ElasticSearch之集群原理
    curl命令操作ElasticSearch总结
    ElasticSearch相关概念总结
    ElasticSearch基础入门
  • 原文地址:https://www.cnblogs.com/zxc2man/p/6650505.html
Copyright © 2011-2022 走看看