本文分享一個CDC設備,?主機程序中set line coding錯誤的案例,?核心是對set line coding請求中的interface參數的理解錯誤。
由于特定需要,使用libusb進行CDC設備操作,而不是使用系統CDC驅動。
在set line coding時設備無響應。但是同樣的設備在windows下和linux使用系統的驅動都是沒有問題的。
對應如下代碼
r?= libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? USB_CDC_SET_LINE_CODING,?0, res->data_interface, coding,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??7,?1000);? ??if?(r?0) {? ? ? ? dbg("Failed to set line coding: %d\n",?r);? ? }
打印如下
Failed to set line coding: -7
錯誤碼在libusb.h中定義如下
/** Operation timed out */? ? LIBUSB_ERROR_TIMEOUT =?-7,
即控制傳輸超時。
抓包看到,如下,發送了8字節的SETUP和7字節的OUT數據之后,設備沒有響應。

設備在windows下和linux?使用系統驅動都是OK的那么就只能是這里上位機程序的問題,
只可能是發送的請求不對,這里對照下使用系統驅動時的抓包
SETUP內容是21 20 00 00?00?00 07 00
而上面錯誤時發送的是21 20 00 00?01?00 07 00
有一字節不一樣,那就來看看這個SETUP的含義,參考規格書
CDC1.2_WMC1.1_012011\CDC1.2_WMC1.1\usbcdc12\PSTN120.pdf

這里不一樣的就是對應的wIndex Interface這個字段,?那么問題就在于這個接口到底填寫什么接口。
相信很多人被上面的一段描述迷惑了
This request allows the host?to?specify typical asynchronous line-character formatting properties, which?may be required by some applications. This request applies?to?asynchronous byte stream data class??interfaces and endpoints; it also applies?to?data transfers both?from?the? host?to?the device and?from?the device?to?the host.?
尤其是This request applies to asynchronous byte stream data class interfaces and endpoints;這一句,感覺是:這個請求應用于異步字節流數據類接口和端點,那么應該就是對應的數據接口號了。實際這里理解錯誤了,描述也有誤導之嫌(話說USB規格書里很多描述確實不是很清楚,廢話很多但是含義不明確,沒有達到協議規格書的言簡意賅的目的),實際這里說的應該是這個請求的作用,會影響(應用到)數據接口和端點,而不是這個請求就是發給數據接口的。 實際這里明確的寫上Interface到底是哪個interface接口即可,而不是一大段文字描述但是意義又不明確,這一點來說USB規格書寫的并不好。
在以下可以看出該請求是屬于ACM模型的,而ACM模型是屬于控制接口中的,所以該請求是發給控制接口的

另外邏輯上理解,set line coding是設置串口通訊參數,各個數據接口理應是一樣的(不可能數據接口不一樣比如端點MPS不一樣就要不同的coding,比如停止位,這些和數據接口沒什么關系),只應該和控制接口有關。
所以修改代碼為如下改為發給控制接口即可
r = libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? USB_CDC_SET_LINE_CODING,?0, res->control_interface, coding,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??7,?1000);? ??if?(r 0) {? ? ? ? dbg("Failed to set line coding: %d\n", r);? ? ? ??//?goto?err;? ? }
以上問題其實很簡單,但是如果不熟悉的話很可能會耽誤很多時間去排查,所以這里作為案例分享,有遇到類似問題的一看就知道了。 其實這里就是澄清了一個問題set line coding是發給控制接口的而不是數據接口的。
這里也有一部分原因是usb規格書的描述并不是很精準,很多時候比較繁冗且含義不精確導致誤解,這里就需要多方參考,并從邏輯等維度去理解印證。