千家信息网

xHci-PCI驱动设计

发表于:2024-11-19 作者:千家信息网编辑
千家信息网最后更新 2024年11月19日,xHci-PCI驱动设计虽然Linux内核拥有C语言构建的身体,但它骨子里散发的是面向对象的气质,这一个个的对象就是struct。面对一个内核模块的时候,首先要找出关键的struct和它们之间的关系,
千家信息网最后更新 2024年11月19日xHci-PCI驱动设计

xHci-PCI驱动设计

虽然Linux内核拥有C语言构建的身体,但它骨子里散发的是面向对象的气质,这一个个的对象就是struct。面对一个内核模块的时候,首先要找出关键的struct和它们之间的关系,才能摸清代码的骨骼脉络。

先上图,下面分析的过程结束之后各个结构体就是这种关系:

重要的配置:

xHCIUSB 3.xhost controller规范,首先进入drivers/usb/host目录浏览一下,其实从文件名就可以知道,跟xHCI关系最密切的必然是xhci.c。保险起见还是看一下KConfig

config USB_XHCI_HCD
tristate "xHCI HCD (USB 3.0)support"
---help---
TheeXtensible Host Controller Interface (xHCI) is standard forUSB 3.0
"SuperSpeed"host controller hardware.

Tocompile this driver as a module, choose M here: the
module will be called xhci-hcd.

ifUSB_XHCI_HCD

config USB_XHCI_PCI
tristate
depends on PCI
defaulty

config USB_XHCI_PLATFORM
tristate

config USB_XHCI_MVEBU
tristate "xHCI support forMarvell Armada 375/38x"
select USB_XHCI_PLATFORM
depends on ARCH_MVEBU || COMPILE_TEST
---help---
Say'Y'to enable the support for the xHCI host controller
found in Marvell Armada 375/38x ARM SOCs.

config USB_XHCI_RCAR
tristate "xHCI support forRenesas R-Car SoCs"
select USB_XHCI_PLATFORM
depends on ARCH_SHMOBILE || COMPILE_TEST
---help---
Say'Y'to enable the support for the xHCI host controller
found in Renesas R-Car ARM SoCs.

endif # USB_XHCI_HCD

主要配置项叫做USB_XHCI_HCD,另外还有USB_XHCI_PCIUSB_XHCI_PLATFORM。再看Makefile,直接搜索XHCI有关的内容:

xhci-hcd-y := xhci.oxhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.oxhci-dbg.o
xhci-hcd-y += xhci-trace.o

xhci-plat-hcd-y := xhci-plat.o
ifneq ($(CONFIG_USB_XHCI_MVEBU), )
xhci-plat-hcd-y +=xhci-mvebu.o
endif
ifneq ($(CONFIG_USB_XHCI_RCAR), )
xhci-plat-hcd-y +=xhci-rcar.o
endif

obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
obj-$(CONFIG_USB_XHCI_PLATFORM) +=xhci-plat-hcd.o

obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o

USB_XHCI_PCI,顾名思义,是xHCI驱动和PCI总线驱动之间的"接口"(内核开发者称这种"接口"glue)。USB控制器大多是PCI设备,若控制器连接到PCI总线上,那么自然是先由PCI驱动发现该设备,识别之后才能交给xHCI驱动处理。所以实际上,作为gluexhci-pci模块代码要早于xhci-hcd模块代码开始工作,因此关键的初始化过程放在xhci-pci里面。

现在进入正题:

xHCI相关的代码,很容易发现几个貌似重要的struct类型:usb_hcdxhci_hcdhc_driver,还有几个全局变量xhci_pci_driverxhci_hc_driverxhci_pci_hc_driver,再加上PCI总线相关的类型pci_devpci_driver

xhci-pci模块启动,执行xhci_pci_init函数

staticint__init xhci_pci_init(void)
{
xhci_init_driver(&xhci_pci_hc_driver, xhci_pci_setup);
#ifdef CONFIG_PM
xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
#endif
returnpci_register_driver(&xhci_pci_driver);
}

