一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

USB子系統(tǒng)學(xué)習(xí)之基礎(chǔ)篇三(host controller)

 云將東游 2015-05-13

理所當(dāng)然,我們需要開始分析usb host controller了。

位置linux-2.6.32.21/drivers/usb/host,哇塞,怎么這么多xhci啊,什么ehci,uhci,fhci甚至還真的有xhci,看來搞host controller的人,自已都絕了索性以x來命名了。其實walfred查過資料之后才發(fā)現(xiàn),或許readme其實早就有提示(請看USB子系統(tǒng)學(xué)習(xí)二中的readme相關(guān)部分),這些眾多的hci只有ehci和uhci和ohci才是pc上用到的,其他是屬于嵌入式系統(tǒng)使用的。那么就算現(xiàn)在我們需要學(xué)習(xí)ehci和ochi和uhci也不輕松,它們之間是什么關(guān)系呢?請別著急,我會娓娓道來。

先看下host controller的作用。見下圖,ldd上有一句話說的很好,我決定引用過來“l(fā)inux內(nèi)核支持兩種主要類型的USB驅(qū)動程序:宿主(host)系統(tǒng)上的驅(qū)動程序和設(shè)備(device)上的驅(qū)動程序。從宿主的觀點來看(一個普通的USB宿主是一個桌面計算機),宿主系統(tǒng)的USB驅(qū)動程序控制插入其中的USB設(shè)備,而USB設(shè)備的驅(qū)動程序則控制該設(shè)備如何作為一個USB驅(qū)動和主機通信”,這一句話就道出來,我們率先學(xué)習(xí)宿主(host controller)的重要性。

那么內(nèi)核驅(qū)動文件中driver/usb/host看到的ehci ohci uhci,雜7雜8的,都有什么用,都是干嘛的呢?

1 名字解釋

uhci(universal host controller interface): Intel用在自家芯片組上的usb 1.1主控制器(host controller)的硬件實例。

ehci(enhanced host controller interface): usb 2.0的主控制器標(biāo)準(zhǔn)接口。

ohci(open host controller inferface):一個不僅僅是usb用的主控制器接口標(biāo)準(zhǔn),下面細(xì)分為usb,1394,或者更多(別的沒有接觸過)。主要是遵循csr (configuration space register)標(biāo)準(zhǔn)(另一個標(biāo)準(zhǔn),呵呵)。是其他廠商在設(shè)計usb host controller時遵循的標(biāo)準(zhǔn),如via, nec, ali, 包括nvidia等等。

2 相關(guān)特性

uhci, ohci在硬件實現(xiàn)以及對底層軟件訪問上都有所不同,但二者又都完全(實際上各自多少都有些不足)支持usb 1.1 specification里邊對usb host controller的要求。

同理,ehci是滿足usb 2.0 specification里面對usb host controller (high speed)的要求的硬件設(shè)計。

應(yīng)該是從win98之后usb1.1就被廣泛支持了,無論是uhci還是ohci。但ms真正支持usb2.0(或者說ehci)是從win2k sp4和winxp sp1。這里所說的真正支持是指系統(tǒng)自帶ehci的驅(qū)動而不需要第三方的驅(qū)動程序。

另外apple現(xiàn)在胳膊拗不過大腿,在mac機上也已經(jīng)都開始支持usb1.1和2.0接口。而上面的host controller一定是ohci的標(biāo)準(zhǔn)。謹(jǐn)以此獻給退居二線的喬老板。

3 他們的規(guī)格

uhci ohci ehci他們都是主機控制器的規(guī)格

OHCI主要為非PC系統(tǒng)上以及帶有SiShe ALi芯片組的PC主板上的USB芯片

UHCI大多為Intel和Via主板上的USB控制器芯片。UHCI的硬件電路比OHCI簡單,成本稍低,但驅(qū)動復(fù)雜。但他們都是由USB1.1規(guī)格的。

EHCI是有Intel等幾個廠商研發(fā),兼容OHCI UHCI 遵循USB2.0規(guī)范。

