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.Linux 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

	android_usb@fe8078c8 {
		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]);	//创建设备链接




  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值