简介

本文主要讲述usb 2.0 host 中struct phy、struct usb_hcd、struct usb_hub、struct usb_port以及struct urb之间的关系。hcd方面只讲述echi,不讲述ohci。理解了它们的关系有助于我们移植usb驱动。

概念

先来理清几个概念:
1、usb controller:USB主机控制器。CPU通过主机控制器跟usb设备进行通信。CPU把要做的事情告诉主机控制器,主机控制器帮CPU把事情完成后以中断的形式告诉CPU。主机控制器对应的驱动叫做usb hcd,linux使用struct usb_hcd描述USB主机控制器。
2、usb phy:usb物理层。它负责最底层的信号转换,类似网口的phy。他有有两种接口,一种是ULPI,一种是UTMI。UTMI是USB2.0的高速设备检测协议,它需要具备能够检测设备是高速端口还是全速端口的功能,并以作相应的速度模式进行工作。从4412的usb框架图可以看出4412芯片上的phy使用的是UTMI。如图1 所示。但是4412的ehci主机控制器并不需要usb phy,只需要phy相关的就行。
3、usb hub:集线器。4412芯片内有一个root hub(如图3),它属于EHCI Host Controller,可以看出它具有3个usb port。所以在注册EHCI相关驱动后会去注册usb device(usb_bus的root_hub),由于它是一个root_hub所以会调用root_hub的hub_probe。这里不止有一个hub哦,因为外挂的usb芯片4604也是属于一个hub,所以当检测到4604之后,会再生成一个hub。
4、usb port:usb端口。4412的root hub(如图3)有3个port,一个给了microUSB,一个给了usb4604(外挂usb usb芯片),一个没有接线。这个usb port的数量是通过hub的描述符获取的。

图1 usb phy UTMI功能模块描述图

图2 4412 USB System Block Diagram

图3 4412 USB 2.0主机控制器模块单元

框架图

以下框架图描述的是Exynos4412平台usb2.0 host模式下的程序框架,并非物理框架和数据流动框架。

1、phy层
phy有四类:device、host、hsic0、hsic1。由exynos4x12_phy_id和exynos4x12_phys指定。4412实例化了4个struct phy,存放在struct samsung_usb2_phy_driver的成员instances[0]成员中。hcd层通过exynos_ehci_hcd结构体可以访问到stuct phy。phy还提供了phy_ops,通过它可以设置对应链路为device模式,host模式,phy时钟,还有使能/失能hsic0、hsic1。
2、hcd
hcd层以stuct usb_hcd为核心。它主要有两个功能,一个是通过ehci_hcd去操作phy层,一个是通过hc_driver去操作上层传递下来的urb数据包。
3、hub层
hub层以struct usb_hub为核心。它主要负责检测端口状态,处理插入/拔出的设备,创建/删除usb_device,对于新插入的设备会去匹配他的设备驱动程序,然后调用相关probe函数。
4、urb层
urb是一种用来描述与USB设备通信所用的基本载体和核心数据结构,与网络设备驱动中的sk_buff结构体类似。

接下来分析代码,一些可以通过框架图看出来的指针关系我不会特地去列出他们的赋值代码。

PHY

首先来看下phy的相关dts

# exynos4.dtsi
sys_reg: syscon@10010000 {compatible = "samsung,exynos4-sysreg", "syscon";reg = <0x10010000 0x400>;
};
exynos_usbphy: exynos-usbphy@125B0000 {compatible = "samsung,exynos4210-usb2-phy";reg = <0x125B0000 0x100>;samsung,pmureg-phandle = <&pmu_system_controller>;clocks = <&clock CLK_USB_DEVICE>, <&clock CLK_XUSBXTI>;clock-names = "phy", "ref";#phy-cells = <1>;status = "disabled";
};
# exynos4412.dtsi
&exynos_usbphy {compatible = "samsung,exynos4x12-usb2-phy";samsung,sysreg-phandle = <&sys_reg>;
};# exynos4412-tiny4412.dts
&exynos_usbphy {status = "okay";
};

exynos_usbphy节点会匹配到的驱动是/drivers/phy/samsung/phy-samsung-usb2.c,来看下它的probe函数

