天天看點

usb-skeleton 代碼分析usb-skeleton 代碼分析

usb-skeleton 代碼分析

文章目錄

  • usb-skeleton 代碼分析
    • 驅動注冊
    • 主端探測函數 probe
    • 裝置操作集
      • 打開裝置
      • 關閉裝置
      • 寫操作
      • 讀操作
      • flush

usb-skeleton.c

是USB Host端代碼的一個骨架,如果想要編寫自己的Host端

bulk

傳輸的代碼,可以參考這個部分的代碼進行編寫,至于其他

isoc

的傳輸方式,可能還需要參考其他的驅動代碼進行編寫。

目前核心版本

linux-4.9.37

驅動注冊

使用

module_usb_driver

注冊HOST端驅動,聲明比對的gadget驅動清單(主要依賴VID與PID),完善相關的探測、斷開連接配接等函數:

usb-skeleton 代碼分析usb-skeleton 代碼分析

主端探測函數 probe

看一下

skel_probe

的第一部分裡面做了什麼:周遊接口的目前配置的所有端點,找到

bulk in

端點位址并申請

urb

傳輸描述符。

usb-skeleton 代碼分析usb-skeleton 代碼分析

一開始用到的

usb_skel

結構體如下,成員變量大部分都有注釋,主要的也增加了中文的注釋。

usb-skeleton 代碼分析usb-skeleton 代碼分析

再看一下第二部分的

skel_probe

,主要是執行一個

USB

裝置注冊,傳入一個

struct usb_class_driver

類型的

skel_class

usb-skeleton 代碼分析usb-skeleton 代碼分析

看一下

skel_class

的内容,主要關注是裝置的操作集合

skel_fops

usb-skeleton 代碼分析usb-skeleton 代碼分析

裝置操作集

看一下

skel_fops

的概況,主要關注打開、關閉、讀寫和

flush

函數。

usb-skeleton 代碼分析usb-skeleton 代碼分析

打開裝置

skel_open()

根據傳入的

inode

節點,找到次裝置号後,使用次裝置号找到對應的裝置接口,再從裝置接口中找到私有的

usb_skel

結構體指針,并儲存在

file

結構體中,友善後續

read/write

等函數使用。

usb-skeleton 代碼分析usb-skeleton 代碼分析

關閉裝置

skel_release()

主要作用是釋放資源。

usb-skeleton 代碼分析usb-skeleton 代碼分析

看一下

skel_delete()

,就是各種資源的釋放。

usb-skeleton 代碼分析usb-skeleton 代碼分析

寫操作

函數分為三個部分截圖,看第一部分,這裡主要就是一些參數的檢查,以及如果上一次傳輸錯誤的話直接報告出錯。

usb-skeleton 代碼分析usb-skeleton 代碼分析

看第二部分的工作就是申請

urb

,申請核心态的記憶體,并将使用者态的資料拷貝過來,填充

urb

的回調函數等資訊後送出給硬體控制器。

copy_form_user/copy_to_user

是比較耗時的工作,如果想要提高傳輸的效率,可以考慮将這個拷貝部分去掉,比如使用

mmap

方式;有些特殊情況可以更加友善,比如

MMZ

的記憶體可以直接将碼流的實體位址交給

USB

驅動,然後也不需要進行

DMA

映射,填充

urb

直接交給

USB

控制器,就可以進行傳輸,省略拷貝的過程速度提高是很可觀的。

usb-skeleton 代碼分析usb-skeleton 代碼分析

看第三部分主要是

urb

的釋放以及出錯處理。

usb-skeleton 代碼分析usb-skeleton 代碼分析

看一下填充

urb

時的回調函數

skel_write_bulk_callback()

,内容也比較簡單,如果有錯誤,儲存錯誤碼;釋放申請的一緻性記憶體。

usb-skeleton 代碼分析usb-skeleton 代碼分析

讀操作

讀操作和寫操作有些不一樣,我們一般的

read

操作是阻塞的,而

write

操作直接送出給USB控制器之後就可以了,而阻塞的

read

需要等待資料的回來并報告應用層。

這裡也分為兩部分,看第一部分,進行檢查相關的參數後,如果發現正在等待資料回來的過程,不是阻塞IO的則傳回

-EAGAIN

,阻塞IO的話則等待讀等待隊列的喚醒。

usb-skeleton 代碼分析usb-skeleton 代碼分析

第二部分就是根據使用者空間要讀取的資料和已經讀取到資料的數量,進行發起實際的IO操作。

usb-skeleton 代碼分析usb-skeleton 代碼分析
usb-skeleton 代碼分析usb-skeleton 代碼分析

看一下實際發起IO操作的函數

skel_do_read_io()

,也是填充

urb

并送出給控制器,以及私有的資料初始化。

usb-skeleton 代碼分析usb-skeleton 代碼分析

以及讀回調函數

skel_read_bulk_callback()

,與寫回掉函數的差異多了實際接收長度的記錄以及喚醒等待隊列。

usb-skeleton 代碼分析usb-skeleton 代碼分析

flush

至于這個

skel_flush()

函數,主要就是調用

skel_draw_down()

進行停止相關的傳輸,如果有錯誤的話将錯誤傳回。

usb-skeleton 代碼分析usb-skeleton 代碼分析

skel_draw_down()

函數等待以及送出的寫

urb

傳回,如果逾時則停止;同時停止讀的

urb

usb-skeleton 代碼分析usb-skeleton 代碼分析

至此整個代碼就基本分析完成了,關于控制器驅動部分,比較複雜,有機會再寫些文檔分析一下,其實這個代碼我進行修改來适配從端的驅動,目前從端的驅動也有修改,主要作用是将

MMZ

碼流從一端傳輸到另一端,中間的優化過程就是上面的省略拷貝的過程。

繼續閱讀