您好,登錄后才能下訂單哦!
xHci-PCI驅(qū)動(dòng)設(shè)計(jì)
雖然Linux內(nèi)核擁有C語(yǔ)言構(gòu)建的身體,但它骨子里散發(fā)的是面向?qū)ο蟮臍赓|(zhì),這一個(gè)個(gè)的對(duì)象就是struct。面對(duì)一個(gè)內(nèi)核模塊的時(shí)候,首先要找出關(guān)鍵的struct和它們之間的關(guān)系,才能摸清代碼的骨骼脈絡(luò)。
先上圖,下面分析的過(guò)程結(jié)束之后各個(gè)結(jié)構(gòu)體就是這種關(guān)系:
重要的配置:
xHCI是USB 3.x的host controller規(guī)范,首先進(jìn)入drivers/usb/host目錄瀏覽一下,其實(shí)從文件名就可以知道,跟xHCI關(guān)系最密切的必然是xhci.c。保險(xiǎn)起見還是看一下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
主要配置項(xiàng)叫做USB_XHCI_HCD,另外還有USB_XHCI_PCI和USB_XHCI_PLATFORM。再看Makefile,直接搜索XHCI有關(guān)的內(nèi)容:
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驅(qū)動(dòng)和PCI總線驅(qū)動(dòng)之間的“接口”(內(nèi)核開發(fā)者稱這種“接口”為glue)。USB控制器大多是PCI設(shè)備,若控制器連接到PCI總線上,那么自然是先由PCI驅(qū)動(dòng)發(fā)現(xiàn)該設(shè)備,識(shí)別之后才能交給xHCI驅(qū)動(dòng)處理。所以實(shí)際上,作為glue的xhci-pci模塊代碼要早于xhci-hcd模塊代碼開始工作,因此關(guān)鍵的初始化過(guò)程放在xhci-pci里面。
現(xiàn)在進(jìn)入正題:
xHCI相關(guān)的代碼,很容易發(fā)現(xiàn)幾個(gè)貌似重要的struct類型:usb_hcd、xhci_hcd和hc_driver,還有幾個(gè)全局變量xhci_pci_driver、xhci_hc_driver和xhci_pci_hc_driver,再加上PCI總線相關(guān)的類型pci_dev和pci_driver。
xhci-pci模塊啟動(dòng),執(zhí)行xhci_pci_init函數(shù)
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調(diào)用xhci_init_driver,初始化xhci_pci_hc_driver變量,主要作用就是把全局變量xhci_hc_driver的值一股腦賦給另一個(gè)全局變量xhci_pci_hc_driver。兩者都是struct hc_driver類型,xhci_pci_hc_driver在xhci-pci.c中定義,是真正起作用的xHCI驅(qū)動(dòng),但它在定義的時(shí)候沒(méi)有進(jìn)行任何成員的初始化:
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_driver在xhci.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函數(shù)將xhci_hc_driver的值賦給xhci_pci_hc_driver后,前者也就退下了舞臺(tái)。
xhci_pci_driver被專業(yè)人員稱為pcidriver glue,屬于一種新型的PCI驅(qū)動(dòng)模塊。
xhci_pci_init調(diào)用pci_register_driver,將xhci_pci_driver注冊(cè)為PCI設(shè)備驅(qū)動(dòng)。在xhci-pci.c中靜態(tài)定義并初始化:
/* 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包含了驅(qū)動(dòng)支持的PCI設(shè)備類型,PCI總線就是靠它判斷驅(qū)動(dòng)和設(shè)備能否配對(duì)。這里的id_table成員設(shè)置為pci_ids,它也是靜態(tài)定義的全局變量:
/* 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中唯一一個(gè)元素的driver_data成員指向剛才在xhci_pci_init中完成初始化的xhci_pci_hc_driver變量,這就將作為PCI設(shè)備驅(qū)動(dòng)的xhci_pci_driver和作為USB主機(jī)控制器設(shè)備驅(qū)動(dòng)xhci_pci_hc_driver聯(lián)系了起來(lái)。
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);
//創(chuàng)建了對(duì)xHCI至關(guān)重要的數(shù)據(jù)結(jié)構(gòu)——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 Spec中Figure 3-1可以知道,USB 3.x的Host包含兩個(gè)roothub,對(duì)應(yīng)兩條USB總線,一條連接USB 2.0設(shè)備,一條連接USB 3.x設(shè)備。
xhci_pci_probe調(diào)用usb_hcd_pci_probe,創(chuàng)建usb_hcd和xhci_hcd?;氐阶畛醯氖疽鈭D,現(xiàn)在所有的連接都已經(jīng)完成!
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芯片的配置的時(shí)序圖:
//@@----------------------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 // 來(lái)自芯片寄存器手冊(cè)
/*
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 // 數(shù)據(jù)頁(yè) 0
#define PCICNF0FC 0xFC // 數(shù)據(jù)頁(yè) 1
主要調(diào)用過(guò)程:
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。