udev (3)
キャラクタデバイスのメジャー番号の登録処理について。
登録手順
以下な手順で登録との事。
- alloc_chrdev_region() でメジャー番号の動的確保
- cdev_init() でシステムコールハンドラを登録
- cdev_add() でカーネルへのドライバの登録
との事。コードも見つつ順にチェックしてみます。
alloc_ret = alloc_chrdev_region(&dev, 0, devone_devs, "devone"); if(alloc_ret) goto error; devone_major = major = MAJOR(dev);
alloc_chrdev_region に渡す引数については
- 上記 dev に確保されたデバイスのメジャー番号とマイナー番号が格納される
- 第二引数はベースとなるマイナー番号を指定
- 第三引数は必要なマイナー番号の個数を指定
- 第四引数はドライバの名前を渡す
との事。戻り値としては 0 が正常でそれ以外は異常。次は cdev_init 手続きで呼び出し例は以下。
cdev_init(&devone_cdev, &devone_fops); devone_cdev.owner = THIS_MODULE; devone_cdev.ops = &devone_fops;
cdev_init 手続きは第一引数の cdev 構造体の初期化とハンドラの登録との事。上の例で言えば devone_cdev という変数はドライバのアンロード時に必要となるため、グローバル変数として定義しておく必要があるとの事。引用している udev な例でもグローバル変数として定義されています。
THIS_MODULE の定義なんですが、include/linux/module.h の中で以下かな。
#define MODULE_GENERIC_TABLE(gtype,name) \ extern const struct gtype##_id __mod_##gtype##_table \ __attribute__ ((unused, alias(__stringify(name)))) extern struct module __this_module; #define THIS_MODULE (&__this_module)
ちょっとこの THIS_MODULE の意味不明です。あと、devone_cdev 構造体の ops 属性にハンドラな構造体のアドレスを設定しておりますな。ひらたさん本lによれば、cdev_init の呼び出し後に owner 属性には THIS_MODULE を代入せよ、との記述あり。
次は cdev_add ですが呼び出し例としては以下。
cdev_err = cdev_add(&devone_cdev, MKDEV(devone_major, devone_minor), 1); if(cdev_err) goto error;
カーネルへの登録については
- 第二引数は確保したメジャー番号とベースになるマイナー番号を MKDEV したものを渡す必要がある模様
- 第三引数はドライバが取り扱うデバイスの個数を渡すとの事
これも成功すると 0 を戻す模様。
登録解除の手順
アンロードする時はロードの逆の手順との事。
- cdev_del() でカーネルからドライバの登録を解除
- unregister_chrdev_region() でメジャー番号の削除
という事で登録解除の例を以下に。
cdev_del(&devone_cdev); unregister_chrdev_region(dev, devone_devs);
これ、第一引数には MKDEV(devone_major, devone_minor) の方が良さげ。ちなみに unregister_chrdev_region の第二引数は確保したマイナー番号の個数との事。
udev 対応
こちらも確認。登録時にやる事は二点な模様。
- ドライバのクラス登録
- /sys/class 配下にドライバ情報を作成
クラス登録の例は以下かな。
devone_class = class_create(THIS_MODULE, "devone"); if(IS_ERR(devone_class)) { goto error; }
ここでも第一引数は THIS_MODULE ですな。このあたりはちょっと調べる必要があるかもしれませんが、当座は固定って考えてても良いのだろうか。
ええと第二引数は「クラス名」との事。この関数呼び出しが成功したら /sys/class/devone なディレクトリが作られるのか。
あと戻りは例示してある通り、IS_ERR なマクロで判断してね、との事。
次は /sys/class/devone/デバイス名を作るために class_device_create() 手続きを呼び出すとの事。サンプルが以下。
devone_dev = MKDEV(devone_major, devone_minor); class_dev = class_device_create( devone_class, NULL, devone_dev, NULL, "devone%d", devone_minor);
- 第一引数は直前で呼び出してるはずの class_create 手続きの戻りを指定
- 第二引数は親クラスを指定したい場合に使う (NULL でも構わない)
- 第三引数は /sys/class/クラス名/デバイス名/dev に記述するメジャー番号、マイナー番号を指定との事
上記、若干意味不明だったので実機で確認してみました。
# insmod devone.ko # cd /sys/class/devone/devone0 # cat dev 252:0 #
なるほど。続きを以下に。
- 第四引数はクラスドライバに関連付けしたい struct device があれば指定との事 (NULL でも構わない)
- 第五引数以降は「デバイス名」との事。上記の例で言えば devone0 がそれにあたる訳か
次は登録解除。以下が例です。
/* unregister class */ class_device_destroy(devone_class, devone_dev); class_destroy(devone_class);
上記、devone_class、devone_dev についてはグローバル変数として定義されているのかな。
static struct class *devone_class = NULL; static dev_t devone_dev;
- class_device_destroy は登録済みのデバイス名の削除
- class_destroy は登録済みのクラスの削除
という事になる模様。
明日以降で
ひらたさん本の 6 章以降とか ldd3 をリファレンスにしつつ pl2303 なソレを確認してみようと思ってます。