设备驱动程序基础
設備驅動程序基礎
? 驅動程序是專用于控制和管理特定硬件設備的軟件,因此也被稱作設備驅動程序。從操作系統的角度來看,它可以位于內核空間(以特權模式運行),也可以位于用戶空間(具有較低的權限)。在編寫設備驅動程序之前,應該了解一些概念。C語言編程技巧是必需的,至少需要熟悉指針,并熟悉一些處理函數和必要的硬件知識。
- 模塊的構建過程及其加載和卸載
- 驅動程序框架以及調試消息管理
- 驅動程序中的錯誤處理
1. 內核空間和用戶空間
內核空間:內存駐留和運行的地址空間。內核內存是由內核擁有的內存范圍,受訪問標志保護,防止任何用戶應用程序有意或無意間與內核搞混。在系統上以更高的優先級運行。
用戶空間:正常程序被限制運行的地址(位置)空間。可以將其視為沙盒或監獄,以便用戶程序不能混用其他程序擁有的內存或任何其他資源。在用戶模式下,CPU只能訪問標有用戶空間訪問權限的內存。
2.模塊的相關概念
模塊對于Linux而言就像插件和用戶軟件一樣,模塊動態擴展了內核的功能。大多數情況下,內核模塊是即插即用的。內核中的模塊可以提供函數或變量,在內核構建過程中運行depmod工具可以生成模塊依賴文件。它通過讀取/lib/modules/<kernel_release>/中的每個模塊來確定它應該導出哪些符號以及它需要什么符號。處理得到的結果寫入文件modules.dep.
【模塊加載】模塊運行需要先加載到內核,可以使用insmod 或modprobe 來實現,前者需要指定模塊路徑作為參數,作為開發期間的首選;后者更加智能化,是生產系統中的首選。
-
手動加載
手動加載需要用戶的干預,該用戶應該擁有root訪問權限。具體方法如下:
1.使用insmod來加載模塊,并給出所加載模塊的路徑:
2.insmod這種模塊加載形式低級,相反,系統管理員或在生產系統中常用的modprobe.modprobe更加智能,它會加載指定的模塊之前解析文件modules.dep,以便首先加載依賴關系。
-
自動加載
depmod實用程序的作用不只是構建modules.dep 和modules.dep.bin 文件。內核開發人員實際編寫驅動程序時已經明確知道該驅動程序將要支持的硬件。將驅動程序支持的所有設備的產品和廠商ID提供給該驅動程序。depmod還處理模塊文件來提取和收集該信息,并生成modules.alias文件,該文件將設備映射到其對應的驅動程序。
-
【模塊卸載】常用的模塊卸載命令是rmmod,使用這個命令來卸載insmod命令加載的模塊。
而另一個更高級的模塊卸載命令是modprobe -r ,它會自動卸載未使用的相關依賴模塊:
在開發中還有一個常用的命令lsmod,可以用來檢查模塊是否已加載:
3.驅動程序框架
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h>static int __init helloworld_init(void) {pr_info("Hello world!\n");return 0; } static void __exit helloworld_exit(void) {pr_info("End of the world\n"); }/* 模塊的入點和出點 */ module_init(helloworld_init); module_init(helloworld_exit); /* 模塊相關信息 */ MODULE_AUTHOR("***** <*****@mail.com>"); MODULE_DESCRIPTION("Hello world! Module"); /* 許可 */ MODULE_LICENSE("GPL");4.錯誤和消息打印
? 錯誤代碼有內核空間應用程序(error變量)解釋。錯誤處理在軟件開發中非常重要,而不僅僅實在內核開發中。在內核當中提供了幾種錯誤,幾乎涵蓋了可能出現的錯誤,有時需要將它們打印出來以幫助調試。
4.1 錯誤處理
由于給定的錯誤返回錯誤代碼會導致內核或用戶空間應用產生不必要的行為,從而做出錯誤的決定。為了方便處理這些錯誤,內核樹中預定義的錯誤幾乎涵蓋了可能遇到的情況。它們被定義在路徑為 include/upia/asm-generic/errno-base.h 的頭文件中 ,下面是定義的所有錯誤定義代碼:
#ifndef _ASM_GENERIC_ERRNO_BASE_H #define _ASM_GENERIC_ERRNO_BASE_H#define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ #define ESRCH 3 /* No such process */ #define EINTR 4 /* Interrupted system call */ #define EIO 5 /* I/O error */ #define ENXIO 6 /* No such device or address */ #define E2BIG 7 /* Argument list too long */ #define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file number */ #define ECHILD 10 /* No child processes */ #define EAGAIN 11 /* Try again */ #define ENOMEM 12 /* Out of memory */ #define EACCES 13 /* Permission denied */ #define EFAULT 14 /* Bad address */ #define ENOTBLK 15 /* Block device required */ #define EBUSY 16 /* Device or resource busy */ #define EEXIST 17 /* File exists */ #define EXDEV 18 /* Cross-device link */ #define ENODEV 19 /* No such device */ #define ENOTDIR 20 /* Not a directory */ #define EISDIR 21 /* Is a directory */ #define EINVAL 22 /* Invalid argument */ #define ENFILE 23 /* File table overflow */ #define EMFILE 24 /* Too many open files */ #define ENOTTY 25 /* Not a typewriter */ #define ETXTBSY 26 /* Text file busy */ #define EFBIG 27 /* File too large */ #define ENOSPC 28 /* No space left on device */ #define ESPIPE 29 /* Illegal seek */ #define EROFS 30 /* Read-only file system */ #define EMLINK 31 /* Too many links */ #define EPIPE 32 /* Broken pipe */ #define EDOM 33 /* Math argument out of domain of func */ #define ERANGE 34 /* Math result not representable */ #endif4.2 消息打印
printk()是在內核空間中使用的,其作用和在用戶空間使用printf()一樣。根據所打印消息的重要性不同,可以選用include/linux/kern_levels.h中定義的八個級別的消息日志。下面是所列出的內核日志級別,每個級別對應一個字符串格式的數字,其優先級與該數字的值成反比。
0具有較高的優先級,以此類推,7的優先級最低。
#define KERN_SOH "\001" /* ASCII Start Of Header */ #define KERN_SOH_ASCII '\001'#define KERN_EMERG KERN_SOH "0" /* system is unusable */ #define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */ #define KERN_CRIT KERN_SOH "2" /* critical conditions */ #define KERN_ERR KERN_SOH "3" /* error conditions */ #define KERN_WARNING KERN_SOH "4" /* warning conditions */ #define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */ #define KERN_INFO KERN_SOH "6" /* informational */ #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */通過下列代碼打印內核消息和日志級別:
printk(KERN_ERR "This is an error\n");通過打印錯誤消息,檢查日志級別參數,方便開發人員更快速的調試驅動程序。
/* integer equivalents of KERN_<LEVEL> */ #define LOGLEVEL_SCHED -2 /* Deferred messages from sched code* are set to this special level */ #define LOGLEVEL_DEFAULT -1 /* default (or last) loglevel */ #define LOGLEVEL_EMERG 0 /* system is unusable */ #define LOGLEVEL_ALERT 1 /* action must be taken immediately */ #define LOGLEVEL_CRIT 2 /* critical conditions */ #define LOGLEVEL_ERR 3 /* error conditions */ #define LOGLEVEL_WARNING 4 /* warning conditions */ #define LOGLEVEL_NOTICE 5 /* normal but significant condition */ #define LOGLEVEL_INFO 6 /* informational */ #define LOGLEVEL_DEBUG 7 /* debug-level messages */總結
- 上一篇: camera基础知识——1、camera
- 下一篇: 红米Note LTE刷机记录