USB規(guī)范都是從寄存器級別規(guī)定好的,不過各個廠商可能有自己的幾個專用的寄存器。

4 有用的東東

usb 2.0 定義了低速(low speed),全速(full speed),高速(high speed)傳輸。EHCI 僅僅支持高速傳輸,所以它必須還要有一個 companion HC,如(UHCI)來支持低速和全速設(shè)備,情況時這樣的:

1), fs/ls 設(shè)備插入到 root hub port,會由 companion HC(uhci/ohci)發(fā)現(xiàn)并管理設(shè)備;

2),fs/ls 設(shè)備插入到 usb 2.0 hub(not root hub),那么由 ehci 通過 split transaction 和 transaction translation(tt)支持 fs/ls 設(shè)備。在usb core層會說到這個tt的。

比如,當(dāng)一個 usb 設(shè)備插入 root hub port 時,先要做一件 routing 的事情。所有的 root hub port默認(rèn)是被 EHCI 占有的,所以,EHCI 和插入的 usb 設(shè)備通信,看是不是 hs 設(shè)備,如果是好說。如果不是,EHCI 就放棄這個 port 的占有權(quán),讓給 companion HC(uhci/ohci)去管理。


USB子系統(tǒng)學(xué)習(xí)之EHCI(EHCI的使命)


既然上一節(jié)USB子系統(tǒng)學(xué)習(xí)之基礎(chǔ)篇三(host controller)提到了我們需要擒賊先擒王,先向host controller下手,我們相信跟著本博客走,肯定是不會有錯的,不過一旦有問題,也被來找walfred,walfred只是一個喜歡更新OurUnix的博客控而已。順便提下本博的廣告語,OurUnix--一個分享嵌入式,Linux新技術(shù)的平臺。這年頭,廣告真是無孔不入呀!汗~~

仍然停在USB HC階段

這邊再補充下,維基上面介紹HCD的一段話:

包含主機控制器和根HUB的硬件為程序員提供了由硬件實現(xiàn)定義的接口主機控制器設(shè)備 (HCD)。而實際上它在計算機上就是端口和內(nèi)存映射。

1.0和1.1的標(biāo)準(zhǔn)有兩個競爭的HCD實現(xiàn)??蛋氐拈_放主機控制器接口(OHCI)和Intel的通用主機控制器接口(UHCI)。VIA威盛采納了UHCI;其他主要的芯片組多使用OHCI。它們的主要區(qū)別是UHCI更加依賴軟件驅(qū)動,因此對CPU要求更高,但是自身的硬件會更廉價。它們的并存導(dǎo)致操作系統(tǒng)開發(fā)和硬件廠商都必須在兩個方案上開發(fā)和測試,從而導(dǎo)致費用上升。因此USB-IF在USB2.0的設(shè)計階段堅持只能有一個實現(xiàn)規(guī)范,這就是擴展主機控制器接口(EHCI)。因為EHCI只支持高速傳輸,所以EHCI控制器包括四個虛擬的全速或者慢速控制器。這里同樣是Intel和Via使用虛擬UHCI,其他一般使用OHCI控制器。

某些版本的Windows上,打開設(shè)備管理器,如果設(shè)備說明中是否有“增強”("Enhanced"),就能夠確認(rèn)它是2.0版的。而在Linux系統(tǒng)中,命令lspci能夠列出所有的PCI設(shè)備,而USB會分別命名為OHCI、UHCI或者EHCI。

那我們就用電腦試試看撒。

walfred@ubuntu:~/Documents/other/usb$ lspci

00:1d.0 USB Controller: Intel Corporation N10/ICH7 Family USB UHCI Controller #1 (rev 01)

00:1d.1 USB Controller: Intel Corporation N10/ICH 7 Family USB UHCI Controller #2 (rev 01)

00:1d.2 USB Controller: Intel Corporation N10/ICH 7 Family USB UHCI Controller #3 (rev 01)

00:1d.3 USB Controller: Intel Corporation N10/ICH 7 Family USB UHCI Controller #4 (rev 01)

