13.3. USB 的 Urbs

2018-02-24 15:50 更新

13.3.?USB 的 Urbs

linux 內(nèi)核中的 USB 代碼和所有的 USB 設(shè)備通訊使用稱為 urb 的東西( USB request block). 這個請求塊用 struct urb 結(jié)構(gòu)描述并且可在 include/linux/usb.h 中找到.

一個 urb 用來發(fā)送或接受數(shù)據(jù)到或者從一個特定 USB 設(shè)備上的特定的 USB 端點, 以一種異步的方式. 它用起來非常象一個 kiocb 結(jié)構(gòu)被用在文件系統(tǒng)異步 I/O 代碼, 或者如同一個 struct skbuff 用在網(wǎng)絡(luò)代碼中. 一個 USB 設(shè)備驅(qū)動可能分配許多 urb 給一個端點或者可能重用單個 urb 給多個不同的端點, 根據(jù)驅(qū)動的需要. 設(shè)備中的每個端點都處理一個 urb 隊列, 以至于多個 urb 可被發(fā)送到相同的端點, 在隊列清空之前. 一個 urb 的典型生命循環(huán)如下:

  • 被一個 USB 設(shè)備驅(qū)動創(chuàng)建.

  • 安排給一個特定 USB 設(shè)備的特定端點.

  • 提交給 USB 核心, 被 USB 設(shè)備驅(qū)動.

  • 提交給特定設(shè)備的被 USB 核心指定的 USB 主機控制器驅(qū)動, .

  • 被 USB 主機控制器處理, 它做一個 USB 傳送到設(shè)備.

  • 當(dāng) urb 完成, USB 主機控制器驅(qū)動通知 USB 設(shè)備驅(qū)動.

urb 也可被提交這個 urb 的驅(qū)動在任何時間取消, 或者被 USB 核心如果設(shè)備被從系統(tǒng)中移出. urb 被動態(tài)創(chuàng)建并且包含一個內(nèi)部引用計數(shù), 使它們在這個 urb 的最后一個用戶釋放它時被自動釋放.

本章中描述的處理 urb 的過程是有用的, 因為它允許流和其他復(fù)雜的, 交疊的通訊以允許驅(qū)動來獲得最高可能的數(shù)據(jù)傳送速度. 但是有更少麻煩的過程可用, 如果你只是想發(fā)送單獨的塊或者控制消息, 并且不關(guān)心數(shù)據(jù)吞吐率.(見"USB 傳送不用 urb"一節(jié)).

13.3.1.?結(jié)構(gòu) struct urb

struct urb 結(jié)構(gòu)中和 USB 設(shè)備驅(qū)動有關(guān)的成員是:

struct usb_device *dev
指向這個 urb 要發(fā)送到的 struct usb_device 的指針. 這個變量必須被 USB 驅(qū)動初始化, 在這個 urb 被發(fā)送到 USB 核心之前.

unsigned int pipe
端點消息, 給這個 urb 要被發(fā)送到的特定 struct usb_device. 這個變量必須被 USB 驅(qū)動初始化, 在這個 urb 被發(fā)送到 USB 核心之前.

為設(shè)置這個結(jié)構(gòu)的成員, 驅(qū)動使用下面的函數(shù)是適當(dāng)?shù)? 依據(jù)流動的方向. 注意每個端點只可是一個類型.

unsigned int usb_sndctrlpipe(struct usb_device *dev, unsigned int endpoint)
指定一個控制 OUT 端點給特定的帶有特定端點號的 USB 設(shè)備.

unsigned int usb_rcvctrlpipe(struct usb_device *dev, unsigned int endpoint)
指定一個控制 IN 端點給帶有特定端點號的特定 USB 設(shè)備.

unsigned int usb_sndbulkpipe(struct usb_device *dev, unsigned int endpoint)
指定一個塊 OUT 端點給帶有特定端點號的特定 USB 設(shè)備

