Linux设备驱动程序笔记2—Urbs

13.3. USB Urbs

linux 内核中的 USB 代码和所有的 USB 设备通讯使用称为 urb 的东西( USB request block).这个请求块用 struct urb 结构描述并且可在 include/linux/usb.h 中找到.

一个 urb 用来发送或接受数据到或者从一个特定 USB 设备上的特定的 USB 端点, 以一种异步的方式. 根据驱动的需要,一个 USB 设备驱动可能分配许多 urb 给一个端点或者可能重用单个 urb 给多个不同的端点。

 

一个 urb 的典型生命循环如下:

·        被一个USB 设备驱动创建.

·        安排给一个特定USB 设备的特定端点.

·        提交给USB 核心,USB 设备驱动.

·        提交给特定设备的被USB 核心指定的USB 主机控制器驱动,.

·        USB 主机控制器处理,它做一个USB 传送到设备.

·        urb 完成,USB 主机控制器驱动通知USB 设备驱动.

13.3.1. struct urb

 

Struct urb定义在include/linux/usb.h(line1179-1215)中,对于每一个对象得具体功能在结构的头部有详细的解释:

struct urb {

       /*private: usb core and host controller only fields in the urb */

       structkref kref;          /* reference count ofthe URB */

       void*hcpriv;               /* private data forhost controller */

       atomic_tuse_count;         /* concurrentsubmissions counter */

       atomic_treject;         /* submissions will fail*/

       intunlinked;               /* unlink errorcode */

 

       /*public: documented fields in the urb that can be used by drivers */

       structlist_head urb_list;   /* list head for useby the urb's

                                    * current owner */

       structlist_head anchor_list;     /* the URB maybe anchored */

       structusb_anchor *anchor;

       structusb_device *dev;            /* (in)pointer to associated device */

       structusb_host_endpoint *ep; /* (internal)pointer to endpoint */

       unsignedint pipe;             /* (in) pipeinformation */

       unsignedint stream_id;            /* (in) streamID */

       intstatus;                   /* (return)non-ISO status */

       unsignedint transfer_flags;      /* (in)URB_SHORT_NOT_OK | ...*/

       void*transfer_buffer;        /* (in)associated data buffer */

       dma_addr_ttransfer_dma; /* (in) dma addr fortransfer_buffer */

       structscatterlist *sg;         /* (in) scattergather buffer list */

       intnum_sgs;               /* (in) number ofentries in the sg list */

       u32transfer_buffer_length;      /* (in) databuffer length */

       u32actual_length;             /* (return)actual transfer length */

       unsignedchar *setup_packet;  /* (in) setup packet(control only) */

       dma_addr_tsetup_dma;           /* (in) dma addr forsetup_packet */

       intstart_frame;          /* (modify) startframe (ISO) */

       intnumber_of_packets;           /* (in)number of ISO packets */

       intinterval;                /* (modify)transfer interval

                                    * (INT/ISO) */

       interror_count;          /* (return) numberof ISO errors */

       void*context;                   /* (in)context for completion */

       usb_complete_tcomplete;       /* (in) completion routine*/

       structusb_iso_packet_descriptor iso_frame_desc[0];

                                   /*(in) ISO ONLY */

};

 

13.3.2. 创建和注销 Urbs

struct urb结构在驱动程序中不能够动态创建,也不能在其他结构中创建,因为这可能破坏 USB 核心给 urb 使用的引用计数方法.它必须使用usb_alloc_urb 函数创建:

 
struct urb *usb_alloc_urb(int iso_packets, int mem_flags);

 

iso_packet:是urb 应当包含的同步报文的数目. 如果你不想创建一个同步 urb, 这个变量应当被设置为 0.

mem_flags:是传递给 kmalloc 函数,用来从内核分配内存的相同的标志类型

 

如果这个函数在分配足够内存给这个 urb 成功, 一个指向 urb 的指针被返回给调用者. 如果返回值是 NULL, 某个错误在 USB 核心中发生了, 并且驱动需要正确地清理.

 

为了告诉 USB 核心驱动用完这个 urb, 驱动必须调用 usb_free_urb 函数:

 

