日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

linux usb声卡 submit urb,linux usb urb详解

發(fā)布時間:2023/12/2 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux usb声卡 submit urb,linux usb urb详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

linux usb urb詳解

謹(jǐn)以此文紀(jì)念過往的歲月

一.前言

在前文中看過了hub的驅(qū)動以及host的驅(qū)動還有usb設(shè)備的驅(qū)動,在把這些東西關(guān)聯(lián)起來的東東中,一個很重要的urb(usb request blk),在本文中會詳細(xì)來看urb的實現(xiàn),以及具體的應(yīng)用。

二.Urb

urb是什么東西,那先來看urb的定義吧。

1struct urb

2{

3/*私有的:只能由usb核心和主機(jī)控制器訪問的字段*/

4struct kref kref; /*urb引用計數(shù)*/

5spinlock_t lock; /* urb鎖*/

6void *hcpriv; /*主機(jī)控制器私有數(shù)據(jù)*/

7int bandwidth; /* int/iso請求的帶寬*/

8atomic_t use_count; /*并發(fā)傳輸計數(shù)*/

9u8 reject; /*傳輸將失敗*/

10

11/*公共的: 可以被驅(qū)動使用的字段*/

12struct list_head urb_list; /*鏈表頭*/

13struct usb_device *dev; /*關(guān)聯(lián)的usb設(shè)備*/

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

15int status; /* urb的當(dāng)前狀態(tài)*/

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

17void *transfer_buffer; /*發(fā)送數(shù)據(jù)到設(shè)備或從設(shè)備接收數(shù)據(jù)的緩沖區(qū)*/

18dma_addr_t transfer_dma; /*用來以dma方式向設(shè)備傳輸數(shù)據(jù)的緩沖區(qū)*/

19int transfer_buffer_length;/*transfer_buffer或transfer_dma指向緩沖區(qū)的大小*/

20

21int actual_length; /* urb結(jié)束后,發(fā)送或接收數(shù)據(jù)的實際長度*/

22unsigned char *setup_packet; /*指向控制urb的設(shè)置數(shù)據(jù)包的指針*/

23dma_addr_t setup_dma; /*控制urb的設(shè)置數(shù)據(jù)包的dma緩沖區(qū)*/

24int start_frame; /*等時傳輸中用于設(shè)置或返回初始幀*/

25int number_of_packets; /*等時傳輸中等時緩沖區(qū)數(shù)據(jù)*/

26int interval; /* urb被輪詢到的時間間隔(對中斷和等時urb有效)*/

27int error_count;/*等時傳輸錯誤數(shù)量 */

28void *context; /* completion函數(shù)上下文*/

29usb_complete_t complete; /*當(dāng)urb被完全傳輸或發(fā)生錯誤時,被調(diào)用*/

30struct usb_iso_packet_descriptor iso_frame_desc[0];

31/*單個urb一次可定義多個等時傳輸時,描述各個等時傳輸*/

32 };

2.1 urb申請

usb_alloc_urb開辟一個urb空間并對其部分的成員初始化。

iso_packets:等時傳輸?shù)陌鼣?shù)

mem_flags:開辟urb空間的mem旗標(biāo),一般為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計數(shù)器

INIT_LIST_HEAD(&urb->anchor_list);--初始化鎖定鏈表

}

}

一般會在初始化之后,對urb的各個成員進(jìn)行初始化。例如調(diào)用usb_fill_int_urb對urb進(jìn)行成員的填充。在此不做講述,這個還是比較簡單的。

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)];

--查找設(shè)備端點

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)--在設(shè)備沒有配置前,傳輸?shù)念愋捅貫榭刂祁愋?#xff0c;唯有設(shè)備配置完成后才能傳輸其他類型的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) {--對等時傳輸和中斷傳輸?shù)牡却龝r間進(jìn)行檢測

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計數(shù)

atomic_inc(&urb->dev->urbnum);--增加dev的urb計數(shù)

usbmon_urb_submit(&hcd->self,

urb);--退化為空函數(shù)

status

= map_urb_for_dma(hcd, urb, mem_flags);--將urb的緩沖區(qū)與dma的區(qū)間映射

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;

}

在函數(shù)usb_hcd_submit_urb調(diào)用該hcd的urb_enqueue,在ohci中將會調(diào)用ohci_urb_enqueue。其實到此我們需要放下urb的探索,重新來看ohci中關(guān)于ed,td的應(yīng)用。在前文中對ohci的probe進(jìn)行了講述,但是對于其余的函數(shù)并沒有仔細(xì)說明,那在后中仔細(xì)來看關(guān)于ohci的詳情。

2.3usb_anchor_urb

當(dāng)urb在處理的時候鎖定。這個函數(shù)其實實現(xiàn)很簡單就是將urb->anchor_list添加到anchor->urb_list中。關(guān)于該函數(shù)的具體實現(xiàn)我并不知道具體是做什么用的。

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

該函數(shù)與上面的函數(shù)剛好相反,解鎖一個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計數(shù)同時刪除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的守護(hù)鏈表,在urb被使用時是不能被刪除的。在刪除一個urb時需要調(diào)用usb_wait_anchor_empty_timeout來等待urb傳輸完全結(jié)束。下面的wait_event_timeout則與上面的wake_up相互對應(yīng)。

int(struct

usb_anchor *anchor,unsigned int timeout)

{

return (anchor->wait,

list_empty(&anchor->urb_list),

msecs_to_jiffies(timeout));

}

三.總結(jié)

urb在某一方面來說是設(shè)備驅(qū)動與hcd的通信的東東,關(guān)于urb的處理其本質(zhì)還是在ohci中。這個將會在后面的學(xué)習(xí)中好好學(xué)習(xí)。

總結(jié)

以上是生活随笔為你收集整理的linux usb声卡 submit urb,linux usb urb详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。