USB請求塊

来源:https://www.cnblogs.com/laoyaodada/archive/2018/02/01/8399169.html
-Advertisement-
Play Games

1 USB請求塊 USB請求塊是USB設備驅動中用來描述與USB設備通信所用的基本載體和核心數據結構。 2 URB處理流程 USB設備中的每個端點都處理一個URB隊列,在隊列被清空之前,一個URB的典型生命周期如下: (1)使用usb_alloc_urb來分配一個URB。 函數原形 struct u ...


1  USB請求塊

USB請求塊是USB設備驅動中用來描述與USB設備通信所用的基本載體和核心數據結構。

 1 /* include/linux/usb.h */
 2 struct urb {
 3     ...
 4     /* public: documented fields in the urb that can be used by drivers */
 5     struct list_head urb_list;  /* list head for use by the urb's
 6                      * current owner */
 7     ...
 8     struct usb_host_endpoint *ep;   /* (internal) pointer to endpoint */
 9     unsigned int pipe;      /* (in) pipe information */
10     unsigned int stream_id;     /* (in) stream ID */
11     int status;         /* (return) non-ISO status */
12     unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/
13     void *transfer_buffer;      /* (in) associated data buffer */
14     dma_addr_t transfer_dma;    /* (in) dma addr for transfer_buffer */
15     struct scatterlist *sg;     /* (in) scatter gather buffer list */
16     int num_mapped_sgs;     /* (internal) mapped sg entries */
17     int num_sgs;            /* (in) number of entries in the sg list */
18     u32 transfer_buffer_length; /* (in) data buffer length */
19     u32 actual_length;      /* (return) actual transfer length */
20     unsigned char *setup_packet;    /* (in) setup packet (control only) */
21     dma_addr_t setup_dma;       /* (in) dma addr for setup_packet */
22     int start_frame;        /* (modify) start frame (ISO) */
23     int number_of_packets;      /* (in) number of ISO packets */
24     int interval;           /* (modify) transfer interval
25                      * (INT/ISO) */
26     int error_count;        /* (return) number of ISO errors */
27     void *context;          /* (in) context for completion */
28     usb_complete_t complete;    /* (in) completion routine */
29     struct usb_iso_packet_descriptor iso_frame_desc[0];
30                     /* (in) ISO ONLY */
31 };

2  URB處理流程

USB設備中的每個端點都處理一個URB隊列,在隊列被清空之前,一個URB的典型生命周期如下:

(1)使用usb_alloc_urb來分配一個URB。

函數原形

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

函數參數

iso_packets:URB應當包含的等時數據包的數目,若為0表示不創建等時數據報

mem_flags:分配記憶體的標誌

返回值

成功:返回URB結構體指針;失敗:返回NULL

URB結構體在驅動中不宜靜態創建,因為這可能破壞USB核心給URB使用的引用計數方法。

釋放由urb_alloc_urb()分配的URB結構體的函數:

函數原形

void usb_free_urb(struct urb *urb);

(2)根據傳輸的類型填充URB。等時傳輸沒有相應的函數,需要手動來實現。

  • 對於中斷URB,使用usb_fill_int_urb()函數來初始化URB:

函數原形

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_fn, void *context, int interval);

函數參數

urb:指向要被初始化的URB指針

dev:指向這個URB要被髮送到的USB設備

pipe:是這個URB要被髮送到的USB設備的特定端點

transfer_buffer:是指向發送數據或接收數據的緩衝區的指針,必須使用kmalloc()來分配

buffer_length:是transfer_buffer指針所指向緩衝區的大小

complete_fn:指向當這個URB完成時被調用的完成處理函數

context:是完成處理函數的“上下文”

interval:是這個URB應當被調度的間隔

上述函數參數的pipe使用usb_sndintpipe()或usb_rcvintpipe()創建。

  • 對於批量URB,使用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_fn, void *context);

函數參數

參數和usb_fill_int_urb()相同

上述函數參數的pipe使用usb_sndbulkpipe()或usb_rcvbulkpipe()創建。

  • 對於控制URB,使用usb_fill_control_urb()函數來初始化:

函數原形

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_fn, void *context);

函數參數

參數和usb_fill_bulk_urb()相同

setup_packet:指向即將被髮送到端點的設置數據包

上述函數參數的pipe使用usb_sndctrlpipe()或usb_rcvictrlpipe()創建。

  • 對於等時URB沒有相應的初始化函數,只能手動對它初始化,而後才能提交給USB核心。

