1. 程式人生 > >Linux usb驅動開發(基礎)

Linux usb驅動開發(基礎)

最近想學幾個基於linux的驅動開發:(想想還是從usb驅動開始記錄,畢竟USB的驅動的開發的講解比較多,學習比較快)

(做個筆記,忘了就進來看看)

參考文件:文件寫的比較基礎:

https://blog.csdn.net/zqixiao_09/article/details/50984074

https://www.cnblogs.com/general001/articles/2319552.html

基礎知識:

USB體系:USB介面標準支援主機和外部裝置之間的資料傳輸,主機預定了各種型別外部裝置的匯流排頻寬,,外部裝置和主機正在執行時,可以新增,新增設定,使用外部裝置。可以分為USB互聯,USB主機,USB裝置,USB互聯是usb裝置和USB主機之間的通訊操作。USB系統中,有唯一的主機,USB和主機的介面稱為主機控制器,,USB裝置包括usb集線器和功能裝置,usb集線器的作用向匯流排提供多個連線點。

USB工作流程:採用輪詢方式控制,,主機控制設定初始化所有的資料傳輸,USB匯流排執行的傳輸動作最多傳輸3個數據包,每次傳輸開始:主機控制器傳送一個描述符描述傳輸侗族偶爾的種類和方向,,這個資料包稱為標誌資料包,,usb裝置收到資料包後,解析資料包。USB傳輸的方式:主機到裝置,裝置到主機,在一個數據傳輸開始,資料包標識傳輸方向,,傳送端傳送包含資訊的資料,接收端傳送一個握手資料標識是否傳輸成功。

USB主機控制器:提供OHCI,EHCI,UHCI匯流排介面,,usb核心部分連線了USB控制器和裝置驅動,

兩種型別的USB驅動:1:宿主上的驅動(host)2:裝置上的驅動(device)

宿主USB是指:控制插入其中的USB裝置,裝置驅動:表示該裝置作為一個USB裝置和主機通訊。

USB期間驅動“USB gadget drivers”

覺得該影象對USB裝置的結構描述很適合,就借用過來了。

一:USB裝置的基礎知識

裝置,配置,介面,端點。

我們從上往下看:(具體引數可檢視上面連結)

1.裝置描述符:一個usb只有一個裝置描述符,說明usb的總體的資訊,並指明配置的個數

結構體描述:struct usb_device_descriptor,

2.配置描述符:作用:介面本身被捆綁為配置,可以在配置之間切換改變裝置的狀態,主要用來說明配置特性和介面個數

結構體:struct usb_host_config

3.介面描述符:(相對比較重要)通俗的說是邏輯上的裝置,eg:usb攝像頭:就將各種不同的解析度設定為不同的介面,

將最終的端點捆綁為介面,

結構體:usb_interface_descriptor

4.端點描述符:主機和裝置之間的物理傳輸usb_endpoint_descriptor,usb中的每個端點都有唯一的端點號,傳輸方向也確定(或主機傳輸到裝置,裝置傳輸到主機,端點傳輸時單方向的)。裝置地址,端點號,傳輸方向就可以傳輸一個地址,

在這裡提出0端點,0端點比較特殊(不用配置就可以傳輸資料),只能用於傳輸控制單元,首先利用0端點與裝置進行通訊,得到usb的基本資訊,配置其他的端點。

端點的傳輸方式:1:控制:用於配置裝置,獲取裝置資訊,傳送命令到裝置,usb協議保證有足夠的頻寬傳輸資料到裝置,

2:中斷:中斷端點以一個固定的速錄傳輸少量的資料,,3:批量:傳輸大量資料(可確保傳輸資料,不確保傳輸時間,eg:儲存裝置),4:等時:傳輸大量資料(確保傳輸時間,不確保傳輸內容,eg:攝像頭)。

結構體:usb_endpoint_descriptor(該結構體由裝置自己定義:具體內容,可參考文件。)

5.最後一個基本概念:管道:usb主機軟體和usb裝置之間的連線,,是在usb配置過程中建立,是usb主機和裝置之間資料流的抽象,usb主機的資料緩衝區域usb裝置的端點之間存在著邏輯資料傳輸,實際的資料傳輸由匯流排介面完成,管道中的資料都是相互獨立的。

以上為最基礎的結構體:

接下來我們要說的是比較上層的資料結構體:也就是包含以上的基礎結構體,卻有增加了新的比較重要的功能(優化後的結構體):(從端點道介面的主機配置描述符)

1:端點描述:usb_host_endpoint

其中有一個比較重要的結構體 :struct list_head urb_list //此端點表示urb佇列

當usb裝置呼叫usb_submit_urb提交urb請求時將此urb新增到該連結串列的末尾。

