国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
網(wǎng)卡驅(qū)動(dòng)注冊(cè)到PCI總線(xiàn)這一過(guò)程的分析
大家好,最近在看網(wǎng)絡(luò)部分的代碼,目前看到了網(wǎng)卡的初始化部分。書(shū)上講到的內(nèi)容主要是網(wǎng)卡驅(qū)動(dòng)程序?qū)W(wǎng)卡自身的初始化部分,即網(wǎng)卡驅(qū)動(dòng)的probe函數(shù)是如何執(zhí)行的,而很少講到網(wǎng)卡是如何注冊(cè)到系統(tǒng)中去的這一部分。
    現(xiàn)在的網(wǎng)卡大部分都是連接到PCI總線(xiàn)上的。因此,網(wǎng)卡驅(qū)動(dòng)是如何連接到PCI總線(xiàn),又是如何與網(wǎng)卡設(shè)備聯(lián)系起來(lái),網(wǎng)卡在注冊(cè)的最后又是
如何調(diào)用到該網(wǎng)卡的probe函數(shù)的,這一個(gè)過(guò)程將在后面的文章中進(jìn)行描述。整個(gè)文章分成兩個(gè)部分,第一部分是講解總線(xiàn)、設(shè)備以及驅(qū)動(dòng)三者的聯(lián)系,為第二
部分具體講解PCI總線(xiàn)、網(wǎng)卡設(shè)備和驅(qū)動(dòng)做一點(diǎn)鋪墊。
    由于我在這方面也是初學(xué),之所以想總結(jié)出來(lái)是想到在總結(jié)的過(guò)程中對(duì)自己的學(xué)習(xí)也是一個(gè)梳理的過(guò)程。所以有什么地方寫(xiě)得不好的,還請(qǐng)各位多多指正,非常感謝!也希望能在這里結(jié)識(shí)更多的朋友。
    在總結(jié)的過(guò)程中參考了下面一些資料,在此表示感謝:
[1]
[2]
[3]
[4]  3rd Edition.
1. 總線(xiàn)、設(shè)備和驅(qū)動(dòng)
1.1 簡(jiǎn)單介紹
        Linux設(shè)備模型中三個(gè)很重要的概念就是總線(xiàn)、設(shè)備和驅(qū)動(dòng),即bus,device和driver。它們分別對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)分別為struct bus_type,struct device和struct device_driver。
        總線(xiàn)是處理器與一個(gè)或多個(gè)設(shè)備之間的通道,在設(shè)備模型中,所有的設(shè)備都通過(guò)總線(xiàn)相連。在最底層,Linux系統(tǒng)中的每一個(gè)設(shè)備都用device結(jié)構(gòu)的一個(gè)實(shí)例來(lái)表示。而驅(qū)動(dòng)則是使總線(xiàn)上的設(shè)備能夠完成它應(yīng)該完成的功能。
在系統(tǒng)中有多種總線(xiàn),如PCI總線(xiàn)、SCSI總線(xiàn)等。系統(tǒng)中的多個(gè)設(shè)備和驅(qū)動(dòng)是通過(guò)總線(xiàn)讓它們聯(lián)系起來(lái)的。在bus_type中兩個(gè)很重要的成員就是
struct kset drivers和struct kset devices。它分別代表了連接在這個(gè)總線(xiàn)上的兩個(gè)鏈,一個(gè)是設(shè)備鏈表,另一個(gè)則是
設(shè)備驅(qū)動(dòng)鏈表。也就是說(shuō),通過(guò)一個(gè)總線(xiàn)描述符,就可以找到掛載到這條總線(xiàn)上的設(shè)備,以及支持該總線(xiàn)的不同的設(shè)備驅(qū)動(dòng)程序。
1.2 總線(xiàn)、設(shè)備與驅(qū)動(dòng)的綁定
在系統(tǒng)啟動(dòng)時(shí),它會(huì)對(duì)每種類(lèi)型的總線(xiàn)創(chuàng)建一個(gè)描述符,并將使用該總線(xiàn)的設(shè)備鏈接到該總線(xiàn)描述符的devices鏈上來(lái)。也即是說(shuō)在系統(tǒng)初始化時(shí),它會(huì)掃描
連接了哪些設(shè)備,并且為每個(gè)設(shè)備建立一個(gè)struce device變量,然后將該變量鏈接到這個(gè)設(shè)備所連接的總線(xiàn)的描述符上去。另一方面,每當(dāng)加載了一
個(gè)設(shè)備驅(qū)動(dòng),則系統(tǒng)也會(huì)準(zhǔn)備一個(gè)struct device_driver結(jié)構(gòu)的變量,然后再將這個(gè)變量也鏈接到它所在總線(xiàn)的描述符的drivers鏈上
去。
對(duì)于設(shè)備來(lái)說(shuō),在結(jié)構(gòu)體struct device中有兩個(gè)重要的成員,一個(gè)是struct bus_type *bus,另一個(gè)是
struct device_driver *driver。bus成員就表示該設(shè)備是鏈接到哪一個(gè)總線(xiàn)上的,而driver成員就表示當(dāng)前設(shè)備是由哪個(gè)
驅(qū)動(dòng)程序所驅(qū)動(dòng)的。對(duì)于驅(qū)動(dòng)程序來(lái)說(shuō),在結(jié)構(gòu)體struct device_driver中也有兩個(gè)成員,struct bus_type *bus和
struct list_head devices,這里的bus成員也是指向這個(gè)驅(qū)動(dòng)是鏈接到哪個(gè)總線(xiàn)上的,而devices這個(gè)鏈表則是表示當(dāng)前這個(gè)
驅(qū)動(dòng)程序可以去進(jìn)行驅(qū)動(dòng)的那些設(shè)備。一個(gè)驅(qū)動(dòng)程序可以支持一個(gè)或多個(gè)設(shè)備,而一個(gè)設(shè)備則只會(huì)綁定給一個(gè)驅(qū)動(dòng)程序。
對(duì)于device與device_driver之間建立聯(lián)系的方式,主要有兩種方式。第一種,在計(jì)算機(jī)啟動(dòng)的時(shí)候,總線(xiàn)開(kāi)始掃描連接在其上的設(shè)備,為每個(gè)
設(shè)備建立一個(gè)struct device變量并鏈接到該總線(xiàn)的devices鏈上,然后開(kāi)始初始化不同的驅(qū)動(dòng)程序,驅(qū)動(dòng)程序到它所在的總線(xiàn)的
devices鏈上去遍歷每一個(gè)還沒(méi)有被綁定給某個(gè)驅(qū)動(dòng)的設(shè)備,然后再查看是否能夠支持這種設(shè)備,如果它能夠支持這種設(shè)備,則將這個(gè)設(shè)備與這個(gè)驅(qū)動(dòng)聯(lián)系起
來(lái)。即,將這個(gè)設(shè)備的device變量加到驅(qū)動(dòng)的devices鏈上,同時(shí)讓struct device中的device_driver指向當(dāng)前這個(gè)驅(qū)
動(dòng)。第二種則是熱插拔。也即是在系統(tǒng)運(yùn)行時(shí)插入了設(shè)備,此時(shí)內(nèi)核會(huì)去查找在該bus鏈上注冊(cè)了的device_driver,然后再將設(shè)備與驅(qū)動(dòng)聯(lián)系起
來(lái)。設(shè)備與驅(qū)動(dòng)根據(jù)什么規(guī)則聯(lián)系起來(lái),它們是如何被聯(lián)系起來(lái)的代碼我們將在后面的章節(jié)進(jìn)行詳細(xì)的描述。
1.3 PCI總線(xiàn)
PCI是一種在CPU與I/O設(shè)備之間進(jìn)行高速數(shù)據(jù)傳輸?shù)囊环N總線(xiàn)。有很多設(shè)備都是使用PCI總線(xiàn)的,網(wǎng)卡就是其中之一。我們?cè)谇懊嬷v了那些總線(xiàn)、設(shè)備與
驅(qū)動(dòng)方面的知識(shí),原因就在于網(wǎng)卡是連接到PCI總線(xiàn)上,所以PCI總線(xiàn)、網(wǎng)卡設(shè)備以及網(wǎng)卡驅(qū)動(dòng)就成了我們研究網(wǎng)卡的一個(gè)很重要的線(xiàn)索,尤其是在網(wǎng)絡(luò)的鏈路
層部分。下圖顯示了在一個(gè)系統(tǒng)中PCI設(shè)備的一個(gè)框圖:
[attach]226528[/attach]
        PCI子系統(tǒng)聲明了一個(gè)bus_type結(jié)構(gòu),為pci_bus_type。它就是PCI總線(xiàn)的描述符。在這個(gè)變量上,鏈接了PCI設(shè)備以及支持PCI設(shè)備的驅(qū)動(dòng)程序。
1.4 PCI設(shè)備與驅(qū)動(dòng)
PCI設(shè)備通常由一組參數(shù)唯一地標(biāo)識(shí),它們被vendorID,deviceID和class nodes所標(biāo)識(shí),即設(shè)備廠(chǎng)商,型號(hào)等,這些參數(shù)保存在
pci_device_id結(jié)構(gòu)中。每個(gè)PCI設(shè)備都會(huì)被分配一個(gè)pci_dev變量,內(nèi)核就用這個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)表示一個(gè)PCI設(shè)備。
所有的PCI驅(qū)動(dòng)程序都必須定義一個(gè)pci_driver結(jié)構(gòu)變量,在該變量中包含了這個(gè)PCI驅(qū)動(dòng)程序所提供的不同功能的函數(shù),同時(shí),在這個(gè)結(jié)構(gòu)中也包
含了一個(gè)device_driver結(jié)構(gòu),這個(gè)結(jié)構(gòu)定義了PCI子系統(tǒng)與PCI設(shè)備之間的接口。在注冊(cè)PCI驅(qū)動(dòng)程序時(shí),這個(gè)結(jié)構(gòu)將被初始化,同時(shí)這個(gè)
pci_driver變量會(huì)被鏈接到pci_bus_type中的驅(qū)動(dòng)鏈上去。
        在pci_driver中有一個(gè)成員struct pci_device_id *id_table,它列出了這個(gè)設(shè)備驅(qū)動(dòng)程序所能夠處理的所有PCI設(shè)備的ID值。
1.5 PCI設(shè)備與驅(qū)動(dòng)的綁定過(guò)程
下面描述一下對(duì)于PCI設(shè)備與驅(qū)動(dòng)綁定的過(guò)程。首先在系統(tǒng)啟動(dòng)的時(shí)候,PCI總線(xiàn)會(huì)去掃描連接到這個(gè)總線(xiàn)上的設(shè)備,同時(shí)為每一個(gè)設(shè)備建立一個(gè)
pci_dev結(jié)構(gòu),在這個(gè)結(jié)構(gòu)中有一個(gè)device成員,并將這些pci_dev結(jié)構(gòu)鏈接到PCI總線(xiàn)描述符上的devices鏈。如下圖所示:
[attach]226529[/attach]
        第二步是當(dāng)PCI驅(qū)動(dòng)被加載時(shí),pci_driver結(jié)構(gòu)體將被初始化,這一過(guò)程在函數(shù)pci_register_driver中:
        drv->driver.bus = &pci_bus_type;
        drv->driver.probe = pci_device_probe;
最后會(huì)調(diào)用driver_register(&drv->driver)將這個(gè)PCI驅(qū)動(dòng)掛載到總線(xiàn)描述符的驅(qū)動(dòng)鏈上。同時(shí)在注冊(cè)的過(guò)程
中,會(huì)根據(jù)pci_driver中的id_table中的ID值去查看該驅(qū)動(dòng)支持哪些設(shè)備,將這些設(shè)備掛載到pci_driver中的devices鏈中
來(lái)。如下圖所示:
[attach]226530[/attach]
        對(duì)于不同的設(shè)備,可能驅(qū)動(dòng)程序也不一樣,因此,對(duì)于上圖中的Dev3,可能就需要另外一個(gè)驅(qū)動(dòng)程序來(lái)對(duì)其進(jìn)行驅(qū)動(dòng)。所以當(dāng)加載了Dev3的驅(qū)動(dòng)程序時(shí),其示意圖如下圖所示:
[attach]226531[/attach]
        上面這三個(gè)示意圖就描述了總線(xiàn)、設(shè)備以及驅(qū)動(dòng)在系統(tǒng)中是如何進(jìn)行相互聯(lián)系的。前面對(duì)于驅(qū)動(dòng)注冊(cè)這些函數(shù)的描述較為簡(jiǎn)單,因?yàn)榫W(wǎng)卡是一個(gè)PCI設(shè)備,因此在后面具體地講到網(wǎng)卡注冊(cè)時(shí)再來(lái)詳細(xì)地講解和PCI相關(guān)的注冊(cè)等函數(shù)。
1.6 小結(jié)
本部分主要講解了總線(xiàn)、設(shè)備以及驅(qū)動(dòng)方面的一些知識(shí),由于網(wǎng)卡是一個(gè)PCI設(shè)備,因此具體地講到了一點(diǎn)PCI總線(xiàn)、PCI設(shè)備及相應(yīng)的PCI驅(qū)動(dòng)方面的知
識(shí),但是由于PCI本身就是很大的一個(gè)子系統(tǒng),因此這里不可能對(duì)其進(jìn)行詳細(xì)地講解,在后面對(duì)網(wǎng)卡的分析中,將對(duì)網(wǎng)卡中涉及到的和PCI相關(guān)的部分進(jìn)行講
解。

