?? linux下usb.c源代碼分析.txt
字號:
Linux下的USB子系統
在Linux系統中有一個名為“The USB Core”子系統,它有特殊的API支持USB設備和控制器。它的作用是通過定義一組數據結構,宏和函數來抽象所有硬件或設備依賴的部分。
USB內核包含所有USB設備和控制器的最外層的驅動。這些函數可以被劃分到上層或下層API。下圖所示的就是針對于USB設備驅動和另外一個主機控制器的API。下層集成在USB設備驅動層,因為主機控制器驅動的開發已經完成。
USB Core API Layers
USB設備驅動程序結構
USB設備驅動在子系統中注冊和注銷。一個驅動程序必須注冊2個入口點和它的名字。對于特殊的USB設備(它不適合在其它子系統中注冊)一個驅動程序可以注冊一對文件操作和一個次設備號。在這種情況下指定的次設備號和隨后的15個數字被分配給驅動程序。這樣就可以使一個驅動程序支持16個相似的USB設備。所有USB設備的主設備號是180。
數據結構:
所有USB相關函數或數據結構都遵循同樣的命名規則而且都是以usb_開始。
name:模塊名字
probe:prob函數的入口
disconnect:disconnect函數的入口
driver_list:子系統初始化時為{NULL,NULL}
fops:驅動程序文件操作的鏈表
minor:分配給這個設備的次設備號(其值是16的倍數)
serialize:
ioctl:
id_table:
結構入口
USB驅動程序結構添加兩個入口到普通的設備驅動:
void *probe(struct usb_device *dev, unsigned int interface, const struct usb_device_id *id_table);在有新的設備接入到總線上時就會調用這個入口函數。然后,驅動程序要為新設備創建一個內部數據結構。
dev聲明了特定的設備正文,它的內容指向所有USB描述符。interface聲明了特定的接口號。如果一個USB驅動程序想把自己與一個具體設備和接口綁定在一起,它就必須返回一個指針。這個指針通常指向設備驅動程序的正文結構。
探查是通過檢查vendor和產品的定義或分類以及子集的定義來實現的。如果它們匹配則接口號就與驅動程序支持的比較。因為設備的特性多不相同所以當探查完成后分類是基于有必要解析一些USB描述符。
Probe函數:
void disconnect(struct usb_device *dev, void *drv_context);當設備與這個函數斷開時就調用這個函數。
dev聲明了特定的設備正文而且driver_context返回一個指針指向當前注冊的probe函數的driver_context。返回后從USB結構的disconnect函數釋放了所有與設備有關的數據結構。所以,特別是usb設備不能再使用usb_device結構
disconnect函數:
結構函數
int usb_register(struct usb_driver *drv);
這個函數用來在子系統中注冊一個新的USB設備。drv指向一個已完全初始化的usb_driver結構。成功返回0,否則返回一個錯誤值。
void usb_deregister(struct usb_driver *drv);
這個函數用來注銷一個已在子系統中注冊的USB設備。
void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *drv_context);
在探查過程中USB設備驅動程序在設備上聲明多于一個接口時就使用這個函數。driver指向一個完全初始化的usb_driver結構。iface指向usb_config_descriptor中的usb_interface結構,usb_config_descriptor在usb_device(在probe函數中給出)結構中可訪問。drv_context指向設備驅動程序的正文結構。
int usb_interface_claimed(struct usb_interface *iface);
如果另一設備驅動已聲明特定的接口則這個函數是用來檢查的。如果接口沒有被其它的驅動程序聲明就返回0。
void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface);
如果一個驅動程序要釋放以前聲明的接口就要調用這個函數。在disconnect函數中你不一定非要釋放在probe函數中聲明的接口。
const struct usb_device_id *usb_match_id( struct usb_device *dev, struct usb_interface *interface, const struct usb_device_id *id);
配置USB設備
API包括一系列的函數用來選擇或查詢描述符,配置和選擇設備設定。所有的標準操作都通過控制設備傳輸來完成。
描述符數據結構
Linux USB子系統通過在子系統特定結構中擴展或嵌入標準USB描述符來描述層次結構。這個結構幫助存儲指向選擇配置和接口的指針。
這些結構的原理直到它們對于后來的API有必要調用時才詳細解釋。
struct usb_device{
...
struct usb_config_descriptor *actconfig;/* the active configuration */
...
struct usb_device_descriptor descriptor;/* Descriptor */
struct usb_config_descriptor *config; /* All of the configs */
}
usb_device結構是所有USB特定描述符的根。有時為了配置設備或適當地啟動傳輸請求有必要在驅動程序中解析描述符。
.可以像這樣來訪問所有可用的配置描述符:
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
struct usb_config_descriptor *cfg = &dev->config[i];
...
}
.像這樣訪問所有可用的特定配置的接口描述符:
for (j = 0; j < cfg->bNumInterfaces; j++) {
struct usb_interface *ifp = &cfg->interface[j];
...
}
用dev?actconfig指針開始解析激活的配置。
.訪問所有特定接口的可選的設置:
for (k = 0; k < ifp->num_altsetting; k++) {
struct usb_interface_descriptor *as = &ifp->altsetting[k];
...
}
可選的設定可以通過*as = &ifp->altsetting[ifp->act_altsetting]來訪問
.訪問所有特定可選的設定端點描述符:
for(l = 0; l < as->bNumEndpoints; l++) {
struct usb_endpoint_descriptor *ep=&as->endpoint[k];
...
}
標準設備請求
有一組函數用來查詢或設置特殊配置或改變設置。這些常用的函數啟動標準設備請求(控制指定設備的傳輸):
.int usb_set_configuration(struct usb_device *dev, int configuration);
用這個函數激活特定配置。
0<=configurationdescriptor.bNumConfigurations。
設備與總線相連后0是缺省值。
.int usb_set_interface(struct usb_device *dev, int interface, int alternate);
這個函數激活指定接口的設置。
0<=interface 0<=alternate
.int usb_get_device_descriptor(struct usb_device *dev);
這個函數從指定的設備中重讀全部的描述符樹。當一個設備連接到總線上或一個USB描述符發生改變就自動調用這個函數。
.int usb_get_descriptor(struct usb_device *dev,unsigned char desctype,unsigned char descindex, void *buf, int size);
單個的USB描述符可以從設備中作為原始數據讀入。這個函數可被用來解析擴展的或指定的描述符。
.int usb_get_string(struct usb_device *dev,unsigned short langid,unsigned char index, void *buf, int size);
如果一設備,配置或接口描述符涉及到一串索引值,則這個函數可被用來遍歷描述符。依照規范USB strings被作為Unicode來編碼。如果成功就返回0,否則返回錯誤代碼。
.int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
這個函數通過把Unicode串轉換成ASCII串來簡化usb_get_string。
.int usb_get_status(struct usb_device *dev, int type, int target, void *data);
.int usb_clear_halt(struct usb_device *dev, int pipe);
如果一個端點被停止,就調用這個函數來清除STALL。STALL表明一個函數不能發送或接收數據,或者是不支持控制管道請求。endpoint定義了一個管道。
.int usb_get_protocol(struct usb_device *dev, int ifnum);
.int usb_set_protocol(struct usb_device *dev, int protocol, int ifnum);
.int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, int ifnum, void *buf, int size);
.int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id);
USB傳輸
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -