嵌入式技術(shù)干貨,及時送達(dá)
---
作者:論壇答疑助手楊老師
授權(quán)轉(zhuǎn)載于公眾號:柒零玖嵌入式(id:fengyuwuzu0519)有刪減修改。
USB(全稱 Universal Serial Bus,通用串行總線),已經(jīng)成為PC及嵌入式設(shè)備中最常用、最便捷的通信接口。Linux USB子系統(tǒng)較為龐大,本文主要對Linux系統(tǒng)下的USB總線驅(qū)動框架進(jìn)行概述,重點的細(xì)節(jié)待后續(xù)文章展開。
首先來看一個現(xiàn)象,插入USB設(shè)備后linux系統(tǒng)打印如下日志:
拔出后提示:usb 1-1: USB disconnect, address 2
如圖集線器(USB Root Hub)端兩條數(shù)據(jù)線(D+D-),都接有15K的下拉電阻,當(dāng)無設(shè)備接入時,集線器數(shù)據(jù)線D+D-的電壓為低電平。當(dāng)設(shè)備接入時,由于設(shè)備的數(shù)據(jù)線上接有1.5K上拉電阻,使得1根數(shù)據(jù)線被拉高。集線器根據(jù)數(shù)據(jù)線被拉高得知有設(shè)備接入,并根據(jù)D+為高還是D-為高來判斷所接入的設(shè)備是全速USB設(shè)備(D+為高)還是低速USB設(shè)備(D-為高)。
當(dāng)識別出有USB設(shè)備插入后,linux內(nèi)的USB總線驅(qū)動程序發(fā)出命令至該設(shè)備,與設(shè)備對話,并詢問設(shè)備信息(描述符),設(shè)備收到請求后,回復(fù)設(shè)備描述符給總線驅(qū)動程序。且總線驅(qū)動程序會為該設(shè)備分配一個地址,如上地址為2,當(dāng)后期訪問某個USB設(shè)備時,均會通過這個地址編號,當(dāng)新接入的USB設(shè)備被第一次訪問時,以地址0來訪問。當(dāng)USB總線驅(qū)動程序識別出設(shè)備后,會為其找到該USB設(shè)備驅(qū)動程序,如鍵盤,鼠標(biāo),U盤。
USB通信過程均為主從結(jié)構(gòu),USB主機(jī)發(fā)起通信請求,設(shè)備進(jìn)行數(shù)據(jù)回復(fù),USB設(shè)備不具備主動向主機(jī)通信的能力。
如上,我們大致了解了USB的簡單通信過程,那么什么是USB總線驅(qū)動程序?什么是USB設(shè)備驅(qū)動呢?
USB總線框架總結(jié)為如下圖:
USB Core這個模塊是純軟件部分,并不代表一個設(shè)備,是獨立于硬件的協(xié)議棧,它是所有USB設(shè)備賴以生存的模塊,即USB子系統(tǒng)的核心。代碼位于kernel/drivers/usb/core目錄下。
USB Core為設(shè)備驅(qū)動程序提供服務(wù),提供一個用于訪問和控制USB硬件的接口,而不用考慮系統(tǒng)當(dāng)前使用的哪種HOST Controller。USB Core將用戶的請求映射到相關(guān)的HCD,用戶不能直接訪問HCD。USB Core就是HCD與USB設(shè)備的橋梁。
其Makefile為:
硬件主機(jī)控制器Host Controller之上運行的是HCD,是對主機(jī)控制器硬件的一個抽象,實現(xiàn)核心層與控制器之間的對話接口,USB HCD包含多種USB接口規(guī)范:
(1)UHCI:Intel提供,通用主機(jī)控制接口,USB1.0/1.1;
(2)OHCI:微軟提供,開放主機(jī)控制接口,USB1.0/1.1;
(3)EHCI:增強(qiáng)主機(jī)控制接口,USB2.0;
USB設(shè)備是由一些配置(configuration)、接口(interface)和端點(endpoint)組成,,即一個USB設(shè)備可以含有一個或多個配置,在每個配置中可含有一個或多個接口,在每個接口中可含有若干個端點。一個USB設(shè)備驅(qū)動可能包含多個子驅(qū)動。一個USB設(shè)備子驅(qū)動程序?qū)?yīng)一個USB接口,而非整個USB設(shè)備。
USB設(shè)備使用各種描述符來說明其設(shè)備架構(gòu),包括設(shè)備描述符、配置描述符、接口描述符、端點描述符、字符串描述符。后面單獨討論USB設(shè)備描述符。
USB傳輸?shù)膶ο鬄槎它c(endpoint),每一個端點都有傳輸類型,傳輸方向,除了端點0外,每一個端點只支持一個方向的數(shù)據(jù)傳輸,端點0用于控制傳輸,既能輸出也能輸入。輸入(IN)、輸出(OUT) '都是' 基于USB主機(jī)的立場說的。比如鼠標(biāo)的數(shù)據(jù)是從鼠標(biāo)傳到PC機(jī), 對應(yīng)的端點稱為'輸入端點'。
USB的傳輸類型:
a. 控制傳輸:可靠,時間有保證,比如:USB設(shè)備的識別過程
b. 批量傳輸: 可靠, 時間沒有保證, 比如:U盤
c. 中斷傳輸:可靠,實時,比如:USB鼠標(biāo)
d. 實時傳輸:不可靠,實時,比如:USB攝像頭
針對不同類型的USB設(shè)備,需要實現(xiàn)特定的USB驅(qū)動程序。如HID(Human Interface Device), 屬于人機(jī)交互類的設(shè)備,如USB鼠標(biāo),USB鍵盤等。該類設(shè)備必須遵循HID設(shè)計規(guī)范。
在Linux內(nèi)核中,使用 struct usb_driver結(jié)構(gòu)體來描述一個USB驅(qū)動,通過usb_register在USB驅(qū)動中注冊進(jìn)內(nèi)核。
因此USB設(shè)備驅(qū)動開發(fā),主要包含如下兩個部分:
分配/設(shè)置usb_driver結(jié)構(gòu)體,實現(xiàn)并填充結(jié)構(gòu)體內(nèi)容
注冊usb_driver
后續(xù)將對USB鼠標(biāo)驅(qū)動進(jìn)行詳細(xì)分析,其代碼在kernel/drivers/hid/usbhid/usbmouse.c
通過以上分析,USB設(shè)備驅(qū)動模型可以概括為如下圖。
主要包含三個部分:USB控制器驅(qū)動,USB核心,USB設(shè)備驅(qū)動。如上圖khubd是USB守護(hù)進(jìn)程,當(dāng)USB設(shè)備插入的時候,守護(hù)進(jìn)程監(jiān)測到,USB主機(jī)控制器就會產(chǎn)生一個hub_irq中斷,控制器調(diào)用hub的探測函數(shù),來解析設(shè)備信息。
下面分析一下USB設(shè)備的識別過程。
以上顯示了設(shè)備插入到USB設(shè)備驅(qū)動被調(diào)用的函數(shù)流程,后面將拿出一章具體分析函數(shù)內(nèi)部實現(xiàn)來進(jìn)一步分析USB設(shè)備識別中做了哪些事情。
通過以上內(nèi)容,我們從整體上認(rèn)識了USB硬件識別過程,USB總線框架及USB設(shè)備驅(qū)動框架。后續(xù)會針對一些重點知識進(jìn)行專題分析。主要包括:
USB設(shè)備描述符解析
USB四類傳輸類型
USB數(shù)據(jù)包格式分析
USB鼠標(biāo)設(shè)備驅(qū)動代碼分析
USB初始化代碼分析
USB枚舉過程代碼分析