《Linux那些事儿之我是USB》我是U盘(23)传说中的urb--总结

(1)
“urb”,全称USB Request Block。USB设备需要通信,要传递数据,就需要使用urb,确切地说,应该是USB设备驱动程序使用urb。实际上,作为USB设备驱动,它本身并不能直接操纵数据的传输,在USB这个大观园里,外接设备永远都是配角,真正的核心只是USB Core,而真正负责调度的是USB主机控制。这个通常看不见的USB主机控制器芯片,俨然是USB大观园中的大管家。设备驱动要发送信息,所需要做的是建立一个urb数据结构,并把这个数据结构交给核心层,而核心层会为所有设备统一完成调度,而设备在提交了urb之后需要做的,只是等待
/* Initialize all the dynamic resources we need */
static int usb_stor_acquire_resources(struct us_data *us) 
{
    int p;
    struct task_struct *th; 
    us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
//等号左边us->current_urb,等号右边usb_alloc_urb()函数被调用。如果说struct us_data是usb mass storage中的主角,那么struct urb将毫无争议地成为整个USB子系统中的主角
    if (!us->current_urb) {
        usb_stor_dbg(us, "URB allocation failed\n");
        return -ENOMEM;
    }    
    /* Just before we start our control thread, initialize
     * the device if it needs initialization */
    if (us->unusual_dev->initFunction) {
        p = us->unusual_dev->initFunction(us);
        if (p)
            return p;
    }
//有些设备需要一些初始化函数,它就定义在unusual_devs.h文件中,而我们通过UNUSUAL_DEV的定义已经把这些初始化函数赋给了us->unusual_dev的initFunction指针了。
    /* Start up our control thread */
    th = kthread_run(usb_stor_control_thread, us, "usb-storage");
    if (IS_ERR(th)) {
        dev_warn(&us->pusb_intf->dev,
                "Unable to start control thread\n");
        return PTR_ERR(th);
    }
    us->ctl_thread = th;
    return 0;
}
struct urb {
    /* private: usb core and host controller only fields in the urb */
    struct kref kref;       /* reference count of the URB */
    void *hcpriv;           /* private data for host controller */
    atomic_t use_count;     /* concurrent submissions counter */
    atomic_t reject;        /* submissions will fail */
    int unlinked;           /* unlink error code */                                                                                                          
    /* public: documented fields in the urb that can be used by drivers */                                       
    struct list_head urb_list;  /* list head for use by the urb's                                                
                     * current owner */                                                                          
    struct list_head anchor_list;   /* the URB may be anchored */                                                
    struct usb_anchor *anchor;                                                                                   
    struct usb_device *dev;     /* (in) pointer to associated device */                                          
    struct usb_host_endpoint *ep;   /* (internal) pointer to endpoint */                                         
    unsigned int pipe;      /* (in) pipe information */                                                          
    unsigned int stream_id;     /* (in) stream ID */                                                             
    int status;         /* (return) non-ISO status */                                                            
    unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/                                             
    void *transfer_buffer;      /* (in) associated data buffer */                                                
    dma_addr_t transfer_dma;    /* (in) dma addr for transfer_buffer */                                          
    struct scatterlist *sg;     /* (in) scatter gather buffer list */                                            
    int num_mapped_sgs;     /* (internal) mapped sg entries */                                                   
    int num_sgs;            /* (in) number of entries in the sg list */                                          
    u32 transfer_buffer_length; /* (in) data buffer length */                                                    
    u32 actual_length;      /* (return) actual transfer length */                                                
    unsigned char *setup_packet;    /* (in) setup packet (control only) */                                       
    dma_addr_t setup_dma;       /* (in) dma addr for setup_packet */                                             
    int start_frame;        /* (modify) start frame (ISO) */
    int number_of_packets;      /* (in) number of ISO packets */
    int interval;           /* (modify) transfer interval
                     * (INT/ISO) */
    int error_count;        /* (return) number of ISO errors */
    void *context;          /* (in) context for completion */
    usb_complete_t complete;    /* (in) completion routine */
    struct usb_iso_packet_descriptor iso_frame_desc[0];
                    /* (in) ISO ONLY */
};
一个urb包含了执行USB传输所需要的所有信息。而作为驱动程序,要通信就必须创建这么一个数据结构,并且赋值,显然不同类型的传输,需要对urb赋不同的值,然后将她提交给底层,完了底层的USB Core会找到相应的USB主机控制器,从而具体实现数据的传输。传输完了之后,USB主机控制器会通知设备驱动程序。
调用usb_alloc_urb()申请了一个struct urb结构体。usb_alloc_urb()这个函数,它是USB Core所提供的一个函数,来自drivers/usb/core/urb.c,USB开发人员的确是给足了urb的面子,专门把和这个数据结构相关的代码整理在这么一个文件中了。
extern struct urb *usb_alloc_urb(intiso_packets, gfp_t mem_flags);
//为一个urb结构体申请内存。它有两个参数,其中第一个iso_packets用来在等时传输的方式下指定你需要传输多少个包,对于非等时模式来说,这个参数直接使用0。另一个参数mem_flags就是一个flag,表示申请内存的方式,这个flag将最终传递给kmalloc函数,我们这里传递的是GFP_KERNEL,usb_alloc_urb最终将返回一个urb指针,而us的成员current_urb也是一个struct urb的指针,所以就赋给它了。不过需要记住,usb_alloc_urb除了申请内存以外,还对结构体做了初始化,结构体urb被初始化为0,struct urb中还有一个引用计数,以及一个自旋锁,这些也同样被初始化了
那么设备和主机控制器的分工又是如何呢?在Linux中,设备驱动程序只要为每一次请求准备一个urb结构体变量,把它填充好(就是说赋上该赋的值),然后它调用USB Core提供的函数,把这个urb传递给主机控制器,主机控制器就会把各个设备驱动程序所提交的urb统一规划,去执行每一个操作。而这期间,USB设备驱动程序通常会进入睡眠,而一旦主机控制器把urb要做的事情给做完了,它会调用一个函数去唤醒USB设备驱动程序,然后USB设备驱动程序就可以继续往下走了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux技术芯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值