PCI

init1

init2

init3

scutan
回復(fù)于:2008-12-15 22:47:47

2. 網(wǎng)卡在PCI層的注冊(cè)
2.1 數(shù)據(jù)結(jié)構(gòu)
        前面第一章講了總線(xiàn)、設(shè)備以及驅(qū)動(dòng)方面的關(guān)系,也講到了大多數(shù)網(wǎng)卡設(shè)備實(shí)際上是一個(gè)PCI設(shè)備。因此,本章就講解網(wǎng)卡設(shè)備在注冊(cè)時(shí)是如何注冊(cè)到PCI總線(xiàn)上去的。在這里,以Intel的E100網(wǎng)卡驅(qū)動(dòng)進(jìn)行講解。
        前面講到每個(gè)PCI設(shè)備都由一組參數(shù)唯一地標(biāo)識(shí),這些參數(shù)保存在結(jié)構(gòu)體pci_device_id中,如下所示:
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 */
};
        每個(gè)PCI設(shè)備驅(qū)動(dòng)都有一個(gè)pci_driver變量,它描述了一個(gè)PCI驅(qū)動(dòng)的信息,如下所示:
struct pci_driver {
        struct list_head node;
        char *name;
        const struct pci_device_id *id_table;        /* must be non-NULL for probe to be called */
        int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);        /* New device inserted */
        void (*remove) (struct pci_dev *dev);        /* Device removed (NULL if not a hot-plug capable driver) */
        int  (*suspend) (struct pci_dev *dev, pm_message_t state);        /* Device suspended */
        int  (*suspend_late) (struct pci_dev *dev, pm_message_t state);
        int  (*resume_early) (struct pci_dev *dev);
        int  (*resume) (struct pci_dev *dev);                        /* Device woken up */
        int  (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable);   /* Enable wake event */
        void (*shutdown) (struct pci_dev *dev);
        struct pci_error_handlers *err_handler;
        struct device_driver        driver;
        struct pci_dynids dynids;
        int multithread_probe;
};
        每個(gè)PCI驅(qū)動(dòng)中都有一個(gè)id_table成員變量,記錄了當(dāng)前這個(gè)驅(qū)動(dòng)所能夠進(jìn)行驅(qū)動(dòng)的那些設(shè)備的ID值。
        對(duì)于E100網(wǎng)卡驅(qū)動(dòng)來(lái)說(shuō),它的pci_driver變量定義為:
static struct pci_driver e100_driver = {
        .name =         DRV_NAME,
        .id_table =     e100_id_table,
        .probe =        e100_probe,
        .remove =       __devexit_p(e100_remove),
#ifdef CONFIG_PM
        /* Power Management hooks */
        .suspend =      e100_suspend,
        .resume =       e100_resume,
#endif
        .shutdown =     e100_shutdown,
        .err_handler = &e100_err_handler,
};
        里面e100_id_table就表示該E100驅(qū)動(dòng)所能夠支持的PCI設(shè)備的ID號(hào),其定義為:
#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
        PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
        PCI_CLASS_NETWORK_ETHERNET
當(dāng)PCI層檢測(cè)到一個(gè)PCI設(shè)備能夠被某PCI驅(qū)動(dòng)所支持時(shí)(這是通過(guò)函數(shù)pci_match_one_device來(lái)進(jìn)行檢測(cè)的),就會(huì)調(diào)用這個(gè)PCI
驅(qū)動(dòng)上的probe函數(shù),在該函數(shù)中會(huì)對(duì)該特定的PCI設(shè)備進(jìn)行一些具體的初始化等操作。比如對(duì)于E100設(shè)備驅(qū)動(dòng)來(lái)說(shuō),其probe函數(shù)為
e100_probe。在這個(gè)函數(shù)中,會(huì)對(duì)網(wǎng)卡設(shè)備進(jìn)行初始化。
        e100_probe主要就涉及到網(wǎng)卡設(shè)備net_device的初始化,我們現(xiàn)在先來(lái)關(guān)注一下從網(wǎng)卡注冊(cè)一直到調(diào)用e100_probe這一個(gè)過(guò)程的整個(gè)流程。
2.2 E100初始化
        E100驅(qū)動(dòng)程序的初始化是在函數(shù)e100_init_module()中的,如下:
