1

Linux ドライバー プログラムの学習を開始しましたが、少し難しいと感じています。

私は i2c ドライバーを研究してきましたが、ドライバー プログラムのエントリ ポイントに関してかなり混乱しました。ドライバープログラムはMOUDULE_INIT()マクロで起動しますか?

また、ドライバープログラムがどのように実行されるかのプロセスを知る方法も知りたいです。Linux Device Driverという本を手に入れましたが、まだかなり混乱しています。私たちを手伝ってくれますか?どうもありがとう。

例として i2c ドライバーを取り上げます。そこには非常に多くの機能があります。i2c ドライバーで機能の調整関係を取得する方法を知りたいのですが?

4

6 に答える 6

11

main {}デバイスドライバーは、開始点と終了点を持つ「プログラム」ではありません。API、ライブラリ、またはルーチンのコレクションに似ています。この場合、それは, , おそらくおよび操作のエントリ ポイントをリストする構造体によって宣言されたエントリ ポイントのセットです。MODULE_INIT()MODULE_EXIT()EXPORT_SYMBOL()

ブロック デバイスの場合、ドライバーは、(からinclude/linux/blkdev.h)でそれらの操作の関数を宣言することにより、実行できる操作のリストを提供することが期待されます。

struct block_device_operations {
        int (*open) ();
        int (*release) ();
        int (*ioctl) ();
        int (*compat_ioctl) ();
        int (*direct_access) ();
        unsigned int (*check_events) ();
        /* ->media_changed() is DEPRECATED, use ->check_events() instead */
        int (*media_changed) ();
        void (*unlock_native_capacity) ();
        int (*revalidate_disk) ();
        int (*getgeo)();
        /* this callback is with swap_lock and sometimes page table lock held */
        void (*swap_slot_free_notify) ();
        struct module *owner;
};

char デバイスの場合、ドライバーは、(from からinclude/linux/fs.h)でそれらの操作の関数を宣言することにより、実行できる操作のリストを提供することが期待されます。

struct file_operations {
        struct module *owner;
        loff_t (*llseek) ();
        ssize_t (*read) ();
        ssize_t (*write) ();
        ssize_t (*aio_read) ();
        ssize_t (*aio_write) ();
        int (*readdir) ();
        unsigned int (*poll) ();
        long (*unlocked_ioctl) ();
        long (*compat_ioctl) ();
        int (*mmap) ();
        int (*open) ();
        int (*flush) ();
        int (*release) ();
        int (*fsync) ();
        int (*aio_fsync) ();
        int (*fasync) ();
        int (*lock) ();
        ssize_t (*sendpage) ();
        unsigned long (*get_unmapped_area)();
        int (*check_flags)();
        int (*flock) ();
        ssize_t (*splice_write)();
        ssize_t (*splice_read)();
        int (*setlease)();
        long (*fallocate)();
};

プラットフォーム デバイスの場合、ドライバーは、実行できる操作のリストを提供することが期待されます。これらの操作の関数を (からinclude/linux/platform_device.h) で宣言します。

struct platform_driver {
        int (*probe)();
        int (*remove)();
        void (*shutdown)();
        int (*suspend)();
        int (*resume)();
        struct device_driver driver;
        const struct platform_device_id *id_table;
};

ドライバー、特に char ドライバーは、リストされているすべての操作をサポートする必要はありません。構造エントリに名前を付けることで、これらの構造のコーディングを容易にするマクロがあることに注意してください。

ドライバ プログラムは MOUDLUE_INIT() マクロで開始しますか?

で指定されたドライバのinit()ルーチンは、MODULE_INIT()起動中 (静的にリンクされている場合) またはモジュールが動的にロードされている場合に呼び出されます。ドライバーは、 init()中に自身を登録するときに、操作の構造をデバイスのサブシステムに渡します。

これらのデバイス ドライバー エントリ ポイント( open()read()など) は通常、ユーザー アプリが (ユーザー空間で) C ライブラリ呼び出しを呼び出したとき、およびカーネル空間への切り替え後に実行されます。あなたが見ている i2c ドライバーは、リーフデバイスによって使用されるバスのプラットフォーム ドライバーであり、によって公開されるその関数は、他のドライバーによって呼び出されることに注意してください。EXPORT_SYMBOL()