// /drivers/phy/samsung/phy-exynos4x12-usb2.c
enum exynos4x12_phy_id {EXYNOS4x12_DEVICE,EXYNOS4x12_HOST,EXYNOS4x12_HSIC0,EXYNOS4x12_HSIC1,EXYNOS4x12_NUM_PHYS,
};
static const struct samsung_usb2_common_phy exynos4x12_phys[] = {{ .label      = "device",.id       = EXYNOS4x12_DEVICE,.power_on  = exynos4x12_power_on, //为了方便处理,这里每个power_on都是一样的,只在exynos4x12_power_on中做区分.power_off    = exynos4x12_power_off,},{ .label      = "host",.id     = EXYNOS4x12_HOST,.power_on    = exynos4x12_power_on, //为了方便处理,这里每个power_on都是一样的,只在exynos4x12_power_on中做区分.power_off    = exynos4x12_power_off,},{ .label      = "hsic0",.id        = EXYNOS4x12_HSIC0,.power_on   = exynos4x12_power_on,  //为了方便处理,这里每个power_on都是一样的,只在exynos4x12_power_on中做区分.power_off   = exynos4x12_power_off,},{ .label      = "hsic1",.id        = EXYNOS4x12_HSIC1,.power_on   = exynos4x12_power_on,  //为了方便处理,这里每个power_on都是一样的,只在exynos4x12_power_on中做区分.power_off   = exynos4x12_power_off,},
};
static struct phy *samsung_usb2_phy_xlate(struct device *dev,struct of_phandle_args *args)
{struct samsung_usb2_phy_driver *drv;drv = dev_get_drvdata(dev);return drv->instances[args->args[0]].phy;//根据参数返回对应的phy
}static int samsung_usb2_phy_power_on(struct phy *phy){struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);ret = inst->cfg->power_on(inst);   //调用到exynos4x12_phys的power_on
}
static const struct phy_ops samsung_usb2_phy_ops = {.power_on  = samsung_usb2_phy_power_on,.power_off = samsung_usb2_phy_power_off,.owner        = THIS_MODULE,
};
const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = {.has_mode_switch    = 1,.num_phys      = EXYNOS4x12_NUM_PHYS, //phy的数量是4.phys         = exynos4x12_phys,.rate_to_clk     = exynos4x12_rate_to_clk,
};
// /drivers/phy/samsung/phy-samsung-usb2.c
static int samsung_usb2_phy_probe(struct platform_device *pdev){const struct samsung_usb2_phy_config *cfg;struct samsung_usb2_phy_driver *drv;cfg = of_device_get_match_data(dev); //匹配到上面的exynos4x12_usb2_phy_configdrv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),GFP_KERNEL); //phy的数量是4drv->cfg = cfg;drv->reg_sys = syscon_regmap_lookup_by_phandle( //地址为10010000pdev->dev.of_node, "samsung,sysreg-phandle");//获取到sys_reg: syscon@10010000for (i = 0; i < drv->cfg->num_phys; i++) {   //4个phy都需要处理struct samsung_usb2_phy_instance *p = &drv->instances[i];p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops);//每个phy的ops需要指向samsung_usb2_phy_ops}//注册samsung_usb2_phy_xlate函数到链表phy_provider_list,然后在ehci-exynos.c中//通过phy = devm_of_phy_get(dev, child, NULL)间接使用samsung_usb2_phy_xlate来取得刚才初始化的phyphy_provider = devm_of_phy_provider_register(dev,samsung_usb2_phy_xlate);
}

可以看出samsung_usb2_phy_probe先解析exynos_usbphy节点的属性,然后填充到相关结构体,里面涉及的结构体的关系可以参考程序框架图。这里创建了一个samsung_usb2_phy_driver,在创建的时候创建了4个samsung_usb2_phy_instance,这4个samsung_usb2_phy_instance都有一个phy成员,在创建phy成员的时候把它们的phy_ops指针都指向了samsung_usb2_phy_ops。这个samsung_usb2_phy_ops里面的power_on、power_off会调用到exynos4x12_phys的power_on(exynos4x12_power_on)、power_off。来看下exynos4x12_power_on做了什么。

// /drivers/phy/samsung/phy-exynos4x12-usb2.c
#define EXYNOS_4x12_MODE_SWITCH_OFFSET      0x21c
static void exynos4x12_power_on_int(struct samsung_usb2_phy_instance *inst)
{if (inst->int_cnt++ > 0)   //只初始化一次,要跟power off配对,已经使能了就不能多次使能了return;exynos4x12_setup_clk(inst);    //设置对应的phy的clkexynos4x12_isol(inst, 0); //设置对应的phy相关的电源管理exynos4x12_phy_pwr(inst, 1);   //使能对应的phy
}
static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst)
{struct samsung_usb2_phy_driver *drv = inst->drv;if (inst->cfg->id == EXYNOS4x12_HOST) {regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET,EXYNOS_4x12_MODE_SWITCH_MASK,EXYNOS_4x12_MODE_SWITCH_HOST);exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]);}if (inst->cfg->id == EXYNOS4x12_DEVICE && drv->cfg->has_mode_switch)regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET,EXYNOS_4x12_MODE_SWITCH_MASK,EXYNOS_4x12_MODE_SWITCH_DEVICE);if (inst->cfg->id == EXYNOS4x12_HSIC0 ||inst->cfg->id == EXYNOS4x12_HSIC1) {//使能HSIC0或者HSIC1exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_DEVICE]);exynos4x12_power_on_int(&drv->instances[EXYNOS4x12_HOST]);}exynos4x12_power_on_int(inst);
}

这里的drv->reg_sys就是从dts节点属性“samsung,sysreg-phandle”获取到的值,这是等于10010000,加上偏移0x21c,我们查看datesheet这个寄存器是做啥的(USB_CFG寄存器),可以看出这个寄存器就是操作usb phy模式:USB Device或者 USB Host。

到这里我们已经明白了phy层无非就是提供操作函数,让hcd层可以使能、失能对应的phy(4条phy:device、host、hsic0、hsic1),为usb的正常运行提供基础。
下一节将hcd层