unsigned int usb_rcvbulkpipe(struct usb_device *dev, unsigned int endpoint)
指定一個塊 IN 端點給帶有特定端點號的特定 USB 設(shè)備

unsigned int usb_sndintpipe(struct usb_device *dev, unsigned int endpoint)
指定一個中斷 OUT 端點給帶有特定端點號的特定 USB 設(shè)備

unsigned int usb_rcvintpipe(struct usb_device *dev, unsigned int endpoint)
指定一個中斷 IN 端點給帶有特定端點號的特定 USB 設(shè)備

unsigned int usb_sndisocpipe(struct usb_device *dev, unsigned int endpoint)
指定一個同步 OUT 端點給帶有特定端點號的特定 USB 設(shè)備

unsigned int usb_rcvisocpipe(struct usb_device *dev, unsigned int endpoint)
指定一個同步 IN 端點給帶有特定端點號的特定 USB 設(shè)備

unsigned int transfer_flags
這個變量可被設(shè)置為不同位值, 根據(jù)這個 USB 驅(qū)動想這個 urb 發(fā)生什么. 可用的值是:

URB_SHORT_NOT_OK
當(dāng)置位, 它指出任何在一個 IN 端點上可能發(fā)生的短讀, 應(yīng)當(dāng)被 USB 核心當(dāng)作一個錯誤. 這個值只對從 USB 設(shè)備讀的 urb 有用, 不是寫 urbs.

URB_ISO_ASAP
如果這個 urb 是同步的, 這個位可被置位如果驅(qū)動想這個 urb 被調(diào)度, 只要帶寬允許它這樣, 并且在此點設(shè)置這個 urb 中的 start_frame 變量. 如果對于同步 urb 這個位沒有被置位, 驅(qū)動必須指定 start_frame 值并且必須能夠正確恢復(fù), 如果沒有在那個時刻啟動. 見下面的章節(jié)關(guān)于同步 urb 更多的消息.

URB_NO_TRANSFER_DMA_MAP
應(yīng)當(dāng)被置位, 當(dāng) urb 包含一個要被發(fā)送的 DMA 緩沖. USB 核心使用這個被 transfer_dma 變量指向的緩沖, 不是被 transfer_buffer 變量指向的緩沖.

URB_NO_SETUP_DMA_MAP
象 URB_NO_TRANSFER_DMA_MAP 位, 這個位用來控制有一個 DMA 緩沖已經(jīng)建立的 urb. 如果它被置位, USB 核心使用這個被 setup_dma 變量而不是 setup_packet 變量指向的緩沖.

URB_ASYNC_UNLINK
如果置位, 給這個 urb 的對 usb_unlink_urb 的調(diào)用幾乎立刻返回, 并且這個 urb 在后面被解除連接. 否則, 這個函數(shù)等待直到 urb 完全被去鏈并且在返回前結(jié)束. 小心使用這個位, 因為它可有非常難于調(diào)試的同步問題.

URB_NO_FSBR
只有 UHCI USB 主機控制器驅(qū)動使用, 并且告訴它不要試圖做 Front Side Bus Reclamation 邏輯. 這個位通常應(yīng)當(dāng)不設(shè)置, 因為有 UHCI 主機控制器的機器創(chuàng)建了許多 CPU 負擔(dān), 并且 PCI 總線被等待設(shè)置了這個位的 urb 所飽和.

URB_ZERO_PACKET
如果置位, 一個塊 OUT urb 通過發(fā)送不包含數(shù)據(jù)的短報文而結(jié)束, 當(dāng)數(shù)據(jù)對齊到一個端點報文邊界. 這被一些壞掉的 USB 設(shè)備所需要(例如一些 USB 到 IR 的設(shè)備) 為了正確的工作..

URB_NO_INTERRUPT
如果置位, 硬件當(dāng) urb 結(jié)束時可能不產(chǎn)生一個中斷. 這個位應(yīng)當(dāng)小心使用并且只在排隊多個到相同端點的 urb 時使用. USB 核心函數(shù)使用這個為了做 DMA 緩沖傳送.