static int __init e100_init_module(void)
{
        if(((1
        在這個(gè)函數(shù)中,調(diào)用了pci_register_driver()函數(shù),對(duì)e100_driver這個(gè)驅(qū)動(dòng)進(jìn)行注冊(cè)。
2.3 PCI注冊(cè)
        在前面我們已經(jīng)看到,PCI的注冊(cè)就是將PCI驅(qū)動(dòng)程序掛載到其所在的總線(xiàn)的drivers鏈,同時(shí)掃描PCI設(shè)備,將它能夠進(jìn)行驅(qū)動(dòng)的設(shè)備掛載到driver上的devices鏈表上來(lái),這里,我們將詳細(xì)地查看這整個(gè)流程的函數(shù)調(diào)用關(guān)系。
        pci_register_driver()->__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);
        在函數(shù)中有幾個(gè)初始化語(yǔ)句:
        drv->driver.name = drv->name;
        drv->driver.bus = &pci_bus_type;
        drv->driver.owner = owner;
        drv->driver.mod_name = mod_name;
        即是將PCI設(shè)備中的driver變量的總線(xiàn)指向pci_bus_type這個(gè)總線(xiàn)描述符,同時(shí)設(shè)置驅(qū)動(dòng)的名字等。
        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,
        .suspend        = pci_device_suspend,
        .suspend_late        = pci_device_suspend_late,
        .resume_early        = pci_device_resume_early,
        .resume                = pci_device_resume,
        .shutdown        = pci_device_shutdown,
        .dev_attrs        = pci_dev_attrs,
};
        然后再調(diào)用函數(shù)driver_register(&drv->driver);通過(guò)這個(gè)函數(shù)將這個(gè)PCI驅(qū)動(dòng)中的struct device_driver driver成員變量注冊(cè)到系統(tǒng)中去。
        pci_register_driver()->__pci_register_driver()->driver_register()
        driver_register()代碼如下:
/**
*        driver_register - register driver with bus
*        @drv:        driver to register
*
*        We pass off most of the work to the bus_add_driver() call,
*        since most of the things we have to do deal with the bus
*        structures.
*
*        The one interesting aspect is that we setup @drv->unloaded
*        as a completion that gets complete when the driver reference
*        count reaches 0.
*/
int driver_register(struct device_driver * drv)
{
        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
            (drv->bus->shutdown && drv->shutdown)) {
                printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
        }
        klist_init(&drv->klist_devices, NULL, NULL);
        init_completion(&drv->unloaded);
        return bus_add_driver(drv);
}
        klist_init()是為設(shè)備驅(qū)動(dòng)的klist_devices成員進(jìn)行初始化,這個(gè)klist_devices是一個(gè)對(duì)鏈表進(jìn)行操作的包裹結(jié)構(gòu),它會(huì)鏈接這個(gè)驅(qū)動(dòng)能夠支持的那些設(shè)備。
        最后就調(diào)用bus_add_driver()函數(shù)。這個(gè)函數(shù)的功能就是將這個(gè)驅(qū)動(dòng)加到其所在的總線(xiàn)的驅(qū)動(dòng)鏈上。
        pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()
        在bus_add_driver()函數(shù)中,最重要的是調(diào)用driver_attach()函數(shù),其定義如下:
/**
*        driver_attach - try to bind driver to devices.
*        @drv:        driver.
*
*        Walk the list of devices that the bus has on it and try to
*        match the driver with each one.  If driver_probe_device()
*        returns 0 and the @dev->driver is set, we've found a
*        compatible pair.
*/
int driver_attach(struct device_driver * drv)
{
        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
        該函數(shù)遍歷這個(gè)驅(qū)動(dòng)所在的總線(xiàn)上的所有設(shè)備,然后將這些設(shè)備與當(dāng)前驅(qū)動(dòng)進(jìn)行匹配,以檢測(cè)這個(gè)驅(qū)動(dòng)是否能夠支持某個(gè)設(shè)備,也即是將設(shè)備與驅(qū)動(dòng)聯(lián)系起來(lái)。
        bus_for_each_dev函數(shù)是掃描在drv->bus這個(gè)總線(xiàn)上的所有設(shè)備,然后將每個(gè)設(shè)備以及當(dāng)前驅(qū)動(dòng)這兩個(gè)指針傳遞給__driver_attach函數(shù)。
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()
        __driver_attach()函數(shù)是將驅(qū)動(dòng)與設(shè)備聯(lián)系起來(lái)的函數(shù)。
static int __driver_attach(struct device * dev, void * data)
{
        struct device_driver * drv = data;
        /*
         * Lock device and try to bind to it. We drop the error
         * here and always return 0, because we need to keep trying
         * to bind to devices and some drivers will return an error
         * simply if it didn't support the device.
         *
         * driver_probe_device() will spit a warning if there
         * is an error.
         */
        if (dev->parent)        /* Needed for USB */
                down(&dev->parent->sem);
        down(&dev->sem);
        if (!dev->driver)
                driver_probe_device(drv, dev);
        up(&dev->sem);
        if (dev->parent)
                up(&dev->parent->sem);
        return 0;
}
        在函數(shù)中有兩條語(yǔ)句:
        if (!dev->driver)
                driver_probe_device(drv, dev);
        也即是判斷當(dāng)前設(shè)備是否已經(jīng)注冊(cè)了一個(gè)驅(qū)動(dòng),如果沒(méi)有注冊(cè)驅(qū)動(dòng),則調(diào)用driver_probe_device()函數(shù)。
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()
        如下:
/**
* driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
*
* First, we call the bus's match function, if one present, which should
* compare the device IDs the driver supports with the device IDs of the
* device. Note we don't do this ourselves because we don't know the
* format of the ID structures, nor what is to be considered a match and
* what is not.
*
* This function returns 1 if a match is found, an error if one occurs
* (that is not -ENODEV or -ENXIO), and 0 otherwise.
*
* This function must be called with @dev->sem held.  When called for a
* USB interface, @dev->parent->sem must be held as well.
*/
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
        struct stupid_thread_structure *data;
        struct task_struct *probe_task;
        int ret = 0;
        if (!device_is_registered(dev))
                return -ENODEV;
        if (drv->bus->match && !drv->bus->match(dev, drv))
                goto done;
        pr_debug("%s: Matched Device %s with Driver %s\n",
                 drv->bus->name, dev->bus_id, drv->name);
        data = kmalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
        data->drv = drv;
        data->dev = dev;
        if (drv->multithread_probe) {
                probe_task = kthread_run(really_probe, data,
                                         "probe-%s", dev->bus_id);
                if (IS_ERR(probe_task))
                        ret = really_probe(data);
        } else
                ret = really_probe(data);
done:
        return ret;
}       
        該函數(shù)首先會(huì)調(diào)用總線(xiàn)上的match函數(shù),以判斷當(dāng)前的PCI驅(qū)動(dòng)能否支持該P(yáng)CI設(shè)備,如果可以,則繼續(xù)往后面執(zhí)行。
        drv->bus->match函數(shù)也即是pci_bus_type中的match成員變量,它為pci_bus_match函數(shù)。
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()->pci_bus_match()
/**
* 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;
}
pci_bus_match函數(shù)的作用就是將PCI設(shè)備與PCI驅(qū)動(dòng)進(jìn)行比較以檢查該驅(qū)動(dòng)是否能夠支持這個(gè)設(shè)備。在函數(shù)的最前面是兩個(gè)宏
to_pci_dev和to_pci_driver。因?yàn)樵诤瘮?shù)執(zhí)行的過(guò)程中,雖然最開(kāi)始傳進(jìn)來(lái)的是pci_driver結(jié)構(gòu)與pci_dev結(jié)構(gòu),但是
在執(zhí)行的時(shí)候卻取了這兩個(gè)結(jié)構(gòu)體中的device_driver和device成員變量,所以現(xiàn)在就要通過(guò)這兩個(gè)成員變量找到之前對(duì)應(yīng)的
pci_driver和pci_dev結(jié)構(gòu)的地址。
#define        to_pci_dev(n) container_of(n, struct pci_dev, dev)
#define        to_pci_driver(drv) container_of(drv,struct pci_driver, driver)
這兩個(gè)宏在 3rd書(shū)上有相應(yīng)的講解,這里也就是找到E100的pci_driver:
e100_driver以及該網(wǎng)卡設(shè)備的pci_dev結(jié)構(gòu)。現(xiàn)在就要對(duì)它們進(jìn)行比較以看它們之間是否能夠聯(lián)系起來(lái)。這是通過(guò)函數(shù)
pci_match_device實(shí)現(xiàn)的。
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()->pci_bus_match()->pci_match_device()
/**
* 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.
*/
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);
}
        pci_match_one_driver函數(shù)的作用是將一個(gè)PCI設(shè)備與PCI驅(qū)動(dòng)進(jìn)行比較,以查看它們是否相匹配。如果相匹配,則返回匹配的pci_device_id結(jié)構(gòu)體指針。
