日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2023/12/2 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux usb声卡 submit urb,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中。這個將會在后面的學習中好好學習。

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。