當(dāng)前位置:首頁(yè) > 嵌入式 > 嵌入式教程
[導(dǎo)讀]設(shè)備驅(qū)動(dòng)程序可以使用模塊的方式動(dòng)態(tài)加載到內(nèi)核中去。加載模塊的方式與以往的應(yīng)用程序開發(fā)有很大的不同。以往在開發(fā)應(yīng)用程序時(shí)都有一個(gè)main()函數(shù)作為程序的入口點(diǎn),而在驅(qū)動(dòng)開發(fā)時(shí)卻沒(méi)有main()函數(shù),模塊在調(diào)用insmod命令時(shí)被加載,此時(shí)的入口點(diǎn)是init_module()函數(shù),通常在該函數(shù)中完成設(shè)備的注冊(cè)。

11.2字符設(shè)備驅(qū)動(dòng)編程

1.字符設(shè)備驅(qū)動(dòng)編寫流程

設(shè)備驅(qū)動(dòng)程序可以使用模塊的方式動(dòng)態(tài)加載到內(nèi)核中去。加載模塊的方式與以往的應(yīng)用程序開發(fā)有很大的不同。以往在開發(fā)應(yīng)用程序時(shí)都有一個(gè)main()函數(shù)作為程序的入口點(diǎn),而在驅(qū)動(dòng)開發(fā)時(shí)卻沒(méi)有main()函數(shù),模塊在調(diào)用insmod命令時(shí)被加載,此時(shí)的入口點(diǎn)是init_module()函數(shù),通常在該函數(shù)中完成設(shè)備的注冊(cè)。同樣,模塊在調(diào)用rmmod命令時(shí)被卸載,此時(shí)的入口點(diǎn)是cleanup_module()函數(shù),在該函數(shù)中完成設(shè)備的卸載。在設(shè)備完成注冊(cè)加載之后,用戶的應(yīng)用程序就可以對(duì)該設(shè)備進(jìn)行一定的操作,如open()、read()、write()等,而驅(qū)動(dòng)程序就是用于實(shí)現(xiàn)這些操作,在用戶應(yīng)用程序調(diào)用相應(yīng)入口函數(shù)時(shí)執(zhí)行相關(guān)的操作,init_module()入口點(diǎn)函數(shù)則不需要完成其他如read()、write()之類功能。

上述函數(shù)之間的關(guān)系如圖11.3所示。

圖11.3設(shè)備驅(qū)動(dòng)程序流程圖

2.重要數(shù)據(jù)結(jié)構(gòu)

用戶應(yīng)用程序調(diào)用設(shè)備的一些功能是在設(shè)備驅(qū)動(dòng)程序中定義的,也就是設(shè)備驅(qū)動(dòng)程序的入口點(diǎn),它是一個(gè)在<linux/fs.h>中定義的structfile_operations結(jié)構(gòu),這是一個(gè)內(nèi)核結(jié)構(gòu),不會(huì)出現(xiàn)在用戶空間的程序中,它定義了常見文件I/O函數(shù)的入口,如下所示:

structfile_operations

{

loff_t(*llseek)(structfile*,loff_t,int);

ssize_t(*read)(structfile*filp,

char*buff,size_tcount,loff_t*offp);

ssize_t(*write)(structfile*filp,

constchar*buff,size_tcount,loff_t*offp);

int(*readdir)(structfile*,void*,filldir_t);

unsignedint(*poll)(structfile*,structpoll_table_struct*);

int(*ioctl)(structinode*,

structfile*,unsignedint,unsignedlong);

int(*mmap)(structfile*,structvm_area_struct*);

int(*open)(structinode*,structfile*);

int(*flush)(structfile*);

int(*release)(structinode*,structfile*);

int(*fsync)(structfile*,structdentry*);

int(*fasync)(int,structfile*,int);

int(*check_media_change)(kdev_tdev);

int(*revalidate)(kdev_tdev);

int(*lock)(structfile*,int,structfile_lock*);

};

