当前位置:网站首页>usb peripheral 驱动 - configfs

usb peripheral 驱动 - configfs

2022-06-23 08:10:00 对我好两点

1. configfs init

1.1 configfs usage

参考文档:msm-kernel\Documentation\usb\gadget_configfs.rst
(1) Creating the gadgets:

mkdir /config/usb_gadget/g3		// mkdir $CONFIGFS_HOME/usb_gadget/<gadget name> 

底层调用gadget_make()

(2) Creating the configurations:

cd /config/usb_gadget/g3
mkdir configs/c.1			// mkdir configs/<name>.<number> 

(3) Creating the functions:

mkdir functions/ncm.usb0	// mkdir functions/<name>.<instance name>

底层调用function_make()

(4) Associating the functions with their configurations:

ln -s functions/ncm.usb0 configs/c.1	// ln -s functions/<name>.<instance name> configs/<name>.<number>

底层调用:config_usb_cfg_link()

(5) Enabling the gadget:

echo <udc name> > UDC
echo "a600000.dwc3" > UDC

底层调用:gadget_dev_desc_UDC_store()

1.2 configfs init file

== init.rc		// 源码路径\system\core\rootdir\init.rc
	== import /vendor/etc/init/hw/init.${
    ro.hardware}.rc
	== init.qcom.rc		// 源码路径\device\qcom\common\rootdir\etc
		== import init.qcom.usb.rc		// filesystem路径/vendor/etc/init/hw/
		== import init.msm.usb.configfs.rc
		== import init.target.rc

1.2.1 init.qcom.usb.rc

该配置文件用于:
(1)创建设备 gadget;
(2)创建配置 config;
(3)创建接口 function。

on boot
    write /sys/class/android_usb/android0/iSerial ${
    ro.serialno}
    mount configfs none /config			// 挂载configfs
    mkdir /config/usb_gadget/g1 0770	// (1)创建设备gadget
    mkdir /config/usb_gadget/g2 0770
    mkdir /config/usb_gadget/g1/strings/0x409 0770
    mkdir /config/usb_gadget/g2/strings/0x409 0770
    write /config/usb_gadget/g1/bcdUSB 0x0200
    write /config/usb_gadget/g2/bcdUSB 0x0200
    write /config/usb_gadget/g1/os_desc/use 1
    write /config/usb_gadget/g1/strings/0x409/serialnumber ${
    ro.serialno}
    write /config/usb_gadget/g2/strings/0x409/serialnumber ${
    ro.serialno}
    write /config/usb_gadget/g1/strings/0x409/manufacturer ${
    ro.product.manufacturer}
    write /config/usb_gadget/g2/strings/0x409/manufacturer ${
    ro.product.manufacturer}
    write /config/usb_gadget/g1/strings/0x409/product ${
    ro.product.model}
    write /config/usb_gadget/g2/strings/0x409/product ${
    ro.product.model}
    mkdir /config/usb_gadget/g1/functions/mass_storage.0	// (3)创建接口 function
    mkdir /config/usb_gadget/g1/functions/mtp.gs0
    mkdir /config/usb_gadget/g1/functions/ptp.gs1
    mkdir /config/usb_gadget/g1/functions/accessory.gs2
    mkdir /config/usb_gadget/g1/functions/audio_source.gs3
    mkdir /config/usb_gadget/g1/functions/midi.gs5
    mkdir /config/usb_gadget/g1/functions/ffs.adb
    mkdir /config/usb_gadget/g1/functions/diag.diag
    mkdir /config/usb_gadget/g1/functions/diag.diag_mdm
    mkdir /config/usb_gadget/g1/functions/cser.dun.0
    mkdir /config/usb_gadget/g1/functions/cser.nmea.1
    mkdir /config/usb_gadget/g1/functions/cser.dun.2
    mkdir /config/usb_gadget/g1/functions/gsi.rmnet
    mkdir /config/usb_gadget/g1/functions/gsi.rndis
    mkdir /config/usb_gadget/g1/functions/gsi.dpl
    mkdir /config/usb_gadget/g1/functions/qdss.qdss
    mkdir /config/usb_gadget/g1/functions/qdss.qdss_mdm
    mkdir /config/usb_gadget/g1/functions/rndis_bam.rndis
    mkdir /config/usb_gadget/g1/functions/rndis.rndis
    mkdir /config/usb_gadget/g1/functions/rmnet_bam.rmnet
    mkdir /config/usb_gadget/g1/functions/rmnet_bam.dpl
    mkdir /config/usb_gadget/g1/functions/rmnet_bam.rmnet_bam_dmux
    mkdir /config/usb_gadget/g1/functions/rmnet_bam.dpl_bam_dmux
    mkdir /config/usb_gadget/g1/functions/ncm.0
    mkdir /config/usb_gadget/g1/functions/ccid.ccid
    mkdir /config/usb_gadget/g1/functions/uac2.0
    mkdir /config/usb_gadget/g1/functions/uvc.0
    mkdir /config/usb_gadget/g1/functions/uvc.1
    mkdir /config/usb_gadget/g1/functions/hid.0
    mkdir /config/usb_gadget/g1/functions/hid.1
    mkdir /config/usb_gadget/g1/functions/hid.2
    mkdir /config/usb_gadget/g1/functions/hid.3
    mkdir /config/usb_gadget/g1/functions/hid.4
    mkdir /config/usb_gadget/g1/functions/hid.5
    mkdir /config/usb_gadget/g1/configs/b.1 0770	//(2)创建配置config
    mkdir /config/usb_gadget/g2/configs/b.1 0770
    mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770
    mkdir /config/usb_gadget/g2/configs/b.1/strings/0x409 0770
    write /config/usb_gadget/g1/os_desc/b_vendor_code 0x1
    write /config/usb_gadget/g1/os_desc/qw_sign "MSFT100"
    symlink /config/usb_gadget/g1/configs/b.1 /config/usb_gadget/g1/os_desc/b.1
    mkdir /dev/usb-ffs 0775 shell system
    mkdir /dev/usb-ffs/adb 0770 shell system
    mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=1000,rmode=0770,fmode=0660
    write /sys/class/android_usb/android0/f_ffs/aliases adb
    setprop sys.usb.mtp.device_type 2
    setprop vendor.usb.controller ${
    sys.usb.controller}
    enable vendor.qcom-usb-sh

