当前位置:网站首页>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);
边栏推荐
- Google common syntax
- 看了5本书,我总结出财富自由的这些理论
- Tensorboard的使用
- Do not put files with garbled names into the CFS of NFS protocol
- @What is the difference between controller and @restcontroller?
- There are some limitations in cluster expansion and contraction
- Cloud computing "half peak"
- 走好数据中台最后一公里,为什么说数据服务API是数据中台的标配?
- Integers and operators in go data types (3)
- Vulnhub | dc: 3 | [actual combat]
猜你喜欢
随机推荐
Check the file through the port
aquatone工具 中的2个bug修复
2-用线段构成图形、坐标转换
力扣(LeetCode)173. 二叉搜索树迭代器(2022.06.22)
vector的深度剖析及模拟实现
Crawler frame
MFC Radio Button分组
爬虫框架
词性家族
C# 内存法复制图像bitmap
Set the time zone in ci4 (CodeIgniter 4)
Deep learning ----- convolution (conv2d) bottom layer
3-ProgressBar和二次裁剪
Capturing packets to find repeated acks and a large number of TCP retransmissions in TCP sessions -- sack (selective acknowledgement) technology
Ignore overlength parameter violation
MySQL小册子笔记 5 InnoDB 记录存储结构
【云计算】GFS思想优势以及架构
You have a string of code, but do not support the lower version of go; Judge the go version number, you deserve it!
Image segmentation - improved network structure
Captain Abu's soul torture