void *transfer_buffer
指向用在發(fā)送數(shù)據(jù)到設(shè)備(對一個 OUT urb)或者從設(shè)備中獲取數(shù)據(jù)(對于一個 IN urb)的緩沖的指針. 對主機控制器為了正確存取這個緩沖, 它必須被使用一個對 kmalloc 調(diào)用來創(chuàng)建, 不是在堆棧或者靜態(tài)地. 對控制端點, 這個緩沖是給發(fā)送的數(shù)據(jù)階段.

dma_addr_t transfer_dma
用來使用 DMA 傳送數(shù)據(jù)到 USB 設(shè)備的緩沖.

int transfer_buffer_length
緩沖的長度, 被 transfer_buffer 或者 transfer_dma 變量指向(由于只有一個可被一個 urb 使用). 如果這是 0, 沒有傳送緩沖被 USB 核心所使用.

對于一個 OUT 端點, 如果這個端點最大的大小比這個變量指定的值小, 對這個 USB 設(shè)備的傳送被分成更小的塊為了正確的傳送數(shù)據(jù). 這種大的傳送發(fā)生在連續(xù)的 USB 幀. 提交一個大塊數(shù)據(jù)在一個 urb 中是非??? 并且使 USB 主機控制器去劃分為更小的快, 比以連續(xù)的順序發(fā)送小緩沖.

unsigned char *setup_packet
指向給一個控制 urb 的 setup 報文的指針. 它在位于傳送緩沖中的數(shù)據(jù)之前被傳送. 這個變量只對控制 urb 有效.

dma_addr_t setup_dma
給控制 urb 的 setupt 報文的 DMA 緩沖. 在位于正常傳送緩沖的數(shù)據(jù)之前被傳送. 這個變量只對控制 urb 有效.

usb_complete_t complete
指向完成處理者函數(shù)的指針, 它被 USB 核心調(diào)用當(dāng)這個 urb 被完全傳送或者當(dāng) urb 發(fā)生一個錯誤. 在這個函數(shù)中, USB 驅(qū)動可檢查這個 urb, 釋放它, 或者重新提交它給另一次傳送.(見"completingUrbs: 完成回調(diào)處理者", 關(guān)于完成處理者的更多細節(jié)).

usb_complete_t 類型定義如此:


typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);

void *context
指向數(shù)據(jù)點的指針, 它可被 USB 驅(qū)動設(shè)置. 它可在完成處理者中使用當(dāng) urb 被返回到驅(qū)動. 關(guān)于這個變量的細節(jié)見后續(xù)章節(jié).

int actual_length
當(dāng)這個 urb 被完成, 這個變量被設(shè)置為數(shù)據(jù)的真實長度, 或者由這個 urb (對于 OUT urb)發(fā)送或者由這個 urb(對于 IN urb)接受. 對于 IN urb, 這個必須被用來替代 transfer_buffer_length 變量, 因為接收的數(shù)據(jù)可能比整個緩沖大小小.

int status
當(dāng)這個 urb 被結(jié)束, 或者開始由 USB 核心處理, 這個變量被設(shè)置為 urb 的當(dāng)前狀態(tài). 一個 USB 驅(qū)動可安全存取這個變量的唯一時間是在 urb 完成處理者函數(shù)中(在"CompletingUrbs: 完成回調(diào)處理者"一節(jié)中描述). 這個限制是阻止競爭情況, 發(fā)生在這個 urb 被 USB 核心處理當(dāng)中. 對于同步 urb, 在這個變量中的一個成功的值(0)只指示是否這個 urb 已被去鏈. 為獲得在同步 urb 上的詳細狀態(tài), 應(yīng)當(dāng)檢查 iso_frame_desc 變量.

這個變量的有效值包括:

0
這個 urb 傳送是成功的.

-ENOENT
這個 urb 被對 usb_kill_urb 的調(diào)用停止.

-ECONNRESET
urb 被對 usb_unlink_urb 的調(diào)用去鏈, 并且 transfer_flags 變量被設(shè)置為 URB_ASYNC_UNLINK.

-EINPROGRESS
這個 urb 仍然在被 USB 主機控制器處理中. 如果你的驅(qū)動曾見到這個值, 它是一個你的驅(qū)動中的 bug.

-EPROTO
這個 urb 發(fā)生下面一個錯誤:

  • 一個 bitstuff 錯誤在傳送中發(fā)生.

  • 硬件沒有及時收到響應(yīng)幀.

-EILSEQ
在這個 urb 傳送中有一個 CRC 不匹配.

-EPIPE
這個端點現(xiàn)在被停止. 如果這個包含的端點不是一個控制端點, 這個錯誤可被清除通過一個對函數(shù) usb_clear_halt 的調(diào)用.

-ECOMM
在傳送中數(shù)據(jù)接收快于能被寫入系統(tǒng)內(nèi)存. 這個錯誤值只對 IN urb.

-ENOSR
在傳送中數(shù)據(jù)不能從系統(tǒng)內(nèi)存中獲取得足夠快, 以便可跟上請求的 USB 數(shù)據(jù)速率. 這個錯誤只對 OUT urb.

-EOVERFLOW
這個 urb 發(fā)生一個"babble"錯誤. 一個"babble"錯誤發(fā)生當(dāng)端點接受數(shù)據(jù)多于端點的特定最大報文大小.

-EREMOTEIO
只發(fā)生在當(dāng) URB_SHORT_NOT_OK 標志被設(shè)置在 urb 的 transfer_flags 變量, 并且意味著 urb 請求的完整數(shù)量的數(shù)據(jù)沒有收到.

-ENODEV
這個 USB 設(shè)備現(xiàn)在從系統(tǒng)中消失.

-EXDEV
只對同步 urb 發(fā)生, 并且意味著傳送只部分完成. 為了決定傳送什么, 驅(qū)動必須看單獨的幀狀態(tài).

-EINVAL
這個 urb 發(fā)生了非常壞的事情. USB 內(nèi)核文檔描述了這個值意味著什么:

ISO 瘋了, 如果發(fā)生這個: 退出并回家.

它也可發(fā)生, 如果一個參數(shù)在 urb 結(jié)構(gòu)中被不正確地設(shè)置了, 或者如果在提交這個 urb 給 USB 核心的 usb_submit_urb 調(diào)用中, 有一個不正確的函數(shù)參數(shù).

-ESHUTDOWN
這個 USB 主機控制器驅(qū)動有嚴重的錯誤; 它現(xiàn)在已被禁止, 或者設(shè)備和系統(tǒng)去掉連接, 并且這個urb 在設(shè)備被去除后被提交. 它也可發(fā)生當(dāng)這個設(shè)備的配置改變, 而這個 urb 被提交給設(shè)備.

通常, 錯誤值 -EPROTO, -EILSEQ, 和 -EOVERFLOW 指示設(shè)備的硬件問題, 設(shè)備固件, 或者連接設(shè)備到計算機的線纜.int start_frame
設(shè)置或返回同步傳送要使用的初始幀號.

int interval
urb 被輪詢的間隔. 這只對中斷或者同步 urb 有效. 這個值的單位依據(jù)設(shè)備速度而不同. 對于低速和高速的設(shè)備, 單位是幀, 它等同于毫秒. 對于設(shè)備, 單位是宏幀的設(shè)備, 它等同于 1/8 微秒單位. 這個值必須被 USB 驅(qū)動設(shè)置給同步或者中斷 urb, 在這個 urb被發(fā)送到 USB 核心之前.

int number_of_packets
只對同步 urb 有效, 并且指定這個 urb 要處理的同步傳送緩沖的編號. 這個值必須被 USB 驅(qū)動設(shè)置給同步 urb, 在這個 urb 發(fā)送給 USB 核心之前.