void usb_free_urb(struct urb *urb);

 

13.3.2.1 中断urbs

函数 usb_fill_int_urb 是一个辅助函数, 来正确初始化一个urb 来发送给 USB 设备的一个中断端点:

void usb_fill_int_urb(struct urb *urb,struct usb_device *dev,

 unsigned int pipe, void *transfer_buffer,

 intbuffer_length, usb_complete_t complete,

 void*context, int interval);

 

13.3.2.2 批量 urbs

批量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);

 

13.3.2.3 控制urbs

控制 urb 的初始化几乎和批量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_tcomplete, void *context);

 

参数定义:

struct urb *urb

指向要被初始化的 urb 的指针.

struct usb_device *dev

这个 urb 要发送到的 USB 设备.

unsigned int pipe

这个 urb 要被发送到的 USB 设备的特定端点. 这个值被创建, 使用前面提过的 usb_sndintpipe 或者usb_rcvintpipe 函数.

void *transfer_buffer

指向缓冲的指针, 从那里外出的数据被获取或者进入数据被接受. 注意这不能是一个静态的缓冲并且必须使用 kmalloc 调用来创建.

int buffer_length

缓冲的长度, 被 transfer_buffer 指针指向.

usb_complete_t complete

指针, 指向当这个 urb 完成时被调用的完成处理者.

void *context

指向数据块的指针, 它被添加到这个 urb 结构为以后被完成处理者函数获取.

int interval

这个 urb 应当被调度的间隔. 见之前的 struct urb 结构的描述, 来找到这个值的正确单位.

 

13.3.2.4 同步 urbs

同步 urb 没有一个象中断, 控制, 和块 urb 的初始化函数. 因此它们必须在驱动中"手动"初始化。以下例程从konicawc.c 内核驱动中取得的, 它位于主内核源码树的 drivers/usb/media 目录。

 

urb->dev = dev;

urb->context = uvd;

urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);

urb->interval = 1;

urb->transfer_flags = URB_ISO_ASAP;

urb->transfer_buffer = cam->sts_buf[i];

urb->complete = konicawc_isoc_irq;

urb->number_of_packets = FRAMES_PER_DESC;

urb->transfer_buffer_length = FRAMES_PER_DESC;

 

for (j=0; j < FRAMES_PER_DESC; j++) {

       urb->iso_frame_desc[j].offset = j;

       urb->iso_frame_desc[j].length = 1;

}

 

13.3.3. 提交 Urbs

一旦 urb 被正确创建并且被 USB 驱动初始化, 即可提交给 USB 核心来发送出到 USB 设备. 这通过调用函数 usb_submit_urb 实现:

 

intusb_submit_urb(struct urb *urb, int mem_flags);

 

urb:是一个指向 urb 的指针, 它要被发送到设备.

mem_flags 参数等同于传递给 kmalloc 调用的同样的参数, 并且用来告诉 USB 核心如何及时分配任何内存缓冲在这个时间,可用状态如下:

 

GFP_ATOMIC

This valueshould be used whenever the following are true:

The caller is within a urb completion handler, an interrupt, abottom half, a tasklet, or a timer callback.

The caller is holding a spinlock or rwlock. Note that if a semaphoreis being held, this value is not necessary.

The current->state is not TASK_RUNNING. The state is alwaysTASK_RUNNING unless the driver has changed the current state itself.

 

GFP_NOIO

This valueshould be used if the driver is in the block I/O patch. It should also be usedin the error handling path of all storage-type devices.

 

GFP_KERNEL

This should beused for all other situations that do not fall into one of the previouslymentioned categories.

 

13.3.5. 取消 Urbs

为停止一个已经提交给 USB 核心的 urb, 应当调用函数 usb_kill_urb 或者 usb_unlink_urb:

int usb_kill_urb(struct urb *urb);

int usb_unlink_urb(struct urb *urb);

当函数是 usb_kill_urb, 这个 urb 的生命循环就停止了. 通常当设备从系统中断开时,在断开回调函数时使用。

你可能感兴趣的:(Linux设备驱动程序笔记2—Urbs)