USB對於這個東西的規範是落在Communication Device Class內,縮寫就是CDC。以下都用CDC描述。因為CDC包含太多類別了,所以CDC規格書裡面有定義這些類別的對應規格:
RS232 over USB是屬於Abstract Control Model這個類別裡,所以請參考USBPSTN這個規格書吧,以下都會用CDC-ACM來代表RS232 over USB。
翻開PSTN規格書,它裡面定義了三種Model:
- Direct Line Control Model
- Abstract Control Model
- Telephony Control Model
接著就是如何寫CDC-ACM的descriptor了。請注意,CDC規格定義一個CDC裝置必須支援兩個Interface,一個Interface描述這個function所支援的功能,而另外一個則是描述資料傳輸的通道。然而,如果一個裝置宣告它支援兩個Interface,一般就表示它支援兩個function。這很明顯跟USB 2.0規範相衝突,所以IAD就上場啦。IAD全名是Interface Association Descriptor,它的功用就是拿來宣告某幾個interface其實是屬於同一個function,這樣就解決這個問題。IAD的規格現在已經包含在USB2.0之內,usb.org可以下載的到。
CDC規格有規定第一個interface要額外支援的descriptor:
- Header Functional Descriptor:沒甚麼特殊,照抄即可。
- Union Functional Descriptor :沒甚麼特殊,照抄即可。
- Country Selection Functional Descriptor:雖然說是必須的,但是好像不用提供也可以?
- Interrupt Endpoint Descriptor (Optional) :雖然說是非必須,但是最好要提供?
- Call Management Functional Descriptor:比較值得注意的是bmCapability這個欄位,其實都是0就可以了...。
- Abstract Control Management Functional Descriptor:一樣,比較值得注意的是bmCapability這個欄位,只要支援D1這個bit就可以,其他的就看要不要支援了。
而第二個Interface則是很簡單,它單純只是宣告資料傳輸的途徑:
- Standard Interface Descriptor
- Bulk-In Endpoint Descriptor
- Bulk-Out Endpoint Descriptor
如果只是要實作CDC-ACM,其實不用管SendEncapsulatedCommmand跟GetEncapsulatedResponse,因為不用支援AT command,所以Host根本就不會發這兩個Class Request。SetLineCoding、GetLineCoding、跟SetControlLineStatus則是要支援,因為我們在Abstract Control Management Functional Descriptor內的bmCapability欄位說有支援。
提供正確的descriptor給Host之後,Host就會認到你的CDC-ACM裝置,如果你用任何一個Terminal工具像是TeraTerm去開啟它的話,Host會透過SetLineCoding跟SetControlLineStatus去設定這個CDC-ACM的屬性,而你的裝置就應該可以開始傳輸資料了。運氣好的話,就可以在TeraTerm內看到一些字了。
市面上有蠻多便宜的CDC-ACM裝置,他們的主要缺點是,只要印多一點的字,就會開始印亂碼,我猜這主要是因為這些裝置通常內建記憶體很小,當從實體UART來的資料超多時,他們就會來不及把這些資料傳給Host,然後就開始掉字,如果很不幸,掉的是一些控制字元,就會出現亂碼了。便宜沒好貨啊。
10 comments:
現在才入坑 windows usb driver開發
windows document上都只剩下最新的WDF的function可用
請問PO主知不知道WDM版本的
書的話Amazon還是找的到啊?不然看微軟的線上說明應該也夠了:
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-wdm
我想請問 在driver的程式內 USB descriptor是不是只能 get 不能 set
我想讓我寫的virtual com driver被辨認為CDC
設定desciptor必須在Win32 app下嗎
你是要寫個虛擬的USB driver嗎?
這有點複雜耶,我記得要掛到某個bus driver上才可以。sample code這裡應該有
https://github.com/microsoft/Windows-driver-samples/tree/master/usb。
不過如果只是要寫個虛擬的comport driver,會比較簡單。虛擬的USB CDC driver感覺沒有甚麼好處。
感謝回覆
virtual comport driver我已經完成
我現在正在想辦法 讓實體裝置也能使用這份我寫的inf和sys
虛擬和實體comport應該差不了太多 (可能實體com port 會需要更多IRP處理? 但大部分IRP我已經處理完)
然後再想辦法 插入USB時能將此份 com port 辨認成 CDC USB (應該是開URB去拿Descriptor?)
我再慢慢研究QQ
等一下,不對啊,你的virtual comport driver是真的需要跟實體USB driver溝通的喔?如果是這樣的話,為什麼還要這樣做?要嘛它是個標準的USB CDC裝置,要嘛它不是。前者你不需要寫windows driver(Windows已經內建),後者你只要把你的virtual comport driver掛到USB bus driver上就好了啊,根本就不需要是CDC裝置,只要Windows認為它是個compport就好。
應該是後者喔
所以我只要將我的 virtual com port 掛在 windows usb bus driver上 windows 就會認為他是CDC USB 且辨識成comport嗎
https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-3-0-driver-stack-architecture
應該是掛在這裡的sys上?
另外我想問 我寫了Win32可以跟我的comport溝通 簡單的設定baudrate Line control 並且可以收發資料
那麼我想讓我丟資料到comA 上 然後能在comB上收到 兩個com port中間是不是還缺少 null modem
如果是跑在單個機器上的兩個virtual com port溝通應該叫 virtual null modem?
這部分應該是中間寫一個win32嗎? 還是也是在virtual com port裡的code實作呢?
阿抱歉
看起來Null modem的機制應該是實作在driver內
我用了com0com的 virtual com port 寫了Win32 app 去對配對起來的其中之一的comport作WriteFile的動作 另一個comport則是作 ReadFile的動作
發現資料有正確的流到另一端 猜測是裡面多create device object當上層bus並讓兩個port成為下層 藉此互通 當然可能還要實作很多 IOCTL細節
我自己再Trace code看看它到底做了什麼QQ
我還是不太懂你最後要做的東西到底是甚麼 :(
感覺你只是要弄個虛擬的comport driver然後作一些資料傳輸,但是其中是沒有真正的硬體存在的。這樣子的話要怎樣都可以啊。
是我沒有表達清楚
其實要做的目標不只一個
1.實現virtual com port 和 類似virtial modem的功能讓 一對com port互相傳輸
2.實現實體com port 並且可以資料傳輸
3.實現實體CDC USB 讓windows辨識其為virtual com port 並且可以資料傳輸
其實3 windows有內建Usbser 但我並不打算使用Usbser
而我現在只完成1的virtual com port 並驗證可以對com port丟資料 接下來是virtual modem讓com port形成pair使資料流通
Post a Comment