1.2.1 init.msm.usb.configfs.rc

该配置文件用于读取上层 property,然后 enable 对应 config 的所有 function。

// sys.usb.config=diag,adb 表示该配置拥有diag 和adb 两个接口功能;
// 可使用getprop sys.usb.config 进行查询,setprop sys.usb.config=**进行配置切换
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=diag,adb && property:sys.usb.configfs=1
    write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "diag_adb"
    rm /config/usb_gadget/g1/configs/b.1/f1
    rm /config/usb_gadget/g1/configs/b.1/f2
    rm /config/usb_gadget/g1/configs/b.1/f3
    rm /config/usb_gadget/g1/configs/b.1/f4
    rm /config/usb_gadget/g1/configs/b.1/f5
    rm /config/usb_gadget/g1/configs/b.1/f6
    rm /config/usb_gadget/g1/configs/b.1/f7
    rm /config/usb_gadget/g1/configs/b.1/f8
    rm /config/usb_gadget/g1/configs/b.1/f9
    rm /config/usb_gadget/g1/configs/b.1/f10
    rm /config/usb_gadget/g1/configs/b.1/f11
    write /config/usb_gadget/g1/idVendor 0x05C6
    write /config/usb_gadget/g1/idProduct 0x901D
    symlink /config/usb_gadget/g1/functions/diag.diag /config/usb_gadget/g1/configs/b.1/f1
    symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
    write /config/usb_gadget/g1/UDC ${
    sys.usb.controller}
    setprop sys.usb.state ${
    sys.usb.config}

2. 驱动模块初始化

2.1 function 驱动初始化

所有的 function 驱动都注册在一个链表中 func_list,当 configfs 驱动启动时,读取上层配置的 function 去与链表中的匹配。
\drivers\usb\gadget\function\f_fs.c 中,用如下宏去注册 function 驱动(将 usb_function_driver 加入func_list链表),该 init 操作在系统初始化的时候就会被执行。

