1. 程式人生 > >Android/Linux USB Gadget:三層架構

Android/Linux USB Gadget:三層架構

1.前言

Linux Gadget的一點研究後陸續續關注了很久Android USB Gadget,一直想寫點什麼記錄一些認識,可是Linux USB實在是太複雜,讓人有點無從下筆的感覺。它的複雜並不是說不可以被人理解,而且涉及的面很廣。USB Host的驅動關注比較少,就對USB device驅動的認識來說,需從兩大方面去對它進行認識和了解,一方面是USB協議本身,如果連USB端點、裝置描述符、介面、複合裝置等概念都不清楚的話,那是無法理解Linux USB device驅動的;另外方面就是USB Gadget架構。而本文就是基於對USB Gadget架構的一點認識而記錄的。

2.Android USB 

Android裝置的USB口實現了OTG的功能,也就是一般Android裝置可以充當Host和Device角色,而我們使用得最多的就是它的Device角色。Android系統開發者更改傳統了Linux USB Gadget實現,在傳統Linux Gadget架構上實現了一個複合裝置:adb和mtp。其中adb就不用多說,玩過Android都懂,mtp就是常見的U盤功能。Android USB Gadget裝置驅動就是Linux的USB Gadget裝置驅動。

3.USB Gadget的三層架構

一般網上關於介紹USB Gadget的資料都是基於Linux2.6.32或在這之前的版本,作者在關注了Linux2.6.37和Linux3.0.4版本的核心,USB Gadget的一些API已經與Linux2.6.32的不同了。但是那些關鍵的資料結構還是一樣滴。 Linux USB Gadget分三層架構: 層次關係從上到下 一層: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轉串列埠)。 二層:USB裝置層。這一層是Linux核心開發維護者實現的,與我們沒太大關係,不用我們操心,我們只關心其的一些介面就行。瀏覽參考關注此層時,會發現“gadget”是此層的關鍵字,此層的關鍵資料結構是:usb_gadget_driver,usb_composite_dev。這層主要的一個驅動檔案為:driver/usb/gadget/composite.c 三層:USB裝置控制器驅動層。這一層主要是與CPU、CPU USB控制器有關,與硬體緊密相關,這一層也比較頭痛,主要它和USB控制器牽扯在一起,涉及有暫存器、時鐘、DMA等等。但是這一層往往是由晶片廠商去實現。我們一般僅需在板級檔案中處理好所需要的USB介面即可。這層的關鍵字就是“UDC”,主要驅動檔案命名含“udc”關鍵字,一般與CPU或晶片廠商有關,如driver/usb/gadget/xxx_udc.c。

4.USB Gadget的三層架構的關係

可以用一句簡單的話去概括三層的關係:USB Gadget功能層呼叫USB裝置層的介面,USB裝置層呼叫USB裝置控制器驅動層的介面,然後USB裝置控制器驅動層回撥USB裝置層,USB裝置層回撥USB Gadget功能層。 【強調本文只是想捋清楚層次的關係而已,對裡面的一些函式,甚至USB gadget如果運作、整個驅動如何處理USB協議等等不做太多說明,後面會在其他文章中陸續補充。】

4.1從Android的gadget功能層去看三層架構的關係

瀏覽driver/usb/gadget/android.c原始碼。 先看init函式,
static int __init init(void)
{
	struct android_dev *dev;
	int err;

	android_class = class_create(THIS_MODULE, "android_usb");
	if (IS_ERR(android_class))
		return PTR_ERR(android_class);

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		return -ENOMEM;

	dev->functions = supported_functions;
	INIT_LIST_HEAD(&dev->enabled_functions);
	INIT_WORK(&dev->work, android_work);
	mutex_init(&dev->mutex);

	err = android_create_device(dev);
	if (err) {
		class_destroy(android_class);
		kfree(dev);
		return err;
	}

	_android_dev = dev;

	/* Override composite driver functions */
	composite_driver.setup = android_setup;
	composite_driver.disconnect = android_disconnect;

	return usb_composite_probe(&android_usb_driver, android_bind);
}
composite_driver是定義在driver/usb/gadget/composite.c中,
static struct usb_gadget_driver composite_driver = {
	.speed		= USB_SPEED_HIGH,

	.unbind		= composite_unbind,

	.setup		= composite_setup,
	.disconnect	= composite_disconnect,

	.suspend	= composite_suspend,
	.resume		= composite_resume,

	.driver	= {
		.owner		= THIS_MODULE,
	},
};
可見它是一個全域性的結構體,android.c中重新實現了它的setup和disconnect方法。然後呼叫函式usb_gadget_probe_driver(&android_usb_driver,android_bind);向USB裝置層進行探測和註冊。 【PS:2.6.32核心在init函式後面呼叫usb_composite_register(&android_usb_driver)進行註冊,2.6.37核心以後統一改為usb_gadget_probe_driver。】 usb_gadget_probe_driver(&composite_driver, composite_bind)函式定製在driver/usb/gadget/composite.c
extern int usb_composite_probe(struct usb_composite_driver *driver,
			       int (*bind)(struct usb_composite_dev *cdev))
{
	if (!driver || !driver->dev || !bind || composite)
		return -EINVAL;

	if (!driver->iProduct)
		driver->iProduct = driver->name;
	if (!driver->name)
		driver->name = "composite";
	composite_driver.function =  (char *) driver->name;
	composite_driver.driver.name = driver->name;
	composite = driver;
	composite_gadget_bind = bind;

	return usb_gadget_probe_driver(&composite_driver, composite_bind);
}
函式usb_gadget_probe_driver呼叫usb_gadget_probe_driver相關USB裝置控制器驅動層進行註冊。
【PS:2.6.32核心在init函式後面呼叫usb_gadget_register_driver(&composite_driver)進行註冊,2.6.37核心以後統一改為usb_gadget_probe_driver(&composite_driver, composite_bind);】

usb_gadget_probe_driver()函式是每一個USB裝置控制器驅動要實現的,這個函式與硬體緊密相關。
至此可以看到三層的關係:USB Gadget功能層呼叫USB裝置層的介面,USB裝置層呼叫USB裝置控制器驅動層的介面。

4.2從傳統Linux的gadget功能層去看三層架構的關係

發現打字好累,分析傳統Linux的gadget功能層程式碼(如:driver/usb/gadget/serial.c)發現其實和android一樣,所以不寫了。 後面會繼續分析gadget層中對USB協議的實現,如怎麼列舉裝置,USB描述符怎麼傳遞,資料怎麼收發等。。。