文章目录
首先,简单了解一下USB的构造,如下图:
从上图可以看到,
- 在主机(host)端,USB驱动包含主机控制器驱动和设备驱动;
- 在设备(device)端,USB驱动包含设备控制器驱动和Gadget Function驱动
而Dwc3驱动是一个USB控制器驱动,即可作为主机控制器驱动,也可作为设备控制器驱动。
本文主要结合code来做简单分析,如有错误的地方,烦请指正,谢谢。
1、 模块初始化
1.1、Dwc3 模块初始化
Dwc3是什么?
dwc3是指DesignWare USB 3.0(SuperSpeed USB) xHCI控制器,它是用于支持USB3.0设备的控制器。
下面来查看该驱动的初始化以及probe过程:
// drivers/usb/dwc3/core.c
----------------------------------------------------------------------
static const struct of_device_id of_dwc3_match[] = {
{
.compatible = "snps,dwc3"},
{
.compatible = "synopsys,dwc3"},
{
},
};
MODULE_DEVICE_TABLE(of, of_dwc3_match);
static struct platform_driver dwc3_driver = {
.probe = dwc3_probe,
.remove = dwc3_remove,
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
.pm = &dwc3_dev_pm_ops,
},
};
module_platform_driver(dwc3_driver);
如下流程图是该函数主干:
step 1: 由linux的设备驱动模型,匹配上device后调用dwc3_probe函数;
step 2: 解析设备树字段,获取设备能力;
step 3 ~ 12: 用于设置dwc3的运行时电源管理,该管理主要能节省模块功耗,实现动态管理;
step 13: 解析当前设备初始化的角色,前面step 2解析出来的初始化角色,会在这里重新赋值一次,默认为otg模式;
step 14: 初始化phy,从rk3568的dts来看:
- usb2_phy是usb2-phy@fe8a0000
- usb3_phy是phy@fe820000
step 15: 进入OTG的case,初始化工作队列;
step 16: 设置role从那种渠道获取,extcon的方式的话会注册回调,瑞芯微默认extcon方式;
- 一种直接通过tcpm,由typec自身控制role的切换
- 另一种通过extcon的方式,由其他设备通知dwc3的来改变role
step 17: 从extcon读取当前typeC插入状态,来确定优先初始化当前设备为那个role,默认为device;
step 18: 传进来的role,推入工作队列;
step 19: 异步触发工作队列回调函数,当进行设备的device或host角色的初始化
step 20: 当传过来的是host role时会执行这步,主要初始化dwc3为主机控制器驱动,创建xhci的host设备并交由usb core进行管理。
step 21: 当传来的是device role时会执行这步,主要初始化dwc3为设备控制器驱动,创建gadget并把当前dwc3的设备当做是UDC设备来处理,注册回调操作函数dwc3_gadget_ops,后续由UDC进行管理,设备名字存储在udc_list列表,同时创建/sys/devices/platform/usbdrd/fcc00000.dwc3/gadget和/sys/class/udc/fcc00000.dwc3两个目录,当然fcc00000.dwc3会根据dts的变化而变化。
1.2、 Gadget模块初始化
Gadget是什么?
Gadget是USB设备驱动,可以按照USB规范和设备类进行配置,使得当前设备成为各种各样的通用USB设备,如键鼠(HID class)、U盘(Mass storage class)、网卡(CDC class)、摄像头(Video class)和串口(Serial class)。
为了方便配置一般Gadget模块会打开configfs(config file system)功能,方便上层也方便linux进行USB设备的配置。Gadget 的configfs功能给上层暴露接口节点进行配置。相关的配置信息在目前查看的瑞芯微的android 代码是存放在rc文件内,本文在后面有进行解析。
static struct configfs_group_operations gadgets_ops = {
// 在usb_gadget内创建目录时,调用.make_group 回调
.make_group = &gadgets_make,
.drop_item = &gadgets_drop,
};
static const struct config_item_type gadgets_type = {
.ct_group_ops = &gadgets_ops,
.ct_owner = THIS_MODULE,
};
static struct configfs_subsystem gadget_subsys = {
.su_group = {
.cg_item = {
.ci_namebuf = "usb_gadget",
.ci_type = &gadgets_type,
},
},
.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
};
static int __init gadget_cfs_init(void)
{
int ret;
config_group_init(&gadget_subsys.su_group);
// 在挂载目录时,会调用.make_group回调
ret = configfs_register_subsystem(&gadget_subsys);
#ifdef CONFIG_USB_CONFIGFS_UEVENT
// 在/sys/class目录下创建android_usb目录
android_class = class_create(THIS_MODULE, "android_usb");
if (IS_ERR(android_class))
return PTR_ERR(android_class);
#endif
return ret;
}
module_init(gadget_cfs_init);
configfs初始化函数很简单,只是简单的注册了一个目录回调,然后在sys/class内创建了一个名为andriod_usb的目录。
on boot
mkdir /dev/usb-ffs 0775 shell shell
mkdir /dev/usb-ffs/adb 0770 shell shell
mkdir /dev/usb-ffs/mtp 0770 mtp mtp
mkdir /dev/usb-ffs/ptp 0770 mtp mtp
mount configfs none /config
mkdir /config/usb_gadget/g1 0770 shell shell
write /config/usb_gadget/g1/idVendor 0x2207
write /config/usb_gadget/g1/bcdDevice 0x0310
write /config/usb_gadget/g1/bcdUSB 0x0200
mkdir /config/usb_gadget/g1/strings/0x409 0770
write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
write /config/usb_gadget/g1/strings/0x409/manufacturer ${ro.product.manufacturer}
write /config/usb_gadget/g1/strings/0x409/product ${ro.product.model}
mkdir /config/usb_gadget/g1/functions/ffs.adb
mkdir /config/usb_gadget/g1/functions/ffs.mtp
mkdir /config/usb_gadget/g1/functions/ffs.ptp
....................................................................................
mkdir /config/usb_gadget/g1/configs/b.1 0770 shell shell
mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770 shell shell
write /config/usb_gadget/g1/os_desc/b_vendor_code 0x1
write /config/usb_gadget/g1/os_desc/qw_sign "MSFT100"
write /config/usb_gadget/g1/configs/b.1/MaxPower 500
symlink /config/usb_gadget/g1/configs/b.1 /config/usb_gadget/g1/os_desc/b.1
mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
mount functionfs mtp /dev/usb-ffs/mtp rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1
mount functionfs ptp /dev/usb-ffs/ptp rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1
setprop sys.usb.mtp.device_type 3
setprop sys.usb.configfs 1
如上是截取的瑞芯微配置configfs的启动项配置,下面对每一行进行分析:
L1 : 是rc文件的label,在android init进程启动时,将自动执行boot的label,所以这里在开机启动到android的init进程时将自动执行boot所写的指令;
L2 ~ L5 :这里只是在dev下创建一个子目录,目前还不会什么作用,后续会把对应的接口通讯port放在这些目录下;
L6 : 挂载configfs文件系统,会生成目录/config/usb_gadget;
L7 : 在usb_gadget目录下创建g1目录,这里会触发.make_group回调,调用函数gadgets_make,调用后会自动生成如下目录结构:

