1. 前言
2. 源碼架構
3. 枚舉過程
1. 前言
Gadget,小飾品。USB Gadget,就是指所開發的電子裝置以USB從裝置的模式通過USB串連到主機。比如手機用USB線插入PC後,手機就是USB Gadget。本文以Mavell為例,以Gadget插入主機的全過程為主線,分析USB Gadget的架構。
2. 源碼架構
USB的源碼位於/drivers/usb檔案夾內,其中包括核心層core,主控制器host,隨身碟storage,以及USB Gadget等。
gadget檔案夾裡存放了各晶片廠商支援的USB Gadget控制器驅動,比如支援Mavell的PXA9XX系列的USB Gadget驅動為mv_gadget.c,其架構如下圖所示,
2.1 Gadget控制器驅動
裝置要有gadget功能,硬體上要整合gadget控制器,軟體上要具備gadget控制器驅動。
首先是該驅動的資料結構 struct mv_usb_dev,
-> struct usb_gadget, 由linux定義的gadget所需要的資料成員,其中包含了sturct usb_ep。
-> struct mv_usb_ep, 其中的struct usb_ep是由linux定義的endpoint所需要的成員,關於endpoint參看USB協議。
-> struct usb_gadget_driver, 對應該gadget裝置功能的驅動,下節將作具體描述。
-> void *mv_usb_handle, 指標指向晶片控制器的資料結構。
概括地講,gadget控制器驅動完成了五個任務, 通過platform_data和resource的到gadget晶片物理地址,中斷號等 (橙色) 初始化gadget晶片和相關資料 (淺灰色) 初始化資料struct usb_gadget (藍色) 初始化資料struct usb_ep (粉色) 註冊gadget服務
gadget服務,即該裝置所具備的gadget能力,比如reset, suspend, resume, speed,以及需要重點關注的枚舉功能mv_usb_ep0_complete_service。注意到,註冊服務的函數usb_device_register_service()的第一個參數mv_usb_handle用於得到底層晶片的資料,第三個參數回呼函數實現具體功能。
2.2 Gadget裝置驅動
需要區別gadget裝置驅動與上節提到的gadget控制器驅動。gadget裝置驅動,是指裝置插入主機後具備的功能,該驅動被掛在到struct usb_gadget_driver下。比如手機插入PC作為隨身碟,那麼隨身碟的驅動程式就是所謂的gadget裝置驅動。
(*bind)綁定裝置的功能,比如隨身碟。
(*setup)實現USB裝置的枚舉。
2.3 Composite
如果一個裝置插入主機後擁有多個功能,比如同時有隨身碟和android調試功能,那麼該裝置稱為composite複用裝置。其資料結構如下,
通過(*bind)綁定裝置的各個功能。
3. 枚舉過程
系統初始化USB裝置的過程就是枚舉過程。
根據USB協議,USB裝置初始化的過程為attached->powered->default->address->configured。
當裝置插入主機,將等待來自主機的中斷訊號,通過request_irq()進入中斷處理函數。
裝置通過讀取控制器狀態寄存器的值,得到來自主機的反饋,進而執行相應的任務,枚舉就是其中的一項任務,通過調用gadget控制器驅動已經註冊好的枚舉服務,開始枚舉過程。
該枚舉服務歸納為兩步,
第一步,通過讀取gadget控制器,得到來自主機的請求,存放至mv_ctrl_req。
第二步,通過switch(mv_ctrl_req),對具體請求作具體處理,處理類別又可分為兩類。
1) 標準請求,即所有USB裝置可通用的請求,具體有得到狀態請求,設定/清除feature請求,設定地址請求。
2) USB裝置請求,即根據具體裝置,處理具體請求,通過回呼函數mv_dev->driver->setup()來實現。
PS: 關於請求,參看USB協議ch9。
重點關注mv_dev->driver->setup()的枚舉過程,其實質就是主機從USB裝置得到描述符。
這裡的mv_dev->driver就是上文2.2所提到的gadget裝置驅動,通過driver->bind綁定具體的驅動功能,如果是composite複用裝置,則綁定usb_composite_driver結構,通過driver->setup實現裝置的枚舉過程,代碼如下,其中的GET_DESCRIPTOR, SET_CONFIGURATION, 以及f->setup是必要的枚舉過程。