此時(shí),如果該P(yáng)CI驅(qū)動(dòng)已經(jīng)找到了一個(gè)可以想符的PCI設(shè)備,則返回,然后再退回到之前的driver_probe_device函數(shù)中。在該函數(shù)最后將
調(diào)用really_probe函數(shù)。將device_driver與device結(jié)構(gòu)體指針作為參數(shù)傳遞到這個(gè)函數(shù)中。下面幾行是調(diào)用驅(qū)動(dòng)或者總線(xiàn)的
probe函數(shù)來(lái)掃描設(shè)備。
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()->really_probe()
        在函數(shù)really_probe()中:
        if (dev->bus->probe) {
                ret = dev->bus->probe(dev);
                if (ret)
                        goto probe_failed;
        } else if (drv->probe) {
                ret = drv->probe(dev);
                if (ret)
                        goto probe_failed;
        }
        此時(shí)的dev->bus為pci_bus_type,其probe函數(shù)則對(duì)應(yīng)為:pci_device_probe。
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()->really_probe()->pci_device_probe()
同樣,在該函數(shù)中會(huì)獲得當(dāng)前的PCI設(shè)備的pci_dev結(jié)構(gòu)體指針以及PCI驅(qū)動(dòng)程序的pci_driver結(jié)構(gòu)體指針。分別使用宏
to_pci_dev和to_pci_driver。最后則調(diào)用函數(shù)__pci_device_probe。在該函數(shù)中還會(huì)調(diào)用函數(shù)
pci_call_probe,這是最后的函數(shù)
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()->really_probe()->pci_device_probe()->__pci_device_probe()->pci_call_probe()
        在函數(shù)pci_call_probe里有一條語(yǔ)句:
static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
                          const struct pci_device_id *id)
{
        int error;
/*  省略  */
        error = drv->probe(dev, id);
        在此處就調(diào)用了pci_driver的probe函數(shù),對(duì)于這里的E100驅(qū)動(dòng)來(lái)說(shuō),它的probe函數(shù)是最開(kāi)始注冊(cè)的e100_probe函數(shù),在該函數(shù)中會(huì)完成對(duì)網(wǎng)卡設(shè)備net_device的初始化等操作。
       pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()->really_probe()->pci_device_probe()->__pci_device_probe()->pci_call_probe()->e100_probe()
        到這里,我們對(duì)網(wǎng)卡驅(qū)動(dòng)的PCI層的初始化分析就告一個(gè)段落了,剩下的部分就是網(wǎng)卡驅(qū)動(dòng)對(duì)網(wǎng)卡設(shè)備本身的初始化等操作。

scutan
回復(fù)于:2008-12-15 22:48:52

2.4 函數(shù)調(diào)用流程圖
        在這里,為網(wǎng)卡在PCI層的注冊(cè)畫(huà)了一個(gè)函數(shù)調(diào)用的流程圖,能夠更直觀(guān)地展現(xiàn)網(wǎng)卡從注冊(cè)到調(diào)用其自身的網(wǎng)卡初始化的這一個(gè)函數(shù)調(diào)用過(guò)程。
[attach]226537[/attach]
[attach]226538[/attach]

1

2

scutan
回復(fù)于:2008-12-15 22:52:22

文筆實(shí)在不行,寫(xiě)了一個(gè)下午加晚上,才寫(xiě)這么點(diǎn)。希望能夠?qū)Τ鯇W(xué)者有一點(diǎn)用吧。因?yàn)槲易铋_(kāi)始在看網(wǎng)卡驅(qū)動(dòng)的時(shí)候,就是迷惑加載了網(wǎng)卡之后是如何調(diào)用到該網(wǎng)卡的probe函數(shù)的。所以就仔細(xì)地看了一下里面的源碼。
這里主要還是起一個(gè)梳理的作用,很多代碼也沒(méi)有進(jìn)一步地深入分析。不過(guò)對(duì)于網(wǎng)絡(luò)架構(gòu)來(lái)說(shuō),首先將整個(gè)調(diào)用的流程掌握了,對(duì)后面的理解也就更加方便了。
:lol:

Godbach
回復(fù)于:2008-12-15 22:54:50

scutan兄又有好文章了,明天仔細(xì)拜讀啊。

albcamus
回復(fù)于:2008-12-15 23:10:29

補(bǔ)充一下,貼一下open函數(shù)的調(diào)用的筆記:
86, ifconfig eth0 up 會(huì)導(dǎo)致 net_device->open被調(diào)用,內(nèi)幕!
       
            # strace ifconfig eth0 up 2>&1 |less -N
   
    可以看到,它是先用sockfd = socket(AF_INET, SOCK_DGRAM, 0)生成一個(gè)sockfd文件描述符,
    再ioctl(sockfd, SIOCSIFFLAGS, 加上IFF_UP標(biāo)志)。 這樣就導(dǎo)致了open方法的調(diào)用。
    socket文件描述符都是用socket(2)系統(tǒng)調(diào)用生成的:
           
        sys_socket() > sock_map_fd() > sock_attach_fd() :
                dentry->d_op = &sockfs_dentry_operations;
                ...
                init_file(file, sock_mnt, dentry, FMODE_READ|FMODE_WRITE, &socket_file_ops);
                SOCK_INODE(sock)->i_fop = &socket_file_ops;
       
        (回憶一下,這個(gè)是不是就類(lèi)似于ext3_iget()里頭對(duì)inode->i_fop的賦值?)
                static const struct file_operations socket_file_ops = {
                        .owner =        THIS_MODULE,
                        .llseek =        no_llseek,
                        .aio_read =        sock_aio_read,
                        .aio_write =        sock_aio_write,
                        .poll =                sock_poll,
                        .unlocked_ioctl = sock_ioctl,
                #ifdef CONFIG_COMPAT
                        .compat_ioctl = compat_sock_ioctl,
                #endif
                        .mmap =                sock_mmap,
                        .open =                sock_no_open,        /* special open code to disallow open via /proc */
                        .release =        sock_close,
                        .fasync =        sock_fasync,
                        .sendpage =        sock_sendpage,
                        .splice_write = generic_splice_sendpage,
                        .splice_read =        sock_splice_read,
                }
        其unlocked_ioctl = sock_ioctl,那么我們沿著sock_ioctl走下去:
               
                sock_ioctl() --switch到了default--> dev_ioctl() > --SIOCSIFFLAGS--> dev_ifsioc()
                > dev_change_flags() :
                       
                        if ((old_flags ^ flags) & IFF_UP) {IFF_UP/* Bit is different  ? */
                                ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);
        如果是設(shè)置了IFF_UP,就調(diào)用dev_open;如果是清除了IFF_UP,就調(diào)用dev_close。 看dev_open里的:
               
                ret = dev->open(dev);
       
        就在此時(shí),struct net_device的open方法被調(diào)用。