int error_count
被 USB 核心設(shè)置, 只給同步 urb 在它們完成之后. 它指定報告任何類型錯誤的同步傳送的號碼.

struct usb_iso_packet_descriptor iso_frame_desc[0]
只對同步 urb 有效. 這個變量是組成這個 urb 的一個 struct usb_iso_packet_descriptor 結(jié)構(gòu)數(shù)組. 這個結(jié)構(gòu)允許單個 urb 來一次定義多個同步傳送. 它也用來收集每個單獨傳送的傳送狀態(tài).

結(jié)構(gòu) usb_iso_packet_descriptor 由下列成員組成:

unsigned int offset
報文數(shù)據(jù)所在的傳送緩沖中的偏移(第一個字節(jié)從 0 開始).

unsigned int length
這個報文的傳送緩沖的長度.

unsigned int actual_length
接收到給這個同步報文的傳送緩沖的數(shù)據(jù)長度.

unsigned int status
這個報文的單獨同步傳送的狀態(tài). 它可采用同樣的返回值如同主 struct urb 結(jié)構(gòu)的狀態(tài)變量.

13.3.2.?創(chuàng)建和銷毀 urb

struct urb 結(jié)構(gòu)在驅(qū)動中必須不被靜態(tài)創(chuàng)建, 或者在另一個結(jié)構(gòu)中, 因為這可能破壞 USB 核心給 urb 使用的引用計數(shù)方法. 它必須使用對 usb_alloc_urb 函數(shù)的調(diào)用而被創(chuàng)建. 這個函數(shù)有這個原型:


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

第一個參數(shù), iso_packet, 是這個 urb 應(yīng)當(dāng)包含的同步報文的數(shù)目. 如果你不想創(chuàng)建一個同步 urb, 這個變量應(yīng)當(dāng)被設(shè)置為 0. 第 2 個參數(shù), mem_flags, 是和傳遞給 kmalloc 函數(shù)調(diào)用來從內(nèi)核分配內(nèi)存的相同的標志類型(見"flags 參數(shù)"一節(jié), 第 8 章, 關(guān)于這些標志的細節(jié)). 如果這個函數(shù)在分配足夠內(nèi)存給這個 urb 成功, 一個指向 urb 的指針被返回給調(diào)用者. 如果返回值是 NULL, 某個錯誤在 USB 核心中發(fā)生了, 并且驅(qū)動需要正確地清理.

在創(chuàng)建了一個 urb 之后, 它必須被正確初始化在它可被 USB 核心使用之前. 如何初始化不同類型 urb 見下一節(jié)

為了告訴 USB 核心驅(qū)動用完這個 urb, 驅(qū)動必須調(diào)用 usb_free_urb 函數(shù). 這個函數(shù)只有一個參數(shù):


void usb_free_urb(struct urb *urb);

參數(shù)是一個指向你要釋放的 struct urb 的指針. 在這個函數(shù)被調(diào)用之后, urb 結(jié)構(gòu)消失, 驅(qū)動不能再存取它.

13.3.2.1.?中斷 urb

函數(shù) usb_fill_int_urb 是一個幫忙函數(shù), 來正確初始化一個urb 來發(fā)送給 USB 設(shè)備的一個中斷端點:


void usb_fill_int_urb(struct urb *urb, struct usb_device *dev,
 unsigned int pipe, void *transfer_buffer,
 int buffer_length, usb_complete_t complete,
 void *context, int interval);

這個函數(shù)包含許多參數(shù):

struct urb *urb
指向要被初始化的 urb 的指針.

struct usb_device *dev
這個 urb 要發(fā)送到的 USB 設(shè)備.

unsigned int pipe
這個 urb 要被發(fā)送到的 USB 設(shè)備的特定端點. 這個值被創(chuàng)建, 使用前面提過的 usb_sndintpipe 或者 usb_rcvintpipe 函數(shù).

