当前位置:网站首页>USB URB

USB URB

2022-08-11 05:25:00 Emily_rong_2021

URB定义:

usb 请求块(usb request block, urb)是usb设备驱动中用来描述与usb设备通信所用的基本载体和核心数据结构,非常类似于网络设备驱动中的sk_buff结构体,是usb主机与设备通信的电波

  1. struct urb {  
  2.     /* private: usb core and host controller only fields in the urb */  
  3.     struct kref kref;        /* URB引用计数 */  
  4.     void *hcpriv;            /* host控制器的私有数据 */  
  5.     atomic_t use_count;        /* 当前提交计数 */  
  6.     atomic_t reject;        /* 提交失败计数 */  
  7.     int unlinked;            /* 连接失败代码 */  
  8.     /* public: documented fields in the urb that can be used by drivers */  
  9.     struct list_head urb_list;    /* list head for use by the urb's 
  10.                      * current owner */  
  11.     struct list_head anchor_list;    /* the URB may be anchored */  
  12.     struct usb_anchor *anchor;  
  13.     struct usb_device *dev;     /* 指向这个 urb 要发送的目标 struct usb_device 的指针,这个变量必须在这个 urb 被发送到 USB 核心之前被 USB 驱动初始化.*/  
  14.     struct usb_host_endpoint *ep;    /* (internal) pointer to endpoint */  
  15.     unsigned int pipe;        
  16.     int status;           
  17.     unsigned int transfer_flags;    /* 传输设置*/  
  18.     void *transfer_buffer;        /* 指向用于发送数据到设备(OUT urb)或者从设备接收数据(IN urb)的缓冲区指针。为了主机控制器驱动正确访问这个缓冲, 它必须使用 kmalloc 调用来创建, 不是在堆栈或者静态内存中。 对控制端点, 这个缓冲区用于数据中转*/  
  19.     dma_addr_t transfer_dma;    /* 用于以 DMA 方式传送数据到 USB 设备的缓冲区*/  
  20.     int transfer_buffer_length;    /* transfer_buffer 或者 transfer_dma 变量指向的缓冲区大小。如果这是 0, 传送缓冲没有被 USB 核心所使用。对于一个 OUT 端点, 如果这个端点大小比这个变量指定的值小, 对这个 USB 设备的传输将被分成更小的块,以正确地传送数据。这种大的传送以连续的 USB 帧进行。在一个 urb 中提交一个大块数据, 并且使 USB 主机控制器去划分为更小的块, 比以连续地顺序发送小缓冲的速度快得多*/  
  21.     int actual_length;        /* 当这个 urb 完成后, 该变量被设置为这个 urb (对于 OUT urb)发送或(对于 IN urb)接受数据的真实长度.对于 IN urb, 必须是用此变量而非 transfer_buffer_length , 因为接收的数据可能比整个缓冲小*/  
  22.     unsigned char *setup_packet;    /* 指向控制urb的设置数据包指针.它在传送缓冲中的数据之前被传送(用于控制 urb)*/  
  23.     dma_addr_t setup_dma;        /* 控制 urb 用于设置数据包的 DMA 缓冲区地址,它在传送普通缓冲区中的数据之前被传送(用于控制 urb)*/  
  24.     int start_frame;        /* 设置或返回初始的帧数量(用于等时urb) */  
  25.     int number_of_packets;          
  26.     int interval;            
  27.     int error_count;        /* 等时urb的错误计数,由USB核心设置 */  
  28.     void *context;            /* 指向一个可以被USB驱动模块设置的数据块. 当 urb 被返回到驱动时,可在结束处理例程中使用. */  
  29.     usb_complete_t complete;    /* 结束处理例程函数指针, 当 urb 被完全传送或发生错误,它将被 USB 核心调用. 此函数检查这个 urb, 并决定释放它或重新提交给另一个传输中*/  
  30.     struct usb_iso_packet_descriptor iso_frame_desc[0];  
  31.     };    

URB 处理流程

1, usb设备驱动程序创建初始化一个访问特定usb设备特定端点的urb,并提交给usb core

2, usb core提交该urb到usb主控制器驱动程序

3, usb主控制器驱动程序根据urb描述的信息,来访问usb设备

4,当设备访问结束后,usb主控制器驱动程序通知usb core(调用这个函数usb_complete_t complete;)然后其再通知usb设备驱动程序

创建URB

struct urb *usb_alloc_urb(int iso_packets, int mem_flags)

参数:

iso_packets 是这个urb 应当包含的等时数据包的数目,若为0 表示不创建等时数据包。
mem_flags 参数是分配内存的标志,和kmalloc()函数的分配标志参数含义相同。如果分配成功,该函数返回一个urb 结构体指针,否则返回0。
urb 结构体在驱动中不能静态创建,因为这可能破坏USB 核心给urb 使用的引用计数方法。