tiny4412 linux-4.2 移植(七)USB 2.0 host框架(1)phy相关推荐

  1. tiny4412 linux-4.2 移植(七)USB 2.0 host框架(2)hcd(ehci主机控制器)

    简介 上一节整体介绍了usb host框架,分析了其中的phy层.这一节我们分析usb 框架中的hcd层.Exynos 4412的USB 2.0的 Host Controller包含USB 2.0 E ...

  2. tiny4412 linux-4.2 移植(九)USB 2.0 host框架(4)支持otg

    由于前面支持了usb host,这里要支持otg模式就比较简单了. make menuconfig打开支持OTG | Symbol: USB_OTG [=n] || Type : bool || Pr ...

  3. linux查看usb3.0还是2.0,Linux分辨电脑是否有USB 3.0接口的命令行 怎么看电脑用独立显卡还是集成显卡...

    延伸:怎么看电脑用独立显卡还是集成显卡 描述:方法一.通过接口来判断我们在主机箱后面的接口上,看你的链接数据线的接口接上了哪个接口,如果是连接集成显卡的话那就是连接到竖的的接口上,因为集成显卡的VGA ...

  4. linux添加ax88772b驱动,佳能 USB 2.0 to Fast Ethernet AX88772B 驱动程序下载-更新佳能软件(以太网控制器)...

    ASIX USB 2.0 to Fast Ethernet AX88772B 驱动程序下载 如何手动下载和更新: 你可以通过 %%os%% 或通过执行 Windows® 更新获取基本的 USB 2.0 ...

  5. 高通平台USB 2.0和USB 3.0接口充电器识别原理

    1 BC 1.2 1.1 充电器类型探测 1)DCD:DP上有150mV(= 10uA x 15K欧姆下拉电阻)的电压,DM上电压为0 2)Primary Det(DP发起检测DM): - DP上加载 ...

  6. USB 2.0 眼图测试

    一. USB 2.0 测试内容 USB 信号质量需要测试有:眼图测试.信号速率.包尾宽度. JK 抖动. KJ 抖动.连续抖动.单调性测试.上升下降时间,详细如下图: 二. USB 2.0 测试命令和 ...

  7. USB | 2. 最新USB 4.0规范解析及一致性测试

    Update: 2022 / 10 / 11 USB | 2. 最新USB 4.0规范解析及一致性测试 目录 背景 USB 1.0 - 4.0 Type-C 接口 拓扑结构 USB 4 USB Typ ...

  8. Linux那些事儿 之 戏说USB(24)设备的生命线(七)

    算是进入了HCD的片儿区,这里的老大不是帮派头目也不是巡逻片儿警,而是几个结构.在HCD这个片儿区,这个山头儿,王中之王就是include/linux/usb/hcd.h里定义的struct usb_ ...

  9. Linux系统移植实验---USB驱动的移植

    实验八 USB驱动的移植 [实验目的] USB接口是现在计算机系统中最通用的一种接口, 说明:在本系统移植课程实验中命令行提示符 "$"表示是在主机上执行,"#" ...

最新文章

  1. Debian+Pure-ftpd+MySQL+User manager for PureFTPd
  2. matlab 定义一个有自变量的方程_Eviews、Stata、Python、Matlab、R描述+相关+回归分析教程汇总...
  3. html设置了标签但是定义不了,在HTML标签管理器中设置不带元素ID的HTML中的事件...
  4. as400还有发展前景吗_web前端还有发展前景吗?该如何去学习
  5. pycharm创建scrapy项目
  6. 去掉thinktime查看响应时间的方法
  7. 如何验证是否正确安装了CUDA
  8. python selenium firefox使用
  9. 新零售做好客流数据分析才是提升线下商场、购物中心人流量的方向
  10. 嵩天python笔记_嵩天Python学习笔记-01
  11. html怎么插入word文档,word中怎样插入html代码?
  12. threejs消除锯齿
  13. Linux下rsync安装与配置
  14. 人工智能的最新进展:比失业更严重?
  15. codeforces 645F Cowslip Collections
  16. android 导航栏navigation
  17. 数据可视化BI平台选型调研报告 Superset VS Redash VS Metabase
  18. 关于SNR和EbN0转换关系
  19. TOJ 3471.Happy XiaoXiao Guo
  20. 自己开发的网站怎么部署到阿里云上?

热门文章

  1. 读论文《SNUNet-CD: A Densely Connected Siamese Network for Change Detection of VHR Images》
  2. python协同过滤算法计算时间_协同过滤算法_coding - SegmentFault 思否
  3. 设备管理系统html,设备管理系统有哪些功能?- 智造家
  4. SAP操作手册之 商品/物料主数据增强
  5. 计算机考研视频哪个机构的好,考研计算机专业视频课哪个好
  6. CAD中怎么合并设备表?CAD合并设备表操作技巧
  7. Mybatis-Plus操作数据库
  8. 网页背景flash素材
  9. 分布式系列之分布式计算框架Flink深度解析
  10. 领扣算法:234 回文链表