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
== import /vendor/etc/init/hw/init.${ro.hardware}.rc
== init.qcom.rc
== import init.qcom.usb.rc
== 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
mkdir /config/usb_gadget/g1 0770
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
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
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.2 init.msm.usb.configfs.rc
该配置文件用于读取上层 property,然后 enable 对应 config 的所有 function。
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();
== struct gadget_info *gi;
== gi->composite.gadget_driver = configfs_driver_template;
struct gadget_info {
struct usb_composite_driver composite;
struct usb_composite_dev cdev;
};
static const struct usb_gadget_driver configfs_driver_template = {
.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,
};
2.3 dwc3 初始化
在dwc3 初始化过程中,会构建 usb_gadget 设备。
== dwc3_probe(struct platform_device *pdev);
== dwc3_core_init_mode(struct dwc3 *dwc);
== dwc3_gadget_init(dwc);
int dwc3_gadget_init(struct dwc3 *dwc)
{
...
dwc->gadget = kzalloc(sizeof(struct usb_gadget), GFP_KERNEL);
usb_initialize_gadget(dwc->dev, dwc->gadget, dwc_gadget_release);
dev = &dwc->gadget->dev;
dev->platform_data = dwc;
dwc->gadget->ops = &dwc3_gadget_ops;
dwc->gadget->speed = USB_SPEED_UNKNOWN;
dwc->gadget->sg_supported = true;
dwc->gadget->name = "dwc3-gadget";
dwc->gadget->lpm_capable = true;
ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
ret = usb_add_gadget(dwc->gadget);
}
2.3.1 struct usb_gadget
struct usb_gadget {
struct work_struct work;
struct usb_udc *udc;
const struct usb_gadget_ops *ops;
struct usb_ep *ep0;
struct list_head ep_list;
enum usb_device_speed speed;
enum usb_device_speed max_speed;
enum usb_device_state state;
const char *name;
struct device dev;
...
}
3. 底层对应上层的接口
3.1 gadget_make
mkdir /config/usb_gadget/g3 底层调用gadget_make()
static struct config_group *gadgets_make(struct config_group *group, const char *name)
{
struct gadget_info *gi;
...
config_group_init_type_name(&gi->group, name, &gadget_root_type);
config_group_init_type_name(&gi->functions_group, "functions", &functions_type);
configfs_add_default_group(&gi->functions_group, &gi->group);
config_group_init_type_name(&gi->configs_group, "configs", &config_desc_type);
configfs_add_default_group(&gi->configs_group, &gi->group);
...
gi->composite.max_speed = USB_SPEED_SUPER;
gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());
gi->composite.gadget_driver = configfs_driver_template;
gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
gi->composite.name = gi->composite.gadget_driver.function;
...
}
3.1.1 struct gadget_info
struct gadget_info {
struct config_group group;
struct config_group functions_group;
struct config_group configs_group;
...
struct usb_composite_driver composite;
struct usb_composite_dev cdev;
...
};
3.1.2 struc usb_composite_driver
struct usb_composite_driver {
const char *name;
const struct usb_device_descriptor *dev;
enum usb_device_speed max_speed;
int (*bind)(struct usb_composite_dev *cdev);
int (*unbind)(struct usb_composite_dev *);
void (*disconnect)(struct usb_composite_dev *);
void (*suspend)(struct usb_composite_dev *);
void (*resume)(struct usb_composite_dev *);
struct usb_gadget_driver gadget_driver;
};
3.1.3 struct usb_composite_dev
struct usb_composite_dev {
struct usb_gadget *gadget;
struct usb_request *req;
struct usb_request *os_desc_req;
struct usb_configuration *config;
struct usb_configuration *os_desc_config;
struct usb_device_descriptor desc;
struct usb_composite_driver *driver;
......
};
3.1.4 struct usb_gadget_driver
struct usb_gadget_driver {
char *function;
enum usb_device_speed max_speed;
int (*bind)(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
void (*unbind)(struct usb_gadget *);
int (*setup)(struct usb_gadget *,
const struct usb_ctrlrequest *);
void (*disconnect)(struct usb_gadget *);
void (*suspend)(struct usb_gadget *);
void (*resume)(struct usb_gadget *);
void (*reset)(struct usb_gadget *);
struct device_driver driver;
char *udc_name;
};
3.2 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);
fd->alloc_inst();
== ncm_alloc_inst();
== create_function_device();
== device_create();
== device_add();
3.3 gadget connect
上层:echo “a600000.dwc3” > UDC 底层:gadget_dev_desc_UDC_store(); (1)绑定usb_gadget 与usb_gadget_driver ; (2)dwc3_gadget_start ,注册中断,接收host 的消息; (3)dwc3_gadget_pullup ,enable 端点传输。 kernel 5.4:
== gadget_dev_desc_UDC_store();
== usb_gadget_probe_driver(struct usb_gadget_driver *driver)
== udc_bind_to_driver();
== driver->bind(udc->gadget, driver);
== configfs_composite_bind();
== usb_add_function(c, f);
== 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);
== 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);
== __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
3.4 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);
usb_gadget_disconnect(udc->gadget);
if (udc->gadget->irq)
synchronize_irq(udc->gadget->irq);
udc->driver->unbind(udc->gadget);
usb_gadget_udc_stop(udc);
udc->driver = NULL;
udc->dev.driver = NULL;
udc->gadget->dev.driver = NULL;
}
3.4.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);
== dwc3_remove_requests(dwc, dep);
== __dwc3_gadget_stop(struct dwc3 *dwc)
== __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
== dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
3.4.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)
== usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
== ret = ep->ops->dequeue(ep, req);
.dequeue = dwc3_gadget_ep_dequeue,
==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:
== 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();
== 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();
== dwc3_process_event_buf();
== dwc3_process_event_entry(); trace_dwc3_event(event->raw, dwc);
== dwc3_endpoint_interrupt();
== dwc3_ep0_interrupt();
== dwc3_ep0_xfer_complete();
== dwc3_ep0_inspect_setup();
== dwc3_ep0_delegate_req();
== dwc->gadget_driver->setup(&dwc->gadget, ctrl);
== configfs_composite_setup();
== composite_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);
== req->complete(ep, req);
== ffs_ep0_complete()
== dwc3_gadget_interrupt(dwc, &event->devt);
== 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);
|