UVCカメラドライバ(ⅲ)カメラを設定し、リアルタイムのデータ取得

USBカメラのハードウェアモデルと記述UVCカメラの前分析、内部が略VCインタフェースとVSのインターフェースに分け、VC内部インタフェースが「制御」に多くのユニットと端子を有するカメラ、例えば、我々はできますホワイトバランス、露出等の設定処理ユニット。インタフェースVSのために、含むVS標準インターフェースは、しばしば、それらが同一のエンドポイントアドレスであってもよいが、各セットは、リアルタイムトランスポートエンドポイントが含まれ、多くの設定が含まれ、それらは異なる最大送信パケットサイズ、インタフェースVS特定のクラスを持っています複数のフォーマット、複数のフォーマットのフレームを含む各々は、フォーマットYUYV MJPGは、フレーム480は、解像度640 * 320 480の様々な等である、などを意味します。これらの情報は、記述子を分析することによって得られます。
 

VideoStreaming要求

  参考UVC 1.5クラス仕様4.3 
ここで説明する絵を書きます

我々は、伝送および通信VS、プローブを制御すると、図を参照して、要求フォーマットを提供コミット必要とします。

bmRequestTypeの要求タイプ、参照標準USBプロトコル
一覧bRequestサブクラス8-Aは、表に定義され
、CS、制御セレクタは、表A-16に定義され、例えば、プローブまたはコミット
wIndexが上位バイトがゼロである、低バイトインタフェース番号
wLengthのとデータは、標準のUSBプロトコル、データ長およびデータのような
、以下に示すようにパラメータ設定手順を交渉するホストとUSBデバイスを必要とする、ネゴシエーションプロセスは、実質的に: 
 

USBデバイスに送信される最初の所望の設定をホスト(プローブ)
デバイスは、所望の設定は、独自の能力の範囲内で変更することができるホストする、ホストに戻る(PROBE)
ホスト(COMMIT)提出をコミットし、実行可能な設定と考え
Setインタフェースが現在設定されています1セット 
   
あなたが交渉するどのようなデータ?これらのデータは、場所を定義しますか?フレームフレームのフレーム周波数、最初の送信パケットサイズ、等が含ま使用リファレンス表4-75、。 
参照コード:
 

静的INT myuvc_try_streaming_params(構造体myuvc_streaming_control * CTRL)
{
    __u8 *データ。
    __u16サイズ;
    int型のRET;
    __u8タイプ= USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int型のパイプ。

    memsetの(Ctrlを押しながら、0、sizeof演算子* CTRL)。

    CTRL-> bmHint = 1。/ * dwFrameInterval * /
    CTRL-> bFormatIndex = 1。
    CTRL-> bFrameIndex = 1。
    CTRL-> dwFrameInterval = 333333;
    CTRL-> dwClockFrequency = 48000000;
    CTRL-> wCompQuality = 61。
    サイズ= 34。
    データ= kzalloc(サイズ、GFP_KERNEL)。
    (データ== NULL)の場合
        、戻り-ENOMEM。

    *(__ le16の*)&データ[0] = cpu_to_le16(CTRL-> bmHint)。
    データ[2] = CTRL-> bFormatIndex。
    データ[3] = CTRL-> bFrameIndex。
    *(__ le32の*)&データ[4] = cpu_to_le32(CTRL-> dwFrameInterval)。
    *(__ le16の*)&データ[8] = cpu_to_le16(CTRL-> wKeyFrameRate)。
    *(__ le16の*)&データ[10] = cpu_to_le16(CTRL-> wPFrameRate)。
    *(__ le16の*)&データ[12] = cpu_to_le16(CTRL-> wCompQuality)。
    *(__ le16の*)&データ[14] = cpu_to_le16(CTRL-> wCompWindowSize)。
    *(__ le16の*)&データ[16] = cpu_to_le16(CTRL-> wDelay)。
    put_unaligned_le32(CTRL-> dwMaxVideoFrameSize、&データ[18])。
    put_unaligned_le32(CTRL-> dwMaxPayloadTransferSize、&データ[22])。

    IF(サイズ== 34){
        put_unaligned_le32(CTRL-> dwClockFrequency、&データ[26])。
        データ[30] = CTRL-> bmFramingInfo。
        データ[31] = CTRL-> bPreferedVersion。
        データ[32] = CTRL-> bMinVersion。
        データ[33] = CTRL-> bMaxVersion。
    }

    パイプ= usb_sndctrlpipe(myuvc_udev、0);
    タイプ| = USB_DIR_OUT。

    RET = usb_control_msg(myuvc_udev、パイプ、0x01の、タイプ、0x01の<< 8、
            0 << 8 | myuvc_streaming_intf、データ、サイズ、5000)。

    kfree(日付);

    リターン(右<0)?右:0;
}