xhci_pci_init调用xhci_init_driver,初始化xhci_pci_hc_driver变量,主要作用就是把全局变量xhci_hc_driver的值一股脑赋给另一个全局变量xhci_pci_hc_driver。两者都是struct hc_driver类型,xhci_pci_hc_driverxhci-pci.c中定义,是真正起作用的xHCI驱动,但它在定义的时候没有进行任何成员的初始化:

void xhci_init_driver(struct hc_driver *drv, int(*setup_fn)(struct usb_hcd *))
{
BUG_ON(!setup_fn);
*drv= xhci_hc_driver;
drv->reset= setup_fn;
}

staticstructhc_driver __read_mostly xhci_pci_hc_driver;

xhci_hc_driverxhci.c中定义,它包揽了所有的脏活累活:

staticconststruct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
.hcd_priv_size= sizeof(structxhci_hcd *),

/*
*generic hardware linkage
*/
.irq= xhci_irq,
.flags = HCD_MEMORY |HCD_USB3 | HCD_SHARED,

/*
*basic lifecycle operations
*/
.reset = NULL, /* set in xhci_init_driver() */
.start = xhci_run,
.stop= xhci_stop,
.shutdown = xhci_shutdown,

/*
*managing i/o requests and associated device resources
*/
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
.free_dev = xhci_free_dev,
.alloc_streams = xhci_alloc_streams,
.free_streams = xhci_free_streams,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint= xhci_drop_endpoint,
.endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
.enable_device = xhci_enable_device,
.update_hub_device = xhci_update_hub_device,
.reset_device = xhci_discover_or_reset_device,

/*
*scheduling support
*/
.get_frame_number = xhci_get_frame,

/*
*root hub support
*/
.hub_control = xhci_hub_control,
.hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume,

/*
*call back when device connected and addressed
*/
.update_device = xhci_update_device,
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
.find_raw_port_number = xhci_find_raw_port_number,
};

xhci_init_driver函数将xhci_hc_driver的值赋给xhci_pci_hc_driver后,前者也就退下了舞台。

xhci_pci_driver被专业人员称为pcidriver glue,属于一种新型的PCI驱动模块。

xhci_pci_init调用pci_register_driver,将xhci_pci_driver注册为PCI设备驱动。在xhci-pci.c中静态定义并初始化:

/* pci driver glue; this is a"new style" PCI driver module */
staticstructpci_driver xhci_pci_driver = {
.name= (char*) hcd_name,
.id_table = pci_ids,

.probe = xhci_pci_probe,
.remove = xhci_pci_remove,
/* suspend and resume implemented later */

.shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
#endif
};

id_table包含了驱动支持的PCI设备类型,PCI总线就是靠它判断驱动和设备能否配对。这里的id_table成员设置为pci_ids,它也是静态定义的全局变量:

/* PCI driver selectionmetadata; PCI hotplugging uses this */
staticconststructpci_device_id pci_ids[] = { {
/* handle any USB 3.0 xHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
.driver_data = (unsignedlong)&xhci_pci_hc_driver,
},
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);

pci_ids中唯一一个元素的driver_data成员指向刚才在xhci_pci_init中完成初始化的xhci_pci_hc_driver变量,这就将作为PCI设备驱动的xhci_pci_driver和作为USB主机控制器设备驱动xhci_pci_hc_driver联系了起来。

staticintxhci_pci_setup(struct usb_hcd *hcd)
{
structxhci_hcd *xhci;
structpci_dev *pdev =to_pci_dev(hcd->self.controller);
int retval;
//uDP720202芯片的配置
xhci_fwdownload(hcd);
//创建了对xHCI至关重要的数据结构--xhci_hcd类型,并完成了大量的初始化工作
retval = xhci_gen_setup(hcd, xhci_pci_quirks);
if(retval)
return retval;

xhci = hcd_to_xhci(hcd);
if(!usb_hcd_is_primary_hcd(hcd))
return0;

pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
xhci_dbg(xhci, "GotSBRN %u\n", (unsignedint)xhci->sbrn);

/* Find any debug ports */
retval = xhci_pci_reinit(xhci, pdev);
if(!retval)
return retval;

kfree(xhci);
returnretval;
}

USB 3.1 SpecFigure 3-1可以知道,USB 3.xHost包含两个roothub,对应两条USB总线,一条连接USB 2.0设备,一条连接USB 3.x设备。

xhci_pci_probe调用usb_hcd_pci_probe,创建usb_hcdxhci_hcd。回到最初的示意图,现在所有的连接都已经完成!

int usb_hcd_pci_probe(struct pci_dev *dev, conststruct pci_device_id *id)
{
structhc_driver *driver;
structusb_hcd *hcd;
int retval;
int hcd_irq = 0;

if(usb_disabled())
return-ENODEV;

if(!id)
return-EINVAL;
driver= (structhc_driver *)id->driver_data;
if(!driver)
return-EINVAL;

if(pci_enable_device(dev) < 0)
return-ENODEV;

/*
* The xHCI driver has its own irq management
* make sure irq setup is not touched for xhciin generic hcd code
*/
if((driver->flags & HCD_MASK) != HCD_USB3) {
if(!dev->irq) {
dev_err(&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
retval= -ENODEV;
gotodisable_pci;
}
hcd_irq= dev->irq;
}

hcd =usb_create_hcd(driver, &dev->dev, pci_name(dev));
if(!hcd) {
retval= -ENOMEM;
gotodisable_pci;
}
......
returnretval;
}

uDP720202芯片的配置的时序图:

//@@----------------------PCI 信息
#define XHCI_FWFILENAME_720201_202ES20 "renesas/K2011070.mem"
//uDp720202 寄存器配置
#define XHCI_VENDOR_ID_720202 (0x1912)
#define XHCI_DEVICE_ID_720202 (0x0015)
#define XHCI_DEVICE_REV_ES20 (0x02)


//@@---------------------- FM下载配置寄存器
#define PCICNF0F4 0xF4 // 来自芯片寄存器手册
/*
0 = FWdownload enable (1), RW
1 = FWdownload lock (1) or unlock (0), need 0 to perform download, RW(Write Once)
6:4 =Result code, RO -- processing (0), success (1), error (2),
8 =Set Data 0, RW
9 =Set Data 1, RW
16:31= (used for serial EEPROM read/write. 31= serial EEPROM present.)
*/
#define PCICNF0F4_FWDOWNLOADENABLE_B (0)
#define PCICNF0F4_FWDOWNLOADLOCK_B (1)
#define PCICNF0F4_SETDATA0_B (8)
#define PCICNF0F4_SETDATA1_B (9)
#define PCICNF0F4_RESULT_B (4)

#define PCICNF0F8 0xF8 // 数据页 0

#define PCICNF0FC 0xFC // 数据页 1

主要调用过程:


驱动 设备 变量 配置 总线 模块 类型 代码 全局 就是 重要 内核 寄存器 成员 控制器 数据 芯片 设备驱动 过程 控制 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 如何选购电梯服务器 网络安全教育的体会200 康复有关数据库 新沂市网络安全民警 在星形拓扑结构中连接文件服务器 有实力的分布式关系型数据库 新零售产品信息数据库系统 时序数据库和关系型数据库区别 舆情网络安全手抄报句子 中国网络安全教育官网 本地服务器可以做代码仓库吗 佛山风云网络技术有限公司 软件开发收入 杨浦区软件开发技术服务前景 标普数据库 网络设备和网络安全设备 网易电脑服务器怎么换图片 中华人民共和国网络安全教育法 服务器管理能力 哪里手机软件开发好 生物数据库建设 知乎 变电站网络安全分区 网络安全法中规定哪些核心制度 幻塔4399服务器 厦门聊天软件开发多少钱 数据库开发工程师的主要职责模板 苏州橙仓网络技术 信息网络安全部门电话 顺义区技术网络技术服务包括什么 曹妃甸区电子网络技术售后服务
0