這里定義的很多函數(shù)是否跟第6章中的文件I/O系統(tǒng)調(diào)用類似?其實(shí)當(dāng)時(shí)的系統(tǒng)調(diào)用函數(shù)通過(guò)內(nèi)核,最終調(diào)用對(duì)應(yīng)的structfile_operations結(jié)構(gòu)的接口函數(shù)(例如,open()文件操作是通過(guò)調(diào)用對(duì)應(yīng)文件的file_operations結(jié)構(gòu)的open函數(shù)接口而被實(shí)現(xiàn))。當(dāng)然,每個(gè)設(shè)備的驅(qū)動(dòng)程序不一定要實(shí)現(xiàn)其中所有的函數(shù)操作,若不需要定義實(shí)現(xiàn)時(shí),則只需將其設(shè)為NULL即可。

structinode結(jié)構(gòu)提供了關(guān)于設(shè)備文件/dev/driver(假設(shè)此設(shè)備名為driver)的信息,structfile結(jié)構(gòu)提供關(guān)于被打開的文件信息,主要用于與文件系統(tǒng)對(duì)應(yīng)的設(shè)備驅(qū)動(dòng)程序使用。structfile結(jié)構(gòu)較為重要,這里列出了它的定義:

structfile

{

mode_tf_mode;/*標(biāo)識(shí)文件是否可讀或可寫,F(xiàn)MODE_READ或FMODE_WRITE*/

dev_tf_rdev;/*用于/dev/tty*/

off_tf_pos;/*當(dāng)前文件位移*/

unsignedshortf_flags;/*文件標(biāo)志,如O_RDONLY、O_NONBLOCK和O_SYNC*/

unsignedshortf_count;/*打開的文件數(shù)目*/

unsignedshortf_reada;

structinode*f_inode;/*指向inode的結(jié)構(gòu)指針*/

structfile_operations*f_op;/*文件索引指針*/

};

3.設(shè)備驅(qū)動(dòng)程序主要組成

(1)早期版本的字符設(shè)備注冊(cè)。

早期版本的設(shè)備注冊(cè)使用函數(shù)register_chrdev(),調(diào)用該函數(shù)后就可以向系統(tǒng)申請(qǐng)主設(shè)備號(hào),如果register_chrdev()操作成功,設(shè)備名就會(huì)出現(xiàn)在/proc/devices文件里。在關(guān)閉設(shè)備時(shí),通常需要解除原先的設(shè)備注冊(cè),此時(shí)可使用函數(shù)unregister_chrdev(),此后該設(shè)備就會(huì)從/proc/devices里消失。其中主設(shè)備號(hào)和次設(shè)備號(hào)不能大于255。

當(dāng)前不少的字符設(shè)備驅(qū)動(dòng)代碼仍然使用這些早期版本的函數(shù)接口,但在未來(lái)內(nèi)核的代碼中,將不會(huì)出現(xiàn)這種編程接口機(jī)制。因此應(yīng)該盡量使用后面講述的編程機(jī)制。

register_chrdev()函數(shù)格式如表11.1所示。

表11.1 register_chrdev()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/fs.h>

函數(shù)原型

intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops)

函數(shù)傳入值

major:設(shè)備驅(qū)動(dòng)程序向系統(tǒng)申請(qǐng)的主設(shè)備號(hào),如果為0則系統(tǒng)為此驅(qū)動(dòng)程序動(dòng)態(tài)地分配一個(gè)主設(shè)備號(hào)

name:設(shè)備名

fops:對(duì)各個(gè)調(diào)用的入口點(diǎn)

函數(shù)返回值

成功:如果是動(dòng)態(tài)分配主設(shè)備號(hào),此返回所分配的主設(shè)備號(hào)。且設(shè)備名就會(huì)出現(xiàn)在/proc/devices文件里

出錯(cuò):-1

unregister_chrdev()函數(shù)格式如下表11.2所示:

表11.2 unregister_chrdev()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/fs.h>

函數(shù)原型