静的INT myuvc_get_streaming_params(構造体myuvc_streaming_control * CTRL)
{
    __u8 *データ。
    __u16サイズ;
    int型のRET;
    __u8タイプ= USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int型のパイプ。

    サイズ= 34。
    データ= kmallocの(サイズ、GFP_KERNEL)。
    (データ== NULL)の場合
        、戻り-ENOMEM。

    パイプ= usb_rcvctrlpipe(myuvc_udev、0);
    タイプ| = USB_DIR_IN。

    RET = usb_control_msg(myuvc_udev、パイプ、0x81と、タイプ、0x01の<< 8、
            0 << 8 | myuvc_streaming_intf、データ、サイズ、5000)。

    (RET <0)場合
        後藤行います。

    CTRL-> bmHint = le16_to_cpup((__ le16の*)&データ[0])。
    CTRL-> bFormatIndex =データ[2]。
    CTRL-> bFrameIndex =データ[3]。
    CTRL-> dwFrameInterval = le32_to_cpup((__ le32の*)&データ[4])。
    CTRL-> wKeyFrameRate = le16_to_cpup((__ le16の*)&データ[8])。
    CTRL-> wPFrameRate = le16_to_cpup((__ le16 *)&データ[10])。
    CTRL-> wCompQuality = le16_to_cpup((__ le16 *)&データ[12])。
    CTRL-> wCompWindowSize = le16_to_cpup((__ le16 *)&データ[14])。
    CTRL-> wDelay = le16_to_cpup((__ le16 *)&データ[16])。
    CTRL-> dwMaxVideoFrameSize = get_unaligned_le32(&データ[18])。
    CTRL-> dwMaxPayloadTransferSize = get_unaligned_le32(&データ[22])。

    (サイズ== 34){もし
        CTRL-> dwClockFrequency = get_unaligned_le32(&データ[26])。
        CTRL-> bmFramingInfo =データ[30]。
        CTRL-> bPreferedVersion =データ[31]。
        CTRL-> bMinVersion =データ[32]。
        CTRL-> bMaxVersion =データ[33]。
    }他{
        // CTRL-> dwClockFrequency =ビデオ- > DEV-> clock_frequency。
        CTRL-> bmFramingInfo = 0;
        CTRL-> bPreferedVersion = 0;
        CTRL-> bMinVersion = 0;
        CTRL-> bMaxVersion = 0;
    }

行わ:
    kfree(データ);

    リターン(右<0)?右:0;
}

静的INT myuvc_set_streaming_params(構造体myuvc_streaming_control * CTRL)
{
    __u8 *データ。
    __u16サイズ;
    int型のRET;
    __u8タイプ= USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int型のパイプ。

    サイズ= 34。
    データ= kzalloc(サイズ、GFP_KERNEL)。
    (データ== NULL)の場合
        、戻り-ENOMEM。

    *(__ le16の*)&データ[0] = cpu_to_le16(CTRL-> bmHint)。
    データ[2] = CTRL-> bFormatIndex。
    データ[3] = CTRL-> bFrameIndex。
    *(__ le32の*)&データ[4] = cpu_to_le32(CTRL-> dwFrameInterval)。
    *(__ le16の*)&データ[8] = cpu_to_le16(CTRL-> wKeyFrameRate)。
    *(__ le16の*)&データ[10] = cpu_to_le16(CTRL-> wPFrameRate)。
    *(__ le16の*)&データ[12] = cpu_to_le16(CTRL-> wCompQuality)。
    *(__ le16の*)&データ[14] = cpu_to_le16(CTRL-> wCompWindowSize)。
    *(__ le16の*)&データ[16] = cpu_to_le16(CTRL-> wDelay)。
    put_unaligned_le32(CTRL-> dwMaxVideoFrameSize、&データ[18])。
    put_unaligned_le32(CTRL-> dwMaxPayloadTransferSize、&データ[22])。

    IF(サイズ== 34){
        put_unaligned_le32(CTRL-> dwClockFrequency、&データ[26])。
        データ[30] = CTRL-> bmFramingInfo。
        データ[31] = CTRL-> bPreferedVersion。
        データ[32] = CTRL-> bMinVersion。
        データ[33] = CTRL-> bMaxVersion。
    }

    パイプ= usb_sndctrlpipe(myuvc_udev、0);
    タイプ| = USB_DIR_OUT。

    RET = usb_control_msg(myuvc_udev、パイプ、0x01の、タイプ、0x02の<< 8、
            0 << 8 | myuvc_streaming_intf、データ、サイズ、5000)。

    kfree(日付);

    リターン(右<0)?右:0;

}

