zoukankan      html  css  js  c++  java
  • urb传输的代码分析【转】

    转自:http://blog.csdn.net/zkami/article/details/2503829

    urb传输的代码分析 
    如需引用,请注明出处blog.csdn.net/zkami 作者ZhengKui

    分配一个urb,并初始化之。返回这个urb的指针
    usb_alloc_urb(int iso_packets, gfp_t mem_flags) (core/message.c)
        ->urb = kmalloc(...);  分配一个urb
        ->usb_init_urb(urb); 初始化这个urb:初始化个字段为0,增加引用计数

    根据传输类型,填写urb的一些字段(usb.h)
    static inline void usb_fill_control_urb (struct urb *urb,
                         struct usb_device *dev,
                         unsigned int pipe,
                         unsigned char *setup_packet,
                         void *transfer_buffer,
                         int buffer_length,
                         usb_complete_t complete_fn,
                         void *context)
    static inline void usb_fill_int_urb (struct urb *urb,
                         struct usb_device *dev,
                         unsigned int pipe,
                         void *transfer_buffer,
                         int buffer_length,
                         usb_complete_t complete_fn,
                         void *context,
                         int interval)
    static inline void usb_fill_bulk_urb (struct urb *urb,
                          struct usb_device *dev,
                          unsigned int pipe,
                          void *transfer_buffer,
                          int buffer_length,
                          usb_complete_t complete_fn,
                          void *context)
    相 同:对于ctl/int/bulk这三种传输类型,在fill urb时都需要填充dev,pipe,transfer_buffer,transfer_buffer_length,complete, context 字段。其中pipe代表当前urb传输的管道,transfer_buffer
    代表当前urb传输的数据的起始地址,transfer_buffer_length是当前urb传输的数据长度,complete是当前urb处理完后调用的回调函数。
    不同:fill control urb时需要fill setup_packet字段,它指向一个setup包的起始地址
    fill int urb时要根据传输速度来fill interval字段

    提交urb。发出一个异步的传输请求,完成后将调用回调函数。在调用usb_submit_urb函数前必须正确的初始化urb, 最后urb的控制将返回给发出申请的dev driver。
    usb_submit_urb(struct urb *urb, gfp_t mem_flags) (core/urb.c)
        ->ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)[usb_pipeendpoint(urb->pipe)];
          根据pipe得到urb要连接到哪个ep的list中
        ->xfertype = usb_endpoint_type(&ep->desc);
          得到端点类型,并根据不同的类型进行设置,如填充urb的transfer_flags字段。
          如果是ISO传输,根据iso packet的数量(urb->number_of_packets),初始化每一个packet。     (urb->iso_frame_desc[n])
          如果是iso/int传输,根据端点速度类型设置urb->interval
        ->usb_hcd_submit_urb(urb, mem_flags)    (core/hcd.c)
          将提交的urb指派给合适的host controller driver,这里的HC遵守OHCI规范
            ->rh_urb_enqueue(hcd, urb); 如果是Root Hub,调用该函数
                ->rh_queue_status (hcd, urb); 如果是中断传输
                    ->usb_hcd_link_urb_to_ep(hcd, urb); 把urb挂到ep上
                    ->mod_timer(); 修改rh_timer polling的时间
                ->rh_call_control (hcd, urb); 如果是控制传输
                    ->usb_hcd_link_urb_to_ep(hcd, urb); 把urb挂到ep上
                      然后根据不同的standard request(ch9.h) Setup Packet的request域来确定len
                    ->ohci_hub_control(hcd,    typeReq, wValue, wIndex,tbuf, wLength)
                      通过操作根Hub寄存器来完成上层对根Hub发送的命令
                    ->usb_hcd_unlink_urb_from_ep(hcd, urb); 出错的话把urb从ep上脱链
                    ->usb_hcd_giveback_urb(hcd, urb, status); urb处理完后调用回调函数
            ->ohci_urb_enqueue(hcd, urb, mem_flags)    如果不是Root Hub,调用该函数
                -> ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) ohci-q.c
                   如果ep上挂有ed,直接返回。如果没有,则用参数pipe、interval以及ep.desc加工一个ed,将其挂在ep上并返回
                    -> ed_alloc (ohci, GFP_ATOMIC); (ohci-mem.c)分配一个struct ed
                    -> td_alloc (ohci, GFP_ATOMIC); (ohci-mem.c)分配一个struct td
                    -> ed_free(ohci, ed);     释放struct ed
                    -> usb_calc_bus_time() 计算传输一个拥有最大字节数的数据包所需要的时间(ms)
                    然后:设定info的各个域,(info其实就是OHCI Spec中定义的Endpoint Descriptor的Dword 0
                    详见P16 OHCI spec figure4-1)再将info赋给ed->hwInfo
                   然后: 根据端点的类型确定size(size决定该端点上挂载的td的数目,除实时端点上的td外,
                     其它端点上的td能够装载4K的数据)
                   接着: 给urb_priv_t分配空间,并为其上所挂载的td指针数组分配空间

                -> td_alloc (ohci, mem_flags); (ohci-mem.c)  分配ed中的每一个td
                -> usb_hcd_link_urb_to_ep(hcd, urb);    urb挂到ep的urb_list上
                -> ed_schedule (ohci, ed);
                   根据ed的类型将ed插入到HC相应队列中,并读/写HC的寄存器
                    -> balance (ohci, ed->interval, ed->load);
                    -> periodic_link(ohci, ed);
                -> usb_hcd_unlink_urb_from_ep(hcd, urb);
                -> td_submit_urb (ohci, urb);    将urb需要发送的数据安排到相应ed下的td队列中
                    -> td_fill(ohci, info, data, 4096, urb, cnt);

    message.c
    usb_interrupt_msg(...) 事实上调用的是usb_bulk_msg()
        ->usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout)
            -> usb_alloc_urb(0, GFP_KERNEL) 分配一个urb
            -> usb_fill_int_urb(urb, usb_dev, pipe, data, len,
                    usb_api_blocking_completion, NULL,
                    ep->desc.bInterval); 如果是int msg
            -> usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
                    usb_api_blocking_completion, NULL); 如果是bulk msg
            -> usb_start_wait_urb(urb, timeout, actual_length);
                   提交urb并等待完成或超时。将urb提交给usb core后就停在wait_for_completion_timeout()等待
               当这个urb完成后,会调用usb_api_blocking_completion()进而调用complete来通知不用再等了。
                ->usb_submit_urb(urb, GFP_NOIO) 提交urb
                ->wait_for_completion_timeout(&ctx.done, expire)) 等待。其中expire是等待的时间限
                  &ctx.done是等到了的话,调用的回调函数
                ->usb_kill_urb(urb) 如果超时就kill这个urb
    usb_control_msg(...)
        ->struct usb_ctrlrequest *dr = kmalloc(...)
            首先创建一个usb_ctrlrequest的数据结构(详见usb2.0 spec ch9),并初始化bRequestType,bRequest,wValue
          wIndex,wLength字段
        ->usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
            ->usb_alloc_urb(0, GFP_NOIO); 分配一个urb
            ->usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
                     len, usb_api_blocking_completion, NULL);
              填充这个ctl urb, usb_api_blocking_completion是回调函数 
            ->usb_start_wait_urb(urb, timeout, &length);
                  提交urb并等待完成或超时。将urb提交给usb core后就停在wait_for_completion_timeout()等待
              当这个urb完成后,会调用usb_api_blocking_completion()进而调用complete来通知不用再等了。
                ->usb_submit_urb(urb, GFP_NOIO) 提交urb
                ->wait_for_completion_timeout(&ctx.done, expire)) 等待。其中expire是等待的时间限
                  &ctx.done是等到了的话,调用的回调函数
                ->usb_kill_urb(urb) 如果超时就kill这个urb    

    如需引用,请注明出处blog.csdn.net/zkami 作者ZhengKui

  • 相关阅读:
    Linux内存管理 —— 为buddy做准备:MMU, TLB, ZONE【转】
    Linux内存管理 —— 文件系统缓存和匿名页的交换【转】
    linux内存源码分析
    Linux中匿名页的反向映射【转】
    zram 简介【转】
    Linux Swap 与 Zram 详解【转】
    Linux中的mmap映射 [一]【转】
    Linux中的mmap映射 [二]【转】
    python测试开发django-rest-framework-95.文件上传接口开发
    Airtest IDE 自动化测试8
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/4992197.html
Copyright © 2011-2022 走看看