メジャー番号/マイナ番号の取り扱い


デバイスファイルのメジャー/マイナー番号は、inode->i_rdev=(((ma) << MINORBITS) | (mi))と設定されます。でメジャー番号でドライバを特定し、マイナー番号でドライバに依存した処理がなされる。と理解していました。しかし実装は、メジャー番号/マイナー番号の組み合わせで(厳密にはマイナー番号の範囲)で、ドライバーが特定できる事も可能となるような実装となっています。

メジャー番号のみでドライバーをhoge_fopsとし、ドライバ側でマイナー番号に掛かる処理を行っています。
#include <linux/module.h>
#include <linux/genhd.h>
#include <linux/uaccess.h>

#define HOGE_MAJOR      100

static int hoge_open (struct inode *inode, struct file *filp)
{
       return 0;
}

static ssize_t hoge_write (struct file *file, const char __user *user_buf,
                                    size_t count, loff_t *ppos)
{
       struct inode *inode = file->f_dentry->d_inode;
       unsigned char   buf[64];
       unsigned int minor = iminor(inode);

       if (_copy_from_user(buf, user_buf, count )) {
               return -EFAULT;
       }
       buf[count - 1] = 0;
       printk("<0>write %s by minor %d\n", buf, minor);
       return count;
}

static struct file_operations hoge_fops = {
       .owner          = THIS_MODULE,
       .write          = hoge_write,
       .open           = hoge_open,
};

static int hoge_init (void)
{
       if (register_chrdev(HOGE_MAJOR, "hoge", &hoge_fops)) {
               printk("<0>chrdev register err\n");
               return -1;
       }
       return 0;
}

static void __exit hoge_exit (void)
{
       unregister_chrdev(HOGE_MAJOR, "hoge");
}

module_init(hoge_init);
module_exit(hoge_exit);
メジャ/マイナ番号でのドライバー設定。メジャ/マイナ番号が100/1の時、hoge_fops1を、100/2の時、hoge_fops2となります。
#include <linux/module.h>
#include <linux/genhd.h>
#include <linux/uaccess.h>

#define         HOGE_MAJOR      100

static int hoge_open (struct inode *inode, struct file *filp)
{
       return 0;
}

static ssize_t hoge_write1 (struct file *file, const char __user *user_buf,
                                    size_t count, loff_t *ppos)
{
       unsigned char   buf[64];

       if (_copy_from_user(buf, user_buf, count )) {
               return -EFAULT;
       }
       buf[count - 1] = 0;
       printk("<0>write %s by minor 1\n", buf);
       return count;
}

static ssize_t hoge_write2 (struct file *file, const char __user *user_buf,
                                    size_t count, loff_t *ppos)
{
       unsigned char   buf[64];

       if (_copy_from_user(buf, user_buf, count )) {
               return -EFAULT;
       }
       buf[count - 1] = 0;
       printk("<0>write %s by minor 2\n", buf);
       return count;
}

static struct file_operations hoge_fops1 = {
       .owner          = THIS_MODULE,
       .write          = hoge_write1,
       .open           = hoge_open,
};

static struct file_operations hoge_fops2 = {
       .owner          = THIS_MODULE,
       .write          = hoge_write2,
       .open           = hoge_open,
};

static int hoge_init (void)
{
       if(__register_chrdev(HOGE_MAJOR, 1, 1, "hoge1", &hoge_fops1)) {
               printk("<0>chrdev register hoge1 err\n");
               return -1;
       }
       if(__register_chrdev(HOGE_MAJOR, 2, 1, "hoge2", &hoge_fops2)) {
               printk("<0>chrdev register hoge2 err\n");
               return -1;
       }
       return 0;
}

static void __exit hoge_exit (void)
{
       __unregister_chrdev(HOGE_MAJOR, 1, 1, "hoge1");
       __unregister_chrdev(HOGE_MAJOR, 2, 1, "hoge2");
}

module_init(hoge_init);
module_exit(hoge_exit);
デバイスファイルの作成
[root@localhost lkm]# mknod hoge1 c 100 1
[root@localhost lkm]# mknod hoge2 c 100 2
[root@localhost lkm]# mknod hoge3 c 100 3
メジャー番号によるコールバック
[root@localhost lkm]# insmod hoge.ko

[root@localhost lkm]# echo "abc" > hoge1
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:36:48 ...
 kernel:[ 4858.277987] write abc by minor 1

[root@localhost lkm]# echo "abc" > hoge2
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:36:56 ...
 kernel:[ 4865.619893] write abc by minor 2

[root@localhost lkm]# echo "abc" > hoge3
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:36:59 ...
 kernel:[ 4869.280976] write abc by minor 3
メジャ/マイナ番号によるコールバック(マイナ番号が3の時はエラー)
[root@localhost lkm]# insmod hoge.ko

[root@localhost lkm]# echo "abc" > hoge1
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:42:00 ...
 kernel:[ 5169.970628] write abc by minor 1

[root@localhost lkm]# echo "abc" > hoge2
[root@localhost lkm]#
Message from syslogd@localhost at Sep  1 02:42:04 ...
 kernel:[ 5173.357401] write abc by minor 2

[root@localhost lkm]# echo "abc" > hoge3
-bash: hoge3: そのようなデバイスやアドレスはありません

補足

メジャー番号が同じ(目的)でも、マイナー番号により、その実装が大きく異なるようなドライバを考慮しての実装かと思います。実際、ttyの/dev/ttyと/dev/console(メジャー番号は同じ)では利用されています。なお、些細な違いなら、ドライバ内で対応したらいいかと思います。(実際tty意外ではそのようになっているようです。)

register_chrdev()は__register_chrdev()をマイナー番号数を256としてコールしています。第二引数の0は、開始マイナ番号で、かかるメジャー番号の全てのマイナー番号のコールバックは、fopsというわけです。
static inline int register_chrdev(unsigned int major, const char *name,
                                 const struct file_operations *fops)
{
       return __register_chrdev(major, 0, 256, name, fops);
}

loopバックデバイスを除くブロックデバイスはメジャー番号だけで、マイナー番号での管理は行っていません。ブロックデバイスはマイナー番号に関係なく同じデバイスで、マイナ番号は参照時のオフセットとして扱われます。(たぶん)

上記内容はキャラクタデバイスについての内容となります。ブロックデバイスの管理方法はキャラクタデバイスとは違っていて、マイナ番号でもってデバイスを区別する必要がないような実装となっています。



最終更新 2014/09/07 18:12:23 - north
(2014/08/24 18:23:56 作成)


検索

アクセス数
3698104
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。