本文轉(zhuǎn)自公眾號,歡迎關(guān)注
基于DWC2的USB驅(qū)動開發(fā)-設(shè)備類驅(qū)動框架 (qq.com)
一.前言
從軟件頂層,從數(shù)據(jù)流的角度來看USB的通訊,我們可以看到主要有兩類通訊,一類是”控制”相關(guān),一類是”數(shù)據(jù)流”相關(guān),前者一般通過控制端點0進(jìn)行,而后者通過接口綁定的其他端點進(jìn)行。其實這是一種常用的通訊設(shè)計范式,不是USB獨有,我們在其他自定義應(yīng)用協(xié)議設(shè)計時也可以參考。比如ftp協(xié)議,服務(wù)器即使用21命令端口建立連接,其他端口傳輸數(shù)據(jù),所以可以看到一些設(shè)計哲學(xué)都是相通的。
至于控制和數(shù)據(jù)流其實都是一個邏輯上的通道,管道的概念,不一定要物理區(qū)分。比如我們只有一個串口,可以定義串口幀,通過幀頭的標(biāo)志區(qū)分,就可以虛擬任意個邏輯管道。類似的USB設(shè)備的端點和主機(jī)的管道也是同樣的概念。
所以我們一定要有頂層思維模式,抽象思維模式,尤其對于USB復(fù)雜的應(yīng)用層協(xié)議,一定要理清楚其上層邏輯。在驅(qū)動編寫時只有摸清其框架,才能進(jìn)行抽象,才能進(jìn)行驅(qū)動程序的編寫。否則一上來就陷入到具體的設(shè)備的具體的協(xié)議內(nèi)容中很快就會迷失,驅(qū)動也會寫的不具備移植性。畢竟每一個設(shè)備類的規(guī)格書都有100頁以上,這么多設(shè)備,協(xié)議文檔就多如牛毛,更不用說里面涉及的各種細(xì)節(jié),所以有頂層框架性的理解很重要。比如對于UAC設(shè)備我們不需要一上來就去關(guān)注音量如何設(shè)置,而是先要了解其所有的屬性的操作是否有一定的框架即共性,是否可以抽象為編程的數(shù)據(jù)結(jié)構(gòu)模型,操作模型。否則雖然能直接根據(jù)手冊,一個字節(jié)一個字節(jié)解析,但是結(jié)果是對于每一個屬性都要這樣單獨解析,代碼將不具備通用性,且變得很冗余,不可維護(hù),增加一個屬性就需要改代碼,這不是驅(qū)動的設(shè)計方式,當(dāng)然一些小型的嵌入式系統(tǒng)沒有驅(qū)動層的考慮有可能也會這么直接做,但是那畢竟是特定應(yīng)用場景上的。
這一篇我們就從框架上,對我們后面要實現(xiàn)的設(shè)備協(xié)議棧進(jìn)行整體設(shè)計,主要是考慮好數(shù)據(jù)結(jié)構(gòu),和操作模型,至于細(xì)節(jié)后面邊寫驅(qū)動,邊調(diào)試設(shè)備,邊修改優(yōu)化。
二.框架設(shè)計
USB的設(shè)計初衷就是功能對應(yīng)接口,即一個功能對應(yīng)一個接口,接口里綁定端點,注意這里的端點是抽象概念比如終端和單元這些概念,邏輯上是一樣的。
但是隨著應(yīng)用的復(fù)雜化和功能需求的多元化,后面出現(xiàn)了多功能設(shè)備,比如一個攝像頭有視頻也有音頻既是攝像頭也是喇叭也可能是麥克風(fēng),那么就需要多個接口來對應(yīng)多個功能,于是UBS規(guī)范添加了IAD接口關(guān)聯(lián)描述符來聚合某個功能的接口。一個功能也不限制于一個接口了,也可能有多個接口,然后一個設(shè)備也可以有多個功能。
即由以下簡單的拓?fù)浣Y(jié)構(gòu)
變?yōu)榱艘韵赂鼜?fù)雜的拓?fù)浣Y(jié)構(gòu),多了一層IAD做功能聚合對應(yīng)一個功能,而IAD下面也可以有多個接口,接口下面有多個端點,注意這里的端點是抽象的概念,也可能是比如UVC里的終端和單元等。
那么看到上述圖形第一個想到的概念是什么呢,上述圖形就是一個鏈表結(jié)構(gòu),一層鏈接一層。
我們設(shè)備類驅(qū)動位于哪一層呢,從上可以看到設(shè)備類即對應(yīng)功能那么就是IAD這一層。
那么我們的設(shè)備類驅(qū)動框架就應(yīng)該是上圖改為如下
我們需要
定義驅(qū)動層實例,并提供接口可以綁定類實例
定義類層實例,并提供接口可以綁定接口實例
定義接口層實例,并提供接口可以綁定端口實例
定義端口實例,并提供接口可以綁定屬性實例
定義屬性實例,比如音量設(shè)置對應(yīng)的CS,數(shù)據(jù)長度,操作類似是GET還是SET,SET GET回調(diào)等
至此恭喜你已經(jīng)完成設(shè)備驅(qū)動框架的設(shè)計,看起來是多么的簡單簡潔,這就是抽象的威力,了解USB協(xié)議頂層邏輯很容易就抽象出該框架,并沒有復(fù)雜的思想和邏輯,也不需要使用復(fù)雜的技術(shù),要說到技術(shù)那么上面使用一個單向鏈表足矣。
三.數(shù)據(jù)結(jié)構(gòu)設(shè)計
上面我們對框架進(jìn)行了設(shè)計,也就是房屋的框架設(shè)計階段完成了,現(xiàn)在去構(gòu)建各個構(gòu)建了,比如類模型就可以對應(yīng)各個功能區(qū)怎么設(shè)計,比如地下室,停車場怎么設(shè)計,
接口模型則對應(yīng)具體的功能區(qū)內(nèi)的各個模塊的設(shè)計,比如停車場如何設(shè)計自動閘門,如何設(shè)計車位布局,端點模型就對應(yīng)具體車位的設(shè)計了,比如車位大小,標(biāo)志,附屬充電樁,編號等。
每個模型對應(yīng)的數(shù)據(jù)結(jié)構(gòu)的屬性和行為可能不同,但是有一點相同即都是通過單向鏈表連接同層實例,并且指向下一層鏈表。
比如對應(yīng)接口的設(shè)計
具體設(shè)計這里就不再講了,每個人自行設(shè)計時考慮,可以后面邊寫驅(qū)動邊完善,但是可以肯定的是一定包括以下幾個元素:
屬性部分
行為部分
指向下一個同層實例的指針
指向下一層實例的鏈表頭指針
比如如下對于設(shè)備類數(shù)據(jù)結(jié)構(gòu)的設(shè)計,即包含了上述4部分
/**
* struct usbd_dev_class
* 設(shè)備類節(jié)點
*/
typedef struct usbd_dev_class {
/* 屬性部分 */
uint8_t id;
char* name;
/* 行為部分 */
void (*init)(void *dwc);
void (*deinit)(void *dwc);
void (*setup)(void *dwc, ureq_t setup);
void (*setitf)(void *dwc, ureq_t setup);
/* 同級鏈接 */
struct usbd_dev_class* next;
/* 下一層鏈接 */
itf_t *itf_list;
} usbd_dev_class;
四.總結(jié)
以上進(jìn)行了設(shè)備類驅(qū)動框架性的設(shè)計,我們遵循自頂向下的設(shè)計思路,先設(shè)計框架,=然后再填充框架,當(dāng)然框架不可能一開始設(shè)計的就合理,我們后續(xù)實際調(diào)試具體的設(shè)備時可能發(fā)現(xiàn)需要修改,我們迭代即可,但是現(xiàn)在開始就需要考慮可擴(kuò)展性,以便將來迭代擴(kuò)展。
審核編輯 黃宇
-
usb
+關(guān)注
關(guān)注
60文章
7936瀏覽量
264454 -
驅(qū)動開發(fā)
+關(guān)注
關(guān)注
0文章
130瀏覽量
12072 -
驅(qū)動框架
+關(guān)注
關(guān)注
0文章
14瀏覽量
4033 -
DWC2
+關(guān)注
關(guān)注
0文章
35瀏覽量
125
發(fā)布評論請先 登錄
相關(guān)推薦
評論