linux usb列表,linux usb urb详解

linux usb urb详解

谨以此文纪念过往的岁月

一.前言

在前文中看过了hub的驱动以及host的驱动还有usb设备的驱动,在把这些东西关联起来的东东中,一个很重要的urb(usb request blk),在本文中会详细来看urb的实现,以及具体的应用。

二.Urb

urb是什么东西,那先来看urb的定义吧。

1struct urb

2{

3/*私有的:只能由usb核心和主机控制器访问的字段*/

4struct kref kref; /*urb引用计数*/

5spinlock_t lock; /* urb锁*/

6void *hcpriv; /*主机控制器私有数据*/

7int bandwidth; /* int/iso请求的带宽*/

8atomic_t use_count; /*并发传输计数*/

9u8 reject; /*传输将失败*/

10

11/*公共的: 可以被驱动使用的字段*/

12struct list_head urb_list; /*链表头*/

13struct usb_device *dev; /*关联的usb设备*/

14unsigned int pipe; /*管道信息*/

15int status; /* urb的当前状态*/

16unsigned int transfer_flags; /* urb_short_not_ok | ...*/

17void *transfer_buffer; /*发送数据到设备或从设备接收数据的缓冲区*/

18dma_addr_t transfer_dma; /*用来以dma方式向设备传输数据的缓冲区*/

19int transfer_buffer_length;/*transfer_buffer或transfer_dma指向缓冲区的大小*/

20

21int actual_length; /* urb结束后,发送或接收数据的实际长度*/

22unsigned char *setup_packet; /*指向控制urb的设置数据包的指针*/

23dma_addr_t setup_dma; /*控制urb的设置数据包的dma缓冲区*/

24int start_frame; /*等时传输中用于设置或返回初始帧*/

25int number_of_packets; /*等时传输中等时缓冲区数据*/

26int interval; /* urb被轮询到的时间间隔(对中断和等时urb有效)*/

27int error_count;/*等时传输错误数量 */

28void *context; /* completion函数上下文*/

29usb_complete_t complete; /*当urb被完全传输或发生错误时,被调用*/

30struct usb_iso_packet_descriptor iso_frame_desc[0];

31/*单个urb一次可定义多个等时传输时,描述各个等时传输*/

32 };

2.1 urb申请

usb_alloc_urb开辟一个urb空间并对其部分的成员初始化。

iso_packets:等时传输的包数

mem_flags:开辟urb空间的mem旗标,一般为GFP_KERNEL

struct urb *usb_alloc_urb(int, gfp_t )

{

struct

urb *urb;

urb

= kmalloc(sizeof(struct urb) +iso_packets * sizeof(struct

usb_iso_packet_descriptor),

mem_flags);--开辟空间

if

(!urb) {

return

NULL;

}

usb_init_urb(urb);

--初始化部分成员

return

urb;

}

void usb_init_urb(struct urb *urb)

{

if

(urb) {

memset(urb,

0, sizeof(*urb));

kref_init(&urb->kref);--初始化urb计数器

INIT_LIST_HEAD(&urb->anchor_list);--初始化锁定链表

}

}

一般会在初始化之后,对urb的各个成员进行初始化。例如调用usb_fill_int_urb对urb进行成员的填充。在此不做讲述,这个还是比较简单的。

2.2 usb_submit_urb提交urb

int usb_submit_urb(struct urb *urb, gfp_t

mem_flags)

