Linux設備驅動開發(第2版)
[法]約翰·馬迪厄(John Madieu)
商品描述
本書講解了Linux設備驅動開發的基礎知識以及所用到的開發環境。全書分為17章,內容涵蓋了各種Linux子系統、內存管理、RTC、IIO和IRQ管理等,還講解了DMA和部分設備驅動程序的使用方法。在學完本書之後,讀者將掌握Linux設備驅動開發過程中涉及的各種概念,並可以從零開始為嵌入式設備編寫驅動程序。
閱讀本書需要具備基本的C語言編程能力,且熟悉Linux基本命令。
作者簡介
約翰·馬迪厄是一位生活在法國巴黎的嵌入式Linux及內核工程師。他的主要工作是為物聯網、交通、醫療、能源和軍事等領域的企業開發設備驅動和板級支持包。他是LABCSMART公司的創始人兼首席顧問,該公司專註於提供嵌入式Linux和Linux內核工程方面的培訓和服務。他還是一位開源和嵌入式系統愛好者,相信通過分享知識才能學到
更多。他對拳擊運動充滿熱情,已經專業練習了 6 年,現在仍通過誌願執教的方式延續著這份熱情。
目錄大綱
第 1篇 Linux內核開發基礎
第 1章 內核開發簡介 3
1.1 設置開發環境 3
1.1.1 設置宿主機 4
1.1.2 獲取Linux內核源代碼 7
1.2 配置和構建Linux內核 10
1.2.1 指定編譯選項 10
1.2.2 理解內核配置過程 11
1.2.3 構建Linux內核 15
第 2章 Linux內核模塊的基本概念 17
2.1 模塊概念的介紹 17
2.2 構建Linux內核模塊 21
2.2.1 理解Linux內核構建系統 22
2.2.2 樹外構建 25
2.2.3 樹內構建 27
2.3 處理模塊參數 28
2.4 處理符號導出和模塊依賴 30
2.5 學習Linux內核編程技巧 34
2.5.1 錯誤處理 34
2.5.2 消息打印 38
2.6 總結 40
第3章 處理內核的核心輔助函數 41
3.1 Linux內核加鎖機制和共享資源 41
3.1.1 自旋鎖 42
3.1.2 互斥鎖 46
3.1.3 trylock方法 48
3.2 處理內核等待、睡眠和延遲機制 50
3.2.1 等待隊列 50
3.2.2 內核中的簡單睡眠 54
3.2.3 內核延遲或忙等待 54
3.3 深入理解Linux內核時間管理 55
3.3.1 時鐘源、時鐘事件和節拍設備的概念 55
3.3.2 使用標準內核低精度(low-res)定時器 67
3.3.3 高精度定時器(hrtimer) 73
3.4 實現工作延遲機制 77
3.4.1 軟中斷(softirq) 78
3.4.2 任務微調度(tasklet) 82
3.4.3 工作隊列(workqueue) 86
3.4.4 新一代的工作隊列 90
3.5 內核中斷處理 93
3.6 總結 109
第4章 編寫字符設備驅動程序 110
4.1 主設備號和次設備號的概念 110
4.2 字符設備數據結構介紹 111
4.2.1 設備文件操作介紹 112
4.2.2 內核中文件的表示 114
4.3 創建設備節點 115
4.3.1 設備識別 115
4.3.2 字符設備號的註冊和分配 115
4.3.3 在系統中初始化和註冊字符設備 116
4.4 實現文件操作 119
4.4.1 在內核空間和用戶空間之間交換數據 119
4.4.2 實現打開文件操作 120
4.4.3 實現釋放文件操作 121
4.4.4 實現寫文件操作 122
4.4.5 實現讀取文件操作 124
4.4.6 實現llseek文件操作 126
4.5 總結 135
第 2篇 Linux內核平臺抽象和設備驅動程序
第5章 理解和利用設備樹 139
5.1 設備樹機制的基本概念 139
5.1.1 設備樹命名約定 140
5.1.2 認識別名、標簽、phandle和路徑 141
5.1.3 理解節點和屬性的覆蓋 144
5.1.4 設備樹源代碼和編譯器 145
5.2 如何表示和尋址設備 151
5.2.1 如何處理SPI和I2C設備尋址 152
5.2.2 內存映射設備和設備尋址 153
5.3 處理資源 155
5.3.1 resource結構體 155
5.3.2 提取應用程序的特定數據 158
5.4 總結 162
第6章 設備、驅動程序和平臺抽象簡介 163
6.1 Linux內核平臺抽象和數據結構 163
6.1.1 device結構體 163
6.1.2 device_driver結構體 165
6.1.3 設備/驅動程序匹配和模塊(自動)加載 170
6.1.4 設備聲明—填充設備 172
6.2 設備與驅動程序匹配機制詳解 173
6.3 總結 176
第7章 平臺設備和驅動程序的概念 177
7.1 Linux內核中的平臺核心抽象 178
7.2 處理平臺設備 180
7.2.1 分配和註冊平臺設備 180
7.2.2 在代碼中如何避免分配平臺設備 182
7.2.3 使用平臺資源 183
7.3 平臺驅動程序抽象和架構 188
7.3.1 探測和釋放平臺設備 188
7.3.2 在驅動程序中對它所支持的設備進行配置 189
7.3.3 驅動程序的初始化和註冊 191
7.4 從零開始編寫平臺驅動程序 193
7.5 總結 198
第8章 編寫I2C設備驅動程序 199
8.1 Linux內核中的I2C框架抽象 200
8.1.1 struct i2c_adapter簡介 200
8.1.2 I2C客戶端和驅動程序數據結構 202
8.1.3 I2C通信接口 204
8.2 I2C設備驅動程序抽象和架構 208
8.2.1 探測I2C設備 208
8.2.2 實現i2c_driver.remove回調函數 209
8.2.3 驅動程序的初始化和註冊 210
8.2.4 在驅動程序中配置設備 211
8.2.5 實例化I2C設備 212
8.3 如何避免編寫I2C設備驅動程序 213
8.4 總結 216
第9章 編寫SPI設備驅動程序 217
9.1 Linux內核中的SPI框架抽象 218
9.1.1 struct spi_controller簡介 218
9.1.2 struct spi_device簡介 222
9.1.3 struct spi_driver簡介 224
9.1.4 消息傳輸數據結構 224
9.1.5 訪問SPI設備 227
9.2 SPI設備驅動程序抽象和架構 231
9.2.1 探測SPI設備 231
9.2.2 在驅動程序中提供設備信息 233
9.2.3 實現spi_driver.remove回調函數 234
9.2.4 驅動程序的初始化和註冊 235
9.2.5 實例化SPI設備 236
9.3 如何避免編寫SPI設備驅動程序 237
9.4 總結 242
第3篇 充分發揮硬件的潛力
第 10章 深入理解Linux內核內存分配 245
10.1 Linux內核內存相關術語簡介 245
10.1.1 32位系統中的內核地址空間布局:低端內存和高端內存的概念 247
10.1.2 低端內存的細節 248
10.1.3 理解高端內存 249
10.2 揭開地址轉換和MMU的神秘面紗 255
10.2.1 頁查找和TLB 259
10.2.2 TLB如何運作 260
10.3 內存分配機制及其API 261
10.3.1 頁分配器 262
10.3.2 Slab分配器 263
10.3.3 kmalloc分配器 267
10.3.4 vmalloc分配器 270
10.3.5 關於進程內存分配的幕後短故事 272
10.4 使用I/O內存與硬件通信 274
10.4.1 PIO設備訪問 275
10.4.2 MMIO 設備訪問 276
10.5 內存(重)映射 278
10.5.1 了解kmap()的用法 278
10.5.2 將內核內存映射到用戶空間 280
10.6 總結 286
第 11章 實現DMA支持 287
11.1 設置DMA映射 288
11.1.1 緩存一致性和DMA的概念 288
11.1.2 DMA的內存映射 288
11.1.3 創建一致性DMA映射 290
11.1.4 創建流DMA映射 290
11.1.5 單緩沖區映射 291
11.1.6 分散/聚集映射 292
11.1.7 流DMA映射的隱式和顯式緩存一致性 294
11.2 完成(completion)的概念 295
11.3 DMA引擎API 296
11.3.1 DMA控制器接口簡介 297
11.3.2 處理設備DMA尋址能力 302
11.3.3 請求DMA通道 304
11.3.4 配置DMA通道 305
11.3.5 配置DMA傳輸 307
11.3.6 提交DMA傳輸 308
11.3.7 發出待處理的DMA請求並等待回調通知 309
11.4 綜合實例——單緩沖區的DMA映射 310
11.5 關於循環DMA的說明 317
11.6 了解DMA和設備樹綁定 321
11.7 總結 322
第 12章 內存訪問抽象化——Regmap API簡介:寄存器映射抽象化 323
12.1 初識Regmap 324
12.2 Regmap初始化 329
12.3 使用Regmap寄存器訪問函數 330
12.3.1 批量和多寄存器讀寫函數 331
12.3.2 理解Regmap緩存系統 332
12.4 將所有內容整合在一起—基於Regmap的SPI設備驅動程序示例 334
12.5 從用戶空間利用Regmap 337
12.6 總結 340
第 13章 揭秘內核IRQ框架 341
13.1 中斷的簡要介紹 341
13.2 理解中斷控制器和中斷多路復用 342
13.3 深入研究高級外設IRQ管理 351
13.3.1 了解IRQ及其傳播 353
13.3.2 鏈式IRQ 354
13.4 揭秘per-CPU中斷 355
13.5 總結 359
第 14章 LDM簡介 360
14.1 LDM數據結構簡介 360
14.1.1 總線 361
14.1.2 驅動程序數據結構 367
14.1.3 設備驅動程序註冊 368
14.1.4 設備數據結構 369
14.1.5 設備註冊 370
14.2 深入理解LDM 371
14.2.1 了解kobject結構體 371
14.2.2 了解kobj_type 375
14.2.3 了解kset結構體 376
14.2.4 使用非默認屬性 377
14.2.5 使用二進制屬性 382
14.3 sysfs中的設備模型概述 388
14.3.1 創建設備、驅動程序、總線和類相關屬性 389
14.3.2 使sysfs屬性poll和select兼容 394
14.4 總結 395
第4篇 嵌入式領域內的多種內核子系統
第 15章 深入了解IIO框架 399
15.1 IIO數據結構簡介 401
15.1.1 了解struct iio_dev 401
15.1.2 了解struct iio_info 405
15.1.3 IIO通道的概念 407
15.1.4 區分通道 411
15.1.5 將所有內容整合在一起——編寫一個虛擬IIO驅動程序 413
15.2 集成IIO觸發緩沖區支持 417
15.2.1 IIO觸發器和sysfs(用戶空間) 420
15.2.2 IIO緩沖區 424
15.2.3 將所有內容整合在一起 426
15.3 訪問IIO數據 432
15.3.1 單次數據采集 432
15.3.2 訪問數據緩沖區 433
15.4 內核中的IIO消費者接口 436
15.5 編寫用戶空間的IIO應用程序 439
15.5.1 掃描和創建IIO上下文 441
15.5.2 遍歷和管理IIO設備 445
15.5.3 遍歷和管理IIO通道 445
15.5.4 使用觸發器進行工作 447
15.5.5 創建緩沖區並讀取數據樣本 448
15.6 遍歷用戶空間IIO工具 455
15.7 總結 455
第 16章 充分利用引腳控制器和GPIO子系統 456
16.1 硬件術語介紹 456
16.2 引腳控制子系統介紹 458
16.3 利用GPIO控制器接口 464
16.3.1 編寫GPIO控制器驅動程序 468
16.3.2 在GPIO控制器中啟用IRQ芯片 470
16.3.3 在GPIO芯片中添加IRQ芯片支持 474
16.3.4 GPIO控制器綁定方式 477
16.4 充分利用GPIO子系統 482
16.4.1 基於整數的GPIO接口(現已棄用) 483
16.4.2 基於描述符的GPIO接口(推薦方式) 486
16.5 學習如何避免編寫GPIO客戶端驅動程序 494
16.5.1 告別舊的sysfs接口 494
16.5.2 歡迎使用GPIO庫libgpiod 495
16.5.3 GPIO聚合器 504
16.6 總結 509
第 17章 利用Linux內核輸入子系統 510
17.1 Linux內核輸入子系統簡介 510
17.2 分配和註冊輸入設備 513
17.3 使用輪詢輸入設備 514
17.4 生成和報告輸入事件 518
17.5 處理來自用戶空間的輸入設備 520
17.6 總結 524