Linux系統核心模組和驅動的編寫(轉)

post0發表於2007-08-09
Linux系統核心模組和驅動的編寫(轉)[@more@]

Linux核心是一個整體是結構,因此向核心新增任何東西,或者刪除某些功能,都十分困難。為了解決這個問題引入了核心機制。從而可以動態的想核心中新增或者刪除模組。

  模組不被編譯在核心中,因而控制了核心的大小.然而模組一旦被插入核心,他就和核心其他部分一樣.這樣一來就會曾家一部分系統開銷。同時,如果模組出現問題,也許會帶來系統的崩潰。

  模組的實現機制:

  啟動時,由函式 void inti_modules() 來初始化模組,因為啟動事很多時候沒有模組.這個函式往往把核心自身當作一個虛模組。

  如由系統需要,則呼叫一系列以sys 開頭的函式,對模組進行操作. 如:

  sys_creat_modules(),sys_inti_modules() ,

  sys_deldte_modules()等等.

  這裡會用到一些模組的資料就結構,在/usr/scr/Linux/include/Linux/module.h 中,有興趣的朋友可以找出來一看塊的加入有兩種方法:一是手動加入:如:insmod modulename.另一種是根據需要,動態的載入模組:如你執行命令:

  $mount -t msdos /dev/hdd /mnt/d 時.系統便自動載入 FAT模組,以支援MSDOS的檔案系統。

  1.模組程式設計

  寫一個模組,必須有一定的多程式程式設計基礎,因為你變得程式不是以一個獨立的程式的來執行的。另外,因為,模組需要在核心模式下執行,會遇到在內和空間和使用者空間資料交換的問題.一般的資料複製函式無法完成這一個過程。因此係統已入了一些特殊的函式以用來完成核心空間和使用者空間資料的交換/

  這些函式有:void put _user (type valude,type *u_addr)

  memcpy_tofs()

  等等,有興趣的朋友可以仔細的看看所有的函式,以及他們的用法.需要說明的是.模組程式設計河核心的版本有很大的關係。如果版本不通可能造成,核心模組不能編譯,或者.在執行這個模組時,出現不可測結果。如:系統崩潰等。

  明白了這些以後,你就可以嘗試著編寫核心模組了。對於每一個核心模組來說,必定包含兩個函式int init_module() 這個函式在插入核心時啟動,在核心中註冊一定的功能函式,或者用他的程式碼代替內和中某些函式的內容(估計這些函式是空的)。因此,內和可以安全的解除安裝。

  int cleanup_module() 當核心模組謝載時,呼叫.將模組從核心中清除.

  同其他的程式設計教程一樣 ,我們給出一個hello world 的例子

/*hello.c a module programm*/

/* the program runing under kernel mod and it is a module*/

#include" Linux/kernerl.h"

#include"lLinux/module.h"

/* pross the CONFIG_MODVERSIONS*/

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include""Linux/modversions.h"

#end if

/* the init function*/

int init_module()

{

printk(" hello world ! ’);

printd(" I have runing in a kerner mod@!! ");

return 1;

}

/* the distory function*/

int cleanup_module()

{

printk(" I will shut down myself in kernerl mod /n)";

retutn 0;

}

這樣一個例子就完成了.我們也寫一個makefile 的例子,以適於我們在大程式重的應用。一下是makfile 檔案的內容 。

# a makefile for a module

CC=gcc

MODCFLAGS:= -Wall _DMODULE -D_KERNEL_ -DLinux

hello.o hello.c /usr/inculde?Linux/version.h

CC $(MODCFLAGS) 0c hello.c

echo the module is complie completely

  然後你執行make 命令 得到hello.o 這個模組,執行

$insmod hello.o

hello world!

I will shut down myself in kernerl mod

$lsmod

hello (unused)

….

$remmod

I will shut down myself in kernerl mod

  這樣你的模組就可以隨意的插入和刪除了。

  Linux中的大部分驅動程式,是以模組的形式編寫的,這些驅動程式原始碼可以修改到核心中,也可以把他們編譯成模組形勢,在需要的時候動態載入。

  一個典型的驅動程式,大體上可以分為這麼幾個部分:

  1.註冊裝置

  在系統初啟,或者模組載入時候,必須將裝置登記到相應的裝置陣列,並返回裝置的主驅動號,例如:對快裝置來說呼叫 refister_blkdec() 將裝置新增到陣列blkdev中,並且獲得該裝置號,並利用這些裝置號對此陣列進行索引。對於字元驅動裝置來說,要使用 module_register_chrdev()來獲得祝裝置的驅動號,然後對這個裝置的所有呼叫都用這個裝置號來實現。

  2.定義功能函式

  對於每一個驅動函式來說,都有一些和此裝置密切相關的功能函式,那最常用的塊裝置或者字元裝置來說,都存在著諸如 open() read() write() ioctrol()這一類的操作。當系統社用這些呼叫時,將自動的使用驅動函式中特定的模組,來實現具體的操作。而對於特定的裝置,上面的系統呼叫對應的函式是一定的。

  如:在塊驅動裝置中.當系統試圖讀取這個裝置(即呼叫read()時),就會執行驅動程式中的block_read() 這個函式。

  開啟新裝置時會呼叫這個裝置驅動程式的device_open() 這個函式.

3.謝載模組

  在不用這個裝置時,可以將他解除安裝,主要是從/proc 中取消這個裝置的特殊檔案,可用特定的函式實現。

下面我們列舉一個字元裝置驅動程式的框架.來說明這個過程.

/* a module of a character device */

/* some include files*/

#include"param.h"

#include"user.h"

#include"tty.h"

#include"dir.h"

#include”fs.h"

/* the include files modules need*/

#include"Linux/kernel.h"

#include"Linux/module.h"

#if CONFIG_MODBERSIONS==1

degine MODBERSIONS

#include" Linux.modversions.h"

#endif

#difine devicename mydevice

/* the init funcion*/

int init_module()

{

int tag=module_register_chrdev(0,mydevice,&Fops);

if (tag<0)

{

printk("the device init is erro! ");

return 1;

}

return 0;

}

/*the funcion which the device will be used */

int device_open ()

{

…….

}

int device_read ()

{

…….

}

int device_write ()

{

…….

}

int device_ioctl ()

{

…….

}

……

/* the deltter function of this module*/

int cleanup_module()

{

int re=module_unregister_chrdev(tag,mydevice);

if( re<0)

{

printk("erro unregister the module !! ");

return 1;

}

return 0;

}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-938637/,如需轉載,請註明出處,否則將追究法律責任。

相關文章