天天看點

USB總線-Linux核心USB3.0裝置控制器驅動架構分析(四)

1.概述

如下圖所示,USB控制器可以呈現出兩種不同的狀态。USB控制器作為Host時,稱為USB主機控制器,使用USB主機控制器驅動。USB控制器作為Device時,稱為USB裝置控制器,使用UDC(usb device controller)驅動。本節隻分析USB控制器作為Device時的驅動架構。

USB控制器作為Device時,驅動架構可分為5層。最上層的是Gadget Function驅動,代表了具體裝置的驅動,如大容量儲存設備驅動(U盤、移動硬碟等)、通訊類裝置驅動(USB序列槽、USB虛拟網卡等)、UAC驅動(USB麥克風、USB聲霸卡等USB音頻類裝置)。接下來是Gadget Funcation API層,該層是一個抽象層,向上和向下提供統一的API,屏蔽了差異,提高了驅動的相容性。Composite驅動層是一個可選的中間層,可通過一種配置或多種配置高效的支援多種功能的裝置,簡化了USB複合裝置驅動的開發。UDC驅動直接通路硬體,控制USB裝置與USB主機之間的通信。USB裝置控制器通過USB線纜連接配接USB主機控制器,負責USB資料的發送和接收。

USB總線-Linux核心USB3.0裝置控制器驅動架構分析(四)

2.Gadget Function驅動

Linux核心的USB Gadget Function驅動都在drivers/usb/gadget/function/目錄下,有通訊裝置類(Communication Device Class)驅動(f_acm.c、f_ecm、f_serial.c等)、USB音頻裝置類驅動(f_uac1.c、f_uac2.c、u_audio.c)、大容量儲存設備驅動(f_mass_storage.c)、USB視訊裝置類驅動(f_uvc.c)等。

Gadget Function驅動的入口使用

usb_function_driver

資料結構描述,驅動需要實作

alloc_inst

alloc_func

函數。

alloc_inst

建立

usb_function_instance

資料結構并初始化。

alloc_func

建立

usb_function

并初始化,重點是設定裡面的回調函數,通常情況下,不直接使用

usb_function

資料結構,而是嵌入到驅動的資料結構中使用。Composite驅動會通過Gadget Function API回調

alloc_inst

alloc_func

函數。

usb_function

了描述Gadget Function驅動,Gadget Function驅動的重點是實作這些回調函數。

[include/linux/usb/composite.h]
struct usb_function_driver {
    const char *name;
    struct module *mod;
    struct list_head list;
    // 建立usb_function_instance并初始化
    struct usb_function_instance *(*alloc_inst)(void);
    // 建立usb_function并初始化
    struct usb_function *(*alloc_func)(struct usb_function_instance *inst);
};
struct usb_function {  // 描述了一個gadget Function驅動
    const char			*name;  // gadget Function驅動名稱
    struct usb_gadget_strings	**strings;  // 字元串表,由bind配置設定和控制請求提供的語言IDs
    struct usb_descriptor_header	**fs_descriptors; // full speed描述符
    struct usb_descriptor_header	**hs_descriptors; // high speed描述符
    struct usb_descriptor_header	**ss_descriptors; // super speed描述符
    struct usb_configuration	*config;  // usb_add_function函數添加的配置
    // 驅動的bind回調函數,配置設定驅動所需的資源,如配置、端點、I/O緩沖區等
    int	(*bind)(struct usb_configuration *, struct usb_function *);
    // 釋放bind配置設定的資源
    void (*unbind)(struct usb_configuration *, struct usb_function *);
    void (*free_func)(struct usb_function *f);  // 釋放usb_function
    // 設定可選的配置,有時候驅動可能有多個配置,需要使用set_alt進行切換
    int (*set_alt)(struct usb_function *, unsigned interface, unsigned alt);
    // 擷取目前的設定的可選配置,如果沒有多個配置,則預設使用配置0,則傳回0
    int (*get_alt)(struct usb_function *, unsigned interface);
    // disable gadget function驅動,主機複位、主機重新配置gadget、斷開連接配接時使用
    void (*disable)(struct usb_function *);
    // 用于特殊接口的控制請求
    int	(*setup)(struct usb_function *, const struct usb_ctrlrequest *);
    // 測試某些裝置類請求能否被處理
    bool (*req_match)(struct usb_function *, const struct usb_ctrlrequest *);
    void (*suspend)(struct usb_function *);
    void (*resume)(struct usb_function *);
    /* USB 3.0 additions */
    // 向GetStatus請求傳回目前gadget Function驅動的狀态
    int (*get_status)(struct usb_function *);  
    // 當接收到SetFeature(FUNCTION_SUSPEND)時,回調該函數
    int (*func_suspend)(struct usb_function *, u8 suspend_opt);
    /* private: internals */
    struct list_head		list;
    DECLARE_BITMAP(endpoints, 32);  // 端點位圖
    const struct usb_function_instance *fi;
    unsigned int		bind_deactivated:1;
};
           