VideoControlは要求
  ここでは、処理ユニット制御におけるVCのインターフェイスは、例えば、明るさを要求分析: 
 


静的ボイドmyuvc_set_le_value(__ S32値、__u8 *データ)
{
    int型ビット= 16。
    = 0のオフセットint型。
    __u8マスク。

    データは+ = / 8オフセット。
    オフセット&= 7。

    以下のために(;ビット> 0;データ++){
        マスク=((1LL <<ビット) - 1)<<オフセット。
        *データ=(*データ&〜マスク)| ((値<<オフセット)&マスク);
        値は>> =オフセット?オフセット:8;
        ビット- = 8 -オフセット。
        = 0をオフセット。
    }
}

静的__s32のmyuvc_get_le_value(CONST __u8 *データ)
{
    int型ビット= 16。
    = 0のオフセットint型。
    __s32値= 0。
    __u8マスク。

    データは+ = / 8オフセット。
    オフセット&= 7。
    ((1LL <<ビット) - 1)=マスク<<オフセット。

    用(;ビット> 0;データ++){
        __u8バイト= *データ&マスク。
        値| => 0のオフセット?(バイト>>オフセット):(バイト<<(-offset));
        ビット- = 8 - (オフセット> 0をオフセット:0?)。
        オフセット- = 8。
        =(1 <<ビット)をマスク- 1。
    }

    / *符号拡張値を必要に応じて。* /
    値| = - (値&(1 <<(15 - 1)))。

    値を返します。
}

/ *参考:uvc_query_v4l2_ctrl * /    
int型myuvc_vidioc_queryctrl(構造体ファイル*ファイル、void *型FH、
                構造体v4l2_queryctrl * CTRL)
{
    __u8タイプ= USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int型のパイプ。
    int型のRET;
    U8データ[2]。

    (!CTRL-> ID = V4L2_CID_BRIGHTNESS)の場合
        -EINVALを返します。

    memsetの(Ctrlを押しながら、0、sizeof演算子* CTRL)。
    CTRL-> ID = V4L2_CID_BRIGHTNESS。
    CTRL-> = V4L2_CTRL_TYPE_INTEGERを入力します。
    strcpyの(CTRL->名、 "MyUVC_BRIGHTNESS");
    CTRL->フラグ= 0;

    パイプ= usb_rcvctrlpipe(udevの、0);
    タイプ| = USB_DIR_IN。

    / *これらの値は、USBを開始することが決定されている* /
    RET = usb_control_msg(udevに、パイプ、GET_MIN、タイプ、PU_BRIGHTNESS_CONTROL << 8、。
            ProcessingUnitID 8 << | myuvc_control_intf、データ、2、5000);
    IF(!RET = 2)
        に戻ります- EIO;
    はCtrl->最小= myuvc_get_le_value(データ); / * *注符合/


    RET = usb_control_msg(udevの、パイプ、GET_MAX、タイプ、PU_BRIGHTNESS_CONTROL << 8、
            ProcessingUnitID << 8 | myuvc_control_intf、データ、2、5000)。
    (RET = 2!)であれば
        -EIOを返します。
    CTRL->最大= myuvc_get_le_value(データ)。/ *注符号の有無* /

    RET = usb_control_msg(udevの、パイプ、GET_RES、タイプ、PU_BRIGHTNESS_CONTROL << 8、
             ProcessingUnitID << 8 | myuvc_control_intf、データ、2、5000)。
    (RET = 2!)であれば
        -EIOを返します。
    CTRL->ステップ= myuvc_get_le_value(データ)。/ *注符号の有無* /

    RET = usb_control_msg(udevの、パイプ、GET_DEF、タイプ、PU_BRIGHTNESS_CONTROL << 8、
            ProcessingUnitID << 8 | myuvc_control_intf、データ、2、5000)。
    (RET = 2!)であれば
        -EIOを返します。
    CTRL-> DEFAULT_VALUE = myuvc_get_le_value(データ)。/ *注符号の有無* /

    printk( "明るさ:最小=%D、最大=%D、ステップ=%D、デフォルト=%d個の\ n"、CTRL->最小、CTRL->最大、CTRL->ステップ、CTRL-> DEFAULT_VALUE)。

    0を返します。
}