albcamus
回復(fù)于:2008-12-15 23:11:23

2). remove函數(shù)何時(shí)被調(diào)用?
            
            當(dāng)pci_dev消失時(shí)(設(shè)備被拔出),或者module被rmmod時(shí)。
            pci_unregister_driver() > driver_unregister() > driver_detach() > __device_release_driver():
                if (dev->bus && dev->bus->remove)
                        dev->bus->remove(dev);
                else if (drv->remove)
                        drv->remove(dev);
          
            對(duì)pci設(shè)備來(lái)說(shuō),這里的dev->bus就是&pci_bus_type,參考1)中的定義,我們知道其remove函數(shù)是
            pci_device_remove():
                        struct pci_dev * pci_dev = to_pci_dev(dev);
                        struct pci_driver * drv = pci_dev->driver;
                        if (drv) {
                                if (drv->remove)
                                        drv->remove(pci_dev);
                                pci_dev->driver = NULL;
                        }

albcamus
回復(fù)于:2008-12-15 23:11:50

[FYI] 增加/刪除一個(gè)PCI device時(shí)的情景。
              (只有boot時(shí)的enumeration和hotplug兩種情況可能導(dǎo)致設(shè)備出現(xiàn)與消失)
              pci device的發(fā)現(xiàn):
                      [ pci_scan_slot() > pci_scan_single_device() > pci_scan_device()
                                                             > pci_device_add() ]
                pci_bus_add_devices() > pci_bus_add_device() > device_add() > bus_attach_device() :
                       
                        int device_attach(struct device *dev)
                        {
                                int ret = 0;
                                down(&dev->sem);
                                if (dev->driver) {
                                        ret = device_bind_driver(dev);
                                        if (ret == 0)
                                                ret = 1;
                                        else {
                                                dev->driver = NULL;
                                                ret = 0;
                                        }
                                } else {
                                        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
                                }
                                up(&dev->sem);
                                return ret;
                        }
                也就是說(shuō),如果已經(jīng)有了dev->driver這個(gè)值,那么就直接bind上去;如果沒(méi)有,那么:
                       
                        bus_for_each_drv() > __device_attach() > driver_probe_device() > really_probe()
                此后發(fā)生的情形就和從pci_register_driver()一直調(diào)用到really_probe()的一樣了。
        remove:
        =======
                pci_remove_bus_device() > pci_destroy_dev() > pci_stop_dev() > device_unregister() >
                device_del() > bus_remove_device() > device_release_driver() > __device_release_driver() :
                        static void __device_release_driver(struct device *dev)
                        {
                                struct device_driver *drv;
                                drv = dev->driver;
                                if (drv) {
                                        driver_sysfs_remove(dev);
                                        sysfs_remove_link(&dev->kobj, "driver");
                                        if (dev->bus)
                                                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                                                             BUS_NOTIFY_UNBIND_DRIVER,
                                                                             dev);
                                        if (dev->bus && dev->bus->remove)
                                                dev->bus->remove(dev);
                                        else if (drv->remove)
                                                drv->remove(dev);
                                        devres_release_all(dev);
                                        dev->driver = NULL;
                                        klist_remove(&dev->knode_driver);
                                }
                        }
                注意,如果可以,首先嘗試調(diào)用pci_bus_type的remove方法(a.k.a pci_device_remove),否則調(diào)用
                device_driver的remove方法。

scutan
回復(fù)于:2008-12-15 23:27:56

:em02:
謝謝albcamus版主精彩的補(bǔ)充。

kns1024wh
回復(fù)于:2008-12-16 08:48:27

實(shí)踐的結(jié)論是最有說(shuō)服力的

dreamice
回復(fù)于:2008-12-16 09:51:09

這貼牛,高手匯集。受益匪淺:lol:

Godbach
回復(fù)于:2008-12-16 10:04:16

是啊。先讀一遍,然后再向scutan和albcamus兄請(qǐng)教。

Godbach
回復(fù)于:2008-12-16 10:56:10

引用:補(bǔ)充一下,貼一下open函數(shù)的調(diào)用的筆記:
大家要學(xué)習(xí)albcamus版主看書(shū)做筆記的好習(xí)慣啊。偶以前就沒(méi)這個(gè)習(xí)慣,理解的東西沒(méi)過(guò)多久就又忘了。

Arthur_
回復(fù)于:2008-12-16 13:25:12

五體投地:shock:

scutan
回復(fù)于:2008-12-16 13:38:57

謝謝各位。:em02:

Godbach
回復(fù)于:2008-12-16 14:09:43

通讀一遍,寫(xiě)的很好。流程比較明確。
整個(gè)流程應(yīng)該是使用了兩個(gè)probe函數(shù)。一個(gè)是pci_bus_type的probe函數(shù)指針,指向pci_device_probe。
另一個(gè)就是驅(qū)動(dòng)程序自己的probe函數(shù),指向e100_probe,該函數(shù)在一下代碼中調(diào)用。完成網(wǎng)卡的具體初始化工作。
引用:static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
                          const struct pci_device_id *id)
{
        int error;
/*  省略  */
        error = drv->probe(dev, id);


Godbach
回復(fù)于:2008-12-16 14:16:41

不同的總線(xiàn)注冊(cè)不同的struct bus_type結(jié)構(gòu)體。隨后在同一總線(xiàn)上注冊(cè)多個(gè)設(shè)備驅(qū)動(dòng)的時(shí)候,它們對(duì)應(yīng)同一個(gè)struct bus_type。

Godbach
回復(fù)于:2008-12-16 14:33:49

一個(gè)小問(wèn)題:
從內(nèi)核代碼中看到USB設(shè)備時(shí)使用usb_register注冊(cè)USB設(shè)備,同時(shí)使用usb自身的bus_type。那這意味著USB總線(xiàn)是和PCI總線(xiàn)屬于兩種不同的總線(xiàn)。
但為什么在pci_ids.h中,有這樣的定義:
引用:#define PCI_BASE_CLASS_SERIAL                0x0c
#define PCI_CLASS_SERIAL_FIREWIRE        0x0c00
#define PCI_CLASS_SERIAL_ACCESS                0x0c01
#define PCI_CLASS_SERIAL_SSA                0x0c02
#define PCI_CLASS_SERIAL_USB                0x0c03
#define PCI_CLASS_SERIAL_USB_UHCI        0x0c0300
#define PCI_CLASS_SERIAL_USB_OHCI        0x0c0310
#define PCI_CLASS_SERIAL_USB_EHCI        0x0c0320
#define PCI_CLASS_SERIAL_FIBER                0x0c04
#define PCI_CLASS_SERIAL_SMBUS                0x0c05

MS在PCI中有USB類(lèi)的設(shè)備。這個(gè)該怎么理解。偶的硬件學(xué)得不好,熟悉的朋友能否幫忙解釋一下?

Godbach
回復(fù)于:2008-12-16 16:44:36

LZ說(shuō)明一下內(nèi)核版本號(hào)吧。我這2.6.18.3,dd.c中沒(méi)有really_probe函數(shù)。:wink:

scutan
回復(fù)于:2008-12-16 16:55:24

引用:原帖由 Godbach 于 2008-12-16 16:44 發(fā)表

LZ說(shuō)明一下內(nèi)核版本號(hào)吧。我這2.6.18.3,dd.c中沒(méi)有really_probe函數(shù)。:wink:

我的是2.6.21

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=551201]scutan