usb_function_driver

通常使用

DECLARE_USB_FUNCTION_INIT

宏定義并初始化。将宏展開後,其定義了

usb_function_driver

結構體執行個體,主要設定

alloc_inst

alloc_func

成員,前置用于建立

usb_function_instance

,表示一個Gadget Function執行個體,後者用于建立

usb_function

并初始化。

usb_function

中的方法實作了具體的Gadget Function驅動。

usb_function_register

usb_function_unregister

函數完成

usb_function_driver

結構體的注冊和登出。

[include/linux/usb/composite.h]
#define DECLARE_USB_FUNCTION_INIT(_name, _inst_alloc, _func_alloc)	\
    DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)		\
    static int __init _name ## mod_init(void)			\
    {								\
        return usb_function_register(&_name ## usb_func);	\  // 注冊UAC裝置驅動
    }								\
    static void __exit _name ## mod_exit(void)			\
    {								\
        usb_function_unregister(&_name ## usb_func);		\  // 登出UAC裝置驅動
    }								\
    module_init(_name ## mod_init);					\  // 子產品初始化
    module_exit(_name ## mod_exit)                     // 子產品解除安裝

#define DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)		\
    // 定義UAC2.0的Gadget Function驅動,名稱為uac2_usb_func
    static struct usb_function_driver _name ## usb_func = {		\
        .name = __stringify(_name),				\  // 驅動名稱為uac2
        .mod  = THIS_MODULE,					\
        .alloc_inst = _inst_alloc,				\
        .alloc_func = _func_alloc,				\
    };								\
    MODULE_ALIAS("usbfunc:"__stringify(_name));
           

3.Gadget Function API

Gadget Funcation API是一個抽象層,上層的Gadget Function驅動使用Gadget Funcation API注冊和登出,下層的Composite驅動使用Gadget Funcation API和Gadget Function驅動綁定和比對。Gadget Function驅動需要實作

usb_function_driver

資料結構并向Gadget Funcation API層注冊。

Gadget Function API的主要API如下。

usb_function_register

将注冊的

usb_function_driver

挂到

func_list

連結清單中。

usb_function_instance

函數會周遊

func_list

連結清單,将參數

name

usb_function_driver

name

進行對比,若名稱一緻,則比對成功,接着調用比對成功的

usb_function_driver

中的

alloc_inst

回調函數擷取

usb_function_instance

,然後将

usb_function_driver

的指針設定到

usb_function_instance

中,最後傳回

usb_function_instance

的指針。

usb_get_function

函數通過回調

alloc_func

函數擷取并初始化

usb_function

。其他API可參考源代碼。

[drivers/usb/gadget/functions.c]
// 向Gadget Function API層注冊Gadget Function驅動
int usb_function_register(struct usb_function_driver *newf)
// 登出Gadget Function驅動
void usb_function_unregister(struct usb_function_driver *fd)
// 從Gadget Function API層擷取usb_function_instance
struct usb_function_instance *usb_get_function_instance(const char *name)
// 回調free_func_inst銷毀usb_function_instance
void usb_put_function_instance(struct usb_function_instance *fi)
// 從Gadget Function API層擷取usb_function_instance
struct usb_function *usb_get_function(struct usb_function_instance *fi)
// 回調free_func銷毀usb_function
void usb_put_function(struct usb_function *f)
           

4.Composite驅動

Linux核心中的USB composite驅動大多都在drivers/usb/gadget/legacy/目錄下,如USB音頻裝置驅動檔案audio.c,USB虛拟以太網裝置驅動檔案ether.c,HID裝置驅動檔案hid.c。USB composite驅動的核心資料結構為

usb_composite_driver

。composite驅動必須實作裝置描述符

dev

bind

回調函數。Composite(複合)裝置使用

usb_composite_dev

資料結構描述,該資料結構在Composite驅動注冊的時候核心會在驅動

bind

函數調用之前自動建立,不需要驅動建立。

gadget

指向dwc3結構體中的

usb_gadget

req

在Composite驅動注冊的時候就提前配置設定好,用于響應主機發送的控制請求。

config

指向目前使用的usb配置。

desc

是目前裝置的描述符,在Composite驅動注冊的時候設定。

driver

指向對應的

usb_composite_driver

[include/linux/usb/composite.h]
struct usb_composite_driver {
    const char  *name;  // 驅動名稱
    const struct usb_device_descriptor *dev;  // 裝置描述符,必須定義
    struct usb_gadget_strings  **strings;
    enum usb_device_speed  max_speed;  // 裝置支援的最大速度
    unsigned  needs_serial:1;
    // 用于配置設定整個裝置共享的資源,使用usb_add_config添加配置,必須實作
    int  (*bind)(struct usb_composite_dev *cdev);  
    int  (*unbind)(struct usb_composite_dev *);       // 銷毀資源
    void  (*disconnect)(struct usb_composite_dev *);  // 可選的驅動disconnect method
    /* global suspend hooks */
    void  (*suspend)(struct usb_composite_dev *);
    void  (*resume)(struct usb_composite_dev *);
    // composite驅動層提供了預設的實作,即composite_driver_template
    struct usb_gadget_driver  gadget_driver;  
};
struct usb_composite_dev {  // 複合裝置
    // 隻讀,usb裝置控制器的抽象,指向dwc3結構體中的usb_gadget
	struct usb_gadget		*gadget;  
	struct usb_request		*req;     // 用于響應控制請求,緩沖區提前配置設定好
	struct usb_request		*os_desc_req;  // 用于響應OS描述符,緩沖區提前配置設定
	struct usb_configuration	*config;  // 目前使用配置
    //  qwSignature part of the OS string
	u8		qw_sign[OS_STRING_QW_SIGN_LEN]; 
	u8		b_vendor_code; // bMS_VendorCode part of the OS string
	struct usb_configuration *os_desc_config;  // OS描述符使用的配置
	unsigned int			use_os_string:1;
	unsigned int			suspended:1;
	struct usb_device_descriptor desc; // 裝置描述符
	struct list_head		configs;
	struct list_head		gstrings;
	struct usb_composite_driver	*driver;  // 指向Composite驅動
    ......
};
           

核心提供了

module_usb_composite_driver

宏,友善驅動定義Composite驅動。參數為

usb_composite_driver

結構體。使用

usb_composite_probe

注冊Composite驅動。使用

usb_composite_unregister

函數登出Composite驅動。

[include/linux/usb/composite.h]
#define module_usb_composite_driver(__usb_composite_driver) \
	module_driver(__usb_composite_driver, usb_composite_probe, \
		       usb_composite_unregister)

[include/linux/device.h]
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \  // 初始化函數
{ \
    return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \  // 登出函數
{ \
    __unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
           

usb_composite_probe

usb_composite_unregister

函數的定義如下。

usb_composite_probe

初始化複合裝置驅動,

usb_composite_unregister

解除安裝複合裝置驅動。

[include/linux/usb/composite.h]
/**
 * usb_composite_probe() - register a composite driver
 * @driver: the driver to register
 *
 * Context: single threaded during gadget setup
 *
 * This function is used to register drivers using the composite driver
 * framework.  The return value is zero, or a negative errno value.
 * Those values normally come from the driver's @bind method, which does
 * all the work of setting up the driver to match the hardware.
 *
 * On successful return, the gadget is ready to respond to requests from
 * the host, unless one of its components invokes usb_gadget_disconnect()
 * while it was binding.  That would usually be done in order to wait for
 * some userspace participation.
 */
int usb_composite_probe(struct usb_composite_driver *driver)
/**
 * usb_composite_unregister() - unregister a composite driver
 * @driver: the driver to unregister
 *
 * This function is used to unregister drivers using the composite
 * driver framework.
 */
void usb_composite_unregister(struct usb_composite_driver *driver)
           

usb_composite_driver

結構體包含了

usb_gadget_driver

資料結構,用來表示usb裝置驅動。核心在Composite驅動層實作了

usb_gadget_driver

,即

composite_driver_template

變量,所有複合裝置都使用該資料結構,無需驅動實作。Composite驅動使用

usb_composite_probe

注冊時,核心會将

composite_driver_template

中的資料拷貝到

usb_composite_driver

gadget_driver

成員。

[include/linux/usb/gadget.h]
struct usb_gadget_driver {
	char *function;  // 描述usb_gadget_driver的字元串
	enum usb_device_speed	max_speed;  // 該驅動可處理的最大速度
    // 回調函數,可通過該函數綁定上層的gadget function驅動
	int	(*bind)(struct usb_gadget *gadget, struct usb_gadget_driver *driver);
	void (*unbind)(struct usb_gadget *);
    // 端點0控制請求調用,用于描述符和配置的管理,通常在中斷中調用,不可睡眠
	int	(*setup)(struct usb_gadget *, const struct usb_ctrlrequest *);
    // 當主機斷開時,所有傳輸停止後調用,可能會在中斷中調用,不可睡眠
	void (*disconnect)(struct usb_gadget *);
	void (*suspend)(struct usb_gadget *);
	void (*resume)(struct usb_gadget *);
    // usb總線複位時調用,必須實作,在中斷中調用
	void (*reset)(struct usb_gadget *);
	struct device_driver	driver;
};

[drivers/usb/gadget/composite.c]
static const struct usb_gadget_driver composite_driver_template = {  // 核心實作的usb裝置驅動
	.bind		= composite_bind,
	.unbind		= composite_unbind,
	.setup		= composite_setup,
	.reset		= composite_disconnect,
	.disconnect	= composite_disconnect,
	.suspend	= composite_suspend,
	.resume		= composite_resume,
	.driver	= {
		.owner		= THIS_MODULE,
	},
};
           

5.UDC驅動

UDC驅動子產品定義如下,核心初始化或子產品加載時初始化,建立

udc_class

,設定

uevent

的回調函數為

usb_udc_uevent

[drivers/usb/gadget/udc/core.c]
static struct class *udc_class;
static int __init usb_udc_init(void)
{
	udc_class = class_create(THIS_MODULE, "udc");
    ......
    udc_class->dev_uevent = usb_udc_uevent;
    return 0;
}
subsys_initcall(usb_udc_init);

static void __exit usb_udc_exit(void)
{
	class_destroy(udc_class);
}
module_exit(usb_udc_exit);
           

UDC驅動使用

usb_udc

資料結構描述,注冊的所有

usb_udc

資料結構都會挂到

udc_list

連結清單上。UDC驅動的功能主要由成員

gadget

實作,即

usb_gadget

資料結構。

usb_gadget_ops

是USB裝置控制器的硬體操作函數,包含啟動USB裝置控制器、停止USB裝置控制器、vbus電源等功能。

ep0

表示端點0,驅動注冊時會提前配置設定好,用于響應控制請求。除端點0外,USB裝置驅動還會使用其他的端點,這些端點資料結構挂到

ep_list

連結清單中。

speed

表示USB裝置控制器目前的速度。

max_speed

表示USB裝置控制器最大的速度。

[drivers/usb/gadget/udc/core.c]
static LIST_HEAD(udc_list);
struct usb_udc {  // 描述usb裝置控制器
    // 指向Composite驅動中的usb_gadget_driver
	struct usb_gadget_driver *driver;
    // 實作udc驅動的結構體,包含usb裝置控制器硬體操作函數
	struct usb_gadget		*gadget;  
	struct device			dev;
    // usb_udc結構體可以組成一個連結清單
	struct list_head		list;
	bool		vbus;  // 對于不關心vbus狀态的udc,該值始終為true
};

[include/linux/usb/gadget.h]
struct usb_gadget {
    // 用于sysfs_notify的工作隊列
	struct work_struct		work;
	struct usb_udc			*udc;  // 指向usb_udc
    // usb裝置控制器硬體操作函數,不涉及io操作
	const struct usb_gadget_ops	*ops;  
	struct usb_ep *ep0;  // 端點0,用于響應控制讀寫請求
	struct list_head ep_list; // 該usb裝置驅動所需的所有端點連結清單
	enum usb_device_speed speed;  // 目前連接配接usb主機的速度
	enum usb_device_speed max_speed;  // udc驅動支援的最大速度
	enum usb_device_state state;  // 目前的狀态
	const char *name;  // udc驅動名稱,用與确認控制器硬體類型
	struct device  dev;
	unsigned out_epnum;  // 最近使用的輸出端點編号
	unsigned in_epnum;   // 最近使用的輸入端點編号
	unsigned mA;         // 最近設定的mA值
	struct usb_otg_caps *otg_caps; // OTG的能力
	unsigned sg_supported:1;       // 是否支援聚合DMA
	unsigned is_otg:1;  // 是否支援OTG,支援OTG必須提供OTG描述符
	unsigned is_a_peripheral:1;    // 一般為false除非支援OTG
    // 輸出端點的請求緩沖區大小按MaxPacketSize對齊
	unsigned quirk_ep_out_aligned_size:1;  
	unsigned is_selfpowered:1;  // 是否是自供電
	unsigned connected:1;       // 是否連接配接成功
	unsigned uvc_enabled:1;     // uvc功能是否使能
    ......
};
struct usb_gadget_ops {  // usb裝置控制器硬體操作函數,不涉及端點和io
	int	(*get_frame)(struct usb_gadget *);
	int	(*wakeup)(struct usb_gadget *);
	int	(*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
	int	(*vbus_session) (struct usb_gadget *, int is_active);
	int	(*vbus_draw) (struct usb_gadget *, unsigned mA);
    // 下拉讓usb主機感覺到usb裝置接入usb總線,usb主機會枚舉usb裝置
	int	(*pullup) (struct usb_gadget *, int is_on);  
	int	(*ioctl)(struct usb_gadget *, unsigned code, unsigned long param);
	void (*get_config_params)(struct usb_dcd_config_params *);
	int	(*udc_start)(struct usb_gadget *, struct usb_gadget_driver *); // 啟動udc
	int	(*udc_stop)(struct usb_gadget *);  // 停止udc
    // 比對usb端點
	struct usb_ep *(*match_ep)(struct usb_gadget *,
		struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *);
};
           

使用

usb_add_gadget_udc

注冊UDC驅動,首先配置設定一個

usb_udc

資料結構,初始化相關成員,最後将

usb_udc

挂到

udc_list

連結清單中,注冊成功後UDC的狀态為

USB_STATE_NOTATTACHED

。使用

usb_del_gadget_udc

删除UDC驅動,首先回調

pullup

斷開連接配接,然後回調

udc_stop

停止USB裝置控制器,最後從

udc_list

連結清單中删除

usb_udc

[drivers/usb/gadget/udc/core.c]
/**
 * usb_add_gadget_udc - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller
 * driver's device.
 * @gadget: the gadget to be added to the list
 *
 * Returns zero on success, negative errno otherwise.
 */
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
/**
 * usb_del_gadget_udc - deletes @udc from udc_list
 * @gadget: the gadget to be removed.
 *
 * This, will call usb_gadget_unregister_driver() if
 * the @udc is still busy.
 */
void usb_del_gadget_udc(struct usb_gadget *gadget);
           

Composite驅動調用

usb_gadget_probe_driver

和UDC驅動比對,首先周遊

udc_list

連結清單,若有

usb_udc

driver

成員為空,則表示比對成功,接着Composite驅動和UDC驅動綁定,通過将Composite驅動的

usb_composite_driver.gadget_driver

的位址設定到

usb_udc.driver

成員中完成綁定,最後回調

udc_start

啟動USB裝置控制器。調用

usb_gadget_unregister_driver

解除Composite驅動和UDC驅動的綁定關系。

[drivers/usb/gadget/udc/core.c]
int usb_gadget_probe_driver(struct usb_gadget_driver *driver);
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
           

繼續閱讀