序文最近、プロジェクトで LED サブシステムを使用する必要があります。組み込み Linux でライトをオンにするのは比較的簡単です。特定のライトに対応するディレクトリ内の対応するファイルに特定の値を書き込むだけで、LED をオン/オフ/点滅させることができます。 # echo 1 > /sys/class/leds/green/brightness // LEDをオンにする # echo 0 > /sys/class/leds/green/brightness // LEDをオフにする # echo heartbeat > /sys/class/leds/green/trigger // LED をハートビートのように点滅させる LEDトリガーもちろん、プロジェクトで使用されている照明機能は、上で紹介したものよりも少し複雑です。ハードディスクのライトに似ており、ハードディスクの読み取りまたは書き込み時に LED が点滅します。このファイルを cat すると、mmc0 という単語が含まれているので、この関数はトリガー ファイルに関連しているはずだと漠然と感じています。 次に、mmc0 をトリガーに書き込み、どのような効果があるかを確認します。 # echo mmc0 > /sys/class/leds/green/trigger # cat /sys/class/leds/green/trigger なし rc-feedback kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock [mmc0] ハートビート デフォルトオン ir-power-click axp20x-usb-online ディスクへのデータの書き込み # タッチ aa | 同期 不思議なことに、ディスクにデータを書き込むコマンドが実行されるたびに、ボード上の緑色のライトが 1 回点滅することを発見しました。 情報を調べてみると、これは LED トリガーに関連する機能であることがわかりました。 一瞬、私は思った
さまざまな疑問が頭に浮かび、これらの機能の背後にある原理を理解したいと思いました。 探索を始める問題が行動を促します。まず知りたい質問をリストアップします。 さまざまなライトに対応するディレクトリはどこから来るのでしょうか?
調査を始めましょう。まずは昨夜私が考えたことから始めましょう。led_classdev_register("aaa") は LED ディレクトリを生成します。 LEDデバイス登録led_classdev_register() が LED ライトに対応するディレクトリを生成するかどうかを確認する実験をしてみましょう。 実行できる場所をランダムに見つけ、次のコード行を追加して、aaaディレクトリがledsディレクトリに生成されることを期待しました。 構造体 led_classdev *cdev; 整数 戻り値; cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); もし (!cdev) -ENOMEM を返します。 cdev->名前 = "aaa"; // cdev->brightness_set = ebsa110_led_set; // cdev->brightness_get = ebsa110_led_get; // cdev->default_trigger = "ハートビート"; ret = led_classdev_register(NULL、cdev); 戻り値 < 0 の場合 cdevを解放します。 ret を返します。 } コンパイル、書き込み、実行、表示
案の定、私が表示したいと思っていたディレクトリ aaa が leds の下に生成され、私の自信は大きく高まりました! その後、基礎となる呼び出し関係をトレースしました。 led_classdev_register() of_led_classdev_register() // led_classdev クラスの新しいオブジェクトを登録します。 led_classdev_next_name() デバイス作成グループ() led_add_brightness_hw_changed() list_add_tail() // LEDのリストに追加 led_update_明るさ() //led_trigger_set_default() LEDディレクトリ特定のライトがどのように登録されるかがわかったので、次は leds ディレクトリがどのように生成されるかを知りたいと思います。コードを検索しましたが、見つけるのは難しくありません。以下は、leds ディレクトリの生成に関連する関数呼び出し関係です。 subsys_initcall(leds_init); leds_init() // leds クラスを作成します。つまり、/sys/class/leds ディレクトリを生成します。class_create() __class_create() クラスレジスタ() kset_register() 類推によって理解する後で情報を確認すると、/sys/class/leds はクラスであることがわかりました。クラスはカーネルサブシステムを表します。カーネルにはこのようなサブシステムが多数あります。 /sys/class/ 内の各ディレクトリはクラスであり、サブシステムでもあります。 # ls /sys/class/ ata_device extcon mdio_bus ptp サウンド ata_link gpio メモリ pwm spi_master ata_port グラフィックス その他 rc サーマル bdi hwmon mmc_host レギュレータ tty ブロック i2c アダプタ ネット rtc udc bsg i2c-dev phy scsi_device vc DMA 入力 電源 SCSI ディスク vtconsole drm leds pps scsi_host ウォッチドッグ 各クラスには、green、aaaなどの特定のインスタンス化オブジェクトがあります。
各オブジェクトには、明るさ、トリガーなどの対応するメンバーメソッド/属性があります。 # ls /sys/class/leds/aaa/ 明るさ電源トリガー max_brightness サブシステム uevent C++ のクラスにとても似ています。実際、それはクラスであり、単純な比較です 後で時間ができたら、特定のクラスでの登録ロジックをゆっくりと勉強します。ルート探索を続けます。ここで、私の探索ルートが変わったことに注意してください。もはや LED サブシステムの探索に限定されず、LED サブシステムの外側のカーネルにまで拡張され始めました。 クラスディレクトリの生成次に、クラス ディレクトリについて説明します。leds ディレクトリの取得元がわかったので、その上のクラス ディレクトリの取得元がどこなのか疑問に思います。 コードに従って クラス初期化() kset_create_and_add("class", NULL, NULL); // 構造体 kset を動的に作成し、sysfs に追加します kset_create() kobject_set_name() kset_register() kset_init() kobject_add_internal() オブジェクト取得() kobj_kset_join() kset_get() リストの末尾を追加() リストに追加() { 次->前 = 新しい; new->next = 次へ; 新しい->前 = 前; } create_dir() // ディレクトリを作成する カーネルを起動する()実際、classes_init() までトレースした後は、下のどのコードをトレースするかを考える必要はなく、上に向かってトレースを続けるだけです。 /* カーネル */ カーネルを起動する() rest_init() // 残りの非__initを実行します。これで完了です kernel_thread(kernel_init, NULL, CLONE_FS); カーネル初期化() kernel_init_freeable() /* * マシンは初期化されました。どのデバイスも *まだ触れられていないが、CPUサブシステムは起動しており、 * 実行中であり、メモリとプロセスの管理が機能します。 * * これで、ようやく実際の作業を開始できます。 */ 基本的なセットアップ() driver_init() // サブシステムを初期化します。 devtmpfs_init() デバイス初期化() バス初期化() classes_init() // 単に classes_init() ファームウェア初期化() ハイパーバイザー初期化() プラットフォームバス初期化() cpu_dev_init() メモリデバイス初期化() コンテナ_dev_init() の_core_init() 上で述べたように、私は偶然 start_kernel() を追跡し、それが夢の始まりとなりました。カーネル コードを追跡することがこんなにも興味深いものであることに初めて気付きました。 カーネルを起動しています…start_kernel() までトレースした後、この文字列「Starting kernel ...」がどこに印刷されているのか気になって仕方ありませんでした。uboot を起動するたびにこの文を見ることができます。見つけられたら素晴らしいと思いませんか?残念ながら、カーネルコード内では見つけられませんでした。 ユーブート最初はstart_kernel()でStarting kernel ...が出力されると思っていましたが、カーネルコード内には見つかりませんでした。このとき、ubbot に出力されているか気になりました。カーネルのロードを開始する前にこの文を出力するのは妥当です。 ubootで検索したら ブートジャンプLinux() アナウンスとクリーンアップ() printf("\nカーネルを開始しています...%s\n", fake ? "(トレース用の偽の実行)" : ""); ここで uboot が終了し、カーネルが実行されようとしています。 完全な通話関係を添付しますuboot からカーネルへ、そして /sys/class へ移動し、leds クラスを登録して LED ライトをインスタンス化します。 /* uboot */ ブートジャンプLinux() アナウンスとクリーンアップ() printf("\nカーネルを起動しています...%s\n"); // printf() bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF、"start_kernel"); クリーンアップ前Linux() kernel_entry(0, machid, r2); /* カーネル */ カーネルを起動する() rest_init() // 残りの非__initを実行します。これで完了です kernel_thread(kernel_init, NULL, CLONE_FS); カーネル初期化() kernel_init_freeable() /* * マシンは初期化されました。どのデバイスも *まだ触れられていないが、CPUサブシステムは起動しており、 * 実行中であり、メモリとプロセスの管理が機能します。 * * これで、ようやく実際の作業を開始できます。 */ 基本的なセットアップ() driver_init() // サブシステムを初期化します。 devtmpfs_init() デバイス初期化() バス初期化() クラス初期化() kset_create_and_add("class", NULL, NULL); // 構造体 kset を動的に作成し、sysfs に追加します kset_create() kobject_set_name() kset_register() kset_init() kobject_add_internal() オブジェクト取得() kobj_kset_join() kset_get() リストの末尾を追加() リストに追加() { 次->前 = 新しい; new->next = 次へ; 新しい->前 = 前; } ディレクトリを作成します。 ファームウェア初期化() ハイパーバイザー初期化() プラットフォームバス初期化() cpu_dev_init() メモリデバイス初期化() コンテナ_dev_init() の_core_init() subsys_initcall(leds_init); leds_init() // LED クラス (/sys/class/leds ディレクトリ) を作成します class_create() __class_create() クラスレジスタ() kset_register() led_classdev_register() of_led_classdev_register() // led_classdev クラスの新しいオブジェクトを登録します。 led_classdev_next_name() デバイス作成グループ() led_add_brightness_hw_changed() list_add_tail() // LEDのリストに追加 led_update_明るさ() //led_trigger_set_default() 人生の入り口上記は、LED サブシステムの観点から見た Linux カーネルの研究です。 Linux カーネルを研究するための入り口を見つけました。 巨大なものに直面すると、私たちはしばしば恐怖を感じます。この恐怖は私たちがさらに研究することを妨げ、その結果、私たちはその物に対する理解を欠き、それを克服することができなくなります。 2つの例:
質問、主題、スキルなどの小さなものから、仕事、生活、さらには人生全体などの大きなものまで。入り口を見つけることができれば幸運であり、それを成功とより良い未来につなげていきます。 今後とも 123WORDPRESS.COM を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
<<: MySQL IDは1から増加し始め、不連続IDの問題を素早く解決します
>>: テーブルの幅を固定して、テキストによって幅が変わらないように設定
目次1. MySQL ワイルドカード ファジー クエリ (%,_) 1-1. ワイルドカードの分類1...
<br />多くのウェブサイト デザイナーが犯す最も一般的な間違いは、ウェブページが I...
目次MVCCとはMVCC 実装MVCC はファントム リードを解決しますか? MVCCとはMVCC ...
最近、小さなプログラムを書いています。その小さなプログラムの公式ウェブサイトはhttpsを使用する必...
Linuxファイアウォールの状態を確認する方法1. 基本操作 # ファイアウォールのステータスを表示...
この記事の例では、動的な背景を実現するためのjsの具体的なコードを参考までに共有しています。具体的な...
序文MySQL テーブルの主キーと外部キーを作成するときは、次の点に注意する必要があります。主キーと...
推奨される Docker 学習教材: https://www.runoob.com/docker/d...
目次スイッチも複雑なコードブロックもありませんPythonからのインスピレーション辞書を使用してスイ...
HTML デザインパターン学習ノート今週は主にHTMLデザインパターンを学びました。学習内容をまとめ...
データベースはスロークエリログを有効にします設定ファイルを変更する設定ファイルmy.iniに次の2つ...
Linux での MySQL データベースのマスター/スレーブ同期構成の利点は、この方法をバックアッ...
Remax は、実行時に構文制限のないソリューションを採用した React を使用して小規模なプロ...
目次JSBridgeの起源JSBridgeの双方向通信原理JSはネイティブを呼び出すネイティブコール...
この記事では、LinuxシステムのVMwareインストールの具体的な手順を参考までに紹介します。具体...