level6
ヌル・デバイスドライバ(何もしないデバイスドライバ)を作成せよ。
デバイスは、/devにあるノードによってアクセスされる。
ノード番号を指定するファイルが、システムコールと同じようにあるので、
それを調査せよ。
デバイスドライバとは、ハードウェアコントローラを操作あるいは管理する
ソフトウェアであります。
Linuxカーネルのデバイスドライバは、本質的に特権を与えられ、
メモリに常駐する、低レベルハードウェアの
処理ルーチンから成る共有ライブラリであります。
担当するデバイスの特殊性に対処するのが、Linuxのデバイスドライバの
役割であります。
また、Linuxではデバイスはキャラクタ型とブロック型があります。
キャラクタ型が1バイト単位の細かい読み書きが可能なのに対して、
ブロック型はブロックというデータの塊を単位に読み書きをします。
ブロック型のデバイスはmountするところでファイルシステムに
組み込むことが可能で、またディスクキャッシュも働きます。
ヌル・デバイスドライバのプログラム
newnull2.c
プログラムは以下のようになっています。
/*必要なヘッダファイルをインクルード*/
#include
#include
#include
/*モジュールについての説明*/
MODULE_DESCRIPTION( "Sample null device driver." );
/*カーネルモジュールのライセンスを表す文字列を引数として指定*/
MODULE_LICENSE( "GPL" );
/*メジャー番号を指定*/
static int devmajor = 241;
static char* devname = "newnull2";
static char* msg = "module [newnull2.o]";
/*モジュール内の各関数とユーザプロセスからの操作を関連づけるためには、
linux/fs.h内のstruct file_operations型*/
/*構造体を作成し、カーネルに登録する必要があります。今回はヌルにしますの
で、何も設定していません*/
static struct file_operations newnulldev_fops =
{
owner : THIS_MODULE, /*カーネルモジュール自身の情報を初期化します。*/
};
/*自分自身をキャラクタデバイスドライバとしてカーネルに登録するためにregister_chrdevを実行しています。*/
int
init_module( void )
{
if ( register_chrdev( devmajor, devname, newnulldev_fops )
) {
printk( KERN_INFO "%s : register_chrdev failed\n" );
return -EBUSY;
}
return 0;
}
/*カーネルに登録されている情報を削除するために、unregister_chrdevを実行
しています。*/
void
cleanup_module( void )
{
if ( unregister_chrdev( devmajor, devname ) ) {
printk( KERN_INFO "%s : unregister_chrdev failed\n" );
/* 対策無し ... */
}
printk( KERN_INFO "%s : removed from kernel\n", msg );
}
プログラムを作り終えたら、ヌル・デバイスをカーネルに追加します。
まず、作成したプログラムを以下のようにコンパイルし、カーネルモジュールを
作成します。
[j03018@pw022 ~]% gcc -DMODULE -D__KERNEL__ -O -c newnull2.c
コンパイルすると、カーネルモジュールのnewnull2.oが作成されます。
次に、ユーザプロセスから実行する為には、デバイスファイルを作成しなけ
ればいけないので、デバイスファイルを作成します。
デバイスドライバとデバイスファイルは、メジャー番号とマイナー番号
と呼ばれる数値で結び付けられています。
メジャー番号とマイナー番号については後で説明します。
ここからは、rootで行います。
[j03018@pw022 ~]% mknod /dev/newnull2 c 241 0
[j03018@pw022 ~]% chmod 0666 /dev/newnull2
mknodでnewnullのメジャー番号を241、マイナー番号を0としています。
ローカルで使用可能な番号が240〜254なので241番にしました。
最後に、作成されたnewnull.oをカーネルへ組込みます。
組込みには、insmodコマンドを使います。
[j03018@pw022 ~]% /sbin/insmod nuwnull2.o
これで何も表示されなければ、カーネルへ無事組込まれています。
ヌル・ドライバデバイスなので、なにも出来ませんが、以下のコマンドを打つと
[j03018@pw022 ~]% cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 ttyS
5 cua
7 vcs
10 misc
14 sound
128 ptm
136 pts
162 raw
180 usb
226 drm
241 newnull2
Block devices:
2 fd
3 ide0
22 ide1
となり、241番にnewnull2が追加されていることが分かります。
ノード番号を指定するファイルは、/usr/include/linux/のmajor.hです。
もしくは、先ほどの/procのdevicesにも番号が少し指定されています。
major.hは以下のようになっています。
#ifndef _LINUX_MAJOR_H
#define _LINUX_MAJOR_H
...
...
#define MAX_CHRDEV 255
#define MAX_BLKDEV 255
#define UNNAMED_MAJOR 0
#define MEM_MAJOR 1
#define RAMDISK_MAJOR 1
#define FLOPPY_MAJOR 2
#define PTY_MASTER_MAJOR 2
#define IDE0_MAJOR 3
...
...
#define MSR_MAJOR 202
#define CPUID_MAJOR 203
#define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */
#define IBM_TTY3270_MAJOR 227 /* Official allocations now */
#define IBM_FS3270_MAJOR 228
...
...
static __inline__ int ide_blk_major(int m)
{
return IDE_DISK_MAJOR(m);
}
#endif
ここで指定されているノード番号は、上で少し出てきましたが、メジャー番号と
呼ばれています。
この他にもマイナー番号というのもあります。それぞれ、以下のような意味を持っ
ています。
- メジャー番号は、デバイスドライバがそれぞれ固有に持っている番号です。
- マイナー番号は、そのデバイスドライバで利用可能なデバイスの内の、どの
デバイスを使うのかを指定しています。これは一つのデバイスドライバで複数
のデバイスが利用可能な場合に識別のために用いられる番号です。
今回の実験を進めていて、カーネルモジュールをカーネルに組込もうとすると
以下のエラーメッセジが表示されました。
newnull2.o: kernel-module version mismatch
chardev.o was compiled for kernel version 2.4.27-0vl7
while this kernel is version 2.4.26-0vl15.
これは、カーネルモジュールの対応カーネルバージョンとpwのLinuxのカーネル
バージョンが違っていて組込めないとのことでした。
それで色々調べてみると、pwのカーネルは、/usr/src/linux-2.4.27
以下に置かれていました。
しかし、コマンドで調べてみると
[j03018@pw022 ~]% uname -r
2.4.26-0vl15
と表示され実際はlinux-2.4.26が動いていることが分かりました。
それで、他の実験で設定し直したLinuxのバージョンが2.4.27だったので、急遽、
そのLinux-2.4.27で起動させた所、無事にカーネルに組込むことが出来ました.
pwの内部のバージョンは、合わせる必要があると思いました。
簡単なキャラクタデバイスをつくる
http://www.mech.tohoku-gakuin.ac.jp/rde/contents/linux/drivers/chardev1.html
THE Linux Kernel
http://www.linux.or.jp/JF/JFdocs/The-Linux-Kernel.html
デバイスドライバとは
ヌル・デバイスドライバのプログラム作成
ヌル・デバイスドライバの追加方法
考察
参考リンク
level5
top
levelX