usb_alloc_urb()的“反函数”为:
void usb_free_urb(struct urb *urb);
该函数用于释放由usb_alloc_urb()分配的urb 结构体。

初始化URB

对于中断urb,使用usb_fill_int_urb函数来初始化:

static inline void usb_fill_int_urb (struct urb *urb,要初始化的urb指针。
                     struct usb_device *dev,所要访问的设备
                     unsigned int      pipe,要访问的端点所对应的管道,使用usb_sndintpipe()或usb_rcvintpipe()创建
                     void              *transfer_buffer,要传输的数据缓冲区
                     int               buffer_length,缓冲区长度
                     usb_complete_t    complete_fn,当完成该urb所请求的操作时,要调用的回调函数
                     void              *context,complet_fn函数所需的上下文,通常取值为dev
                     int               interval)urb被调度的时间间隔

管道:驱动程序的数据缓冲区与一个端点的连接,它代表了一种在两者之间移动数据的能力

对于批量urb,使用usb_fill_bulk_urb函数来初始化。

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,void *context);
除了没有对应于调度间隔的interval 参数以外,其他参数和usb_fill_int_urb()函数的参数含义相同。
pipe 使用usb_sndbulkpipe()或者usb_rcvbulkpipe()函数来创建。

对于控制urb,使用usb_fill_control_urb函数来初始化。

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, void *context);
除了增加了新的setup_packet 参数以外,其他参数和usb_fill_bulk_urb()函数的参数含义相同。setup_packet 参数指向即将被发送到端点的设置数据包。
上述函数参数中的pipe 使用usb_sndctrlpipe()或usb_rcvictrlpipe()函数来创建。

等时urb没有像中断,控制和批量urb那样的初始化函数,我们只能手动的初始化urb

提交URB

(3)被USB 设备驱动提交给USB 核心。
在完成第(1)、(2)步的创建和初始化urb 后,urb 便可以提交给USB 核心,通过usb_submit_urb()函数来完成,如下所示:
int usb_submit_urb(struct urb *urb, int mem_flags);
urb 参数是指向urb 的指针,mem_flags 参数与传递给kmalloc()函数参数的意义相同,它用于告知USB 核心如何在此时分配内存缓冲区。
在提交urb 到USB 核心后,直到完成函数被调用之前,不要访问urb 中的任何成员


usb_submit_urb()在原子上下文和进程上下文中都可以被调用,mem_flags 变量需根据调用环
境进行相应的设置,如下所示。
GFP_ATOMIC:在中断处理函数、底半部、tasklet、定时器处理函数以及urb 完成函数中,在调用者持有自旋锁或者读写锁时以及当驱动将current→state 修改为非 TASK_RUNNING 时,应使用此标志。
GFP_NOIO:在存储设备的块I/O 和错误处理路径中,应使用此标志;
GFP_KERNEL:如果没有任何理由使用GFP_ATOMIC 和GFP_NOIO,就使用GFP_KERNEL。

如果usb_submit_urb()调用成功,即urb 的控制权被移交给USB 核心,该函数返回0;否则,
返回错误号。
(4)提交由USB 核心指定的USB 主机控制器驱动
(5)被USB 主机控制器处理,进行一次到USB 设备的传送。
第(4)~(5)步由USB 核心和主机控制器完成,不受USB 设备驱动的控制。
(6)当urb 完成,USB 主机控制器驱动通知USB 设备驱动

在如下3 种情况下,urb 将结束,urb 完成函数将被调用。
1、urb 被成功发送给设备,并且设备返回正确的确认。如果urb→status 为0,意味着对于一个输出urb,数据被成功发送;对于一个输入urb,请求的数据被成功收到。
2、如果发送数据到设备或从设备接收数据时发生了错误,urb→status 将记录错误值。
3、urb 被从USB 核心“去除连接”,这发生在驱动通过usb_unlink_urb()或usb_kill_urb()函数取消urb,或urb 虽已提交,而USB 设备被拔出的情况下。

当urb 生命结束时(处理完成或被解除链接),通过urb 结构体的status 成员可以获知其原因,
如0 表示传输成功,

-ENOENT 表示被usb_kill_urb()杀死,

-ECONNRESET 表示被usb_unlink_urb()杀死,

-EPROTO 表示传输中发生了bitstuff 错误或者硬件未能及时收到响应数据包,

-ENODEV表示USB 设备已被移除,-EXDEV 表示等时传输仅完成了一部分等。

 处理URB:

来源:

 USB URB_君子当自强不息-CSDN博客_usb的urb

 URB(USB request block)_平常心的专栏-CSDN博客_usb_request

原网站

版权声明
本文为[Emily_rong_2021]所创,转载请带上原文链接,感谢
https://blog.csdn.net/Emily_rong_2021/article/details/122543904