intunregister_chrdev(unsignedintmajor,constchar*name)

函數(shù)傳入值

major:設(shè)備的主設(shè)備號(hào),必須和注冊(cè)時(shí)的主設(shè)備號(hào)相同

name:設(shè)備名

函數(shù)返回值

成功:0,且設(shè)備名從/proc/devices文件里消失

出錯(cuò):-1

(2)設(shè)備號(hào)相關(guān)函數(shù)。

在前面已經(jīng)提到設(shè)備號(hào)有主設(shè)備號(hào)和次設(shè)備號(hào),其中主設(shè)備號(hào)表示設(shè)備類型,對(duì)應(yīng)于確定的驅(qū)動(dòng)程序,具備相同主設(shè)備號(hào)的設(shè)備之間共用同一個(gè)驅(qū)動(dòng)程序,而用次設(shè)備號(hào)來(lái)標(biāo)識(shí)具體物理設(shè)備。因此在創(chuàng)建字符設(shè)備之前,必須先獲得設(shè)備的編號(hào)(可能需要分配多個(gè)設(shè)備號(hào))。

在Linux2.6的版本中,用dev_t類型來(lái)描述設(shè)備號(hào)(dev_t是32位數(shù)值類型,其中高12位表示主設(shè)備號(hào),低20位表示次設(shè)備號(hào))。用兩個(gè)宏MAJOR和MINOR分別獲得dev_t設(shè)備號(hào)的主設(shè)備號(hào)和次設(shè)備號(hào),而且用MKDEV宏來(lái)實(shí)現(xiàn)逆過(guò)程,即組合主設(shè)備號(hào)和次設(shè)備號(hào)而獲得dev_t類型設(shè)備號(hào)。

分配設(shè)備號(hào)有靜態(tài)和動(dòng)態(tài)的兩種方法。靜態(tài)分配(register_chrdev_region()函數(shù))是指在事先知道設(shè)備主設(shè)備號(hào)的情況下,通過(guò)參數(shù)函數(shù)指定第一個(gè)設(shè)備號(hào)(它的次設(shè)備號(hào)通常為0)而向系統(tǒng)申請(qǐng)分配一定數(shù)目的設(shè)備號(hào)。動(dòng)態(tài)分配(alloc_chrdev_region())是指通過(guò)參數(shù)僅設(shè)置第一個(gè)次設(shè)備號(hào)(通常為0,事先不會(huì)知道主設(shè)備號(hào))和要分配的設(shè)備數(shù)目而系統(tǒng)動(dòng)態(tài)分配所需的設(shè)備號(hào)。

通過(guò)unregister_chrdev_region()函數(shù)釋放已分配的(無(wú)論是靜態(tài)的還是動(dòng)態(tài)的)設(shè)備號(hào)。

它們的函數(shù)格式如表11.3所示。

表11.3 設(shè)備號(hào)分配與釋放函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/fs.h>

函數(shù)原型

intregister_chrdev_region(dev_tfirst,unsignedintcount,char*name)

intalloc_chrdev_region(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name)

voidunregister_chrdev_region(dev_tfirst,unsignedintcount)

函數(shù)傳入值

first:要分配的設(shè)備號(hào)的初始值

count:要分配(釋放)的設(shè)備號(hào)數(shù)目

name:要申請(qǐng)?jiān)O(shè)備號(hào)的設(shè)備名稱(在/proc/devices和sysfs中顯示)

dev:動(dòng)態(tài)分配的第一個(gè)設(shè)備號(hào)

函數(shù)返回值

成功:0(只限于兩種注冊(cè)函數(shù))

出錯(cuò):-1(只限于兩種注冊(cè)函數(shù))

(3)最新版本的字符設(shè)備注冊(cè)。

在獲得了系統(tǒng)分配的設(shè)備號(hào)之后,通過(guò)注冊(cè)設(shè)備才能實(shí)現(xiàn)設(shè)備號(hào)和驅(qū)動(dòng)程序之間的關(guān)聯(lián)。這里講解2.6內(nèi)核中的字符設(shè)備的注冊(cè)和注銷過(guò)程。