#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); \ } \ static void __exit _name ## mod_exit(void) \ {
       \ usb_function_unregister(&_name ## usb_func); \ } \ module_init(_name ## mod_init); \ module_exit(_name ## mod_exit)

2.2 configfs 驱动初始化

\drivers\usb\gadget\configfs.c

在系统加载驱动模块的时候初始化gadget configfs,包括提供给上层的一些操作接口(mkdir write…

== module_init(gadget_cfs_init);
	== configfs_register_subsystem(&gadget_subsys);
		gadget_subsys == gadgets_type == gadgets_ops
		== gadgets_make();		//gadget_make会在上层执行mkdir 的时候调用
			== struct gadget_info *gi;		//构建gadget_info
			== gi->composite.gadget_driver = configfs_driver_template;		//构建usb_gadget_driver

struct gadget_info {
    
	struct usb_composite_driver composite;
	struct usb_composite_dev cdev;
};

static const struct usb_gadget_driver configfs_driver_template = {
    	//usb_gadget_driver
	.bind           = configfs_composite_bind,
	.unbind         = configfs_composite_unbind,

#ifdef CONFIG_USB_CONFIGFS_UEVENT
	.setup          = android_setup,
#else
	.setup          = configfs_composite_setup,
#endif
	.reset          = configfs_composite_reset,
	.disconnect     = configfs_composite_disconnect,
	.suspend	= configfs_composite_suspend,
	.resume		= configfs_composite_resume,
};

3. 底层对应上层的接口

3.1 function_make

上层:mkdir /config/usb_gadget/g1/functions/diag.diag
底层:function_make()

 static struct config_group *function_make(
		struct config_group *group,
		const char *name)

function_make 调用过程:

== configfs_mkdir();
	== function_make(struct config_group *group, const char *name); 
		== usb_get_function_instance(); 
			== try_get_usb_function_instance(const char *name);		// 从func_list 中找到fd
				fd->alloc_inst(); 
				== ncm_alloc_inst(); 
					== create_function_device(); 
						== device_create(); 
							== device_add();

3.2 gadget connect

上层:echo “a600000.dwc3” > UDC
kernel 5.4:

== gadget_dev_desc_UDC_store();		// \drivers\usb\gadget\configfs.c
	== usb_gadget_probe_driver(struct usb_gadget_driver *driver)	 // \drivers\usb\gadget\udc\core.c
		== udc_bind_to_driver();	//绑定usb_gadget_driver 与usb_udc
			== driver->bind(udc->gadget, driver);
				== configfs_composite_bind();
					== usb_add_function(c, f);		//添加function,执行function 的函数
			== usb_gadget_udc_start(udc);
				== udc->gadget->ops->udc_start(udc->gadget, udc->driver);
					== dwc3_gadget_start();
						== request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, IRQF_SHARED, "dwc3", dwc->ev_buf);
						//注册dwc3中断,当host发消息过来时,触发中断函数
			== usb_udc_connect_control(struct usb_udc *udc)
				== usb_gadget_connect(struct usb_gadget *gadget)
					== gadget->ops->pullup(gadget, 1);
					== dwc3_gadget_pullup(struct usb_gadget *g, int is_on);
						== dwc3_gadget_run_stop_util();
							== dwc3_gadget_run_stop(dwc, true, false);
								== __dwc3_gadget_start(dwc);		//enable端点传输
									== __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)		// initializes a hw endpoint

3.2 gadget disconnect

上层:echo “none” > UDC

== gadget_dev_desc_UDC_store
	== unregister_gadget(struct gadget_info *gi)
		== usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
			== usb_gadget_remove_driver(struct usb_udc *udc)
			
static void usb_gadget_remove_driver(struct usb_udc *udc)
{
    
	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
			udc->driver->function);

	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);	//产生一个uevent 上报

	usb_gadget_disconnect(udc->gadget);				//gadget 驱动断开
	if (udc->gadget->irq)
		synchronize_irq(udc->gadget->irq);
	udc->driver->unbind(udc->gadget);				//取消req(gadget 的端点0 usb_ep)
	usb_gadget_udc_stop(udc);						//udc 停止

	udc->driver = NULL;
	udc->dev.driver = NULL;
	udc->gadget->dev.driver = NULL;
}

3.2.1 disable 控制器的端点dwc3_ep(32个)

== usb_gadget_disconnect(struct usb_gadget *gadget)       
	gadget->ops->pullup(gadget, 0);
	.pullup			= dwc3_gadget_pullup,
	== dwc3_gadget_pullup(struct usb_gadget *g, int is_on)    	// 打开/关闭端点、写寄存器
		== dwc3_stop_active_transfers(dwc);						// 非0 端点
			== dwc3_remove_requests(dwc, dep);
		== __dwc3_gadget_stop(struct dwc3 *dwc)					// disable 端点0(控制端点)传输
			== __dwc3_gadget_ep_disable(struct dwc3_ep *dep)  	// disables a hw endpoint
				== dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)   

3.2.2 取消req(gadget 的端点0 usb_ep)