/ *参考:uvc_ctrl_get * /
int型myuvc_vidioc_g_ctrl(構造体ファイル*ファイル、void *型FH、
                構造体v4l2_control * CTRL)
{
    __u8タイプ= USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int型のパイプ。
    int型のRET;
    U8データ[2]。

    (!CTRL-> ID = V4L2_CID_BRIGHTNESS)の場合
        -EINVALを返します。

    パイプ= usb_rcvctrlpipe(udevの、0);
    タイプ| = USB_DIR_IN。

    RET = usb_control_msg(udevの、パイプ、GET_CUR、タイプ、PU_BRIGHTNESS_CONTROL << 8、
            ProcessingUnitID << 8 | myuvc_control_intf、データ、2、5000)。
    (RET = 2!)であれば
        -EIOを返します。
    CTRL->値= myuvc_get_le_value(データ)。/ *注符号の有無* /

    0を返します。
}

/ *参考:uvc_ctrl_set / uvc_ctrl_commit * /
int型myuvc_vidioc_s_ctrl(構造体ファイル*ファイル、void *型FH、
                構造体v4l2_control * CTRL)
{
    __u8タイプ= USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int型のパイプ。
    int型のRET;
    U8データ[2]。

    (!CTRL-> ID = V4L2_CID_BRIGHTNESS)の場合
        -EINVALを返します。

    myuvc_set_le_value(CTRL->値、データ)。

    パイプ= usb_sndctrlpipe(udevの、0);
    タイプ| = USB_DIR_OUT。

    RET = usb_control_msg(udevの、パイプ、SET_CUR、タイプ、PU_BRIGHTNESS_CONTROL << 8、
            ProcessingUnitID << 8 | myuvc_control_intf、データ、2、5000)。
    (RET = 2!)であれば
        -EIOを返します。

    0リターン;
}


データ取得
  データ取得、我々はVS標準リアルタイムデータ収集、分配、集合、その後URBに設けられた通信インターフェースを終了する必要があります。 
  私のトランスミッション撮像初めて例えば640×320解像度の画像は、各画素16ビットなので、画像空間640×320×2バイト、3060バイト。バッファ32 URB UVC規格の最大数を制限するカメラドライバでなお、ので、データはURB 3060 * 32のように実施することができる、複数の画像データは、URBを送信する必要がある、計算されました。そのため、ユーザ空間バッファは、それは二つの画像内の1つのURBデータへの画像データのコピー中に含めることができる、あなたは、画像データの損失につながること、画像データの第2フレームが破棄される前に処理置く必要はありません。