00:1d.7 USB Controller: Intel Corporation N10/ICH 7 Family USB2 EHCI Controller (rev 01)

那現(xiàn)在我們在lsusb看看,是不是應(yīng)該有4個USB1.1(1.0)接口和1個USB2.0接口。

walfred@ubuntu:~/Documents/other/usb$ lsusb

Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

果真,猜測成功!我這可是真正的猜測成功,而不是前兩天在上海出現(xiàn)了,類“UFO”的天體,各方專家各顯神通的猜測,紫金山派認(rèn)準(zhǔn)即是真UFO,其它門派立即辟謠。各自猜測,卻沒有任何結(jié)論。。。

插播一則報道:

2011年8月23日,中國科學(xué)院紫金山天文臺研究員王思潮對記者介紹他的判斷:“這是一起重大UFO事件,不明飛行物是特殊的空間飛行器,用人類的飛行器很難解釋。該飛行器高度是在空間,和楊利偉飛船高度差不多,飛得很慢。”此前有天文專家指出,20日晚多地觀測到的UFO是“正處于噴火狀態(tài)的推進火箭,由于推力不平衡產(chǎn)生如此現(xiàn)象?!?/p>

蛋疼,這邊講USB,怎么扯到PCI上面去了,現(xiàn)在心中有疑惑,為什么維基上面會提示我們使用lspci呢,原來我們現(xiàn)在使用的HC都是PCI設(shè)備,乖乖,心中恍然大悟,有關(guān)PCI暫且不表,因為我暫時也不會,看官現(xiàn)在只要知道USB的HC都是PCI設(shè)備即可。

ehci_hcd_init的使命

歡迎程序員回歸自己的老本行,walfred一起讀代碼!

位置:kernels/linux-2.6.32.21/drivers/usb/host

walfred@ubuntu:~/work/kernels/linux-2.6.32.21/drivers/usb/host$ vim ehci-hcd.c

static int __init ehci_hcd_init(void)

{

        int retval = 0;

 

        if (usb_disabled())

                return -ENODEV;

 

        printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);

        set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);

        if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||

                        test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))

                printk(KERN_WARNING "Warning! ehci_hcd should always be loaded"

                                " before uhci_hcd and ohci_hcd, not after\n");

 

        pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",

                 hcd_name,

                 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),

                 sizeof(struct ehci_itd), sizeof(struct ehci_sitd));

 

#ifdef DEBUG

        ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);

        if (!ehci_debug_root) {

                retval = -ENOENT;

                goto err_debug;

        }

#endif

 

#ifdef PLATFORM_DRIVER

        retval = platform_driver_register(&PLATFORM_DRIVER);

        if (retval < 0)

                goto clean0;

#endif

 

#ifdef PCI_DRIVER

        retval = pci_register_driver(&PCI_DRIVER);

        if (retval < 0)

                goto clean1;

#endif

 

#ifdef PS3_SYSTEM_BUS_DRIVER

        retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);

        if (retval < 0)

                goto clean2;

#endif

 

#ifdef OF_PLATFORM_DRIVER

        retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);

        if (retval < 0)

                goto clean3;

#endif

        return retval;

 

#ifdef OF_PLATFORM_DRIVER

        /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */

clean3:

#endif

#ifdef PS3_SYSTEM_BUS_DRIVER

        ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);

clean2:

#endif

#ifdef PCI_DRIVER

        pci_unregister_driver(&PCI_DRIVER);

clean1:

#endif

#ifdef PLATFORM_DRIVER

        platform_driver_unregister(&PLATFORM_DRIVER);

clean0:

#endif

#ifdef DEBUG

        debugfs_remove(ehci_debug_root);

        ehci_debug_root = NULL;

err_debug:

#endif

        clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);

        return retval;

}

module_init(ehci_hcd_init);

 

