【V4L2】V4L2フレームワーク-v4l2デバイス

シリーズ記事の目次

【V4L2】V4L2フレームワーク-v4l2デバイス



この記事では、v4l2_device と v4l2_subdev という 2 つのコア構造を含む、V4L2 のバックボーン構造をわかりやすく紹介します
この記事では、これら 2 つの構造に焦点を当て、
Linux-4.4 カーネルの omap3isp コードを例として使用して紹介していますが、いわゆる「導入」は依然として補助的な役割を果たしています。

以下の「ルーチン」は、omap3isp ルーチンを指します。

V4L2 フレームワークの補足

まずは写真を見てください:
ここに画像の説明を挿入します
V4L2のサブモジュール分割
これは正式な分割ではありませんが、私の感覚で分割した、そういうものです。したがって、この記事で示されているテーマは、上の図の 3 番目の「サブデバイス」であるサブデバイス システムです。写真からわかるように、この記事では主に多数の入力デバイスを管理する方法について説明します。注: 対象となるのはすべてのデバイスであり、実行時のデータ フロー パス上のデバイスではありません。


メインデバイス

メインデバイスは、v4l2_device を使用して抽象的に表現されます。このルーチンは、デバイス ツリーを使用してデバイス解析を実行し、プラットフォーム ドライバーを使用して対応するドライバー プローブを実行します。ファイルにはdrivers/media/platform/omap3isp/isp.cisp_probe 関数があります。この関数の最初のパラメータ定義は isp_device です。前の記事を思い出してください。ほとんどの場合、v4l2_device 構造体はより大きな構造体に埋め込む必要があると述べられています。ここでは、これは、カスタマイズされた構造体です。ドライバーの場合、その定義は次のようになります(解析に関係のない部分は削除されています)。

struct isp_device {
    
    
    struct v4l2_device v4l2_dev;
    struct v4l2_async_notifier notifier;
    struct media_device media_dev;

    ... ...
}

このうち、このセクションに関連するのは struct v4l2_device v4l2_dev で、一連の omap3isp 全体のマネージャーとして機能します。

同時に、その使用法は上記の「埋め込み」と一致します。構造体 isp_device はドライバー定義の構造体です。この構造体は、omap3isp 全体のデバイス抽象化構造体と見なすことができます。つまり、次のことを表します。の大型装置。以下にその使い方を示します。

v4l2_device を登録する

isp.c の isp_probe 関数の中に call 関数がありisp_register_entities、その冒頭の内容はおおよそ以下のとおりです。

... ...
    isp->v4l2_dev.mdev = &isp->media_dev;
    ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
    if (ret < 0) {
    
    
        dev_err(isp->dev, "%s: V4L2 device registration failed (%d)\n",
            __func__, ret);
        goto done;
    }
... ...

実際、登録関数はハイエンド デバイスをリンク リストに追加するのではなく、サブデバイスのリンク リストのヘッダーの初期化、dev への参照の追加など、構造メンバーを初期化することがわかります。すべてのサブデバイスを直列に接続する前に、v4l2_deviceまずデバイス全体を初期化して登録する必要があります。

v4l2_subdev

この構造は抽象的なサブデバイスであり、サブデバイスの管理に使用されます。「初期化」、「サブデバイスの登録」、「サブデバイスノードの登録」などのいくつかの操作があります。通常、「初期化」関数インスタンスは各サブデバイス ドライバー モジュール内で定義され、次のような 2 つの関数「サブデバイスの登録」および「サブデバイス ノードの登録」のエンティティは親デバイス モジュール内で定義されます。 isp .c インチ

上記のコード (isp_probe 関数内):

ret = isp_initialize_modules(isp);
if (ret < 0)
    goto error_iommu;
ret = isp_register_entities(isp);
if (ret < 0)
    goto error_modules;

まずisp_initialize_modules関数の実装を見てみましょう。