在Linux內(nèi)核中使用structcdev結(jié)構(gòu)來(lái)描述字符設(shè)備,我們?cè)隍?qū)動(dòng)程序中必須將已分配到的設(shè)備號(hào)以及設(shè)備操作接口(即為structfile_operations結(jié)構(gòu))賦予structcdev結(jié)構(gòu)變量。首先使用cdev_alloc()函數(shù)向系統(tǒng)申請(qǐng)分配structcdev結(jié)構(gòu),再用cdev_init()函數(shù)初始化已分配到的結(jié)構(gòu)并與file_operations結(jié)構(gòu)關(guān)聯(lián)起來(lái)。最后調(diào)用cdev_add()函數(shù)將設(shè)備號(hào)與structcdev結(jié)構(gòu)進(jìn)行關(guān)聯(lián)并向內(nèi)核正式報(bào)告新設(shè)備的注冊(cè),這樣新設(shè)備可以被用起來(lái)了。

如果要從系統(tǒng)中刪除一個(gè)設(shè)備,則要調(diào)用cdev_del()函數(shù)。具體函數(shù)格式如表11.4所示。

表11.4 最新版本的字符設(shè)備注冊(cè)

所需頭文件

#include<linux/cdev.h>

函數(shù)原型

sturctcdev*cdev_alloc(void)

voidcdev_init(structcdev*cdev,structfile_operations*fops)

intcdev_add(structcdev*cdev,dev_tnum,unsignedintcount)

voidcdev_del(structcdev*dev)

函數(shù)傳入值

cdev:需要初始化/注冊(cè)/刪除的structcdev結(jié)構(gòu)

fops:該字符設(shè)備的file_operations結(jié)構(gòu)

num:系統(tǒng)給該設(shè)備分配的第一個(gè)設(shè)備號(hào)

count:該設(shè)備對(duì)應(yīng)的設(shè)備號(hào)數(shù)量

函數(shù)返回值

成功:

cdev_alloc:返回分配到的structcdev結(jié)構(gòu)指針

cdev_add:返回0

出錯(cuò):

cdev_alloc:返回NULL

cdev_add:返回-1

2.6內(nèi)核仍然保留早期版本的register_chrdev()等字符設(shè)備相關(guān)函數(shù),其實(shí)從內(nèi)核代碼中可以發(fā)現(xiàn),在register_chrdev()函數(shù)的實(shí)現(xiàn)中用到cdev_alloc()和cdev_add()函數(shù),而在unregister_chrdev()函數(shù)的實(shí)現(xiàn)中調(diào)用cdev_del()函數(shù)。因此很多代碼仍然使用早期版本接口,但這種機(jī)制將來(lái)會(huì)從內(nèi)核中消失。

前面已經(jīng)提到字符設(shè)備的實(shí)際操作在structfile_operations結(jié)構(gòu)的一組函數(shù)中定義,并在驅(qū)動(dòng)程序中需要與字符設(shè)備結(jié)構(gòu)關(guān)聯(lián)起來(lái)。下面討論structfile_operations結(jié)構(gòu)中最主要的成員函數(shù)和它們的用法。

(4)打開設(shè)備。

打開設(shè)備的函數(shù)接口是open,根據(jù)設(shè)備的不同,open函數(shù)接口完成的功能也有所不同,但通常情況下在open函數(shù)接口中要完成如下工作。

n 遞增計(jì)數(shù)器,檢查錯(cuò)誤。

n 如果未初始化,則進(jìn)行初始化。

n 識(shí)別次設(shè)備號(hào),如果必要,更新f_op指針。

n 分配并填寫被置于filp->private_data的數(shù)據(jù)結(jié)構(gòu)。