回復(fù)于:2008-12-16 16:56:34

引用:原帖由 Godbach 于 2008-12-16 16:44 發(fā)表

LZ說(shuō)明一下內(nèi)核版本號(hào)吧。我這2.6.18.3,dd.c中沒(méi)有really_probe函數(shù)。:wink:

driver_probe_device 函數(shù)
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
        struct stupid_thread_structure *data;
        struct task_struct *probe_task;
        int ret = 0;
        if (!device_is_registered(dev))
                return -ENODEV;
        if (drv->bus->match && !drv->bus->match(dev, drv))
                goto done;
        pr_debug("%s: Matched Device %s with Driver %s\n",
                 drv->bus->name, dev->bus_id, drv->name);
        data = kmalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
        data->drv = drv;
        data->dev = dev;
        if (drv->multithread_probe) {
                probe_task = kthread_run(really_probe, data,
                                         "probe-%s", dev->bus_id);
                if (IS_ERR(probe_task))
                        ret = really_probe(data);
        } else
                ret = really_probe(data);
done:
        return ret;
}

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=534931]Godbach

回復(fù)于:2008-12-16 17:00:51

2.6.18.3中dd.c.
函數(shù)driver_probe_device代碼中dev->bus->probe對(duì)應(yīng)的函數(shù)為pci_device_probe,隨后調(diào)用關(guān)系為:->__pci_device_probe->pci_call_probe
該函數(shù)里面執(zhí)行了 drv->probe,即e100驅(qū)動(dòng)注冊(cè)的e100_probe()
driver_probe_device函數(shù)的實(shí)現(xiàn):
引用:int driver_probe_device(struct device_driver * drv, struct device * dev)
{
        int ret = 0;
        if (drv->bus->match && !drv->bus->match(dev, drv))
                goto Done;
        pr_debug("%s: Matched Device %s with Driver %s\n",
                 drv->bus->name, dev->bus_id, drv->name);
        dev->driver = drv;
        if (dev->bus->probe) {
                ret = dev->bus->probe(dev);
                if (ret) {
                        dev->driver = NULL;
                        goto ProbeFailed;
                }
        } else if (drv->probe) {
                ret = drv->probe(dev);
                if (ret) {
                        dev->driver = NULL;
                        goto ProbeFailed;
                }
        }
        device_bind_driver(dev);
        ret = 1;
        pr_debug("%s: Bound Device %s to Driver %s\n",
                 drv->bus->name, dev->bus_id, drv->name);
        goto Done;
ProbeFailed:
        if (ret == -ENODEV || ret == -ENXIO) {
                /* Driver matched, but didn't support device
                 * or device not found.
                 * Not an error; keep going.
                 */
                ret = 0;
        } else {
                /* driver matched but the probe failed */
                printk(KERN_WARNING
                       "%s: probe of %s failed with error %d\n",
                       drv->name, dev->bus_id, ret);
        }
Done:
        return ret;
}

pci_call_probe函數(shù)的實(shí)現(xiàn)
引用:static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
                          const struct pci_device_id *id)
{
        int error;
#ifdef CONFIG_NUMA
        /* Execute driver initialization on node where the
           device's bus is attached to.  This way the driver likely
           allocates its local memory on the right node without
           any need to change it. */
        struct mempolicy *oldpol;
        cpumask_t oldmask = current->cpus_allowed;
        int node = pcibus_to_node(dev->bus);
        if (node >= 0 && node_online(node))
            set_cpus_allowed(current, node_to_cpumask(node));
        /* And set default memory allocation policy */
        oldpol = current->mempolicy;
        current->mempolicy = &default_policy;
        mpol_get(current->mempolicy);
#endif
        error = drv->probe(dev, id);
#ifdef CONFIG_NUMA
        set_cpus_allowed(current, oldmask);
        mpol_free(current->mempolicy);
        current->mempolicy = oldpol;
#endif
        return error;
}

[ 本帖最后由 Godbach 于 2008-12-16 17:04 編輯 ]

Godbach
回復(fù)于:2008-12-16 17:07:01

代碼是變化了。應(yīng)該是2.6.21的代碼里面把driver_probe_device()函數(shù)的實(shí)現(xiàn)進(jìn)行了封裝。
[ 本帖最后由 Godbach 于 2008-12-16 17:09 編輯 ]

qinjiana0786
回復(fù)于:2008-12-16 19:16:57

分析的過(guò)程是正確的,但是在內(nèi)核的PCI的過(guò)程上要是展開(kāi)下就很好,不要只是用圖片或者函數(shù)的調(diào)用路線(xiàn)來(lái)形容,畢竟內(nèi)核的部分不是能用只
言片語(yǔ)就能一筆帶過(guò)的,核心部分還是圍繞著PCI的過(guò)程詳細(xì)一下就太精彩了,如果LZ沒(méi)有時(shí)間將來(lái)我會(huì)把這部分完成。只是現(xiàn)在還在進(jìn)行TCP協(xié)議內(nèi)容,而
且我看了一下其他人對(duì)這些內(nèi)容的補(bǔ)充,實(shí)話(huà)說(shuō),在點(diǎn)但不在譜,就是說(shuō)太零散,不利用于群內(nèi)大多數(shù)朋友的學(xué)習(xí),有點(diǎn)嘩眾取寵的感覺(jué),這又不是問(wèn)題貼沒(méi)有必要
展開(kāi)某個(gè)細(xì)節(jié)來(lái)說(shuō)明,況且展開(kāi)的也不是難點(diǎn)所在,沒(méi)有主線(xiàn),就象一個(gè)樂(lè)譜,每個(gè)人都做做自己的曲子插進(jìn)來(lái),這樣的音樂(lè)能聽(tīng)嗎?希望各位發(fā)揚(yáng)自主寫(xiě)作的精
神,而不是靠討論貼來(lái)完成一篇精華的文章。


Godbach
回復(fù)于:2008-12-16 20:51:39

