13.3. USB 的 Urbs

2018-02-24 15:50 更新

13.3.?USB 的 Urbs

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

URB_ASYNC_UNLINK
如果置位, 給這個(gè) urb 的對(duì) usb_unlink_urb 的調(diào)用幾乎立刻返回, 并且這個(gè) urb 在后面被解除連接. 否則, 這個(gè)函數(shù)等待直到 urb 完全被去鏈并且在返回前結(jié)束. 小心使用這個(gè)位, 因?yàn)樗捎蟹浅ky于調(diào)試的同步問題.

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

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

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

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

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

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

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

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

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

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

usb_complete_t 類型定義如此:


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

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

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

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

這個(gè)變量的有效值包括:

0
這個(gè) urb 傳送是成功的.

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

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

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

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

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

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

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

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

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

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

-EOVERFLOW
這個(gè) urb 發(fā)生一個(gè)"babble"錯(cuò)誤. 一個(gè)"babble"錯(cuò)誤發(fā)生當(dāng)端點(diǎn)接受數(shù)據(jù)多于端點(diǎn)的特定最大報(bào)文大小.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

unsigned int length
這個(gè)報(bào)文的傳送緩沖的長度.

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

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

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

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


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

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

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

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


void usb_free_urb(struct urb *urb);

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

13.3.2.1.?中斷 urb

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


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

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

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

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

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

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

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

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

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

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

13.3.2.2.?塊 urb

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

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

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

13.3.2.3.?控制 urb

控制 urb 被初始化幾乎和 塊 urb 相同的方式, 使用對(duì)函數(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ù)都相同, 除了有個(gè)新參數(shù), unsigned char *setup_packet, 它必須指向要發(fā)送給端點(diǎn)的 setup 報(bào)文數(shù)據(jù). 還有, unsigned int pipe 變量必須被初始化, 使用對(duì) usb_sndctrlpipe 或者 usb_rcvictrlpipe 函數(shù)的調(diào)用.

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

13.3.2.4.?同步 urb

不幸的是, 同步 urb 沒有一個(gè)象中斷, 控制, 和塊 urb 的初始化函數(shù). 因此它們必須在驅(qū)動(dòng)中"手動(dòng)"初始化, 在它們可被提交給 USB 核心之前. 下面是一個(gè)如何正確初始化這類 urb 的例子. 它是從 konicawc.c 內(nèi)核驅(qū)動(dòng)中取得的, 它位于主內(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ū)動(dòng)初始化, 它已準(zhǔn)備好被提交給 USB 核心來發(fā)送出到 USB 設(shè)備. 這通過調(diào)用函數(shù) usb_submit_urb 實(shí)現(xiàn):


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

13.3.5.?取消 urb

為停止一個(gè)已經(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, 這個(gè) urb 的生命循環(huán)就停止了. 這個(gè)函數(shù)常常在設(shè)備從系統(tǒng)去除時(shí)被使用, 在去連接回調(diào)中.

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

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)