其中遞增計(jì)數(shù)器是用于設(shè)備計(jì)數(shù)的。由于設(shè)備在使用時(shí)通常會(huì)打開多次,也可以由不同的進(jìn)程所使用,所以若有一進(jìn)程想要?jiǎng)h除該設(shè)備,則必須保證其他設(shè)備沒(méi)有使用該設(shè)備。因此使用計(jì)數(shù)器就可以很好地完成這項(xiàng)功能。

這里,實(shí)現(xiàn)計(jì)數(shù)器操作的是在2.6內(nèi)核早期版本的<linux/module.h>中定義的3個(gè)宏,它們?cè)谧钚掳姹纠镌缇拖Я耍谙旅媪谐鲋皇菫榱藥妥x者理解老版本中的驅(qū)動(dòng)代碼。

n MOD_INC_USE_COUNT:計(jì)數(shù)器加1。

n MOD_DEC_USE_COUNT:計(jì)數(shù)器減1。

n MOD_IN_USE:計(jì)數(shù)器非零時(shí)返回真。

另外,當(dāng)有多個(gè)物理設(shè)備時(shí),就需要識(shí)別次設(shè)備號(hào)來(lái)對(duì)各個(gè)不同的設(shè)備進(jìn)行不同的操作,在有些驅(qū)動(dòng)程序中并不需要用到。

注意

雖然這是對(duì)設(shè)備文件執(zhí)行的第一個(gè)操作,但卻不是驅(qū)動(dòng)程序一定要聲明的操作。若這個(gè)函數(shù)的入口為NULL,那么設(shè)備的打開操作將永遠(yuǎn)成功,但系統(tǒng)不會(huì)通知驅(qū)動(dòng)程序。

(5)釋放設(shè)備。

釋放設(shè)備的函數(shù)接口是release()。要注意釋放設(shè)備和關(guān)閉設(shè)備是完全不同的。當(dāng)一個(gè)進(jìn)程釋放設(shè)備時(shí),其他進(jìn)程還能繼續(xù)使用該設(shè)備,只是該進(jìn)程暫時(shí)停止對(duì)該設(shè)備的使用;而當(dāng)一個(gè)進(jìn)程關(guān)閉設(shè)備時(shí),其他進(jìn)程必須重新打開此設(shè)備才能使用它。

釋放設(shè)備時(shí)要完成的工作如下。

n 遞減計(jì)數(shù)器MOD_DEC_USE_COUNT(最新版本已經(jīng)不再使用)。

n 釋放打開設(shè)備時(shí)系統(tǒng)所分配的內(nèi)存空間(包括filp->private_data指向的內(nèi)存空間)。

n 在最后一次釋放設(shè)備操作時(shí)關(guān)閉設(shè)備。

(6)讀寫設(shè)備。

讀寫設(shè)備的主要任務(wù)就是把內(nèi)核空間的數(shù)據(jù)復(fù)制到用戶空間,或者從用戶空間復(fù)制到內(nèi)核空間,也就是將內(nèi)核空間緩沖區(qū)里的數(shù)據(jù)復(fù)制到用戶空間的緩沖區(qū)中或者相反。這里首先解釋一個(gè)read()和write()函數(shù)的入口函數(shù),如表11.5所示。

表11.5 read、write函數(shù)接口語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/fs.h>

函數(shù)原型

ssize_t(*read)(structfile*filp,char*buff,size_tcount,loff_t*offp)
ssize_t(*write)(structfile*filp,constchar*buff,size_tcount,loff_t*offp)

函數(shù)傳入值

filp:文件指針

buff:指向用戶緩沖區(qū)

count:傳入的數(shù)據(jù)長(zhǎng)度

offp:用戶在文件中的位置

函數(shù)返回值

成功:寫入的數(shù)據(jù)長(zhǎng)度

雖然這個(gè)過(guò)程看起來(lái)很簡(jiǎn)單,但是內(nèi)核空間地址和應(yīng)用空間地址是有很大區(qū)別的,其中一個(gè)區(qū)別是用戶空間的內(nèi)存是可以被換出的,因此可能會(huì)出現(xiàn)頁(yè)面失效等情況。所以不能使用諸如memcpy()之類的函數(shù)來(lái)完成這樣的操作。在這里要使用copy_to_user()或copy_from_user()等函數(shù),它們是用來(lái)實(shí)現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)交換的。