下麵是初始化等時URB的例子:

 1 /* drivers/media/usb/uvc/uvc_video.c */
 2 for (i = 0; i < UVC_URBS; ++i) {
 3     urb = usb_alloc_urb(npackets, gfp_flags);
 4     if (urb == NULL) {
 5         uvc_uninit_video(stream, 1);
 6         return -ENOMEM;
 7     }
 8 
 9     urb->dev = stream->dev->udev;
10     urb->context = stream;
11     urb->pipe = usb_rcvisocpipe(stream->dev->udev,
12             ep->desc.bEndpointAddress);
13 #ifndef CONFIG_DMA_NONCOHERENT
14     urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
15     urb->transfer_dma = stream->urb_dma[i];
16 #else
17     urb->transfer_flags = URB_ISO_ASAP;
18 #endif
19     urb->interval = ep->desc.bInterval;
20     urb->transfer_buffer = stream->urb_buffer[i];
21     urb->complete = uvc_video_complete;
22     urb->number_of_packets = npackets;
23     urb->transfer_buffer_length = size;
24 
25     for (j = 0; j < npackets; ++j) {
26         urb->iso_frame_desc[j].offset = j * psize;
27         urb->iso_frame_desc[j].length = psize;
28     }
29 
30     stream->urb[i] = urb;
31 }

(3)使用usb_submit_urb來提交一個URB來完成傳輸。(提交給URB核心)

在完成(1)、(2)步的創建和初始化URB後,URB便可以提交給USB核心了,可通過usb_submit_urb()函數來完成:

函數原形

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

函數參數

urb:指向URB的指針

mem_flags:用於告知USB核心如何在此時分配記憶體緩衝區,與kmalloc()參數一致,通常為GPF

返回值

成功:返回0;失敗:返回錯誤碼

usb_submit_urb()在原子上下文和進程上下文都可以被調用,mem_flags變數需根據調用環境進行相應的設置,如下所示:

  • GFP_ATOMIC:在中斷處理函數、底半部、tasklet、定時器處理函數以及URB完成函數中,在調用者持有自旋鎖或者讀寫鎖時以及當驅動將current->state修改為非TASK_RUNNING時,應使用此標誌。
  • GFP_NOIO:在存儲設備的塊I/O和錯誤處理路徑中,應使用此標誌。
  • GFP_KERNEL:如果沒有任何理由使用GFP_ATOMIC和GFP_NOIO,就使用GFP_KERNEL。

(4)提交由USB核心指定的USB主機控制器驅動。

(5)被USB主機控制器處理,進行一次到USB設備的傳送。

【溫馨提示】第(4)、(5)步由USB核心和主機控制器完成,不受USB設備驅動的控制。

(6)當URB完成,USB主機控制器驅動通知USB設備驅動。

在如下3種情況下,URB將結束,URB完成回調函數將被調用(完成回調是通過usb_fill_xxx_urb的參數傳入的)。在完成回調中,通常要進行urb->status判斷。

  • URB被成功發送給設備,並且設備返回正確的確認。如果urb->status為0,意味著對於一個輸出URB,數據被成功發送;對於一個輸入URB,請求的數據被成功收到。
  • 如果發送數據到設備或從設備接收數據時發送了錯誤,urb->status將記錄錯誤碼。
  • URB被從USB核心“去除連接”,這發生在驅動通過usb->unlink_urb()或usb_kill_urb()函數取消或URB雖已提交而USB設備被拔出的情況下。

下麵函數用於取消已提交的URB:

函數原形

int usb_kill_urb(struct urb *urb);

int usb_unlink_urb(struct urb *urb);

函數參數

urb:要取消的URB

【溫馨提示】usb_unlink_urb()是非同步的,搞定後對應的完成回調會被調用;而usb_kill_urb()會徹底終止URB的生命周期並等待這一行為,它通常在設備的disconnect()函數中被調用。

當URB生命結束時(處理完成或被解除鏈接),在URB的完成回調中通過URB結構體的status成員可以獲知其原因:

  • 0:表示傳輸成功;
  • -ENOENT:表示被usb_kill_urb()殺死;
  • -ECONNRESET:表示被usb_unlink_urb()殺死;
  • -EPROTO:表示傳輸中發生了bitstuff錯誤或者硬體未能及時收到響應數據包;
  • -ENODEV:表示USB設備已被移除;
  • -EXDEV:表示等時傳輸僅完成一部分等。

