USB驅動的一點了解(gadget)
參考以下部落格:
http://blog.csdn.net/myarrow/article/details/7012230 Linux USB驅動詳解
http://blog.csdn.net/myarrow/article/details/7013198 Linux USB驅動工作流程
http://www.cnblogs.com/general001/articles/2319552.html Linux下USB驅動框架分析
http://blog.csdn.net/gotosola/article/details/7473730 Linux usb驅動程式全註釋
http://m.blog.csdn.net/blog/wuyuwei45/9047035 Android/Linux USB Gadget:三層架構
http://blog.chinaunix.net/uid-25909619-id-3153939.html 基於android4.0的usb gadget分析 (系列 USB 驅動分析)
http://blog.csdn.net/airk000/article/details/7887645 Android4.0 USB掛載核心驅動層流程分析(一)
http://blog.csdn.net/successcw/article/details/17137361 linux usb gadget
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
一、主機驅動(略寫)
1,Linux usb裝置驅動框架:
分兩種,主機驅動與gadget驅動,前者控制插入其中的USB裝置,後者控制USB裝置(嵌入式)如何與主機通訊,如下:
2.usb系統一般由三個部分組成,主機,usb hub,usb裝置
在任何的usb系統中僅有一個主機
所有的usb device都連線在hub埠上
3.USB 四種傳輸方式
(1)控制傳輸模式(Control)
(2)等時傳輸方式(lsochronous)
(3)中斷傳輸模式(Interrupt)
(4)批量傳輸模式(bulk)
4. usb裝置組成
(1)一個usb裝置由可以有一個或多個配置(任一時刻,只能有一個配置生效)
(2)一個配置通常可以有一個或多個介面
(3)一個介面通常可以有一個或多個端點
通常所盡的usb裝置驅動是指介面驅動,即一個介面對應一個驅動。
所以Linux usb裝置有四大描述符,分別為裝置描述符,配置描述符,介面描述符,端點描述符
5.urb主要用於Linux host與裝置進行資料傳輸
所有USB通訊均為請求-->響應模式,USB裝置不會主動向Host傳送資料。
寫資料:USB裝置驅動傳送urb請求給USB裝置,USB裝置不需要回資料。
讀資料:USB裝置驅動傳送urb請求給USB裝置,USB裝置需要回資料。
urb的生命週期:
(1)由usb裝置驅動建立
(2)分配到usb裝置的指定端點
(3)由Usb裝置驅動提交到usb core
(4)由Usb core提交到usb 主機控制器
(5)由Usb主機控制器控制裝置進行資料傳輸
(6)當urb完成的時候,usb主機控制器驅動通知usb 裝置驅動
6.driver/usb/usb-skeleton.c
在Linux kernel原始碼目錄中driver/usb/usb-skeleton.c為我們提供了一個最基礎的USB驅動程式。我們稱為USB骨架。通過它我們僅需要修改極少的部分,就可以完成一個USB裝置的驅動,略。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
二.gadget驅動
(1). USB Gadget 功能層:
BSP/Driver開發者通常是要實現這一層,從而實現一個具體的裝置驅動,如Anddroid在此層實現了 adb,mtp,mass_storage 等
瀏覽參考關注此層程式碼時,會發現“composite”是此層的關鍵字,此層中關鍵的資料結構是:struct usb_composite_driver
這一層的驅動檔案一般為:driver/usb/gadget/android.c(android實現的)或driver/usb/gadget/serial.c(傳統Linux實現的USB轉串列埠)
(2). USB 裝置層
這一層是Linux核心開發維護者實現的,與我們沒太大關係,不用我們操心,我們只關心其的一些介面就行。
瀏覽參考關注此層時,會發現“gadget”是此層的關鍵字
此層的關鍵資料結構是: usb_gadget_driver,usb_composite_dev。 這層主要的一個驅動檔案為:driver/usb/gadget/composite.c
(3). USB 裝置控制器驅動層:
這一層主要是與CPU、CPU USB控制器有關,與硬體緊密相關
這一層也比較頭痛,主要它和USB控制器牽扯在一起,涉及有 暫存器、時鐘、DMA等等。但是這一層往往是由晶片廠商去實現。
我們一般僅需在板級檔案中處理好所需要的USB介面即可。這層的關鍵字就是“UDC”,
主要驅動檔案命名含“udc”關鍵字,一般與CPU或晶片廠商有關,如driver/usb/gadget/xxx_udc.c。
USB Gadget功能層呼叫USB裝置層的介面,USB裝置層呼叫USB裝置控制器驅動層的介面
然後USB裝置控制器驅動層回撥USB裝置層,USB裝置層回撥USB Gadget功能層
2.重要的結構體
struct android_dev {
const char *name;
struct android_usb_function **functions; //該android_dev支援的功能如adb,大容量儲存
struct usb_composite_dev *cdev; //符合裝置的dev
struct device *dev; //支援裝置驅動模型的dev
bool enabled;
int disable_depth;
struct mutex mutex; //操作該結構體是用到的互斥鎖
struct android_usb_platform_data *pdata;
bool connected; //記錄當前的連線狀態
bool sw_connected; //記錄切換後的連線狀態
bool suspended;
bool sw_suspended;
char pm_qos[5];
struct pm_qos_request pm_qos_req_dma;
struct work_struct work; //支援的工作佇列
/* A list of struct android_configuration */
struct list_head configs;
int configs_num;
/* A list node inside the android_dev_list */
struct list_head list_item;
};
struct android_usb_function {
char *name; //該功能的名字
void *config; //該功能所依賴的配置
struct device *dev; //為裝置驅動模型準備的device
char *dev_name;
struct device_attribute **attributes;
struct android_dev *android_dev;
/* Optional: initialization during gadget bind */
int (*init)(struct android_usb_function *, struct usb_composite_dev *); //在繫結的時候,執行的初始化函式
/* Optional: cleanup during gadget unbind */
void (*cleanup)(struct android_usb_function *); //在解除繫結時,執行清除的函式
/* Optional: called when the function is added the list of enabled functions */
void (*enable)(struct android_usb_function *);
/* Optional: called when it is removed */
void (*disable)(struct android_usb_function *);
int (*bind_config)(struct android_usb_function *, //把該function繫結到特定的配置上,此時function相當一個介面
struct usb_configuration *);
/* Optional: called when the configuration is removed */
void (*unbind_config)(struct android_usb_function *,
struct usb_configuration *);
/* Optional: handle ctrl requests before the device is configured */
int (*ctrlrequest)(struct android_usb_function *,
struct usb_composite_dev *,
const struct usb_ctrlrequest *);
};
static struct usb_gadget_driver composite_driver = {
.unbind = composite_unbind,
.setup = composite_setup,
.disconnect = composite_disconnect,
.suspend = composite_suspend,
.resume = composite_resume,
.driver = {
.owner = THIS_MODULE,
},
};
struct usb_gadget {
/* readonly to gadget driver */
const struct usb_gadget_ops *ops;
struct usb_ep *ep0;
struct list_head ep_list; /* of usb_ep */
enum usb_device_speed speed;
enum usb_device_speed max_speed;
unsigned sg_supported:1;
unsigned is_otg:1;
unsigned is_a_peripheral:1;
unsigned b_hnp_enable:1;
unsigned a_hnp_support:1;
unsigned a_alt_hnp_support:1;
unsigned host_request:1;
unsigned otg_srp_reqd:1;
const char *name;
struct device dev;
u8 usb_core_id;
bool l1_supported;
bool remote_wakeup;
};
static struct android_usb_function *supported_functions[] = {
&mbim_function,
&ecm_qc_function,
#ifdef CONFIG_SND_PCM
&audio_function,
#endif
&rmnet_smd_function,
&rmnet_sdio_function,
&rmnet_smd_sdio_function,
&rmnet_function,
&gps_function,
&diag_function,
&qdss_function,
&serial_function,
&adb_function, //支援的adb功能
&ccid_function,
&acm_function,
&mtp_function,
&ptp_function,
&rndis_function, //Remote Network Driver Interface Specification,既是RemoteNDIS,既是遠端網路驅動介面規範。
//基於USB實現RNDIS實際上就是TCP/IP over USB,就是在USB裝置上跑TCP/IP,讓USB裝置看上去像一塊網絡卡
&rndis_qc_function,
&ecm_function, //ecm
&ncm_function,
&mass_storage_function, //支援的大容量儲存功能
&accessory_function,
#ifdef CONFIG_SND_PCM
&audio_source_function,
#endif
&uasp_function,
NULL
};
static struct usb_composite_driver android_usb_driver = {
.name = "android_usb", //該複合裝置驅動的名稱
.dev = &device_desc, //裝置描述符
.strings = dev_strings,
.unbind = android_usb_unbind,
.max_speed = USB_SPEED_SUPER
};
static struct usb_device_descriptor device_desc = {
.bLength = sizeof(device_desc),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.idVendor = __constant_cpu_to_le16(VENDOR_ID),
.idProduct = __constant_cpu_to_le16(PRODUCT_ID),
.bcdDevice = __constant_cpu_to_le16(0xffff),
.bNumConfigurations = 1,
};
driver/usb/gadget/f_mass_storage.c
struct fsg_config {
unsigned nluns; //最大支援的LUN數量(LUN:Logical units)
struct fsg_lun_config { //每個LUN的引數
const char *filename; //此LUN的名字,如果不是可移除的(removable)則不需要
char ro; //FALSE(TRUE),設定read-only,如果是CD-ROM則不可能掛載成R/W
char removable; //TRUE(FALSE),說明此LUN可移除
char cdrom; //FALSE(TRUE),此LUN是否為CD-ROM
char nofua; //FALSE(TRUE),此LUN是否可忽略
} luns[FSG_MAX_LUNS];
const char *lun_name_format;//建議為lun%d形式,如果不只是一個LUN,可以用%d來引導,必須是整型數字,如果不符合,可能將出現不可預知的錯誤
const char *thread_name; //預設名字是"file_storage",是應該叫核心執行緒名字吧
/* Callback functions. */
const struct fsg_operations *ops;
/* Gadget's private data. */
void *private_data;
const char *vendor_name; /* 8 characters or less */
const char *product_name; /* 16 characters or less */
u16 release;
char can_stall;
};
3.呼叫流程
./arch/arm/boot/dts/msm9625-v2.1.dtsi
[email protected] {
compatible = "qcom,android-usb";
reg = <0xfe8078c8 0xc8>;
qcom,android-usb-swfi-latency = <100>;
};
Android.c (drivers\usb\gadget)
static int __init init(void)
composite_driver.setup = android_setup;//composite_driver 是一個全域性的結構體,android.c中重新實現了它的setup和disconnect方法
composite_driver.disconnect = android_disconnect;
composite_driver.suspend = android_suspend;
composite_driver.resume = android_resume;
ret = platform_driver_register(&android_platform_driver);
static struct platform_driver android_platform_driver = {
.driver = {
.name = "android_usb",
.of_match_table = usb_android_dt_match,
},
.probe = android_probe,
.remove = android_remove,
.id_table = android_id_table,
};
static int __devinit android_probe(struct platform_device *pdev)
android_class = class_create(THIS_MODULE, "android_usb");//建立一個class,建立這個 class 的目的是支援使用者空間的 udev,自動建立裝置節點,/sys/devices/virtual/android_usb/
android_dev = kzalloc(sizeof(*android_dev), GFP_KERNEL);//分配一個該結構體的例項
android_dev->functions = supported_functions; //初始化該結構體的 functions 成員,supported_functions 結構體見上面
INIT_LIST_HEAD(&android_dev->configs); //初始化dev的 enabled_functions 成員連結串列頭
INIT_WORK(&android_dev->work, android_work); //初始化dev的work成員,支援的工作佇列
mutex_init(&android_dev->mutex); //初始化dev的成員mutex互斥鎖
composite_driver.usb_core_id = pdata->usb_core_id;
//繼續初始化 android_dev 中的成員dev ,支援動態建立裝置節點,併為該裝置建立屬性,/sys/devices/virtual/android_usb/android0
ret = android_create_device(android_dev, composite_driver.usb_core_id); ----
ret = usb_composite_probe(&android_usb_driver, android_bind); //這個函式才是函式的開始,到裡面牽涉的東西會越來越多
driver/usb/gadget/composite.c
/*將註冊進來的 usb_composite_driver (這裡是 android_usb_driver)與usb_gadget_driver(這裡是composite_driver)聯絡起來,
然後呼叫 udc core 提供的函式: usb_gadget_probe_driver ,並提供 callback function: composite_bind 給udc core*/
int usb_composite_probe(struct usb_composite_driver *driver, int (*bind)(struct usb_composite_dev *cdev))
composite_driver.function = (char *) driver->name;
composite_driver.driver.name = driver->name;
composite_driver.max_speed = driver->max_speed;
composite = driver;
composite_gadget_bind = bind;
retval = usb_gadget_probe_driver(&composite_driver, composite_bind); //向USB裝置層進行探測和註冊
driver/usb/gadget/udc-core.c
//usb_gadget_probe_driver() 函式是每一個USB裝置控制器驅動要實現的,這個函式與硬體緊密相關
int usb_gadget_probe_driver(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *))
ret = usb_gadget_udc_start(udc->gadget, driver);
static inline int usb_gadget_udc_start(struct usb_gadget *gadget,struct usb_gadget_driver *driver)
gadget->ops->udc_start(gadget, driver);
/*這個函式是udc core層實現的一個介面函式,具體實現在對應的 usb device controller 中,但由於不知 msm9625 是哪個 ???udc.c 故 udc_start 不分析了
將 usb_gadget_driver 和 usb_gadget 對應起來,並呼叫bind(這裡為 composite_bind)*/
static int composite_bind(struct usb_gadget *gadget)
struct usb_composite_dev *cdev; //新建 usb_composite_dev
cdev->gadget = gadget; //建立 usb_gadget 與 usb_composite_dev 的關係
set_gadget_data(gadget, cdev);
cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); //給這個端點分配一個請求物件,ep0 usb request
cdev->driver = composite;//這裡指定 usb_composite_dev 的driver為 usb_composite_probe 註冊進來的 usb_composite_driver: android_usb_driver
status = composite_gadget_bind(cdev);
/*這裡呼叫的是 usb_composite_probe 傳進來的 android_bind, android_bind 會呼叫 usb_add_config 來新增 config
具體的每一個function的新增會在呼叫 usb_add_config 時傳進來的 callback function 中完成
(這裡是 android_bind_config , 這個函式會呼叫每一個需要新增的function的 bind_config, 而 bind_config 呼叫的是 usb_add_function)
*/
***********
/*初始化所有支援的 usb 裝置型別, 繼續建立 mtp,ptp, rndis, acm, ffs, mass_storage等屬性結點。
儲存來自 cdev 的 manufacturer_id, product_id, manufacturer_string, product_string, serial_string 資訊。
設定裝置自供電能力特性*/
static int android_bind(struct usb_composite_dev *cdev)
usb_gadget_disconnect(gadget); //初始化前確保是斷開的
ret = android_init_functions(dev->functions, cdev);
id = usb_string_id(cdev); //通過讀取裝置ID來填充一下驅動引數
strlcpy(manufacturer_string, "Android", sizeof(manufacturer_string) - 1); //填充一下預設的廠商和產品資訊,根據說明意思是可以通過上層改變
gcnum = usb_gadget_controller_number(gadget); //識別一下控制晶片,返回一個BCD值
static int android_init_functions(struct android_usb_function **functions, struct usb_composite_dev *cdev)
f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name); //拿 mass_storage_function 來說,dev_name 就是 f_mass_storage 了
f->dev = device_create(android_class, dev->dev, MKDEV(0, index), f, f->dev_name); //建立裝置
if (f->init) //f->init指向 mass_storage_function_init,所以是在這個時候執行的
4.rndis部分
static struct android_usb_function rndis_function = {
.name = "rndis",
.init = rndis_function_init,
.cleanup = rndis_function_cleanup,
.bind_config = rndis_function_bind_config,
.unbind_config = rndis_function_unbind_config,
.attributes = rndis_function_attributes,
};
//rndis_bind_config_vendor() 是和 android usb 層溝通的橋樑函式,也是整個 f_rndis.c 檔案的唯一入口函式
static int rndis_function_bind_config(struct android_usb_function *f,struct usb_configuration *c)
return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID, rndis->manufacturer);
int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],u32 vendorID, const char *manufacturer)
status = rndis_init(); //通過呼叫 rndis_init(),向下打通了 kernel/drivers/usb/gadget/rndis.c 層
rndis->vendorID = vendorID; //在設定好 f_rndis 成員變數,也就是分配好必須的資源
rndis->port.func.set_alt = rndis_set_alt; //對於控制id,呼叫 usb_ep_enable() ,對於資料id, 呼叫 gether_connect()
rndis->port.func.setup = rndis_setup; //使用CDC命令封裝機制來實現一個 RPC呼叫,只檢查一種 USB_DIR_OUT, 一種 USB_DIR_IN
rrndis->port.func.bind = rndis_bind;
rndis->port.func.disable = rndis_disable; //釋放資源,gether_disconnect() 斷開gether連線,呼叫 usb_ep_disable() 關閉端點
status = usb_add_function(c, &rndis->port.func);//把該usb功能加入到配置中去,對應 USB規範可知,每個 usb 配置必須包含一個或多個usb功能
//usb_add_function() 將呼叫 rndis->port.func.bind 函式並返回其值,實際就是呼叫 rndis_bind() 函式。
int usb_add_function(struct usb_configuration *config,struct usb_function *function)
value = function->bind(config, function);
return value;
//rndis_bind() 進行乙太網功能驅動的初始化和繫結操作
static int rndis_bind(struct usb_configuration *c, struct usb_function *f)
status = usb_interface_id(c, f); //分配usb 未使用的介面id值,是 drivers/usb/gadget/composite.c 的通用功能函式
ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc); //分配和配置必要的 usb 端點資源
rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); //分配並返回一個 usb_request 物件指標
rndis->notify_req->complete = rndis_response_complete; //usb請求執行結束後,回撥函式 rndis_response_complete() ---- 1
status = rndis_register(rndis_response_available, rndis); //rndis_response_available() 函式傳送 RNDIS RESPONSE_AVAILABLE 訊息到端點。
static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); //如果 usb_request 返回狀態正常,則通過 usb_ep_queue() 放入佇列
f_rndis.c 溝通的下層是 drivers/usb/gadget/u_ether.c。
5.adb 部分
adb:
static struct android_usb_function adb_function = {
.name = "adb",
.enable = adb_android_function_enable,
.disable = adb_android_function_disable,
.init = adb_function_init,
.cleanup = adb_function_cleanup,
.bind_config = adb_function_bind_config,
};
static int adb_function_bind_config(struct android_usb_function *f, struct usb_configuration *c)
return adb_bind_config(c);
static int adb_bind_config(struct usb_configuration *c)
dev->cdev = c->cdev;
dev->function.name = "adb";
dev->function.descriptors = fs_adb_descs;
dev->function.hs_descriptors = hs_adb_descs;
dev->function.bind = adb_function_bind;
return usb_add_function(c, &dev->function);
int usb_add_function(struct usb_configuration *config,struct usb_function *function)
value = function->bind(config, function); ---- 即呼叫 adb_function_bind
static int adb_function_bind(struct usb_configuration *c, struct usb_function *f)
ret = adb_create_bulk_endpoints(dev, &adb_fullspeed_in_desc, &adb_fullspeed_out_desc);
static int adb_create_bulk_endpoints(struct adb_dev *dev,
struct usb_endpoint_descriptor *in_desc,
struct usb_endpoint_descriptor *out_desc)
ep = usb_ep_autoconfig(cdev->gadget, in_desc); ---- 分配gadget初始化註冊的endpoint
req = adb_request_new(dev->ep_out, ADB_BULK_BUFFER_SIZE); ---- (主要呼叫 usb_ep_alloc_request)來分配對應的endpoint的request
req->complete = adb_complete_out; ---- 指定request的complete函式,這個函式會在usb device controller對應的endpoint收發中斷完成之後被呼叫
6.mass_storage 部分
static int mass_storage_function_init(struct android_usb_function *f,struct usb_composite_dev *cdev)
config->fsg.nluns = 2; //支援2個儲存裝置
config->fsg.luns[1].cdrom = 1; //支援 cdrom
config->fsg.luns[1].ro = 1; //read only
config->fsg.luns[1].removable = 0; //不可移除
name[1] = "lun0";
common = fsg_common_init(NULL, cdev, &config->fsg); //根據配置建立裝置
err = sysfs_create_link(&f->dev->kobj,&common->luns[i].dev.kobj,name[i]); //建立裝置連結