從模塊的入口函數(shù)看,ehci_hcd_init的主要作用就是向各平臺注冊echi控制器驅(qū)動,比如PLATFORM_DRIVER,PCI_DRIVER,PS3_SYSTEM_BUS_DRIVER,OF_PLATFORM_DRIVER等等,這邊我們主要看看向pci總線注冊驅(qū)動的PCI_DRIVER。這邊的PCI_DRIVER是一個宏,跟著代碼走!

 

#define PCI_DRIVER              ehci_pci_driver

 

/* pci driver glue; this is a "new style" PCI driver module */

static struct pci_driver ehci_pci_driver = {

        .name =         (char *) hcd_name,

        .id_table =     pci_ids,

 

        .probe =        usb_hcd_pci_probe,

        .remove =       usb_hcd_pci_remove,

        .shutdown =     usb_hcd_pci_shutdown,

 

#ifdef CONFIG_PM_SLEEP

        .driver =       {

                .pm =   &usb_hcd_pci_pm_ops

        },

#endif

};

既然分析的是PCI這一塊,我們看看代碼怎么走的

#ifdef PCI_DRIVER

        retval = pci_register_driver(&PCI_DRIVER);

        if (retval < 0)

                goto clean1;

#endif

在上面函數(shù)中調(diào)用了,這么一個函數(shù),用source insight找到其

#define pci_register_driver(driver)             \

        __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

看看這個帶參宏,調(diào)用的是__pci_register_driver,接著找啊找,游阿游

/**

 * __pci_register_driver - register a new pci driver

 * @drv: the driver structure to register

 * @owner: owner module of drv

 * @mod_name: module name string

 *

 * Adds the driver structure to the list of registered drivers.

 * Returns a negative value on error, otherwise 0.

 * If no error occurred, the driver remains registered even if

 * no device was claimed during registration.

 */

int __pci_register_driver(struct pci_driver *drv, struct module *owner,

                          const char *mod_name)

{

        int error;

 

        /* initialize common driver fields */

        drv->driver.name = drv->name;

        drv->driver.bus = &pci_bus_type;

        drv->driver.owner = owner;

        drv->driver.mod_name = mod_name;

 

        spin_lock_init(&drv->dynids.lock);

        INIT_LIST_HEAD(&drv->dynids.list);

 

        /* register with core */

        error = driver_register(&drv->driver);

        if (error)

                goto out;

 

        error = pci_create_newid_file(drv);

        if (error)

                goto out_newid;

 

        error = pci_create_removeid_file(drv);

        if (error)

                goto out_removeid;

out:

        return error;

 

out_removeid:

        pci_remove_newid_file(drv);

out_newid:

        driver_unregister(&drv->driver);

        goto out;

}

 

追尋著一系類的函數(shù),我們終于找到了我們的母親,error = driver_register(&drv->driver);就這下輕輕一調(diào),我們才把知道了在ehci_hcd_init完成的使命是注冊主控驅(qū)動。


USB子系統(tǒng)學(xué)習(xí)之EHCI(pci_bus_type兩個重量級函數(shù))


設(shè)備驅(qū)動和設(shè)備是怎么相遇的呢?

那就順便分析下   drv->driver.bus = &pci_bus_type;這個蛋疼的玩意吧

struct bus_type pci_bus_type = {

        .name           = "pci",

        .match          = pci_bus_match,

        .uevent         = pci_uevent,

        .probe          = pci_device_probe,

        .remove         = pci_device_remove,

        .shutdown       = pci_device_shutdown,

        .dev_attrs      = pci_dev_attrs,

        .bus_attrs      = pci_bus_attrs,

        .pm             = PCI_PM_OPS_PTR,

};

其中有個bus的專用的,pci_bus_match函數(shù),這是linux設(shè)備模型中,bus所獨有的,我們也看下

  /**

 * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure

 * @dev: the PCI device structure to match against

 * @drv: the device driver to search for matching PCI device id structures

 *

 * Used by a driver to check whether a PCI device present in the

 * system is in its list of supported devices. Returns the matching

 * pci_device_id structure or %NULL if there is no match.

 */

static int pci_bus_match(struct device *dev, struct device_driver *drv)

{

        struct pci_dev *pci_dev = to_pci_dev(dev);

        struct pci_driver *pci_drv = to_pci_driver(drv);

        const struct pci_device_id *found_id;

 

        found_id = pci_match_device(pci_drv, pci_dev);

        if (found_id)

                return 1;

 

        return 0;

}

這個函數(shù)是條用了你一個比較NB的函數(shù),對,曾經(jīng)是宏,現(xiàn)在是函數(shù)的container_of,這里調(diào)用就是能夠從設(shè)備鏈表中找到這個pci的dev。

而其中pci_match_device()函數(shù)則就起到了媒婆的作用,這個函數(shù)做了什么事情呢?怎么讓驅(qū)動在茫茫設(shè)備海中找到這個獨一無二的EHCI呢?

事實的真相是這樣的:

/**

 * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure

 * @drv: the PCI driver to match against

 * @dev: the PCI device structure to match against

 *

 * Used by a driver to check whether a PCI device present in the

 * system is in its list of supported devices.  Returns the matching

 * pci_device_id structure or %NULL if there is no match.

 */

static const struct pci_device_id *pci_match_device(struct pci_driver *drv,

                                                    struct pci_dev *dev)

{

        struct pci_dynid *dynid;

 

        /* Look at the dynamic ids first, before the static ones */

        spin_lock(&drv->dynids.lock);

        list_for_each_entry(dynid, &drv->dynids.list, node) {

                if (pci_match_one_device(&dynid->id, dev)) {

                        spin_unlock(&drv->dynids.lock);

                        return &dynid->id;

                }

        }

        spin_unlock(&drv->dynids.lock);

 

        return pci_match_id(drv->id_table, dev);

}

這個函數(shù)所用做的就是分別在driver->dynid,driver->id_table這兩個列表(由一系列的pci_device_id構(gòu)成)里面查找,找到則返回這個設(shè)備的pci_device_id。(不妨比較一下pci_bus_type->match 和 usb_bus_type->match)

     struct pci_device_id {

         __u32 vendor, device;      /* Vendor and device ID or PCI_ANY_ID*/

         __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */

         __u32 class, class_mask; /* (class,subclass,prog-if) triplet */

         kernel_ulong_t driver_data; /* Data private to the driver */

  };

注意,pci_device_id->driver_data 指向了每個 pci 設(shè)備驅(qū)動所特有的數(shù)據(jù)結(jié)構(gòu),比如 ehci 來說:.driver_data = (unsigned long) &ehci_pci_hc_driver。

而pci_device_probe()的行程呢?

pci_device_probe() ---> __pci_device_probe() ---> pci_call_probe() ---> ( pci_driver->probe() )而ehci_pci_driver->probe = usb_hcd_pci_probe()。

所以說設(shè)備模型中總線也有probe函數(shù)的目的,是最終調(diào)用驅(qū)動的probe函數(shù)。記不得了總線模型的,可以回看:

所以現(xiàn)在很多電影都是搞倒序,最后再回到一開始的地方,總感覺這些導(dǎo)演上輩子曾是程序員,看代碼看多了,那么我們還是回到大導(dǎo)演們曾經(jīng)看過的代碼的開始處吧!

int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)