静的INT myuvc_alloc_init_urbs(ボイド)
{
    U16のPSIZE。
    U32サイズ;
    int型npackets;
    int型I、J。
    構造体URB * URB。
    //構造体URB * URB。

    PSIZE = 3060;バイトの/ *最大数は、トランスポートエンドポイント* /へリアルタイムに送信することができる
    最大データ* /の/ *長さ;サイズ= 614400
    npackets = DIV_ROUND_UP(サイズ、PSIZE);
    IF(npackets> 32)
        npackets = 32;
    myprintk( "D npackets PSIZE%D%\ N-"、PSIZE、npackets);
    サイズ= PSIZE * npackets;
    のための(I = 0;私は<5; Iは++){ 
        / * * 1分配usb_buffers /
        urb_buffer [I] = usb_alloc_coherent(
            myuvc_udev、サイズ、
            GFP_KERNEL | __GFP_NOWARN、&urb_dma [I])。

        / * 2分配URB * /
        myurb [I] = usb_alloc_urb(npackets、GFP_KERNEL)。

        もし(urb_buffer [I] || myurb [i]が!!)
        {
            // myuvc_uninit_urbs();
            myprintk( "ALLOCバッファ又はURBがn \失敗")。
            -ENOMEMを返します。
        }
    }

    / * 3设置URB * / 
    用(i = 0; iは5 '; ++ I){
        URB = myurb [I]。
        urb-> DEV = myuvc_udev。
        urb->コンテキスト= NULL;
        urb->パイプ= usb_rcvisocpipe(myuvc_udev、0x81と)。
        urb-> transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
        urb->間隔= 1。
        urb-> transfer_buffer = urb_buffer [I]。
        urb-> transfer_dma = urb_dma [I]。
        urb->完全= myuvc_video_complete。
        urb-> number_of_packets = npackets。
        urb-> transfer_buffer_length =サイズ;

        (; J、J = 0 <npackets; ++ J){
            urb-> iso_frame_desc [J] .offset = J *のPSIZE。
            urb-> iso_frame_desc [J] .LENGTH = PSIZE。
        }
    }  
    0を返します。
}

静的ボイドmyuvc_video_complete(構造体URB * URB)
{
    U8 * SRC。
    // U8 * DEST。
    int型のRET、I。
    int型のlen;
    int型のmaxlen;
// int型nバイト。
//構造体myuvc_buffer * BUF。
    myprintk( "ビデオ完全な\ nを");
    スイッチ(urb->ステータス){
    ケース0:
        ブレーク。

    デフォルト:
        myprintk( "ビデオでの非ゼロのステータス(%d)は、"
            。完了ハンドラ"\ n"は、urb->状態)。
        返します。
    }

    {(; I <urb-> number_of_packets ++ I I = 0)のための
        IF(urb-> iso_frame_desc [I] .status <0){
            myprintk( "USBアイソクロナスフレームが"
                。 "(%D)\ n"を失いました、urb-> iso_frame_desc [I] .status)。
            持続する;
        }

        SRC = urb-> transfer_buffer + urb-> iso_frame_desc [I] .offset。

        // DEST = myuvc_queue.mem + buf-> buf.m.offset + buf-> buf.bytesused。

        urb- = LEN> iso_frame_desc [I] .actual_length;
        myprintk( "LEN%D \ N-"、urb-> iso_frame_desc [I]は.actual_length);
        / * * /データが有効であるかどうかを判断する
        / * URBデータの意味:
         * DATA [ 0]:ヘッダ長
         *データ[1]:エラーステータス
         * /
        IF(SRC || SRC [0] <2 || LEN <2 [0]> LEN)
            続けます。

        / *エラービット(「エラーフレーム」)でマークされたペイロードをスキップします。* /
        IF(SRC [1]&UVC_STREAM_ERR){
            myprintk( ")ペイロード(エラービットセットを削除する\ n");
            持続する;
        }

        / *ヘッド後のデータ長が除去された* /
        LEN - SRC = [0]。

        / *バッファも格納することができる数のデータ* /
        // MAXLEN = BUF - > buf.lengthする- BUF - > buf.bytesused;
        // nバイト=分(LEN、MAXLEN)を、

        / *コピーデータ* /
        //のmemcpy(DEST、SRC SRC + [0]、nバイト);
        //buf->buf.bytesused + = nバイト。

        / * / 1フレームの全てのデータが受信されたか否かが判断される
        {IF(LEN> MAXLEN)
            - >状態= VIDEOBUF_DONE // BUF;
        }

        / *マークEOFマーカーが設定されている場合に行われるよう、バッファ。* /
        (SRC [1]&UVC_STREAM_EOF){もし
            myprintk( "フレーム完全(EOF見出さ)\ n");
            IF(LEN == 0)
                myprintk( "空のペイロードにおけるEOF \ n");
            // buf->状態= VIDEOBUF_DONE。
        }

    }

    / *再提出のURB * /


    IF((RET = usb_submit_urb(URB、GFP_ATOMIC))<0){
        myprintk( "ビデオURBを再送信に失敗しました(%D)\ n"は、RET)。
    }
}
--------------------- 
 

おすすめ

転載: blog.csdn.net/u010783226/article/details/93299554