3  簡單的批量與控制URB

有時USB驅動程式只是從USB設備上接收或向USB設備發送一些簡單的數據,這時候,沒有必要將URB創建、初始化、提交、完成處理的整個流程走一遍,而可以使用更簡單的函數。

1usb_bulk_msg()

usb_bulk_msg()函數創建一個USB批量URB並將它們發送到特定的設備,這個函數是同步的,它一直等待URB完成後才返回。

函數原形

int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout);

函數參數

usb_dev:指向批量消息要發送的USB的設備指針

pipe:為批量消息要發送到的USB設備的端點

data:指向要發送或接收的數據緩衝區的指針

len:為data參數所指向的緩衝區的長度

actual_length:用於返回實際發送或接收的位元組數

timeout:發送超時,以jiffies為單位,0意味著永遠等待

返回值

成功:返回0;失敗:返回錯誤碼

2usb_control_msg()

usb_control_msg()函數與usb_bulk_msg()函數類似,不過它提供給驅動發送和結束USB控制信息而不是批量信息。

函數原形

int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);

函數參數

dev:指向控制消息發往的USB設備

pipe:是控制消息要發往的USB設備的端點

request:是這個控制消息的USB請求值

requesttype:是這個控制消息的USB請求類型

value:是這個控制消息的USB消息值

index:是這個控制消息的USB消息索引值

data:指向要發送或接收的數據緩衝區

size:是data參數所指向的緩衝區的大小

timeout:是發送超時,以毫秒為單位,0意味著永遠等待

返回值

成功:返回發送到設備或從設備接收到的位元組數;失敗:返回錯誤碼

【溫馨提示】對usb_bulk_msg()usb_control_msg()函數的使用要特別要慎重,usb_bulk_msg()usb_control_msg()是同步的,因此不能在中斷上下文和持有自旋鎖的情況下使用。而且,該函數也不能被任何其他函數取消,因此,務必要使得驅動程式的disconnect()函數掌握足夠的信息,以判斷和等待該調用的結束。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.echo 輸出字元,或者輸出變數的值。 2.date %Y:年; %m:月; %d:日; %H:小時,24小時制; %I:小時,12小時制; %M:分鐘; %S:秒; %F:年-月-日; %T:時-分-秒; -s:設置日期和時間; 3.reboot 重啟電腦。 4.poweroff 關機。 5 ...
  • 1. Oracle官網下載JDK linux安裝包,這裡使用的是【jdk-8u11-linux-i586.tar.gz】 註:下載前先用命令查看系統位數再下載對應位數的JDK【[root@localhost /]# getconf LONG_BIT】 2. 在 usr 文件夾下新增 java 文件夾 ...
  • 這裡介紹Linux下兩種安裝mysql的方式:yum安裝和源碼編譯安裝。 1. yum安裝 (1)首先查看centos自帶的mysql是否被安裝: (2)下載MySQL官網的yum倉庫:https://dev.mysql.com/downloads/repo/yum/, (3)使用mysql yum ...
  • shell 什麼是shell bash shell bash的配置文件 shell 登錄兩種方式 bash中的退出時的任務 ...
  • 編譯安裝 程式包編譯 編譯安裝 ...
  • I2C設備驅動要使用i2c_driver和i2c_client數據結構並填充i2c_driver中的成員函數。i2c_client一般被包含在設備的私有信息結構體xxx_data中,而i2c_driver則適合被定義為全局變數並初始化。下麵提供i2c_driver的初始化模版: 1 Linux I2 ...
  • 1 I2C子系統框架 Linux I2C子系統分成三部分:I2C核心層、I2C匯流排驅動和I2C設備驅動。 (1)I2C核心層 I2C核心提供了I2C匯流排驅動和設備驅動的註冊、註銷方法,I2C通信方法(即algorithm)上層的與具體適配器無關的代碼以及探測設備、檢測設備地址的上層代碼等。核心層的代 ...
  • 1 I2C匯流排 IIC匯流排由數據線SDA和時鐘線SCL兩條線構成通信線,既可以發送數據,又可以接收數據。 IIC匯流排典型電路:SDA和SCL連接線上有兩個上拉電阻,所有的IIC設備並聯在匯流排上。 2 I2C信號 IIC匯流排通信有著嚴格的時序,如果時序錯誤將會無法通信。IIC匯流排在傳送數據的過程中,有 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...