copy_to_user()和copy_from_user()的格式如表11.6所示。

表11.6 copy_to_user()/copy_from_user()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<asm/uaccess.h>

函數(shù)原型

unsignedlongcopy_to_user(void*to,constvoid*from,unsignedlongcount)
unsignedlongcopy_from_user(void*to,constvoid*from,unsignedlongcount)

函數(shù)傳入值

to:數(shù)據(jù)目的緩沖區(qū)

from:數(shù)據(jù)源緩沖區(qū)

count:數(shù)據(jù)長(zhǎng)度

函數(shù)返回值

成功:寫入的數(shù)據(jù)長(zhǎng)度
失?。?EFAULT

要注意,這兩個(gè)函數(shù)不僅實(shí)現(xiàn)了用戶空間和內(nèi)核空間的數(shù)據(jù)轉(zhuǎn)換,而且還會(huì)檢查用戶空間指針的有效性。如果指針無(wú)效,那么就不進(jìn)行復(fù)制。

(7)ioctl。

大部分設(shè)備除了讀寫操作,還需要硬件配置和控制(例如,設(shè)置串口設(shè)備的波特率)等很多其他操作。在字符設(shè)備驅(qū)動(dòng)中ioctl函數(shù)接口給用戶提供對(duì)設(shè)備的非讀寫操作機(jī)制。

ioctl函數(shù)接口的具體格式如表11.7所示。

表11.7 ioctl函數(shù)接口語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/fs.h>

函數(shù)原型

int(*ioctl)(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg)

函數(shù)傳入值

inode:文件的內(nèi)核內(nèi)部結(jié)構(gòu)指針

filp:被打開的文件描述符

cmd:命令類型

arg:命令相關(guān)參數(shù)

下面列出其他在驅(qū)動(dòng)程序中常用的內(nèi)核函數(shù)。

(8)獲取內(nèi)存。

在應(yīng)用程序中獲取內(nèi)存通常使用函數(shù)malloc(),但在設(shè)備驅(qū)動(dòng)程序中動(dòng)態(tài)開辟內(nèi)存可以以字節(jié)或頁(yè)面為單位。其中,以字節(jié)為單位分配內(nèi)存的函數(shù)有kmalloc(),注意的是,kmalloc()函數(shù)返回的是物理地址,而malloc()等返回的是線性虛擬地址,因此在驅(qū)動(dòng)程序中不能使用malloc()函數(shù)。與malloc()不同,kmalloc()申請(qǐng)空間有大小限制。長(zhǎng)度是2的整次方,并且不會(huì)對(duì)所獲取的內(nèi)存空間清零。

以頁(yè)為單位分配內(nèi)存的函數(shù)如下所示。

n get_zeroed_page():獲得一個(gè)已清零頁(yè)面。

n get_free_page():獲得一個(gè)或幾個(gè)連續(xù)頁(yè)面。

n get_dma_pages():獲得用于DMA傳輸?shù)捻?yè)面。

與之相對(duì)應(yīng)的釋放內(nèi)存用也有kfree()或free_page函數(shù)族。

表11.8給出了kmalloc()函數(shù)的語(yǔ)法格式。

表11.8 kmalloc()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/malloc.h>

函數(shù)原型

void*kmalloc(unsignedintlen,intflags)

函數(shù)傳入值

len:希望申請(qǐng)的字節(jié)數(shù)

flags

GFP_KERNEL:內(nèi)核內(nèi)存的通常分配方法,可能引起睡眠

GFP_BUFFER:用于管理緩沖區(qū)高速緩存

GFP_ATOMIC:為中斷處理程序或其他運(yùn)行于進(jìn)程上下文之外的代碼分配內(nèi)存,且不會(huì)引起睡眠