== udc->driver->unbind(udc->gadget);
	.unbind		= composite_unbind,
	.unbind     = configfs_composite_unbind,
	== configfs_composite_unbind(struct usb_gadget *gadget)
		== composite_dev_cleanup(struct usb_composite_dev *cdev)    		// 清除composite dev上的req
			== usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)	// dequeues (cancels, unlinks) an I/O request from an endpoint
				== ret = ep->ops->dequeue(ep, req);					
					.dequeue	= dwc3_gadget_ep_dequeue, 					//usb_ep转化为dwc3_ep
					==dwc3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *request)

4. 一次完整的 Gadget 数据流

Configfs子系统与控制器之间的数据交换是通过struct usb_request *request结构体,一次完整的流程如下:

4.1 function 申请req

\drivers\usb\gadget\function\f_fs.c
(1) 申请 req:

== ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);	trace_usb_ep_alloc_request(ep, req, req ? 0 : -ENOMEM);
	== ep->ops->alloc_request(ep, gfp_flags);
	== dwc3_gadget_ep_alloc_request();									trace_dwc3_alloc_request(req);
== ffs->ep0req->complete = ffs_ep0_complete;	// req的完成函数

释放 req:

== ffs_func_unbind();
	== usb_ep_free_request();					trace_usb_ep_free_request(ep, req, 0);
		== ep->ops->free_request(ep, req);
		== dwc3_gadget_ep_free_request();		trace_dwc3_free_request();	

(2) 将req提交到控制器:

== usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);		trace_usb_ep_queue(ep, req, ret);
	== ret = ep->ops->queue(ep, req, gfp_flags);
	==  dwc3_gadget_ep0_queue();
		== __dwc3_gadget_ep0_queue();
			== __dwc3_ep0_do_control_data();
				== dwc3_ep0_start_trans();
					== dwc3_send_gadget_ep_cmd();		trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status);
						== dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0);

4.2 控制器处理req (写寄存器)

== dwc3_gadget_ep_queue();
	== __dwc3_gadget_ep_queue();
		== __dwc3_gadget_start_isoc(struct dwc3_ep *dep);
			==__dwc3_gadget_kick_transfer(struct dwc3_ep *dep);
				== dwc3_send_gadget_ep_cmd(); 	// This function will issue @cmd with given @params to @dep and wait for its completion.
					== dwc3_writel(void __iomem *base, u32 offset, u32 value)

4.3 控制器返回req (中断回调函数)

== dwc3_gadget_start();  						//注册中断
	== request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, IRQF_SHARED, "dwc3", dwc->ev_buf);
	== dwc3_thread_interrupt();					//中断产生(host发消息过来),调用回调函数
		== dwc3_process_event_buf();			//处理中断事件buf(dwc3_event_buffer )
			== dwc3_process_event_entry();		trace_dwc3_event(event->raw, dwc);
				== dwc3_endpoint_interrupt();	//对端点处理的中断
					== dwc3_ep0_interrupt();	//控制传输if (epnum == 0 || epnum == 1) 
						== dwc3_ep0_xfer_complete();		//event->endpoint_event = DWC3_DEPEVT_XFERCOMPLETE
							== dwc3_ep0_inspect_setup();	//dwc->ep0state = EP0_SETUP_PHASE
								//dwc3_ep0_std_request() == dwc3_ep0_set_config()
								== dwc3_ep0_delegate_req();
									== dwc->gadget_driver->setup(&dwc->gadget, ctrl);
									== configfs_composite_setup();	
										== composite_setup();		//setup 包括获取描述符,配置,地址等操作
											== set_config(cdev, ctrl, w_value);	ctrl->bRequest = USB_REQ_SET_CONFIGURATION
					== dwc3_gadget_endpoint_transfer_complete();		//传输完成
						== dwc3_gadget_endpoint_trbs_complete();
							== dwc3_gadget_ep_cleanup_completed_requests()
								== dwc3_gadget_giveback();				//数据返回
									== dwc3_gadget_del_and_unmap_request();		trace_dwc3_gadget_giveback(req);
									== usb_gadget_giveback_request()			trace_usb_gadget_giveback_request(ep, req, 0);// give the request back to the gadget layer
										== req->complete(ep, req);
										== ffs_ep0_complete()	// function的完成函数
				== dwc3_gadget_interrupt(dwc, &event->devt);	//对gadget设备的中断
					== usb_gadget_vbus_draw(&dwc->gadget, 2);	trace_usb_gadget_vbus_draw(gadget, ret);
						== gadget->ops->vbus_draw(gadget, mA);
						== dwc3_gadget_vbus_draw();	
							== dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, 0);		
原网站

版权声明
本文为[对我好两点]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_42129680/article/details/125405008