2:介面描述:struct usb_host_interface :主機端的介面包裝器,用於解析介面設定描述符。用於描述介面本身的資訊,一個介面由多個設定,以及所使用的端點

struct usb_interface 其中有個結構體usb_host_interface *cur_altsetting,用於表示當前的世界設定介面。

3:配置描述:struct usb_host_config:配置所有的介面以及介面快取,配置描述符等引數。

4:通訊描述符:struct usb_skeleton是一個區域性的結構體:用於端點的通訊。

其中包括裝置資訊,介面描述,塊輸入端點,塊輸出端點。

以上為基本配置引數,以下為基本設定函式:

1:struct usb_device(基於匯流排驅動裝置描述符的:device)核心usb裝置的表示

其中:struct usb_device *parent//表示裝置從root hub開始一個個往外連,每個口連一個usb裝置,一個hub可以有多個口,一級級的往下連。

其中發現有兩處呼叫usb_device :usb_alloc_dev(usb.c分配一個dev usb_hcd主機控制器驅動)usb_set_configuaration(message.c設定一個特定裝置為當前裝置)

在hub.c的hub_thread。。hub_events。。hub_port_connect_change (處理物理邏輯和連線更改事件)。。時間中分配和建立一個dev結構體

2:struct usb_driver所有的usb驅動程式必須要建立的主結構體。,想usb戶型程式碼描述了usb驅動程式,(一般我們開發填充修改的是這個結構體)

採用usb_register註冊usb_driver結構體。

我們先談該結構體的id_table

其中包含的結構體:struct usb_device_id結構體,包含了該驅動可以支援的所有不同型別的usb的裝置,沒有該變數,usb驅動程式的探測函式將不會被呼叫,(*****一個驅動usb_driver可以對應多個裝置usb_device)熱插拔指令碼使用它來確定一個特定的裝置插入到系統時該自動掛載那一個驅動程式。

初始化usb_device_id結構體的巨集:USB_DEVICE(),和指定的製造商和ID匹配

USB_INTERFACE_INFO只和usb的制定型別相匹配,

使用初始化函式:MODULE_DEVICE_TABLE()容許使用者空間的工具判斷該驅動可以控制什麼裝置。

還用proble函式:usb驅動程式中的探測函式的指標,當usb核心認為有一個usb_interface可以由該驅動處理時,它將呼叫該函式,,usb核心用來判斷的指向usb_device_id的指標也被傳給該函式。(一個裝置被安裝而usb核心認為該驅動應該被處理)

disconnect函式:usb_interface被從系統中移除或者驅動程式從usb核心中解除安裝時被呼叫。(驅動程式因為某些原因不應該控制裝置時)。

proble和disconnect(探測和斷開的細節):

都是在USB集線器(usb_hub)核心執行緒的上下文被呼叫,其中的休眠合法(其中可以看hub.c的程式)(所以我們應該將探測函式時間減少),系統傳遞給探測函式兩個結構體:1:usb_interface Usb的介面描述符,2:usb_device_id作為引數,

注意:USB驅動程式應該初始化任何用於控制USB裝置的區域性結構體,並把任何裝置的相關資訊儲存到結構體中,:USB驅動程式需要探測裝置的端點地址和緩衝區大小,根據這些然後建立與usb驅動的通訊。(探測批量的IN和OUT端點)(eg:Usb_skeleton.c中的skel_probe函式中做了探測全部的IN和out端點的例程)

過程:1:迴圈訪問改介面中的每個端點,賦予該端點區域性指標,一遍稍後訪問:結構體引數

struct usb_host_interface *iface_desc;

usb_interface *interface

    iface_desc = interface->cur_altsetting;
    for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
        endpoint = &iface_desc->endpoint[i].desc;

檢視端點是輸入還是輸出:

        if (!dev->bulk_in_endpointAddr &&
            usb_endpoint_is_bulk_in(endpoint)) {}

        if (!dev->bulk_out_endpointAddr &&
            usb_endpoint_is_bulk_out(endpoint)) {

然後把該端點的相關資訊儲存到區域性結構體中,以便稍後的端點通訊。

把初始化的資料儲存到介面裝置中:usb_set_intfdata(interface,dev).用啦註冊一個data,這個data的結構是任意的,這個程式向核心註冊了一個usb_skel結構

得到裝置中的介面資訊:usb_get_intfdata()

基於上面的兩個函式,以上為我們的介面函式,

還有一種註冊usb裝置的方法:usb_register_dev(interface,&skel_class)USB驅動程式沒有和處理裝置與使用者互動的子系統,驅動程式可以使用USB主裝置號,一遍使用者空間使用傳統的字元驅動介面,(具體檢視上面的連線)。