当前位置:网站首页>USB peripheral driver - configfs

USB peripheral driver - configfs

2022-06-23 08:25:00 Be good to me

1. configfs init

1.1 configfs usage

Reference documents :msm-kernel\Documentation\usb\gadget_configfs.rst
(1) Creating the gadgets:

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

Bottom call 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>

Bottom call 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>

Bottom call :config_usb_cfg_link()

(5) Enabling the gadget:

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

Bottom call :gadget_dev_desc_UDC_store()

1.2 configfs init file

== init.rc		//  Source path \system\core\rootdir\init.rc
	== import /vendor/etc/init/hw/init.${
    ro.hardware}.rc
	== init.qcom.rc		//  Source path \device\qcom\common\rootdir\etc
		== import init.qcom.usb.rc		// filesystem route /vendor/etc/init/hw/
		== import init.msm.usb.configfs.rc
		== import init.target.rc

1.2.1 init.qcom.usb.rc

This configuration file is used for :
(1) Create device gadget;
(2) Create a configuration config;
(3) Create an interface function.

on boot
    write /sys/class/android_usb/android0/iSerial ${
    ro.serialno}
    mount configfs none /config			//  mount configfs
    mkdir /config/usb_gadget/g1 0770	// (1) Create device 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) Create an interface  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) Create a configuration 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

This configuration file is used to read the upper layer property, then enable Corresponding config All of the function.

// sys.usb.config=diag,adb  Indicates that the configuration has diag  and adb  Two interface functions ;
//  You can use getprop sys.usb.config  The query ,setprop sys.usb.config=** Perform configuration switching 
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. Driver module initialization

2.1 function Drive initialization

be-all function Drivers are registered in a linked list func_list, When configfs When the drive is started , Read the upper layer configuration function To match with the list .
stay \drivers\usb\gadget\function\f_fs.c in , Use the following macro to register function drive ( take usb_function_driver Join in func_list Linked list ), The init The operation will be executed when the system is initialized .

#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 Drive initialization

\drivers\usb\gadget\configfs.c

Initialize when the system loads the driver module gadget configfs, Including some operation interfaces provided to the upper layer (mkdir write…

== module_init(gadget_cfs_init);
	== configfs_register_subsystem(&gadget_subsys);
		gadget_subsys == gadgets_type == gadgets_ops
		== gadgets_make();		//gadget_make Will be executed at the upper level mkdir  Called when 
			== struct gadget_info *gi;		// structure gadget_info
			== gi->composite.gadget_driver = configfs_driver_template;		// structure 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. The bottom layer corresponds to the interface of the upper layer

3.1 function_make

The upper :mkdir /config/usb_gadget/g1/functions/diag.diag
Bottom :function_make()

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

function_make Call the process :

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

3.2 gadget connect

The upper :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();	// binding usb_gadget_driver  And usb_udc
			== driver->bind(udc->gadget, driver);
				== configfs_composite_bind();
					== usb_add_function(c, f);		// add to function, perform function  Function of 
			== 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);
						// register dwc3 interrupt , When host When you send a message , Trigger interrupt function 
			== 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 Endpoint transport 
									== __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)		// initializes a hw endpoint

3.2 gadget disconnect

The upper :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);	// Produce a uevent  Report 

	usb_gadget_disconnect(udc->gadget);				//gadget  Drive off 
	if (udc->gadget->irq)
		synchronize_irq(udc->gadget->irq);
	udc->driver->unbind(udc->gadget);				// Cancel req(gadget  The endpoint of 0 usb_ep)
	usb_gadget_udc_stop(udc);						//udc  stop it 

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

3.2.1 disable The endpoint of the controller dwc3_ep(32 individual )

== 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)    	//  open / Close endpoint 、 Write register 
		== dwc3_stop_active_transfers(dwc);						//  Not 0  Endpoint 
			== dwc3_remove_requests(dwc, dep);
		== __dwc3_gadget_stop(struct dwc3 *dwc)					// disable  Endpoint 0( Control endpoints ) transmission 
			== __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 Cancel req(gadget The endpoint of 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)    		//  eliminate composite dev Upper 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 Turn into dwc3_ep
					==dwc3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *request)

4. Once complete Gadget Data flow

Configfs The data exchange between the subsystem and the controller is through struct usb_request *request Structure , A complete process is as follows :

4.1 function apply req

\drivers\usb\gadget\function\f_fs.c
(1) apply 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 Completion function of 

Release 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) take req Submit to controller :

== 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 Controller processing req ( Write register )

== 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 Controller return req ( Interrupt callback function )

== dwc3_gadget_start();  						// Registration interrupted 
	== request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, IRQF_SHARED, "dwc3", dwc->ev_buf);
	== dwc3_thread_interrupt();					// Interrupt generation (host Send a message ), Call callback function 
		== dwc3_process_event_buf();			// Handling interrupt events buf(dwc3_event_buffer )
			== dwc3_process_event_entry();		trace_dwc3_event(event->raw, dwc);
				== dwc3_endpoint_interrupt();	// Interruption of endpoint processing 
					== dwc3_ep0_interrupt();	// Control transmission 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  Including getting descriptors , To configure , Address and other operations 
											== set_config(cdev, ctrl, w_value);	ctrl->bRequest = USB_REQ_SET_CONFIGURATION
					== dwc3_gadget_endpoint_transfer_complete();		// Transmission complete 
						== dwc3_gadget_endpoint_trbs_complete();
							== dwc3_gadget_ep_cleanup_completed_requests()
								== dwc3_gadget_giveback();				// The data returned 
									== 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 Completion function of 
				== dwc3_gadget_interrupt(dwc, &event->devt);	// Yes gadget The interruption of the device 
					== 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);		
原网站

版权声明
本文为[Be good to me]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/174/202206230809397095.html