注意事項(Caveats)

 

設備復位

libusb_reset_device() 函數允許你復位一個設備。 如果你的程序已經調用了這個函數,需要注意的一點是復位將會導致設備狀態的改變(如:寄存器的值也許會被複位)。

問題在於任何時候任何其他的程序都可能會復位你的程序正在使用的設備。libusb並沒有提供當復位發生時可以通知你的機制 ,所以如果有其他人復位了你的設備,你自己的程序將不清楚爲什麼設備狀態改變了。

最後,這是一個在用戶空間編寫驅動所受的限制。由於來自位於低層內核的USB棧的隔離,使得系統很難傳遞這樣一個消息通知你的程序。Linux內核的 USB棧允許這樣一個復位 消息被傳遞給內核中的USB驅動,但是,如何將這樣的消息傳遞給存在於用戶空間的二級驅動仍沒有可行的方法。

阻塞操作

下面列出的功能僅能通過同步方式使用,屬於阻塞函數。沒有異步/非阻塞的方式,而且沒有什麼好的方法可以實現它們。

不支持熱拔插

libusb-1.0缺乏當設備插入或移除操作時提供通知的功能。這個功能計劃在libusb-1.1中實現。

這就是說,對於打開的設備句柄,只有基本的斷開處理:

  • 如果存在正在執行的傳輸, libusb的handle_events 循環將會檢測到斷開並且以LIBUSB_TRANSFER_NO_DEVICE狀態代碼結束正在執行的傳輸。
  • 很多函數如 libusb_set_configuration() 在當設備已經被斷開連接時,返回特定的 LIBUSB_ERROR_NO_DEVICE 錯誤代碼。

配置選擇和處理

當libusb爲一個程序提供了一個設備句柄,存在一種可能的情況,相應的設備處於爲配置狀態。多配置設備,同樣有一種可能當前選擇的配置並不是應用程序要使用的。

很明顯解決方法就是增加一個調用libusb_set_configuration() 在你的設備初始化例程,但是有以下注意事項:

  1. 如果設備已經處於所期望的配置,使用相同的配置調用libusb_set_configuration() 將會引起一個輕量級的復位。 這可能不是一個期望的行爲。
  2. 如果設備處於另一個配置並且其他程序或驅動已經在該配置下聲明瞭接口,libusb將不能改變配置。
  3. 在所期望的配置被啓用的情況下,libusb可能甚至不能執行一個輕量級的復位。例如,拿我帶指紋讀取功能的USB鍵盤來說:我很想使用libusb來驅動指紋讀取器 ,但是內核的USB-HID驅動幾乎總是已經聲明瞭鍵盤接口。由於內核已經聲明瞭一個接口,執行一個輕量級的復位甚至是不可能的。所以libusb_set_configuration() 將會失敗。 (幸運的是,有問題的設備只有一個單一配置)

一個解決以上問題的解決方案是考慮當前啓用的配置。如果當前是我們想要的配置,我們不需要選擇任何配置:

cfg = libusb_get_configuration(dev);

if (cfg != desired)

    libusb_set_configuration(dev, desired);

對大部分情況來說這也許時最適合的,但不是最好的:另一個應用程序或者驅動也許會在調用libusb_get_configuration() 改變被選擇的配置。

甚至在某些調用 libusb_set_configuration() 成功的情況下,想象其他的應用程序和驅動也許會在你的應用程序調用libusb_set_configuration()後改變配置。

一個可行的鎖定特定的配置的方法如下:

  1. 設置需要的配置 (或者使用上面提供的方法判斷已經是需要的配置)
  2. 聲明你希望使用的接口
  3. 檢查當前啓用的配置是否是你所期望使用的

以上的方法之所以有效是因爲一個接口一但被聲明,沒有應用程序或驅動可以選擇另一個配置。

提前的傳輸完成

注意: 這段是以Linux爲主的。我不確定是否適用於Darwin和其他平臺。.

當一個傳輸提前結束(例如:在任何一個包中,當少於傳輸緩衝區要求的數據被接收或者發送時),這種情況libusb被設計成直接結束傳輸,除非用戶將其他傳輸放置到隊列中,否則都不會再傳輸或者接收任何數據。

在原有的平臺, libusb在所有的平臺下都無法做到。在一個不完整的包出現後, "多餘的" 數據可能會被傳輸。在libusb v1.0.2之前,這個信息是丟失的(並且對於device-to-host 傳輸,相應的數據是被丟棄的)。 到了libusb v1.0.3,這個信息是被保留的。this information is kept (傳輸的數據長度會被更新) ,並且對於device-to-host傳輸,任何多餘的數據都會被增加到緩衝區。但是,這不是一個很好的解決方案,因爲它會丟失短數據包的結束信息。 而且,用戶可能想讓多餘的數據在下個邏輯傳輸時到達。

先前的解決方法只是提交大小爲16kb或者更少的數據。

等到libusb v1.0.4和Linux v2.6.32,這個問題被解決了。 對這一問題的技術解釋如下:

當你讓libusb提交體積大於16kb的塊傳輸時,libusb將它分解爲一系列更小的子傳輸。這是因爲usbfs內核接口只接受最大16kb的傳輸。這些子傳輸會被一次全部提交,以便於內核能在硬件層面上使其隊列化,因此是總線吞吐量最大化。

在原有平臺上, 在這一事件上當傳輸提前完成時會引起問題,內核將會結束所有在那個子傳輸中的將要到來的包 (但不是任何接下來的子傳輸)。libusb將會注意到這個事件,並且直接取消已經在隊列中的接下來的子傳輸 ,但是libusb通常並非足夠快,在libusb抽出時間去取消它們的時候,子傳輸很可能已經開始了

感謝usbfs的API擴展,最近的內核和libusb發佈版本修復了這個問題。這個解決方案允許libusb在邏輯層面的libusb-level間的傳輸時使用臨界區與內核通信。當一個短數據傳輸(或者其他錯誤) 發生時,在沒有允許這些傳輸開始前,內核將取消所有的子傳輸,直到臨界區結束。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章