非常歡迎qinjiana0786兄來(lái)完成更詳細(xì)的分析啊。
LZ在這篇文章的開(kāi)篇也說(shuō)了,這里整理出來(lái)一個(gè)流程,提供一個(gè)主線(xiàn),幫著梳理一下。這樣可以幫助希望自己熟悉和分析代碼,但又不知道如何下手的朋友。

eexplorer
回復(fù)于:2008-12-17 09:19:49

引用:原帖由 Godbach 于 2008-12-16 14:33 發(fā)表

一個(gè)小問(wèn)題:
從內(nèi)核代碼中看到USB設(shè)備時(shí)使用usb_register注冊(cè)USB設(shè)備,同時(shí)使用usb自身的bus_type。那這意味著USB總線(xiàn)是和PCI總線(xiàn)屬于兩種不同的總線(xiàn)。
但為什么在pci_ids.h中,有這樣的定義:
MS在PCI ...

這些是usb host controller,是一個(gè)pci device(可通過(guò)lspci找到), 和usb host controller 通信的usb devices才是掛在usb bus上的

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=534931]Godbach

回復(fù)于:2008-12-17 09:42:01

引用:原帖由 eexplorer 于 2008-12-17 09:19 發(fā)表

這些是usb host controller,是一個(gè)pci device(可通過(guò)lspci找到), 和usb host controller 通信的usb devices才是掛在usb bus上的

多謝LS。那應(yīng)該還有一些USB Device是不同USB host controller通信的,這樣的設(shè)備是怎么工作的呢?

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=686144]bbaqq222

回復(fù)于:2008-12-17 09:58:09

感謝高人的講解,認(rèn)真琢磨一下

scutan
回復(fù)于:2008-12-17 13:40:13

引用:原帖由 qinjiana0786 于 2008-12-16 19:16 發(fā)表

分析的過(guò)程是正確的,但是在內(nèi)核的PCI的過(guò)程上要是展開(kāi)下就很好,不要只是用圖片或者函數(shù)的調(diào)用路線(xiàn)來(lái)形容,畢竟內(nèi)核的部分不是能用只言片語(yǔ)就能一筆帶過(guò)的,核心部分還是圍繞著PCI的過(guò)程詳細(xì)一下就太精彩了,如 ...

小弟在硬件這塊目前還沒(méi)有精力去深入下去,所以希望qinjiana0786兄能夠多多指點(diǎn)一下。
謝謝。
BTW: 我從您的TCP/IP核心過(guò)程分析中學(xué)到了很多東西,表示感謝!

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=256598]eexplorer

回復(fù)于:2008-12-17 17:33:05

引用:原帖由 Godbach 于 2008-12-17 09:42 發(fā)表

多謝LS。那應(yīng)該還有一些USB Device是不同USB host controller通信的,這樣的設(shè)備是怎么工作的呢?

不太明白你的問(wèn)題,USB device應(yīng)該只有通過(guò)USB host controller才能和CPU交互,

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=534931]Godbach

回復(fù)于:2008-12-17 17:49:10

引用:和usb host controller 通信的usb devices才是掛在usb bus上的
對(duì)這句話(huà)我的理解是,可能還有一些不通過(guò)usb host controller 通信的usb devices。
看來(lái)我的理解能力很弱

ller
回復(fù)于:2008-12-18 22:55:42

網(wǎng)卡驅(qū)動(dòng)模塊是什么時(shí)候加載的,是根據(jù)udev規(guī)則嗎,我沒(méi)有找到相應(yīng)規(guī)則,還是起網(wǎng)絡(luò)服務(wù)時(shí)加載的,我在運(yùn)行級(jí)別1上仍然可以lsmod到我的網(wǎng)卡驅(qū)動(dòng)模塊

ller
回復(fù)于:2008-12-18 23:38:30

在網(wǎng)終的啟動(dòng)腳本上看到了對(duì)ethN的modprobe操作,然后根據(jù)modprobe.conf中的alias找到相應(yīng)的驅(qū)動(dòng)

albcamus
回復(fù)于:2008-12-19 12:56:53

引用:原帖由 qinjiana0786 于 2008-12-16 19:16 發(fā)表

分析的過(guò)程是正確的,但是在內(nèi)核的PCI的過(guò)程上要是展開(kāi)下就很好,不要只是用圖片或者函數(shù)的調(diào)用路線(xiàn)來(lái)形容,畢竟內(nèi)核的部分不是能用只言片語(yǔ)就能一筆帶過(guò)的,核心部分還是圍繞著PCI的過(guò)程詳細(xì)一下就太精彩了,如 ...

linux有的看、有的用嗎? 每個(gè)人就寫(xiě)了那么一點(diǎn), 拼湊起來(lái)的:outu: :outu:

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=784896]OraBSD

回復(fù)于:2008-12-20 23:59:05

:shock:

emmoblin
回復(fù)于:2008-12-21 21:19:04

好貼啊,我也是不清楚怎么調(diào)用到probe的。
努力以后我也能寫(xiě)幾篇加精的文章。努力。。。。

Godbach
回復(fù)于:2008-12-21 22:22:16

引用:原帖由 emmoblin 于 2008-12-21 21:19 發(fā)表

好貼啊,我也是不清楚怎么調(diào)用到probe的。
努力以后我也能寫(xiě)幾篇加精的文章。努力。。。。

期待emmoblin兄多發(fā)幾篇精品文章上來(lái)啊。

[url=http://linux.chinaunix.net/bbs/viewpro.php?uid=182323]hb12112

回復(fù)于:2008-12-23 15:46:59

精彩!

efr6
回復(fù)于:2008-12-23 18:42:42

thank you!

WFCJZ
回復(fù)于:2008-12-24 01:01:56

搞懂了,整死電信,叫它給人玩網(wǎng)卡綁定這招,最煩人!:lol:
[flash]http://eblog.cersp.com/UploadFiles/2007-5/59797326.swf [/flash]

ops
回復(fù)于:2008-12-24 12:44:41

好東西

wylhistory
回復(fù)于:2009-01-14 20:09:13

學(xué)習(xí)了!

原文鏈接:
http://linux.chinaunix.net/bbs/viewthread.php?tid=1052717
轉(zhuǎn)載請(qǐng)注明作者名及原文出處
               
               
               

本文來(lái)自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u2/83200/showart_1799736.html
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
PCI驅(qū)動(dòng)框架簡(jiǎn)單分析
c風(fēng)格的面向?qū)ο?-linux內(nèi)核學(xué)習(xí)
Linux設(shè)備模型 - 鍵盤(pán)棒棒的日志 - 網(wǎng)易博客
struct device_driver的probe的調(diào)用 - linux驅(qū)動(dòng)程序 - l...
USB子系統(tǒng)學(xué)習(xí)之基礎(chǔ)篇三(host controller)
LINUX設(shè)備驅(qū)動(dòng)之設(shè)備模型五--devicedriverbus(四)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服