static int isp_initialize_modules(struct isp_device *isp)
{
    
    
    int ret;

    ret = omap3isp_csiphy_init(isp);

    ret = omap3isp_csi2_init(isp);

... ...

    ret = omap3isp_h3a_aewb_init(isp);

    ret = omap3isp_h3a_af_init(isp);
... ...
    return 0;
... ...

次に、関数に移動するomap3isp_xxxx_initと、同様の関数呼び出しがあることがわかりますv4l2_subdev_init。この記事では、できるだけ少ないコードを貼り付けるよう努めており、実装と使用メカニズムについて詳しく説明しています。関連するコードは自分で見つけることができると思います。 。

したがって、構造はおおよそ次のようになります。

  1. 入力デバイス omap3isp があり、そのマネージャーは isp.c という別のコード ファイルにリストされています。

  2. isp_device という名前の omap3isp デバイスを表すカスタム抽象構造を定義し、v4l2_device をサブデバイス管理ツールとして埋め込みます。

  3. 抽象サブデバイス - サブデバイスへの csi、プレビュー、3a などに似ています。各サブデバイスには ispxxx.c という名前のコード ファイルがあります。各サブデバイスには isp_xxx_dev という名前の独自の抽象構造があり、v4l2_subdev が埋め込まれていますサブデバイスとして内部的にデバイス抽象ツールの使用法。同時に、xxx_init_eneities という名前の独自のデバイス初期化関数を実装します。

  4. マネージャー isp.c のプローブ関数でサブデバイスの xxx_init_entities を呼び出すと、サブデバイス初期化関数が v4l2_subdev の初期化を実行します。

  5. 必要に応じて、マネージャーのプローブ関数に v4l2_device を登録し、サブデバイスを登録し、サブデバイス ノードを登録してユーザー空間に /dev/nodeX を生成します。

  6. これで、v4l2_device を通じてすべてのサブデバイスを管理できるようになります。フレームワーク自体は、非常に便利な管理メソッドと関連するコールバック関数、構造体メンバーなどを提供します。

設備管理

デバイスを管理するには、必然的にメインデバイスとサブデバイスの相互接続と相互運用が必要になりますが、そうでないと管理の方法がありません。ここでは、メインデバイスとサブデバイスの間でデータの相互接続と相互運用を実現する方法を紹介します。 -デバイス。

メインデバイスとサブデバイスの相互運用性

上記の手順で接続を確立した後、メインデバイスからサブデバイスを見つけるにはどうすればよいですか? サブデバイスからマスターデバイスを見つけるにはどうすればよいですか? v4l2_device からカスタムのメインデバイス抽象構造に到達するにはどうすればよいですか? v4l2_subdev からサブデバイスのカスタム構造に移動するにはどうすればよいですか?

  • メイン デバイスからサブデバイスを検索する方法。まず、v4l2_device 構造体を取得する必要があります。次に、list_for_each_entry を使用してサブデバイスを横断できます。サブデバイス構造体内には、長さ 32 の name メンバーがあります。バイト。このフィールドは v4l2_device 全体である必要があります。これは下位デバイス間で一意であるため、指定したサブデバイスを見つけたい場合は、トラバーサル中にサブデバイスの名前フィールドを比較して、それが目的のものであるかどうかを確認できます。見つけたいです。

  • サブデバイスからメインデバイスを見つける方法 v4l2_subdev 構造体には v4l2_dev ポインター メンバーがあり、サブデバイスの登録時に v4l2_device メンバーを指します。登録関数は v4l2_device_register_subdev です。この手順が完了すると、サブデバイス構造内の v4l2_dev メンバーを取得することで、メイン デバイス構造を取得できます。

  • マスター デバイスからマスター デバイスへ構造体をインスタンス化するにはどうすればよいですか? v4l2_device 内にプライベート ポインターがないことがわかります。次にマスター デバイスのインスタンス化構造体を見つける方法です。このとき、別のパーシャル メソッドを通じて取得できます。たとえば、構造体を定義するときに、構造体の最初のメンバーに v4l2_device を配置し、v4l2_subdev を介して v4l2_device を取得した後、そのアドレスをマスター デバイスによってカスタマイズされたインスタンス化された構造体に強制的に挿入してアクセスを実現できます。

  • サブデバイスからサブデバイスへ構造体をインスタンス化する方法 サブデバイス内には 2 つのプライベート ポインター (dev_priv、host_priv) があります。前者は理解しやすく、使いやすく、使用する場合は、v4l2_set_subdevdatadev_priv をサブデバイスのインスタンス化構造体にポイントする関数を呼び出し、それを使用してv4l2_get_subdevdatav4l2_subdev からサブデバイスのインスタンス化構造体の構造体データを取得します。後者は使い方が分かりにくいですが、v4l2_set_subdev_hostdata/v4l2_get_subdev_hostdata設定・取得も可能です ホストもメインの制御端です たとえばカメラセンサーのSOC側のコントローラーをメインとして使用することもできます別の例としては、通信に I2C を使用するカメラがあり、センサーの SOC 側の I2C コントローラーを host_priv として使用し、必要に応じて I2C を通じてサブデバイスの動作を制御できます。または、メイン デバイスによってインスタンス化された構造をホスト データとして単純に使用することもできます。

マスターとサブデバイス間の情報交換

このセクションでは、複数の実際的な使用例を使用して、さまざまな情報交換方法とシナリオについて詳しく説明します。例: 特定のタイプのサブデバイスへのアクセスを制御するにはどうすればよいですか? 子デバイスはどのようにしてマスターデバイスに通知を返すのでしょうか?

  • すべてのセンサー デバイスにアクセスし、そのデータ フローを閉じる
  1. サブデバイスを登録する際には、関連する操作関数 (v4l2_subdev_ops 構造体) を提供する必要があります。この例では、video メンバーの s_stream メンバーのみを設定します。

  2. v4l2_subdev の grp_id メンバーであるサブデバイス グループ ID を指定します。ここでは、それを想定した列挙型に設定します (この列挙型が v4l2_device 下位全体に対して一意であることだけを確認する必要があります)。OMAP3ISP_CAMSENSOR であるとします。

  3. サブデバイスの初期化と登録方法については、前述したので説明を省略します。

  4. v4l2_device_call_all(v4l2_device, OMAP3ISP_CAMSENSOR, video, s_stream, 0) を実行します。この時点で、v4l2_device という名前で OMAP3ISP_CAMSENSOR グループのすべてのサブデバイスを走査し、その s_stream モジュール関数を呼び出してデータ ストリームを閉じます。

  • サブデバイスのデータ フローが閉じられた後、通知がメイン デバイスに返されます。
  1. 本体装置の会員通知操作機能を備える必要がある。

  2. 通知フォーマットを定義します (独自の定義など)。上位 8 ビットはどのサブデバイスを示し、2 番目の 8 ビットは操作のタイプ (ここではビデオ タイプ ops) を示し、3 番目の 8 ビットは特定の操作機能を示します ( s_stream).の下位8ビットが演算値を表します(0はオフ)。

  3. サブデバイスは v4l2_subdev_notify 関数を呼び出して正式な通知を送信します。このとき、いくつかのパラメータも受け取ることができます。アドレスを渡すだけで済みます。メインデバイス側とサブデバイス側はデータの形式に同意します。

  4. メインデバイスは通知を受信した後、関連する動作を実行します。

交通ハブ video_device

この構造は、データフロー管理の端末モジュール機能を統合し、カーネル空間からユーザー空間へのデータ交換を提供する役割を果たしており、非常に重要で不可欠な機能です。

通常、すべてのサブデバイスは video_device 構造体を登録して、ユーザーが操作できるデバイス ノードをユーザー空間に生成できますが、違いは、ビデオ データの実際の送信を担当するモジュールのみがビデオ タイプのデバイス ノード名を登録する必要があることです (たとえば、カーネル入力デバイス データ リンクの DMA データ端末)、その他のものは v4l-subdev タイプを使用できます。

video_device は v4l2_device にのみバインドおよび関連付けられており、これを介してサブデバイス ネットワーク全体のリソースにアクセスできます。

ビデオタイプノードの登録方法

video_register_deviceパラメータを付けて登録するVFL_TYPE_GRABBERと、関数が実行されてリターンすると、/dev/videoXユーザー空間にデバイスノードが表示されます。

次のような操作関数を提供する必要があることに注意してください。

static struct v4l2_file_operations isp_video_fops = {
    
    
    .owner = THIS_MODULE,
    .unlocked_ioctl = video_ioctl2,
    .open = isp_video_open,
    .release = isp_video_release,
    .poll = isp_video_poll,
    .mmap = isp_video_mmap,
};

このセクションでは、メンバーがどのように実装しているかについては詳しく紹介しませんが、後の記事videobuf2で詳しく紹介します。

他のタイプのノードを登録する方法

v4l2 入力デバイスの場合、バッチ デバイス ノード登録を実行するために使用されます。内部的には関数がv4l2_device_register_subdev_nodes呼び出されますが、タイプを使用して上記を置き換えます。その場合、ユーザー空間で生成されるデバイス ノード名は v4l- ですvideo_register_deviceVFL_TYPE_SUBDEVVFL_TYPE_GRABBERsubdevX

この場合、登録されたデバイスノードの動作機能は、v4l2-device.c で定義されているデフォルトの動作機能となり、その定義は以下のとおりです。

const struct v4l2_file_operations v4l2_subdev_fops = {
    
    
    .owner = THIS_MODULE,
    .open = subdev_open,
    .unlocked_ioctl = subdev_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl32 = subdev_compat_ioctl32,
#endif
    .release = subdev_close,
    .poll = subdev_poll,
};

結論

ここまでは基本的に機器の基本操作を紹介しましたが、より高度な操作については次回以降に紹介していきます。プレビューとして、次の記事ではメディア フレームワークについて段階的に説明します。この記事を読んで実践すると、ユーザー空間に /dev/video デバイス ノードがあることがわかります。小さなテスト ケースを作成できます。デバイス ノードを開くと、サブデバイスを走査し、サブデバイスの名前。さらに詳細な情報を追加することもできます。つまり、この記事の目的は、v4l2_device 管理フレームワークの下でデバイス トポロジを実装することです。このトポロジを印刷して、タスクを完全に完了することができます。

おすすめ

転載: blog.csdn.net/qq_44710568/article/details/132605425