{

intxfertype, max;

struct

usb_device*dev;

struct

usb_host_endpoint*ep;

intis_out;

if

(!urb || urb->hcpriv || !urb->complete)

return

-EINVAL;

dev

= urb->dev;

if

((!dev) || (dev->state < USB_STATE_DEFAULT))

return

-ENODEV;

ep

= (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) [usb_pipeendpoint(urb->pipe)];

--查找设备端点

if

(!ep)

return

-ENOENT;

urb->ep

= ep;

urb->status

= -EINPROGRESS;

urb->actual_length

= 0;

xfertype

= usb_endpoint_type(&ep->desc);

if

(xfertype == USB_ENDPOINT_XFER_CONTROL) {--如果是控制类型

struct

usb_ctrlrequest *setup = (struct usb_ctrlrequest *) urb->setup_packet;

if

(!setup)

return

-ENOEXEC;

is_out

= !(setup->bRequestType & USB_DIR_IN) ||!setup->wLength;

}

else {

is_out

= usb_endpoint_dir_out(&ep->desc);

}

urb->transfer_flags

= (urb->transfer_flags & ~URB_DIR_MASK) | (is_out ? URB_DIR_OUT :

URB_DIR_IN);--缓存的方向留待后用

if

(xfertype != USB_ENDPOINT_XFER_CONTROL &&dev->state <

USB_STATE_CONFIGURED)--在设备没有配置前,传输的类型必为控制类型,唯有设备配置完成后才能传输其他类型的urb

return

-ENODEV;

max

= le16_to_cpu(ep->desc.wMaxPacketSize);

if

(max <= 0) {

return

-EMSGSIZE;

}

if

(xfertype == USB_ENDPOINT_XFER_ISOC) {--等时传输

intn, len;

if

(dev->speed == USB_SPEED_HIGH) {

intmult = 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;

switch

(xfertype) {--对等时传输和中断传输的等待时间进行检测

case

USB_ENDPOINT_XFER_ISOC:

case

USB_ENDPOINT_XFER_INT:

if

(urb->interval <= 0)

return

-EINVAL;

switch

(dev->speed) {

case

USB_SPEED_HIGH:

/*

NOTE usb handles 2^15 */

if

(urb->interval > (1024 * 8))

urb->interval

= 1024 * 8;

max

= 1024 * 8;

break;

case

USB_SPEED_FULL:

case

USB_SPEED_LOW:

if

(xfertype == USB_ENDPOINT_XFER_INT) {

if

(urb->interval > 255)

return

-EINVAL;

max

= 128;

}

else {

if

(urb->interval > 1024)

urb->interval

= 1024;

max

= 1024;

}

break;

default:

return

-EINVAL;

}

urb->interval

= min(max, 1 << ilog2(urb->interval));

}

return

(urb,

mem_flags);

}

int usb_hcd_submit_urb (struct urb *urb,

gfp_t mem_flags)

{

intstatus;

struct

usb_hcd*hcd =

bus_to_hcd(urb->dev->bus);

usb_get_urb(urb);

atomic_inc(&urb->use_count);--增减urb计数

atomic_inc(&urb->dev->urbnum);--增加dev的urb计数

usbmon_urb_submit(&hcd->self,

urb);--退化为空函数

status

= map_urb_for_dma(hcd, urb, mem_flags);--将urb的缓冲区与dma的区间映射

if

(unlikely(status)) {

usbmon_urb_submit_error(&hcd->self,

urb, status);

goto

error;

}

if

(is_root_hub(urb->dev))

status

= rh_urb_enqueue(hcd, urb);

else

status

= hcd->driver->urb_enqueue(hcd, urb, mem_flags);--将urb入队

if

(unlikely(status)) {

usbmon_urb_submit_error(&hcd->self,

urb, status);

unmap_urb_for_dma(hcd,

urb);

error:

urb->hcpriv

= NULL;

INIT_LIST_HEAD(&urb->urb_list);

atomic_dec(&urb->use_count);

atomic_dec(&urb->dev->urbnum);

if

(atomic_read(&urb->reject))

wake_up(&usb_kill_urb_queue);

usb_put_urb(urb);

}

return

status;

}

在函数usb_hcd_submit_urb调用该hcd的urb_enqueue,在ohci中将会调用ohci_urb_enqueue。其实到此我们需要放下urb的探索,重新来看ohci中关于ed,td的应用。在前文中对ohci的probe进行了讲述,但是对于其余的函数并没有仔细说明,那在后中仔细来看关于ohci的详情。

2.3usb_anchor_urb

当urb在处理的时候锁定。这个函数其实实现很简单就是将urb->anchor_list添加到anchor->urb_list中。关于该函数的具体实现我并不知道具体是做什么用的。

void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)

{

unsigned long flags;

spin_lock_irqsave(&anchor->lock,

flags);

usb_get_urb(urb);

list_add_tail(&,

&;

urb->anchor = anchor;

if

(unlikely(anchor->poisoned)) {

atomic_inc(&urb->reject);

}

spin_unlock_irqrestore(&anchor->lock,

flags);

}

2.4 usb_unanchor_urb

该函数与上面的函数刚好相反,解锁一个urb同时删除urb

void(struct urb *urb)

{

unsigned long flags;

struct usb_anchor

*anchor;

if (!urb)

return;

anchor =

urb->anchor;

if (!anchor)

return;

spin_lock_irqsave(&anchor->lock,

flags);

if (unlikely(anchor !=

urb->anchor)) {

spin_unlock_irqrestore(&anchor->lock,

flags);

return;

}

urb->anchor = NULL;

list_del(&urb->anchor_list);--将urb从anchor的链表中删除

spin_unlock_irqrestore(&anchor->lock,

flags);

usb_put_urb(urb);--减少urb计数同时删除urb == usb_free_urb

if

(list_empty(&anchor->urb_list))

(&anchor->wait);

}

void (struct urb *urb)

{

if (urb)

kref_put(&urb->kref,

urb_destroy);

}

在某一方面来讲anchor类似一个urb的守护链表,在urb被使用时是不能被删除的。在删除一个urb时需要调用usb_wait_anchor_empty_timeout来等待urb传输完全结束。下面的wait_event_timeout则与上面的wake_up相互对应。

int(struct

usb_anchor *anchor,unsigned int timeout)

{

return (anchor->wait,

list_empty(&anchor->urb_list),

msecs_to_jiffies(timeout));

}

三.总结

urb在某一方面来说是设备驱动与hcd的通信的东东,关于urb的处理其本质还是在ohci中。这个将会在后面的学习中好好学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值