sysfs ノードからデバイスをアクセスする †Linux kernel のデバイスとドライバの管理作法に従ってデバイスを kernel に登録すれば sysfs 上に対応するノードができます。sysfs は多くの Linux で /sys に mount されています。 sysfs のツリーを辿ってデバイスを探してみましょう。 /sys/devices/platform の下を見ていきます。このディレクトリには platform device が並びます。デバイス名の一部または機能名の一部がディレクトリ名になって並んでいます。環境によりデバイスの有無は仮想的な物も含めて違うので、存在するディレクトリは増減します。shell command を操作して /sys/devices 以下のノードと /sys/devices/platform 以下のノードの一覧を出してみます。 ~ $ cd /sys/devices /sys/devices $ ls -la total 0 drwxr-xr-x 16 root root 0 Jul 24 01:43 . dr-xr-xr-x 13 root root 0 Jul 24 01:43 .. drwxr-xr-x 10 root root 0 Jul 24 01:43 LNXSYSTM:00 drwxr-xr-x 3 root root 0 Jul 24 01:43 breakpoint drwxr-xr-x 5 root root 0 Jul 24 01:43 cpu drwxr-xr-x 5 root root 0 Jul 24 01:43 cstate_core drwxr-xr-x 5 root root 0 Jul 24 01:43 cstate_pkg drwxr-xr-x 3 root root 0 Jul 24 01:43 intel_bts drwxr-xr-x 5 root root 0 Jul 24 01:43 msr drwxr-xr-x 16 root root 0 Jul 24 01:43 pci0000:00 drwxr-xr-x 22 root root 0 Jul 24 01:43 platform drwxr-xr-x 10 root root 0 Jul 24 01:43 pnp0 drwxr-xr-x 3 root root 0 Jul 24 01:43 software drwxr-xr-x 9 root root 0 Jul 24 01:43 system drwxr-xr-x 3 root root 0 Jul 24 01:43 tracepoint drwxr-xr-x 18 root root 0 Jul 24 01:43 virtual /sys/devices/platform $ cd platform /sys/devices/platform $ ls -la total 0 drwxr-xr-x 22 root root 0 Jul 24 01:43 . drwxr-xr-x 16 root root 0 Jul 24 01:43 .. drwxr-xr-x 3 root root 0 Jul 24 01:45 ACPI000C:00 drwxr-xr-x 4 root root 0 Jul 24 01:45 Fixed MDIO bus.0 drwxr-xr-x 3 root root 0 Jul 24 01:45 INT33FF:00 drwxr-xr-x 3 root root 0 Jul 24 01:45 INT33FF:01 drwxr-xr-x 3 root root 0 Jul 24 01:45 INT33FF:02 drwxr-xr-x 3 root root 0 Jul 24 01:45 INT33FF:03 drwxr-xr-x 3 root root 0 Jul 24 01:45 PNP0103:00 drwxr-xr-x 3 root root 0 Jul 24 01:45 PNP0C0C:00 drwxr-xr-x 3 root root 0 Jul 24 01:45 PNP0C0E:00 drwxr-xr-x 3 root root 0 Jul 24 01:45 alarmtimer drwxr-xr-x 4 root root 0 Jul 20 11:14 coretemp.0 drwxr-xr-x 3 root root 0 Jul 24 01:45 efi-framebuffer.0 drwxr-xr-x 5 root root 0 Jul 24 01:45 i8042 drwxr-xr-x 3 root root 0 Jul 24 01:45 microcode drwxr-xr-x 3 root root 0 Jul 24 01:45 pcspkr drwxr-xr-x 2 root root 0 Jul 24 01:45 power drwxr-xr-x 4 root root 0 Jul 24 01:45 reg-dummy drwxr-xr-x 4 root root 0 Jul 24 01:45 serial8250 drwxr-xr-x 3 root root 0 Jul 24 01:45 snd-soc-dummy -rw-r--r-- 1 root root 4096 Jul 24 01:45 uevent drwxr-xr-x 3 root root 0 Jul 24 01:45 vboxdrv.0 i8042 ディレクトリを見てみましょう。このディレクトリには PS/2 keyboard と mouse デバイスが対応します。/sys/devices/platform/i8042/serio0 ディレクトリの下にある bind_mode ノードのために kernel の中で対応している関数は serio_set_bind_mode(), serio_show_bind_mode()) です。description ノードに対応している関数は (serio_show_description() と description ノードに文字列 "i8042 KBD port" を設定しているのは i8042_create_kbd_port()) です。デバイスを制御、機能確認するためノードです。このようなノードの多くは shell から cat, echo command で読み出し、書き込みできる様に実装されています。手軽にスクリプトで動作確認・制御できる user space API になっています。続く操作例はノードを読み出しているところです。 /sys/devices/platform $ cd i8042 /sys/devices/platform/i8042 $ ls -la total 0 drwxr-xr-x 5 root root 0 Jul 24 01:45 . drwxr-xr-x 22 root root 0 Jul 24 01:43 .. lrwxrwxrwx 1 root root 0 Jul 24 01:53 driver -> ../../../bus/platform/drivers/i8042 -rw-r--r-- 1 root root 4096 Jul 24 01:53 driver_override -r--r--r-- 1 root root 4096 Jul 24 01:53 modalias drwxr-xr-x 2 root root 0 Jul 24 01:53 power drwxr-xr-x 4 root root 0 Jul 24 01:53 serio0 drwxr-xr-x 4 root root 0 Jul 24 01:53 serio1 lrwxrwxrwx 1 root root 0 Jul 24 01:53 subsystem -> ../../../bus/platform -rw-r--r-- 1 root root 4096 Jul 24 01:53 uevent /sys/devices/platform/i8042 $ cd serio0 /sys/devices/platform/i8042/serio0$ ls -la total 0 drwxr-xr-x 4 root root 0 Jul 24 01:53 . drwxr-xr-x 5 root root 0 Jul 24 01:45 .. -rw-r--r-- 1 root root 4096 Jul 24 01:54 bind_mode -r--r--r-- 1 root root 4096 Jul 24 01:54 description --w------- 1 root root 4096 Jul 24 01:54 drvctl -r--r--r-- 1 root root 4096 Jul 24 01:54 firmware_id drwxr-xr-x 2 root root 0 Jul 24 01:54 id -r--r--r-- 1 root root 4096 Jul 24 01:54 modalias drwxr-xr-x 2 root root 0 Jul 24 01:54 power lrwxrwxrwx 1 root root 0 Jul 24 01:54 subsystem -> ../../../../bus/serio -rw-r--r-- 1 root root 4096 Jul 24 01:54 uevent /sys/devices/platform/i8042/serio0 $ cat bind_mode auto /sys/devices/platform/i8042/serio0 $ cat description i8042 KBD port bind_mode ノードの実装を詳しく見ていきましょう。このノードは DEVICE_ATTR() マクロでノードの名前、パーミッション、show(), store() 関数が定義されています。 attribute 構造体、attribute_group 構造体、attribute_group 構造体を指すポインタの配列で包み、serio_init_port() で device 構造体の group メンバに設定しています。
|
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | - | | | | | | ! - | ! - | | | ! |
|
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | - | ! - | | | | | | | | | | | | | | | - | | ! | | ! |
|
group メンバは sysfs_create_groups() が呼び出されるまでそのままです。sysfs_create_groups() までを追います。イベント "serio_queue_event(), SERIO_REGISTER_PORT" を経由して serio_handle_event() イベントハンドラ関数内で serio_add_port() で serio クラス・デバイスとして追加されます。ドライバとデバイスの基底的な処理/drivers/base にある device_add() で kernel にデバイスとして追加されます。device_add() から device_add_attrs(), device_add_groups() を経て、先の group メンバを sysfs_create_groups() に渡して sysfs ノードとして登録しています。
458
459
460
461
| - | ! |
|
sysfs ノードの追加は serio クラス・デバイスなので複雑です。簡易に sysfs ノードを設けるのであれば DEVICE_ATTR() マクロでノード定義し、attribute 構造体、attribute_group 構造体で包み、sysfs_create_group() (group が単数形であることに注意) でノードを登録、sysfs_remove_group() でノードを削除することができます。DEVICE_ATTR() の沢山の用例を見て使い方を習得できるでしょう。sysfs_create_group() の引数 kobject 構造体を指すポインタ kobj は device 構造体のメンバとして存在している kobj を指すポインタを使って下さい。
あちこちにある uevent node はどんな機能があるの?
書き込む (uevent_store()) と uevent を発行する (kobject_uevent_env()) 機能と、読み込む (uevent_show()) 機能が実装されています。読み込む機能は一部のノード、例えば /sys/class/input/* の下にある uevent ノードに実装 (input_dev_uevent()) されています。読み込む機能は uevent で発行される情報の一部をいつでも取得できる様になっています。
uevent が発行するイベントは socket (AF_NETLINK.NETLINK_KOBJECT_UEVENT) から配信されるか、イベント発生時に /proc/sys/kernel/hotplug または /sys/kernel/uevent_helper に設定した path のファイルを user space の process として起動することで配信されます。多くのディストリビューションでは user space に udev あるいはこれに類似する名前の daemon が socket を開いて kernel から配信されるイベントを受信しています。uevent で起動される実行ファイルの path は慣例的に /sbin/hotplug (CONFIG_UEVENT_HELPER_PATH) です。