设备驱动程序基础
設備驅(qū)動程序基礎
? 驅(qū)動程序是專用于控制和管理特定硬件設備的軟件,因此也被稱作設備驅(qū)動程序。從操作系統(tǒng)的角度來看,它可以位于內(nèi)核空間(以特權(quán)模式運行),也可以位于用戶空間(具有較低的權(quán)限)。在編寫設備驅(qū)動程序之前,應該了解一些概念。C語言編程技巧是必需的,至少需要熟悉指針,并熟悉一些處理函數(shù)和必要的硬件知識。
- 模塊的構(gòu)建過程及其加載和卸載
- 驅(qū)動程序框架以及調(diào)試消息管理
- 驅(qū)動程序中的錯誤處理
1. 內(nèi)核空間和用戶空間
內(nèi)核空間:內(nèi)存駐留和運行的地址空間。內(nèi)核內(nèi)存是由內(nèi)核擁有的內(nèi)存范圍,受訪問標志保護,防止任何用戶應用程序有意或無意間與內(nèi)核搞混。在系統(tǒng)上以更高的優(yōu)先級運行。
用戶空間:正常程序被限制運行的地址(位置)空間。可以將其視為沙盒或監(jiān)獄,以便用戶程序不能混用其他程序擁有的內(nèi)存或任何其他資源。在用戶模式下,CPU只能訪問標有用戶空間訪問權(quán)限的內(nèi)存。
2.模塊的相關概念
模塊對于Linux而言就像插件和用戶軟件一樣,模塊動態(tài)擴展了內(nèi)核的功能。大多數(shù)情況下,內(nèi)核模塊是即插即用的。內(nèi)核中的模塊可以提供函數(shù)或變量,在內(nèi)核構(gòu)建過程中運行depmod工具可以生成模塊依賴文件。它通過讀取/lib/modules/<kernel_release>/中的每個模塊來確定它應該導出哪些符號以及它需要什么符號。處理得到的結(jié)果寫入文件modules.dep.
【模塊加載】模塊運行需要先加載到內(nèi)核,可以使用insmod 或modprobe 來實現(xiàn),前者需要指定模塊路徑作為參數(shù),作為開發(fā)期間的首選;后者更加智能化,是生產(chǎn)系統(tǒng)中的首選。
-
手動加載
手動加載需要用戶的干預,該用戶應該擁有root訪問權(quán)限。具體方法如下:
1.使用insmod來加載模塊,并給出所加載模塊的路徑:
2.insmod這種模塊加載形式低級,相反,系統(tǒng)管理員或在生產(chǎn)系統(tǒng)中常用的modprobe.modprobe更加智能,它會加載指定的模塊之前解析文件modules.dep,以便首先加載依賴關系。
-
自動加載
depmod實用程序的作用不只是構(gòu)建modules.dep 和modules.dep.bin 文件。內(nèi)核開發(fā)人員實際編寫驅(qū)動程序時已經(jīng)明確知道該驅(qū)動程序?qū)⒁С值挠布Ⅱ?qū)動程序支持的所有設備的產(chǎn)品和廠商ID提供給該驅(qū)動程序。depmod還處理模塊文件來提取和收集該信息,并生成modules.alias文件,該文件將設備映射到其對應的驅(qū)動程序。
-
【模塊卸載】常用的模塊卸載命令是rmmod,使用這個命令來卸載insmod命令加載的模塊。
而另一個更高級的模塊卸載命令是modprobe -r ,它會自動卸載未使用的相關依賴模塊:
在開發(fā)中還有一個常用的命令lsmod,可以用來檢查模塊是否已加載:
3.驅(qū)動程序框架
#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.錯誤和消息打印
? 錯誤代碼有內(nèi)核空間應用程序(error變量)解釋。錯誤處理在軟件開發(fā)中非常重要,而不僅僅實在內(nèi)核開發(fā)中。在內(nèi)核當中提供了幾種錯誤,幾乎涵蓋了可能出現(xiàn)的錯誤,有時需要將它們打印出來以幫助調(diào)試。
4.1 錯誤處理
由于給定的錯誤返回錯誤代碼會導致內(nèi)核或用戶空間應用產(chǎn)生不必要的行為,從而做出錯誤的決定。為了方便處理這些錯誤,內(nèi)核樹中預定義的錯誤幾乎涵蓋了可能遇到的情況。它們被定義在路徑為 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()是在內(nèi)核空間中使用的,其作用和在用戶空間使用printf()一樣。根據(jù)所打印消息的重要性不同,可以選用include/linux/kern_levels.h中定義的八個級別的消息日志。下面是所列出的內(nèi)核日志級別,每個級別對應一個字符串格式的數(shù)字,其優(yōu)先級與該數(shù)字的值成反比。
0具有較高的優(yōu)先級,以此類推,7的優(yōu)先級最低。
#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 */通過下列代碼打印內(nèi)核消息和日志級別:
printk(KERN_ERR "This is an error\n");通過打印錯誤消息,檢查日志級別參數(shù),方便開發(fā)人員更快速的調(diào)試驅(qū)動程序。
/* 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 */總結(jié)
- 上一篇: camera基础知识——1、camera
- 下一篇: 红米Note LTE刷机记录