void *transfer_buffer
指向緩沖的指針, 從那里外出的數(shù)據(jù)被獲取或者進入數(shù)據(jù)被接受. 注意這不能是一個靜態(tài)的緩沖并且必須使用 kmalloc 調(diào)用來創(chuàng)建.

int buffer_length
緩沖的長度, 被 transfer_buffer 指針指向.

usb_complete_t complete
指針, 指向當(dāng)這個 urb 完成時被調(diào)用的完成處理者.

void *context
指向數(shù)據(jù)塊的指針, 它被添加到這個 urb 結(jié)構(gòu)為以后被完成處理者函數(shù)獲取.

int interval
這個 urb 應(yīng)當(dāng)被調(diào)度的間隔. 見之前的 struct urb 結(jié)構(gòu)的描述, 來找到這個值的正確單位.

13.3.2.2.?塊 urb

塊 urb 被初始化非常象中斷 urb. 做這個的函數(shù)是 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);

這個函數(shù)參數(shù)和 usb_fill_int_urb 函數(shù)的都相同. 但是, 沒有 interval 參數(shù)因為 bulk urb 沒有間隔值. 請注意這個 unsiged int pipe 變量必須被初始化用對 usb_sndbulkpipe 或者 usb_rcvbulkpipe 函數(shù)的調(diào)用.

usb_fill_int_urb 函數(shù)不設(shè)置 urb 中的 transfer_flags 變量, 因此任何對這個成員的修改不得不由這個驅(qū)動自己完成.

13.3.2.3.?控制 urb

控制 urb 被初始化幾乎和 塊 urb 相同的方式, 使用對函數(shù) usb_fill_control_urb 的調(diào)用:


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

函數(shù)參數(shù)和 usb_fill_bulk_urb 函數(shù)都相同, 除了有個新參數(shù), unsigned char *setup_packet, 它必須指向要發(fā)送給端點的 setup 報文數(shù)據(jù). 還有, unsigned int pipe 變量必須被初始化, 使用對 usb_sndctrlpipe 或者 usb_rcvictrlpipe 函數(shù)的調(diào)用.

usb_fill_control_urb 函數(shù)不設(shè)置 transfer_flags 變量在 urb 中, 因此任何對這個成員的修改必須游驅(qū)動自己完成. 大部分驅(qū)動不使用這個函數(shù), 因為使用在"USB 傳送不用 urb"一節(jié)中介紹的同步 API 調(diào)用更簡單.

13.3.2.4.?同步 urb

不幸的是, 同步 urb 沒有一個象中斷, 控制, 和塊 urb 的初始化函數(shù). 因此它們必須在驅(qū)動中"手動"初始化, 在它們可被提交給 USB 核心之前. 下面是一個如何正確初始化這類 urb 的例子. 它是從 konicawc.c 內(nèi)核驅(qū)動中取得的, 它位于主內(nèi)核源碼樹的 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.?提交 urb

一旦 urb 被正確地創(chuàng)建,并且被 USB 驅(qū)動初始化, 它已準備好被提交給 USB 核心來發(fā)送出到 USB 設(shè)備. 這通過調(diào)用函數(shù) usb_submit_urb 實現(xiàn):


int usb_submit_urb(struct urb *urb, int mem_flags);

urb 參數(shù)是一個指向 urb 的指針, 它要被發(fā)送到設(shè)備. mem_flags 參數(shù)等同于傳遞給 kmalloc 調(diào)用的同樣的參數(shù), 并且用來告訴 USB 核心如何及時分配任何內(nèi)存緩沖在這個時間.

在 urb 被成功提交給 USB 核心之后, 應(yīng)當(dāng)從不試圖存取 urb 結(jié)構(gòu)的任何成員直到完成函數(shù)被調(diào)用.

因為函數(shù) usb_submit_urb 可被在任何時候被調(diào)用(包括從一個中斷上下文), mem_flags 變量的指定必須正確. 真正只有 3 個有效值可用, 根據(jù)何時 usb_submit_urb 被調(diào)用:

GFP_ATOMIC
這個值應(yīng)當(dāng)被使用無論何時下面的是真:

  • 調(diào)用者處于一個 urb 完成處理者, 一個中斷, 一個后半部, 一個 tasklet, 或者一個時鐘回調(diào).

  • 調(diào)用者持有一個自旋鎖或者讀寫鎖. 注意如果正持有一個旗標, 這個值不必要.

  • current->state 不是 TASK_RUNNING. 狀態(tài)一直是 TASK_RUNNING 除非驅(qū)動已自己改變 current 狀態(tài).

GFP_NOIO
這個值應(yīng)當(dāng)被使用, 如果驅(qū)動在塊 I/O 補丁中. 它還應(yīng)當(dāng)用在所有的存儲類型的錯誤處理補丁中.

GFP_KERNEL
這應(yīng)當(dāng)用在所有其他的情況中, 不屬于之前提到的類別.

13.3.4.?完成 urb: 完成回調(diào)處理者

如果對 usb_submit_urb 的調(diào)用成功, 傳遞對 urb 的控制給 USB 核心, 這個函數(shù)返回 0; 否則, 一個負錯誤值被返回. 如果函數(shù)成功, urb 的完成處理者(如同被完成函數(shù)指針指定的)被確切地調(diào)用一次, 當(dāng) urb 被完成. 當(dāng)這個函數(shù)被調(diào)用, USB 核心完成這個 urb, 并且對它的控制現(xiàn)在返回給設(shè)備驅(qū)動.

只有 3 個方法, 一個urb 可被結(jié)束并且使完成函數(shù)被調(diào)用:

  • urb 被成功發(fā)送給設(shè)備, 并且設(shè)備返回正確的確認. 對于一個 OUT urb, 數(shù)據(jù)被成功發(fā)送, 對于一個 IN urb, 請求的數(shù)據(jù)被成功收到. 如果發(fā)生這個, urb 中的狀態(tài)變量被設(shè)置為 0.

  • 一些錯誤連續(xù)發(fā)生, 當(dāng)發(fā)送或者接受數(shù)據(jù)從設(shè)備中. 被 urb 結(jié)構(gòu)中的 status 變量中的錯誤值所記錄.

  • 這個 urb 被從 USB 核心去鏈. 這發(fā)生在要么當(dāng)驅(qū)動告知 USB 核心取消一個已提交的 urb 通過調(diào)用 usb_unlink_urb 或者 usb_kill_urb, 要么當(dāng)設(shè)備從系統(tǒng)中去除, 以及一個 urb 已經(jīng)被提交給它.

一個如何測試在一個 urb 完成調(diào)用中不同返回值的例子在本章稍后展示.

13.3.5.?取消 urb

為停止一個已經(jīng)提交給 USB 核心的 urb, 函數(shù) usb_kill_urb 或者 usb_unlink_urb 應(yīng)當(dāng)被調(diào)用:


int usb_kill_urb(struct urb *urb); 
int usb_unlink_urb(struct urb *urb);

The urb parameter for both of these functions is a pointer to the urb that is to be canceled.

當(dāng)函數(shù)是 usb_kill_urb, 這個 urb 的生命循環(huán)就停止了. 這個函數(shù)常常在設(shè)備從系統(tǒng)去除時被使用, 在去連接回調(diào)中.

對一些驅(qū)動, 應(yīng)當(dāng)用 usb_unlink_urb 函數(shù)來告知 USB 核心去停止 urb. 這個函數(shù)在返回到調(diào)用者之前不等待這個 urb 完全停止. 這對于在中斷處理或者持有一個自旋鎖時停止 urb 時是有用的, 因為等待一個 urb 完全停止需要 USB 核心有能力使調(diào)用進程睡眠. 為了正確工作這個函數(shù)要求 URB_ASYNC_UNLINK 標志值被設(shè)置在正被要求停止的 urb 中.

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號