で指定されたドライバのinit()ルーチンのみMODULE_INIT()が呼び出されることが保証されています。で指定されたドライバのexit()ルーチンMODULE_EXIT()は、モジュールが動的にアンロードされた場合にのみ実行されます。ドライバの op ルーチンは、未知の順序で (割り込みサービス ルーチンと同様に) 非同期的に呼び出されます。ユーザー プログラムがread()またはioctl()操作を発行する前にopen()を呼び出し、適切な方法で他の操作を呼び出すことを願っています。適切に作成された堅牢なドライバーは、操作の順序やシーケンスに対応し、適切な結果を生成してシステムの整合性を確保する必要があります。

于 2012-10-16T20:44:12.953 に答える
2

デバイス ドライバをプログラムと考えるのをやめるのがおそらく助けになるでしょう。それらは完全に異なります。プログラムには特定の開始点があり、いくつかのことを行い、1 つまたは複数のかなり明確に定義された (まあ、いずれにしてもそうすべきです) 終了点があります。ドライバーは、最初にロードされたときにやるべきことがいくつかあり (たとえばMODULE_INIT()、その他のもの)、二度と何かをするかもしれないし、しないかもしれません (システムが実際に持っていないハードウェアのドライバーを強制的にロードすることができます)。ドライバーがアンロードされた場合に実行する必要があるもの。それとは別に、ドライバーは通常、ユーザーランドアプリケーションがアクセスしてドライバーに何かをするように要求できる特定のエントリポイント (システムコール、ioctl など) を提供します。

恐ろしい例えですが、プログラムを車のようなものだと考えてください。乗り、始動し、どこかを運転し、降ります。ドライバーは自動販売機のようなものです。プラグを差し込んで在庫があることを確認しますが、時折人々がやって来て、ボタンを押して何かをさせるだけです。

于 2012-10-16T14:58:37.067 に答える
0

簡潔で鮮明な方法: .probe から開始し、insmod を実行するとすぐに init まで進みます。これにより、ドライバーがドライバー サブシステムに登録され、init も開始されます。ドライバー機能がユーザー アプリケーションから呼び出されるたびに、コールバックを使用して関数が呼び出されます。

于 2016-08-10T06:49:04.427 に答える
0

実際には、最初に (I2C) プラットフォーム (ネイティブ) ドライバーについて取り上げています。プラットフォーム ドライバーの MOUDULE_INIT() が他のロード可能なモジュールに対してどのように呼び出されたかを理解する必要があります。

/*
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module).  There can only
* be one per module.*/

i2c ドライバーについては、このリンクhttp://www.linuxjournal.com/article/7136および http://www.embedded-bits.co.uk/2009/i2c-in-the-2632-linux-kernelを参照できます。 /

于 2014-06-02T07:00:46.793 に答える
0

カーネルモジュールの開始は、主に関数名の直前のマクロ__initでアドレス指定される初期化関数から開始されます。

__init マクロは、次の関数が初期化関数であり、初期化関数のコードが実行されると、この初期化関数に使用されるリソースが解放されることを Linux カーネルに示します。

[上記のように] module_init() および module_exit() という名前の、初期化の検出と関数の解放に使用される他のマルコがあります。

これらの 2 つのマクロは、デバイス ドライバーが実行時にロードおよびリムーバブル カーネル モジュールとして動作するようにターゲット設定されている場合に使用されます (つまり、insmod または rmmod コマンドを使用)。

于 2016-02-29T11:56:21.050 に答える
-1

「Linux Device Driver」は良い本ですが、古いです!

基本的な例:

#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Name and e-mail");
MODULE_DESCRIPTION("my_first_driver"); 

static int __init insert_mod(void)
{
    printk(KERN_INFO "Module constructor");
    return 0;
}

static void __exit remove_mod(void)
{
    printk(KERN_INFO "Module destructor");
}

module_init(insert_mod);
module_exit(remove_mod);

非常によく書かれた最新のチュートリアルは、「Linux Device Drivers Series」です。

于 2012-10-16T15:22:17.427 に答える