{

        struct hc_driver        *driver;

        struct usb_hcd          *hcd;

        int                     retval;

 

        if (usb_disabled())

                return -ENODEV;

 

        if (!id)

                return -EINVAL;

        driver = (struct hc_driver *)id->driver_data;

        if (!driver)

                return -EINVAL;

 

        if (pci_enable_device(dev) < 0)

                return -ENODEV;

        dev->current_state = PCI_D0;

 

        if (!dev->irq) {

                dev_err(&dev->dev,

                        "Found HC with no IRQ.  Check BIOS/PCI %s setup!\n",

                        pci_name(dev));

                retval = -ENODEV;

                goto err1;

        }

 

        hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));

        if (!hcd) {

                retval = -ENOMEM;

                goto err1;

        }

 

        if (driver->flags & HCD_MEMORY) {

                /* EHCI, OHCI */

                hcd->rsrc_start = pci_resource_start(dev, 0);

                hcd->rsrc_len = pci_resource_len(dev, 0);

                if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,

                                driver->description)) {

                        dev_dbg(&dev->dev, "controller already in use\n");

                        retval = -EBUSY;

                        goto err2;

                }

                hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);

                if (hcd->regs == NULL) {

                        dev_dbg(&dev->dev, "error mapping memory\n");

                        retval = -EFAULT;

                        goto err3;

                }

 

        } else {

                /* UHCI */

                int     region;

 

                for (region = 0; region < PCI_ROM_RESOURCE; region++) {

                        if (!(pci_resource_flags(dev, region) &

                                        IORESOURCE_IO))

                                continue;

 

                        hcd->rsrc_start = pci_resource_start(dev, region);

                        hcd->rsrc_len = pci_resource_len(dev, region);

                        if (request_region(hcd->rsrc_start, hcd->rsrc_len,

                                        driver->description))

                                break;

                }

                if (region == PCI_ROM_RESOURCE) {

                        dev_dbg(&dev->dev, "no i/o regions available\n");

                        retval = -EBUSY;

                        goto err2;

                }

        }

 

        pci_set_master(dev);

 

        retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);

        if (retval != 0)

                goto err4;

        set_hs_companion(dev, hcd);

        return retval;

 

 err4:

        if (driver->flags & HCD_MEMORY) {

                iounmap(hcd->regs);

 err3:

                release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

        } else

                release_region(hcd->rsrc_start, hcd->rsrc_len);

 err2:

        clear_hs_companion(dev, hcd);

        usb_put_hcd(hcd);

 err1:

        pci_disable_device(dev);

        dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);

        return retval;

}

下一節(jié)將重點分析這個probe函數(shù)! 


USB子系統(tǒng)學(xué)習(xí)之EHCI(pci_bus_type兩個重量級函數(shù))


上一篇文章,說到了EHCI的使命,本該繼續(xù)usb_hcd_pci_probe的,但是在討論usb_hcd_pci_probe之前呢,需要理下未來會在usb_hcd_pci_probe中遇到的結(jié)構(gòu)體。

現(xiàn)看先下面這張數(shù)個結(jié)構(gòu)體纏綿的圖吧,圖像生動,但是截止目前還是不太好理解的,看完圖,喝口茶,看看下面的分析對你能不能起點作用。

難纏的結(jié)構(gòu)體,不過C語言就是這樣組織的

1.struct pci_driver ehci_pci_driver

還記得在ehci_hcd_init中注冊PCI_DRIVER嗎,記不得的話記得大明湖畔的PCI_DRIVER也行:

記不得可以翻看下retval = pci_register_driver(&PCI_DRIVER);

該PCI_DRIVER是一個宏

#define PCI_DRIVER ehci_pci_driver

所以我們需要找到ehci_pci_driver

static struct pci_driver ehci_pci_driver = {

.name = (char *) hcd_name,//static const char hcd_name [] = "ehci_hcd";

.id_table = pci_ids,

.probe = usb_hcd_pci_probe,

.remove = usb_hcd_pci_remove,

.shutdown = usb_hcd_pci_shutdown,

#ifdef CONFIG_PM_SLEEP

.driver = {

.pm = &usb_hcd_pci_pm_ops

},

#endif

};

這里面的pci_ids,就會是將來usb_hcd_pci_probe中的第二個參數(shù),我們上一篇中講過PCI總線的probe最后會調(diào)用usb_hcd_pci_probe的,上面的向總線注冊ehci_pci_driver,最后還是還回來了。

2.看下pci_ids:

static const struct pci_device_id pci_ids [] = { {

/* handle any USB 2.0 EHCI controller */

PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0),

.driver_data = (unsigned long) &ehci_pci_hc_driver,

},

{ /* end: all zeroes */ }

};

3.static const struct hc_driver ehci_pci_hc_driver

確切的說會用到pci_ids中的ehci_pci_hc_driver,那我們再把ehci_pci_hc_driver提出來看看:

static const struct hc_driver ehci_pci_hc_driver = {

.description = hcd_name,

.product_desc = "EHCI Host Controller",

.hcd_priv_size = sizeof(struct ehci_hcd),

/*

* generic hardware linkage

*/

.irq = ehci_irq,

.flags = HCD_MEMORY | HCD_USB2,

/*

* basic lifecycle operations

*/

.reset = ehci_pci_setup,

.start = ehci_run,

#ifdef CONFIG_PM

.pci_suspend = ehci_pci_suspend,

.pci_resume = ehci_pci_resume,

#endif

.stop = ehci_stop,

.shutdown = ehci_shutdown,

/*

* managing i/o requests and associated device resources

*/

.urb_enqueue = ehci_urb_enqueue,

.urb_dequeue = ehci_urb_dequeue,

.endpoint_disable = ehci_endpoint_disable,

.endpoint_reset = ehci_endpoint_reset,

/*

* scheduling support

*/

.get_frame_number = ehci_get_frame,

/*

* root hub support

*/

.hub_status_data = ehci_hub_status_data,

.hub_control = ehci_hub_control,

.bus_suspend = ehci_bus_suspend,

.bus_resume = ehci_bus_resume,

.relinquish_port = ehci_relinquish_port,

.port_handed_over = ehci_port_handed_over,

.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,

};

/*-------------------------------------------------------------------------*/

/* PCI driver selection metadata; PCI hotplugging uses this */

static const struct pci_device_id pci_ids [] = { {

/* handle any USB 2.0 EHCI controller */

PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0),

.driver_data = (unsigned long) &ehci_pci_hc_driver,

},

{ /* end: all zeroes */ }

};

可以看到這個結(jié)構(gòu)個頭不小,似乎有點意思,看這個我就知道了.product_desc = "EHCI Host Controller",它實際上就是EHCI的驅(qū)動,之前提到過EHCI是一個PCI設(shè)備,所以它應(yīng)該包含了PCI用來控制其操作的函數(shù),比如開啟(start),關(guān)閉(stop),重啟(reset),中斷的函數(shù),另外還看到了和urb相關(guān)的操作,這個urb可是USB通信的核心結(jié)構(gòu)體,暫且不表,以后會詳解。

在usb_hcd_pci_probe函數(shù)用到結(jié)構(gòu)體基本就是這些了,但是。。。

struct usb_hcd會提意見了,這坨結(jié)構(gòu)體的老大還沒有登場昵。這個講的很好,可以參閱。



    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    久久精品蜜桃一区二区av| 亚洲中文字幕在线综合视频| 国产欧美亚洲精品自拍| 日韩精品视频一二三区| 国产黑人一区二区三区| 成年男女午夜久久久精品| 一区二区三区人妻在线| 91麻豆精品欧美一区| 大屁股肥臀熟女一区二区视频| 日韩精品少妇人妻一区二区| 中国美女偷拍福利视频| 日韩一级毛一欧美一级乱| 亚洲第一区二区三区女厕偷拍| 午夜成年人黄片免费观看| 国产精品视频一区二区秋霞| 在线免费观看一二区视频| 亚洲熟女诱惑一区二区| 日韩精品毛片视频免费看| 久久香蕉综合网精品视频| 中文字幕一区二区三区大片| 老熟女露脸一二三四区| 国产精品欧美一级免费| 麻豆印象传媒在线观看| 亚洲中文在线观看小视频| 亚洲第一香蕉视频在线| 久热青青草视频在线观看| 日本加勒比不卡二三四区| av免费视屏在线观看| 日韩性生活视频免费在线观看| 日韩中文字幕欧美亚洲| 微拍一区二区三区福利| 欧美精品亚洲精品日韩专区| 国产亚洲神马午夜福利| 国产又黄又爽又粗视频在线| 熟女高潮一区二区三区| 在线免费观看一二区视频| 亚洲av秘片一区二区三区| 91久久精品国产成人| 久久精品福利在线观看| 日本高清视频在线观看不卡| 成年午夜在线免费视频|