溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

xHci-PCI驅(qū)動(dòng)設(shè)計(jì)

發(fā)布時(shí)間:2020-06-26 08:26:02 來(lái)源:網(wǎng)絡(luò) 閱讀:7912 作者:zhao_anan 欄目:軟件技術(shù)

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-PCI驅(qū)動(dòng)設(shè)計(jì)

 

重要的配置:

xHCIUSB 3.xhost 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_PCIUSB_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í)際上,作為gluexhci-pci模塊代碼要早于xhci-hcd模塊代碼開始工作,因此關(guān)鍵的初始化過(guò)程放在xhci-pci里面。

現(xiàn)在進(jìn)入正題:

xHCI相關(guān)的代碼,很容易發(fā)現(xiàn)幾個(gè)貌似重要的struct類型:usb_hcd、xhci_hcdhc_driver,還有幾個(gè)全局變量xhci_pci_driver、xhci_hc_driverxhci_pci_hc_driver,再加上PCI總線相關(guān)的類型pci_devpci_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_driverxhci-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_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函數(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 SpecFigure 3-1可以知道,USB 3.xHost包含兩個(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_hcdxhci_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í)序圖:

xHci-PCI驅(qū)動(dòng)設(shè)計(jì)

 

//@@----------------------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ò)程:

xHci-PCI驅(qū)動(dòng)設(shè)計(jì)

 

 


向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI