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