![](/img/0.jpg)
一.USB主机控制器HCD(Host Controller Device)简介 USB的主机控制器(HCD),出现了多种不同的类型,即OHCI和UHCI,EHCI,和xHCI,不同USB控制器类型OHCI,UHCI,EHCI,xHCI的区别和联系 ![](https://img2020.cnblogs.com/blog/2060378/202101/2060378-20210115143233192-931271113.png)
USB采用树形拓扑结构,主机侧和设备侧的USB控制器分别称为主机控制器(Host Controller)和USB设备控制器(UDC),每条总线上只有一个主机控制器,负责协调主机和设备间的通信,设备不能主动向主机发送任何消息。 1.usb phy ![](https://img2020.cnblogs.com/blog/2060378/202101/2060378-20210115143234752-335612899.png)
二.USB主机控制器驱动 1.分析的usb主机控制器硬件情况 USB Host带有Root Hub,第一个USB设备是一个根集线器(Root_hub)它控制连接到其上的整个USB总线。 ![](https://img2020.cnblogs.com/blog/2060378/202101/2060378-20210115143236187-1330066772.png)
鉴于现在大部分设备都已经支持usb3.0, 我们来分析xHCI主机控制器驱动代码。 我手里的设备是imx8mq,用的DWC3 USB控制芯片 USB设备分为HOST(主设备)和SLAVE(从设备),只有当一台HOST与一台SLAVE连接时才能实现数据的传输,而OTG设备既能充当HOST,亦能充当SLAVE,也即DRD(Dual-role-devices).我现在只分析当主设备的情况。2.usb主机控制器驱动分析代码位置: drivers\usb\dwc3\Core.c首先是platform驱动的加载, 会通过of_dwc3_match配置dtsstatic 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);匹配成功后,会进入dwc3_probe函数。主要进行一些资源的分配,硬件的初始化等,这里化简一下static int dwc3_probe(struct platform_device *pdev)
{
dwc3_get_properties(dwc); //获取一些属性,主要是读取dts里面的配置,比如dr_mode可以配置为otg、host或者peripheral。
dwc3_cache_hwparams(dwc); //读取一些硬件参数
ret = dwc3_core_init(dwc); //这里面是最重要的初始化,一些硬件初始化,包括USB PHY
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize core: %d\n", ret);
goto err4;
}
ret = dwc3_core_init_mode(dwc); //根据不同的模式进行初始化
if (ret)
goto err5;
dwc3_debugfs_init(dwc); //调试节点,/sys/kernel/debug/38100000.usb/
}dwc3_core_init_mode里面会进行不同模式的初始化,包括otg、host或者peripheral。static int dwc3_core_init_mode(struct dwc3 *dwc)
{
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL: //外围模式,也就是当从设备
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize gadget\n");
return ret;
}
break;
case USB_DR_MODE_HOST: //主机模式,也就是当主设备
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize host\n");
return ret;
}
break;
case USB_DR_MODE_OTG: //otg模式,OTG控制器可以做host,也能做device
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
ret = dwc3_drd_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize dual-role\n");
return ret;
}
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
return -EINVAL;
}
return 0;
}只做从设备的情况比较少,只做host或者otg的情况比较多。我们先来分析当做host的情况int dwc3_host_init(struct dwc3 *dwc)
{
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); //创建一个平台设备,名字是xhci-hcd
if (!xhci) {
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
return -ENOMEM;
}
ret = platform_device_add_resources(xhci, dwc->xhci_resources,
DWC3_XHCI_RESOURCES_NUM); //添加资源到这个平台设备
if (ret) {
dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
goto err;
}
/**
* WORKAROUND: dwc3 revisions uses_new_polling ? HCD_POLL_RH(hcd) : //这里hcd->uses_new_polling=1 HCD_POLL_RH(hcd)如果不等于0,会一直调用mod_timer
(length == 0 && hcd->status_urb != NULL))
//此时开启rh_timer.rh_timer的处理函数rh_timer_func,实际就是usb_hcd_poll_rh_status。
mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
}参考: USB驱动框架_WuYujun's blog-CSDN博客_usb驱动框架 USB PHY芯片
|