并且在sys/class/android_usb内生成android0,android0目录结构如下:

在gadgets_make函数内,有一个重要的赋值:
这个回调函数指针的赋值很重要,是暴露给UDC驱动操作configfs、functionfs的重要接口回调API,UDC内会协调Gadget和Dwc3的回调函数;
L8 ~ L10 : 设置产品的VendorID、设备版本号和USB规范版本号;
L11 ~L14 : 创建字符串描述符,并赋值对应字段包含产品序列号、产品厂家和产品型号,生成如下目录结构:

L15 ~ L17: 创建function的过程类似,这里以创建ffs.adb为例:
L19 ~ L20 : 新建b.1目录,会调用configs的.make_group回调,对应函数config_desc_make,生成如下目录结构:

L21 ~L23 : 对目录所生成的属性项进行赋值;
L24 : 把configs/b.1映射到os_desc目录下,此时会调用os_desc_link函数,里面没有啥实质性的操作只是简单的赋值这里不细说。
L25 ~ L27 : 三条类似的指令,以L25条为例,把functionsFs挂载到/dev/usb-ffs/adb目录下;根据functionFs注册文件系统的初始化代码,如下:
static const struct fs_context_operations ffs_fs_context_ops = {
.free = ffs_fs_free_fc,
.parse_param = ffs_fs_parse_param,
.get_tree = ffs_fs_get_tree,
};
static int ffs_fs_init_fs_context(struct fs_context *fc)
{
struct ffs_sb_fill_data *ctx;
ctx = kzalloc(sizeof(struct


2158

被折叠的 条评论
为什么被折叠?



