USB typec to adb

USB typec to adb


首先,简单了解一下USB的构造,如下图:
在这里插入图片描述

Linux 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);

​ 如下流程图是该函数主干:

core.c pm_runtime drd.c host.c gadget.c dwc3_probe 1 分析设备树内的字段 dwc3_get_properties(dwc) 2 设置rpm当前dev是active状态,默认不是active状态, 由hw决定在enable之前是否调用该函数,否则状态紊乱 pm_runtime_set_active(dev) 3 return 4 设置使用autosuspend的功能 pmrunetime_use_auto_suspend(dev) 5 return 6 设置autosuspend的delay时间为5000ms pm_runtime_set_autosuspend_delay(dev,5000) 7 return 8 打开该dev的rpm功能 pm_runtime_enable(dev) 9 return 10 通过rpm同步给dev供电,会同步调用resume回调 pm_runtime_get_sync(dev) 11 return 12 dwc3_get_dr_mode(dwc) 13 dwc3_core_init(dwc) 14 dwc3_core_init_mode(dwc) 15 dwc3_drd_init(dwc) 16 dwc3_drd_update(dwc) 17 dwc3_set_mode(dwc,DWC3_GCTL_PRTCAP_DEVICE) 18 return 19 return 20 注意这里是异步调用 __dwc3_set_mode 21 初始化为host控制器驱动(xhci-hcd),然后交由usb core驱动处理 dwc3_host_init(dwc) 22 初始化为device控制器驱动(gadget),然后交由UDC驱动处理 dwc3_gadget_init(dwc) 23 alt [role is host] [role is device] core.c pm_runtime drd.c host.c gadget.c

​ 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,调用后会自动生成如下目录结构:
在这里插入图片描述

/config/usb_gadget/g1

并且在sys/class/android_usb内生成android0,android0目录结构如下:
在这里插入图片描述

/sys/class/android_usb/android0

​ 在gadgets_make函数内,有一个重要的赋值:

gi->composite.gadget_driver = configfs_driver_template;

  这个回调函数指针的赋值很重要,是暴露给UDC驱动操作configfs、functionfs的重要接口回调API,UDC内会协调Gadget和Dwc3的回调函数;

L8 ~ L10 : 设置产品的VendorID、设备版本号和USB规范版本号;

L11 ~L14 : 创建字符串描述符,并赋值对应字段包含产品序列号、产品厂家和产品型号,生成如下目录结构:
在这里插入图片描述
L15 ~ L17: 创建function的过程类似,这里以创建ffs.adb为例:

user configfs.c functions.c f_fs.c 由mkdir /config/usb_gadget/g1/functions/ffs.adb触发 function_make(ffs.adb) 1 usb_get_function_instance(ffs) 2 try_get_usb_function_instance(ffs) 3 ffs_alloc_inst() 4 return 5 return 6 ffs_set_inst_name(adb) 7 return 8 return 9 user configfs.c functions.c f_fs.c

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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坚持不秃0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值