GFP_USER:用戶分配內(nèi)存,可能引起睡眠

GFP_HIGHUSER:優(yōu)先高端內(nèi)存分配

__GFP_DMA:DMA數(shù)據(jù)傳輸請(qǐng)求內(nèi)存

__GFP_HIGHMEN:請(qǐng)求高端內(nèi)存

函數(shù)返回值

成功:寫入的數(shù)據(jù)長(zhǎng)度
失?。?EFAULT

表11.9給出了kfree()函數(shù)的語(yǔ)法格式。

表11.9 kfree()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/malloc.h>

函數(shù)原型

voidkfree(void*obj)

函數(shù)傳入值

obj:要釋放的內(nèi)存指針

函數(shù)返回值

成功:寫入的數(shù)據(jù)長(zhǎng)度
失?。?EFAULT

表11.10給出了以頁(yè)為單位的分配函數(shù)get_free_page類函數(shù)的語(yǔ)法格式。

表11.10 get_free_page類函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/malloc.h>

函數(shù)原型

unsignedlongget_zeroed_page(intflags)
unsignedlong__get_free_page(intflags)
unsignedlong__get_free_page(intflags,unsignedlongorder)
unsignedlong__get_dma_page(intflags,unsignedlongorder)

函數(shù)傳入值

flags:同kmalloc()

order:要請(qǐng)求的頁(yè)面數(shù),以2為底的對(duì)數(shù)

函數(shù)返回值

成功:返回指向新分配的頁(yè)面的指針
失?。?EFAULT

表11.11給出了基于頁(yè)的內(nèi)存釋放函數(shù)free_page族函數(shù)的語(yǔ)法格式。

表11.11 free_page類函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/malloc.h>

函數(shù)原型

unsignedlongfree_page(unsignedlongaddr)
unsignedlongfree_pages(unsignedlongaddr,unsignedlongorder)

函數(shù)傳入值

addr:要釋放的內(nèi)存起始地址

order:要請(qǐng)求的頁(yè)面數(shù),以2為底的對(duì)數(shù)

函數(shù)返回值

成功:寫入的數(shù)據(jù)長(zhǎng)度
失?。?EFAULT

(9)打印信息。

就如同在編寫用戶空間的應(yīng)用程序,打印信息有時(shí)是很好的調(diào)試手段,也是在代碼中很常用的組成部分。但是與用戶空間不同,在內(nèi)核空間要用函數(shù)printk()而不能用平常的函數(shù)printf()。printk()和printf()很類似,都可以按照一定的格式打印消息,所不同的是,printk()還可以定義打印消息的優(yōu)先級(jí)。

表11.12給出了printk()函數(shù)的語(yǔ)法格式。

表11.12 printk類函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<linux/kernel>

函數(shù)原型

intprintk(constchar*fmt,…)

函數(shù)傳入值

fmt:
日志級(jí)別

KERN_EMERG:緊急時(shí)間消息

KERN_ALERT:需要立即采取動(dòng)作的情況

KERN_CRIT:臨界狀態(tài),通常涉及嚴(yán)重的硬件或軟件操作失敗

KERN_ERR:錯(cuò)誤報(bào)告

KERN_WARNING:對(duì)可能出現(xiàn)的問(wèn)題提出警告

KERN_NOTICE:有必要進(jìn)行提示的正常情況

KERN_INFO:提示性信息

KERN_DEBUG:調(diào)試信息

…:與printf()相同

函數(shù)返回值

成功:0
失?。?1

這些不同優(yōu)先級(jí)的信息輸出到系統(tǒng)日志文件(例如:“/var/log/messages”),有時(shí)也可以輸出到虛擬控制臺(tái)上。其中,對(duì)輸出給控制臺(tái)的信息有一個(gè)特定的優(yōu)先級(jí)console_loglevel。只有打印信息的優(yōu)先級(jí)小于這個(gè)整數(shù)值,信息才能被輸出到虛擬控制臺(tái)上,否則,信息僅僅被寫入到系統(tǒng)日志文件中。若不加任何優(yōu)先級(jí)選項(xiàng),則消息默認(rèn)輸出到系統(tǒng)日志文件中。

注意

要開啟klogd和syslogd服務(wù),消息才能正常輸出。

4.proc文件系統(tǒng)

/proc文件系統(tǒng)是一個(gè)偽文件系統(tǒng),它是一種內(nèi)核和內(nèi)核模塊用來(lái)向進(jìn)程發(fā)送信息的機(jī)制。這個(gè)偽文件系統(tǒng)讓用戶可以和內(nèi)核內(nèi)部數(shù)據(jù)結(jié)構(gòu)進(jìn)行交互,獲取有關(guān)系統(tǒng)和進(jìn)程的有用信息,在運(yùn)行時(shí)通過(guò)改變內(nèi)核參數(shù)來(lái)改變?cè)O(shè)置。與其他文件系統(tǒng)不同,/proc存在于內(nèi)存之中而不是在硬盤上。讀者可以通過(guò)“ls”查看/proc文件系統(tǒng)的內(nèi)容。

表11.13列出了/proc文件系統(tǒng)的主要目錄內(nèi)容。

表11.13 /proc文件系統(tǒng)主要目錄內(nèi)容

目錄名稱

目錄內(nèi)容

目錄名稱

目錄內(nèi)容

apm

高級(jí)電源管理信息

locks

內(nèi)核鎖

cmdline

內(nèi)核命令行

meminfo

內(nèi)存信息

cpuinfo

CPU相關(guān)信息

misc

雜項(xiàng)

devices

設(shè)備信息(塊設(shè)備/字符設(shè)備)

modules

加載模塊列表

dma

使用的DMA通道信息

mounts

加載的文件系統(tǒng)

filesystems

支持的文件系統(tǒng)信息

partitions

系統(tǒng)識(shí)別的分區(qū)表

interrupts

中斷的使用信息

rtc

實(shí)時(shí)時(shí)鐘

ioports

I/O端口的使用信息

stat

全面統(tǒng)計(jì)狀態(tài)表

kcore

內(nèi)核映像

swaps

對(duì)換空間的利用情況

kmsg

內(nèi)核消息

version

內(nèi)核版本

ksyms

內(nèi)核符號(hào)表

uptime

系統(tǒng)正常運(yùn)行時(shí)間

loadavg

負(fù)載均衡

除此之外,還有一些是以數(shù)字命名的目錄,它們是進(jìn)程目錄。系統(tǒng)中當(dāng)前運(yùn)行的每一個(gè)進(jìn)程都有對(duì)應(yīng)的一個(gè)目錄在/proc下,以進(jìn)程的PID號(hào)為目錄名,它們是讀取進(jìn)程信息的接口。進(jìn)程目錄的結(jié)構(gòu)如表11.14所示。

表11.14 /proc中進(jìn)程目錄結(jié)構(gòu)

目錄名稱

目錄內(nèi)容

目錄名稱

目錄內(nèi)容

cmdline

命令行參數(shù)

cwd

當(dāng)前工作目錄的鏈接

environ

環(huán)境變量值

exe

指向該進(jìn)程的執(zhí)行命令文件

fd

一個(gè)包含所有文件描述符的目錄

maps

內(nèi)存映像

mem

進(jìn)程的內(nèi)存被利用情況

statm

進(jìn)程內(nèi)存狀態(tài)信息

stat

進(jìn)程狀態(tài)

root

鏈接此進(jìn)程的root目錄

status

進(jìn)程當(dāng)前狀態(tài),以可讀的方式顯示出來(lái)

用戶可以使用cat命令來(lái)查看其中的內(nèi)容。

可以看到,/proc文件系統(tǒng)體現(xiàn)了內(nèi)核及進(jìn)程運(yùn)行的內(nèi)容,在加載模塊成功后,讀者可以通過(guò)查看/proc/device文件獲得相關(guān)設(shè)備的主設(shè)備號(hào)。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