Linux驅動開發 ---- 4_驅動開發框架和 API
目錄
- Linux驅動開發 ---- 4_驅動開發框架和 API
- 🎯 目標:
- 📌 1. Linux 設備模型(Linux Device Model)
- **設備模型的核心概念**:
- 📌 2. 設備樹(Device Tree)
- **設備樹示例**:
- 📌 3. `sysfs`:與用戶空間交互的接口
- 📌 4. 平臺設備(Platform Devices)
- **平臺設備注冊示例**:
- 📌 5. 驅動 API 及常用操作
- 📌 6. 實踐任務:設備樹與 `sysfs` 文件操作
- **實踐 1:設備樹配置與查看**
- **實踐 2:`sysfs` 操作**
- 📌 7. 總結回顧
- 🧠 今日練習題(可選)
- 1). `compatible` 字段
- 2). `reg` 字段
- `compatible` 和 `reg` 結合使用
- 小結
- 1). **不依賴總線的硬件抽象**
- 2). **簡化硬件抽象層(HAL)**
- 3). **設備樹的使用**
- 4). **適應嵌入式硬件**
- 5). **易于驅動管理**
- 6). **資源的靜態配置**
- 7). **適用范圍**
- 8). **內核和硬件耦合緊密**
- 9). **提升系統啟動速度**
- 10). **避免復雜的設備管理**
- 結論:
🎯 目標:
掌握 Linux 設備模型、設備樹、sysfs
和平臺設備的概念,為編寫更復雜的驅動程序奠定基礎。
📌 1. Linux 設備模型(Linux Device Model)
Linux 內核采用了 設備模型(Device Model) 來管理系統中的所有設備。設備模型為內核提供了一個統一的方式來管理硬件設備和與之交互的驅動程序。
設備模型的核心概念:
- 設備(Device):硬件設備的抽象,通過
struct device
來表示。 - 驅動程序(Driver):處理設備的內核代碼,通過
struct device_driver
來表示。 - 總線(Bus):設備和驅動程序之間的中介,表示設備所屬的類型(例如:PCI 總線、USB 總線)。
- 類(Class):設備的一類,用于組織設備。
- 注冊(Registration):設備、驅動程序和總線的注冊機制,使內核能夠識別硬件和驅動之間的關系。
📌 2. 設備樹(Device Tree)
設備樹(Device Tree)是一個數據結構,描述了硬件設備的布局。在嵌入式系統中,設備樹用于幫助內核識別和初始化硬件設備。設備樹不依賴于內核代碼,它是一個純粹的數據文件,允許內核在啟動時加載硬件信息。
- 主要作用:在系統啟動時,內核通過設備樹來獲取硬件設備的配置信息,并根據該信息驅動設備。
- 設備樹文件:通常存放在
/boot/dtbs
目錄下,文件擴展名為.dtb
。
設備樹示例:
/dts-v1/;
/ {model = "My Custom Board";compatible = "generic-board";memory {reg = <0x80000000 0x40000000>; // 內存起始地址和大小};uart0: serial@9000000 {compatible = "uart16550";reg = <0x9000000 0x1000>;interrupts = <0x14>;};
};
在這個示例中,定義了一個 UART 設備(serial@9000000
),它的內存映射基地址是 0x9000000
,并且配置了中斷。
compatible
字段定義了該設備支持的設備類型。reg
表示設備的寄存器地址。interrupts
定義了設備中斷號。
📌 3. sysfs
:與用戶空間交互的接口
sysfs 詳細解釋
sysfs
是 Linux 提供的一個虛擬文件系統,旨在使內核中的設備信息和狀態暴露給用戶空間程序。通過讀取和寫入 sysfs
中的文件,用戶可以與設備驅動進行交互,并且通過這種方式進行設備配置、狀態查詢等操作。sysfs
通過 /sys
目錄提供了一種訪問內核對象(如設備、驅動、總線等)屬性的方式。
sysfs
的常見路徑
/sys/class/
:設備類型目錄,每個設備類別(例如net
,block
等)都會在這里有一個子目錄。/sys/devices/
:所有設備的路徑信息,包括硬件設備的具體描述。/sys/bus/
:與總線相關的設備,像 PCI、USB 總線等會在這里列出。
sysfs
作用
- 配置設備參數:通過向
/sys
中的文件寫入數據,可以改變設備的配置。 - 讀取設備狀態:可以通過讀取
/sys
中的文件獲取設備的實時狀態或參數。 - 查看內核信息:通過訪問
/sys
中的文件,用戶可以查看內核的內存、CPU 資源使用情況等信息。
-
創建設備屬性文件
設備屬性文件允許用戶空間程序通過簡單的文件 I/O 操作(如讀取、寫入)來交互。驅動程序可以使用sysfs
來創建這些文件,并通過文件暴露設備的狀態或控制接口。代碼示例:
struct device_attribute dev_attr_myattribute = {.attr = { .name = "myattribute", .mode = S_IRUGO },.show = myattribute_show, };
-
struct device_attribute
:這是 Linux 內核中定義的一個結構體,用來表示一個設備的屬性。通過這個結構體,設備驅動可以指定屬性的名稱、訪問權限以及讀取(show
)和寫入(store
)操作函數。 -
dev_attr_myattribute
:這是定義的設備屬性結構體實例。每個屬性結構體包含了以下信息: -
.attr
:屬性的具體信息,包括文件名(name
)和訪問模式(mode
)。S_IRUGO
表示該文件是只讀的,且可以被用戶空間讀取。 -
.show
:設備屬性文件的讀取操作函數。該函數的作用是將設備的狀態或配置輸出到緩沖區buf
中。
show
函數:static ssize_t myattribute_show(struct device *dev, struct device_attribute *attr, char *buf) {return sprintf(buf, "42\n"); }
-
myattribute_show
:這是屬性的讀取函數,它會在用戶空間讀取/sys
文件時調用。 -
dev
:設備指針,指向調用該函數的設備實例。 -
attr
:屬性指針,指向該屬性。 -
buf
:緩沖區,用于將屬性值返回給用戶空間。 -
sprintf(buf, "42\n")
:將42
作為屬性值寫入緩沖區buf
中。 -
該函數的作用是當用戶讀取
/sys/.../myattribute
文件時,返回 “42” 字符串。
-
-
注冊設備屬性
設備屬性文件需要通過sysfs_create_file
注冊到sysfs
中。這使得屬性文件出現在/sys
下,并且允許用戶空間應用通過文件訪問該屬性。注冊屬性:
sysfs_create_file(&dev->kobj, &dev_attr_myattribute.attr);
-
dev->kobj
:每個設備都有一個kobject
,它是與設備相關的內核對象。在sysfs
中,所有的設備屬性都與kobject
緊密相關。kobject
是內核對象的一個基本表示,它具有與設備相關的屬性。 -
dev_attr_myattribute.attr
:這是我們在前面定義的屬性結構體dev_attr_myattribute
。通過sysfs_create_file
,該屬性會被創建并注冊到設備的kobject
中,形成/sys
目錄下的一個文件。 -
sysfs_create_file
:此函數將屬性文件添加到sysfs
文件系統中。如果成功,用戶可以通過/sys
目錄訪問該文件。例如,如果設備dev
關聯了屬性myattribute
,那么該文件將出現在/sys/.../myattribute
下。
-
-
訪問屬性文件
一旦設備屬性文件創建并注冊到sysfs
中,用戶空間的應用程序就可以通過標準的文件 I/O 操作(如讀取)來與設備進行交互。例如,可以使用cat /sys/.../myattribute
來讀取屬性值。- 當用戶空間應用程序讀取
/sys/.../myattribute
文件時,myattribute_show
函數會被調用,返回屬性值 “42”。
- 當用戶空間應用程序讀取
-
刪除設備屬性
當設備不再需要該屬性時,需要通過sysfs_remove_file
刪除該屬性文件,防止內存泄漏:sysfs_remove_file(&dev->kobj, &dev_attr_myattribute.attr);
-
總結
通過sysfs
,驅動程序能夠將內核對象的屬性暴露給用戶空間。sysfs
通過虛擬文件系統提供了一種簡單、直觀的機制,使得設備、內核信息可以通過文件系統接口訪問。驅動程序通過創建和注冊設備屬性文件,允許用戶空間讀取和寫入設備參數或狀態。這種機制簡化了內核與用戶空間的交互,廣泛應用于設備配置、調試和狀態查詢等場景。
📌 4. 平臺設備(Platform Devices)
平臺設備(Platform Devices) 是嵌入式系統中用于表示硬件設備的一種設備類型,通常與平臺(如 ARM)相關聯。平臺設備不依賴于總線(例如:PCI、USB),而是通過靜態配置或設備樹來配置。
- 用途:嵌入式設備通常使用平臺設備,例如 GPIO、SPI 等控制器。
- 注冊方法:平臺設備通過
platform_device_register()
和platform_driver_register()
來注冊。
平臺設備注冊示例:
static struct platform_device *pdev;static int __init platform_dev_init(void) {pdev = platform_device_register_simple("my_platform_device", -1, NULL, 0);if (IS_ERR(pdev))return PTR_ERR(pdev);return 0;
}static void __exit platform_dev_exit(void) {platform_device_unregister(pdev);
}module_init(platform_dev_init);
module_exit(platform_dev_exit);
在這個例子中,我們使用 platform_device_register_simple
來注冊一個平臺設備,并使用 platform_device_unregister
來注銷設備。
📌 5. 驅動 API 及常用操作
platform_driver_register
:注冊平臺驅動程序。platform_device_register
:注冊平臺設備。device_create
:在/dev
中創建一個設備文件。class_create
:創建一個設備類(/sys/class/
)。sysfs_create_file
:在sysfs
中創建一個設備屬性文件。alloc_chrdev_region
:分配一個字符設備號。cdev_add
:注冊字符設備。
📌 6. 實踐任務:設備樹與 sysfs
文件操作
實踐 1:設備樹配置與查看
- 查看設備樹文件并理解設備節點的定義。
- 在設備樹中增加一個自定義設備節點,并讓內核啟動時加載。
實踐 2:sysfs
操作
- 編寫一個簡單的內核模塊,創建一個
sysfs
文件,并通過show
函數讀取一個值。 - 在用戶空間讀取該值,檢查
sysfs
操作是否成功。
📌 7. 總結回顧
內容項 | 說明 |
---|---|
設備模型 | Linux 使用設備模型管理設備、驅動和總線。 |
設備樹 | 設備樹是硬件配置的描述文件,幫助內核識別硬件設備。 |
sysfs | 用于內核與用戶空間交互的虛擬文件系統,設備信息通過文件暴露。 |
平臺設備 | 嵌入式系統中硬件設備的抽象,通常通過設備樹或靜態配置。 |
驅動注冊和注銷 | 使用 platform_driver_register 和 platform_device_register 注冊驅動與設備。 |
🧠 今日練習題(可選)
-
解釋設備樹中的
reg
和compatible
字段的作用。在設備樹(Device Tree)中,
reg
和compatible
是兩個非常常見且重要的字段,它們用來描述設備的硬件資源和設備類型。它們的作用如下:1).
compatible
字段作用:
compatible
字段用于描述設備或硬件節點的硬件類型或設備驅動程序類型。- 它是一個字符串,通常包含了設備的名稱和可能的硬件兼容性信息。它幫助設備樹中的設備節點與內核中正確的驅動程序進行匹配。內核根據這個字段來查找并加載適當的驅動程序。
具體作用:
- 內核會使用
compatible
字段來確定哪個驅動程序適配該設備。 - 如果
compatible
字段值與內核中驅動程序的of_match_table
匹配,內核就會選擇對應的驅動程序進行初始化。 - 該字段通常包含主機架構信息(如 ARM、x86)或硬件平臺特定信息,確保驅動程序可以正確識別并支持特定硬件。
示例:
compatible = "vendor,device-model", "arm,platform";
在這個示例中,設備的硬件類型被定義為
vendor,device-model
,并且該設備與arm,platform
兼容。內核會根據這些信息來選擇合適的驅動程序。2).
reg
字段作用:
reg
字段用于定義設備的地址或端口等硬件資源。在設備樹中,這個字段通常指定了設備的物理地址、I/O 端口、內存區間等資源位置。- 對于某些設備,
reg
字段指定了設備寄存器的地址范圍或內存映射的區域。 reg
通常與設備的硬件資源(如地址空間)一起使用,內核通過這些信息來確定如何訪問和控制硬件設備。
具體作用:
reg
字段指定了設備在內存中的地址,或者設備的 I/O 地址(如 PCI 總線地址、內存映射寄存器的物理地址)。- 該字段的值是一個整數數組或地址范圍。內核使用這些地址信息來配置設備并與硬件交互。
示例:
reg = <0x10000000 0x1000>;
在這個示例中,
reg
定義了設備的地址為0x10000000
,大小為0x1000
字節。compatible
和reg
結合使用設備樹中的
compatible
和reg
字段通常一起使用,來標識設備類型和資源位置。內核會根據compatible
字段找到對應的驅動程序,然后根據reg
字段提供的地址信息來配置硬件設備。結合示例:
mydevice@10000000 {compatible = "vendor,mydevice";reg = <0x10000000 0x1000>; };
- 在這個示例中,
mydevice
是一個設備節點。 compatible = "vendor,mydevice"
指定了設備的類型,內核將使用這個字段來查找驅動程序。reg = <0x10000000 0x1000>
表示該設備的寄存器地址為0x10000000
,并且設備的寄存器空間大小為0x1000
字節。
小結
compatible
:標識設備的類型和兼容性,幫助內核加載合適的驅動程序。reg
:定義設備的硬件資源地址,如內存地址、I/O 地址等。
這些字段幫助設備樹描述硬件設備的具體配置,使內核能夠識別、初始化和配置硬件設備。
- 在你的驅動程序中,使用
sysfs
創建一個簡單的屬性文件,允許用戶空間訪問。
-
為什么平臺設備常用于嵌入式系統?
平臺設備(Platform Devices)在嵌入式系統中常被使用,原因可以從多個方面進行分析,主要包括以下幾個關鍵點:1). 不依賴總線的硬件抽象
- 平臺設備不依賴于傳統的硬件總線(如 PCI、USB 等)。它們通常通過靜態配置或設備樹來描述硬件設備,并通過內核直接進行管理和操作。這使得平臺設備特別適用于嵌入式系統,因為嵌入式系統的硬件平臺通常是固定的且沒有復雜的總線系統。
2). 簡化硬件抽象層(HAL)
- 嵌入式系統中,硬件通常具有固定的配置,且設備間的通信不需要依賴于復雜的總線協議。平臺設備為設備驅動提供了一個簡單而一致的接口,使得硬件抽象層變得更加簡潔且高效。開發者可以使用平臺設備直接訪問和控制硬件,而不必為每種硬件設計不同的驅動。
3). 設備樹的使用
- 在許多嵌入式系統中,尤其是基于 ARM 架構的系統,設備樹(Device Tree)用于描述硬件信息。在設備樹中,平臺設備的節點描述了硬件的屬性和配置,使得內核能夠在啟動時根據設備樹來配置設備。設備樹通常會靜態地定義系統中所有設備的屬性,因此不需要依賴動態總線掃描機制,這進一步提升了系統的啟動速度和效率。
4). 適應嵌入式硬件
- 嵌入式設備通常是一些嵌入式控制器、傳感器、通信接口等硬件模塊,這些硬件設備在嵌入式系統中扮演著重要角色。平臺設備使得這些設備可以直接與內核交互而無需復雜的總線支持,這正是嵌入式系統所需要的簡潔和高效的方式。
5). 易于驅動管理
- 使用平臺設備注冊的硬件設備通常是與某個平臺或某些硬件特性密切相關的。這種設備通常可以通過
platform_driver
與設備驅動進行匹配。通過這種方式,設備驅動和硬件設備之間的關系更加緊密,可以為每種平臺硬件設備提供定制化的驅動程序,簡化了驅動程序的管理和維護。
6). 資源的靜態配置
- 在嵌入式系統中,設備通常是預先配置并且是固定的。平臺設備通過內核靜態地注冊設備,使得這些設備在系統啟動時自動可用,減少了硬件配置的復雜性。對于大多數嵌入式系統而言,靜態配置和簡化管理正是系統要求的特性。
7). 適用范圍
- 平臺設備廣泛用于嵌入式系統中,如 GPIO、SPI、I2C 控制器、PWM 控制器、UART 控制器等。它們通常不依賴于標準總線協議(如 PCI、USB 等),而是直接與內核和驅動程序交互,提供簡單且高效的硬件訪問。
8). 內核和硬件耦合緊密
- 平臺設備的特點是與特定平臺硬件緊密耦合。每個平臺的硬件都有自己的配置和需求,而通過平臺設備機制,內核可以直接控制這些硬件設備,不需要額外的硬件抽象層(HAL)或總線管理,減少了系統開銷。
9). 提升系統啟動速度
- 嵌入式系統中的啟動速度通常是至關重要的,平臺設備通常不需要設備枚舉和動態加載驅動。通過在設備樹或內核配置中靜態定義設備,系統可以更快地啟動,并且能夠高效地加載硬件驅動。
10). 避免復雜的設備管理
- 嵌入式系統中的設備通常比較簡單,沒有復雜的硬件總線和設備發現機制。因此,使用平臺設備能夠避免在設備管理時引入過多的復雜性,簡化了設備的注冊、驅動綁定和資源管理過程。
結論:
平臺設備的這些特點使得它非常適合嵌入式系統的應用。嵌入式系統通常有較為固定的硬件配置,并且對啟動速度和系統效率有較高的要求,平臺設備提供了一個簡潔高效的方式來管理這些硬件設備。通過設備樹和平臺設備,嵌入式系統能夠實現高效、可定制的硬件管理,從而滿足各種嵌入式應用的需求。