Linux網路驅動原始碼分析 一

2021-06-21 11:44:07 字數 3781 閱讀 8218

網路驅動是一種典型的pci裝置驅動,無論在嵌入式平台還是在pc領域,網路相關的專案開發有著比較廣闊的前景,因此,分析當前linux核心中網路裝置的驅動,不但能了解網路相關的基本原理,而且可以借鑑linux核心的先進的技術,將其應用到嵌入式或其他領域。本文以linux核心中的rtl8139網路驅動為例,對網路驅動的原始碼進行了簡單分析,並對其中涉及的相關概念和技術進行了簡單的介紹。

一、pci裝置驅動模型

rtl8139是典型的pci裝置,linux核心的pci核心驅動為pci驅動開發者提供了方便的系統介面,極大地方便了pci裝置驅動的開發。

1 pci裝置驅動相關的資料結構

struct pci_driver ;

pci裝置描述結構體

struct pci_dev

;struct pci_ats *ats;

/* address translation service *

/#endif}

驅動開發者要想為某個pci裝置開發驅動就必須定義乙個與當前pci裝置相對應的pci_driver資料結構,用來描述將要開發的pci驅動的相關資訊,比如驅動的名稱,當前驅動可以支援哪些裝置,以及當前驅動支援的一些操作等,類似地,還需要有個結構體來表示pci裝置,描述pci裝置的硬體資訊,如廠商id,裝置id,以及各種資源等,詳見注釋。

二、pci核心驅動api

linux核心的pci驅動為pci裝置驅動的開發提供了方便的結構,下面列舉幾個常用的介面:

pci_register_driver(struct pci_driver *drv)

功能:註冊pci驅動,引數為要註冊的pci驅動的結構體。

下面來詳細的分析以下這個函式,如此,才能更清楚的了解驅動和裝置的匹配過程。

pci_register_driver-

>driver_register(

&drv-

>driver);-

>bus_add_driver-

>driver_attach-

>bus_for_each_dev(drv-

>bus,

null

, drv, __driver_attach);

在這個過程中有涉及到乙個更為抽象的結構體struct device_driver,它是pci_driver的更高階的抽象,即下層是pci_driver,其上是device_driver,這符合通常的程式設計邏輯,越往上層抽象級別越高,因為在作業系統看來,它並不需要知道具體是什麼裝置,所有的裝置對作業系統來說都是相同的,即都用struct device_driver來表示。

在driver_register中先呼叫driver_find(drv->name, drv->bus),首先在相應的匯流排上查詢drv->name的驅動是否已經被註冊過,如果被註冊過則返回,否則進行註冊過程,即呼叫bus_add_driver(drv)。

int bus_add_driver(struct device_driver *drv)函式首先判斷當前匯流排是否支援自動探測,如果執行則執行探測函式driver_attach(drv)。

if(drv-

>bus-

>p-

>drivers_autoprobe)

int driver_attach(struct device_driver *drv)

這個函式對pci匯流排的上所有已經連線的pci裝置與當前的pci驅動程序一次匹配的過程,即對每乙個pci裝置都呼叫匹配函式__driver_attach。

static int __driver_attach(struct device *dev, void *data)

該函式首先判斷匯流排提供的match函式是否為空,如果非空則執行匯流排提供的match函式,在rtl8139網路驅動中,match非空,參見**:

drv-

>driver.bus =

&pci_bus_type;struct bus_type pci_bus_type =;

這裡將match函式即pci_bus_match,最後該函式呼叫到

static inline const struct pci_device_id *

pci_match_one_device(

const struct pci_device_id *id,

const struct pci_dev *dev)

在這裡進行了pci_driver和pci_dev的匹配,如果匹配成功,則返回pci_device_id。如果匹配不成功,而且當前裝置還沒有驅動,則呼叫driver_probe_device(drv,dev)。

int driver_probe_device(struct device_driver *drv, struct device *dev)

執行到這裡說明,說明pci匯流排沒有提供match函式或者匯流排提供的match函式返回非空。還需要進行更深層次的探測,至少在匯流排提供的match函式中僅僅是進行了匹配,並沒有將驅動和裝置關聯起來,這些操作就是在下面的函式中實現的。

int driver_probe_device(struct device_driver *drv, struct device *dev)

重點看really_probe函式:

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

if(dev-

>bus-

>probe)

else

if(drv-

>probe)

driver_bound(dev)

;ret = 1;

pr_debug(

"bus: '%s': %s: bound device %s to driver %s/n"

,drv-

>bus-

>name, __func__, dev_name(dev)

, drv-

>name)

;goto done;

probe_failed:

devres_release_all(dev)

;driver_sysfs_remove(dev)

;dev-

>driver =

null;if

(ret !

=-enodev &

& ret !

=-enxio)/*

* ignore errors returned by -

>probe so that the next driver can try

* its luck.*/

ret = 0;

done:

atomic_dec(

&probe_count)

;wake_up(

&probe_waitqueue)

;return ret;}

在此函式中,首先將驅動和裝置關聯起來,即紅色**dev->driver = drv;指明了當前裝置的驅動。按照常規的程式設計思想,驅動和裝置關聯後是否還需要做一些其他工作才能是裝置在相應的驅動下正常工作呢,這就是probe函式實現的功能了,很明顯裝置和驅動獲取都需要做一些工作,因此這裡分別留出裝置和驅動的probe函式。其中裝置的probe即裝置所在匯流排的probe,這裡暫且不去分析,因為與網路驅動關係不大,都是pci匯流排相關的東西,重點來看驅動的probe,在前面提到的pci_driver結構體中,對於rtl8139驅動來說,其pci_driver結構體被初始化為:

static struct pci_driver rtl8139_pci_driver =

;

Linux驅動開發原始碼分析

目錄 一 前言 二 驅動開發步驟分析 1驅動模組都有兩個函式 2實現初始化函式和退出函式 3初始化函式分析 3.1通過函式register chrdev 註冊如下結構體 3.2通過裝置類函式class register 註冊 3.3呼叫spi register driver 4退出函式分析登出spi...

Linux網路介面的原始碼分析

二.網路介面程式的結構五.網路協議部分 協議層是真正實現是在這一層。在linux include linux socket.h裡面,linux的bsd socket 定義了多至32支援的協議族,其中pf inet就是我們最熟悉的tcp ip協議族 ipv4,以下沒有特別宣告都指ipv4 以這個協議族...

USB 滑鼠驅動原始碼分析

kernel kernel 3.4.39 uhci intel,低速 1.5mbps 全速 12mbps ohci microsoft 低速 全速 ehci 高速 480mbps usb匯流排驅動程式的作用 1 分配位址給usb裝置,同時將分配的位址發給usb裝置 最開始通訊位址是埠0 2 發出命令...