乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Android設(shè)備驅(qū)動之--v4l2

       WUCANADA 2016-09-01
      Video for Linux Two
                
                 V4L2的是V4L的第二個版本。原來的V4L被引入到Linux內(nèi)核2.1.x的開發(fā)周期後期。Video4Linux2修正了一些設(shè)計缺陷,並開始出現(xiàn)在2.5.X內(nèi)核。Video4Linux2驅(qū)動程序包括Video4Linux1應(yīng)用的兼容模式,但實際上,支持是不完整的,並建議V4L2的設(shè)備使用V4L2的模式?,F(xiàn)在,該項目的DVB-Wiki托管在LinuxTV的網(wǎng)站上。

              要想了解 V4l2 有幾個重要的文檔是必須要讀的,Documentation/video4linux目錄下的V4L2-framework.txt和videobuf、V4L2的官方API文檔V4L2 API Specification 、drivers/media/video目錄下的vivi.c(虛擬視頻驅(qū)動程序 -此代碼模擬一個真正的視頻設(shè)備V4L2 API)。


              V4l2可以支持多種設(shè)備,它可以有以下幾種接口:

               1. 視頻采集接口(video capture interface):這種應(yīng)用的設(shè)備可以是高頻頭或者攝像頭.V4L2的最初設(shè)計就是應(yīng)用於這種功能的.

               2. 視頻輸出接口(video output interface):可以驅(qū)動計算機(jī)的外圍視頻圖像設(shè)備--像可以輸出電視信號格式的設(shè)備.

               3. 直接傳輸視頻接口(video overlay interface):它的主要工作是把從視頻采集設(shè)備采集過來的信號直接輸出到輸出設(shè)備之上,而不用經(jīng)過系統(tǒng)的CPU.

               4. 視頻間隔消隱信號接口(VBI interface):它可以使應(yīng)用可以訪問傳輸消隱期的視頻信號.

               5. 收音機(jī)接口(radio interface):可用來處理從AM或FM高頻頭設(shè)備接收來的音頻流.

      V4L2 驅(qū)動核心

               V4L2 的驅(qū)動源碼在 drivers/media/video目錄下,主要核心代碼有:
                    v4l2-dev.c                  //linux版本2視頻捕捉接口,主要結(jié)構(gòu)體 video_device 的注冊
       
                    v4l2-common.c        //在Linux操作系統(tǒng)體系采用低級別的操作一套設(shè)備structures/vectors的通用視頻設(shè)備接口。
                                        //此文件將替換videodev.c的文件配備常規(guī)的內(nèi)核分配。

                    v4l2-device.c            //V4L2的設(shè)備支持。注冊v4l2_device
       
                    v4l22-ioctl.c             //處理V4L2的ioctl命令的一個通用的框架。
                          
                    v4l2-subdev.c          //v4l2子設(shè)備
       
                    v4l2-mem2mem.c  //內(nèi)存到內(nèi)存為Linux和videobuf視頻設(shè)備的框架。設(shè)備的輔助函數(shù),使用其源和目的地videobuf緩沖區(qū)。

         頭文件linux/videodev2.h、media/v4l2-common.h、media/v4l2-device.h、media/v4l2-ioctl.h、media/v4l2-dev.h、media/v4l2-ioctl.h等。


      V4l2相關(guān)結(jié)構(gòu)體

       1.V4l2_device

       struct V4l2_device{

            /* DEV-> driver_data指向這個結(jié)構(gòu)。 注:DEV可能是空的,如果沒有父設(shè)備是如同ISA設(shè)備。 */
            struct device *dev;
           /* 用於跟蹤注冊的subdevs */
          struct list_head subdevs;
          /*鎖定此結(jié)構(gòu)體;可以使用的驅(qū)動程序以及如果這個結(jié)構(gòu)嵌入到一個更大的結(jié)構(gòu)。 */
          spinlock_t lock;
          /* 獨特的設(shè)備名稱,默認(rèn)情況下,驅(qū)動程序姓名+總線ID */
          char name[V4L2_DEVICE_NAME_SIZE];
         /*報告由一些子設(shè)備調(diào)用的回調(diào)函數(shù)。 */
           void (*notify)(struct v4l2_subdev *sd,
           unsigned int notification, void *arg);
      };

      v4l2_device注冊和注銷      
          
             v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);   

           第一個參數(shù)‘dev’通常是一個pci_dev的struct device的指針,但它是ISA設(shè)備或一個設(shè)備創(chuàng)建多個PCI設(shè)備時這是罕見的DEV為NULL,因此makingit不可能聯(lián)想到一個特定的父母v4l2_dev。 您也可以提供一個notify()回調(diào)子設(shè)備,可以通過調(diào)用通知你的事件。取決於你是否需要設(shè)置子設(shè)備。一個子設(shè)備支持的任何通知必須在頭文件中定義 .
         
          注冊時將初始化 v4l2_device 結(jié)構(gòu)體. 如果 dev->driver_data字段是空, 它將連接到 v4l2_dev.

             v4l2_device_unregister(struct v4l2_device *v4l2_dev);
               
          注銷也將自動注銷設(shè)備所有子設(shè)備。

      2.video_device

            在/dev目錄下的設(shè)備節(jié)點使用的 struct video_device(v4l2_dev.h)創(chuàng)建。
       struct video_device
           {
               /*設(shè)備操作函數(shù) */
               const struct v4l2_file_operations *fops;

               /* 虛擬文件系統(tǒng) */
               struct device dev;        /* v4l 設(shè)備 */
               struct cdev *cdev;        /* 字符設(shè)備 */

              struct device *parent;        /*父設(shè)備 */
              struct v4l2_device *v4l2_dev;    /* v4l2_device parent */

              /* 設(shè)備信息 */
               char name[32];
               int vfl_type;
               /* 'minor' is set to -1 if the registration failed */
              int minor;
              u16 num;
               /* use bitops to set/clear/test flags */
               unsigned long flags;
               /*屬性來區(qū)分一個物理設(shè)備上的多個索引 */
              int index;

               /* V4L2 文件句柄 */
               spinlock_t        fh_lock; /*鎖定所有的 v4l2_fhs */
               struct list_head    fh_list; /* List of struct v4l2_fh */

               int debug;            /* Activates debug level*/

               /* Video standard vars */
               v4l2_std_id tvnorms;        /* Supported tv norms */
               v4l2_std_id current_norm;    /* Current tvnorm */

               /* 釋放的回調(diào)函數(shù) */
              void (*release)(struct video_device *vdev);

               /* 控制的回調(diào)函數(shù) */
               const struct v4l2_ioctl_ops *ioctl_ops;
           }

        動態(tài)分配:
                struct video_device *vdev = video_device_alloc();

         結(jié)構(gòu)體配置:

               fops:設(shè)置這個v4l2_file_operations結(jié)構(gòu),file_operations的一個子集。v4l2_dev: 設(shè)置這個v4l2_device父設(shè)備
               name:
               ioctl_ops:使用v4l2_ioctl_ops簡化的IOCTL,然後設(shè)置v4l2_ioctl_ops結(jié)構(gòu)。
               lock:如果你想要做的全部驅(qū)動程序鎖定就保留為NULL。否則你給它一個指針指向一個mutex_lock結(jié)構(gòu)體和任何v4l2_file_operations被調(diào)用之前核心應(yīng)該釋放釋放鎖。
               parent:一個硬件設(shè)備有多個PCI設(shè)備,都共享相同v4l2_device核心時,設(shè)置注冊使用NULL v4l2_device作為父設(shè)備結(jié)構(gòu)。
               flags:可選的。設(shè)置到V4L2_FL_USE_FH_PRIO如你想讓框架處理VIDIOC_G/ S_PRIORITY的ioctl。這就需要您使用結(jié)構(gòu)v4l2_fh。這個標(biāo)志最終會消失,一旦所有的驅(qū)動程序使用的核心優(yōu)先處理。但現(xiàn)在它必須明確設(shè)定。

         如果使用v4l2_ioctl_ops,那麼你應(yīng)該設(shè)置。unlocked_ioctlvideo_ioctl2在v4l2_file_operations結(jié)構(gòu)。

       注冊/注銷 video_device:

          video_register_device(struct video_device *vdev, int type, int nr);
          __video_register_device(struct video_device *vdev, int type, int nr,int warn_if_nr_in_use)
              參數(shù):
                 vdev:我們要注冊的視頻設(shè)備結(jié)構(gòu)。
                 type:設(shè)備類型注冊
                 nr:設(shè)備號(0==/dev/video0,1??== /dev/video1,...-1==釋放第一個)
                 warn_if_nr_in_use:如果所需的設(shè)備節(jié)點號碼已經(jīng)在使用另一個號碼代替選擇。
          
             注冊程式分配次設(shè)備號和設(shè)備節(jié)點的數(shù)字根據(jù)請求的類型和注冊到內(nèi)核新設(shè)備節(jié)點。如果無法找到空閑次設(shè)備號或設(shè)備節(jié)點編號,或者如果設(shè)備節(jié)點注冊失敗,就返回一個錯誤。
       
                 video_unregister_device(struct video_device *vdev);

        3.v4l2_subdev
       
                每個子設(shè)備驅(qū)動程序必須有一個v4l2_subdev結(jié)構(gòu)。這個結(jié)構(gòu)可以獨立簡單的設(shè)備或者如果需要存儲更多的狀態(tài)信息它可能被嵌入在一個更大的結(jié)構(gòu)。由於子設(shè)備可以做很多不同的東西,你不想結(jié)束一個巨大的OPS結(jié)構(gòu)其中只有少數(shù)的OPS通常執(zhí)行,函數(shù)指針進(jìn)行排序按類別,每個類別都有其自己的OPS結(jié)構(gòu)。頂層OPS結(jié)構(gòu)包含的類別OPS結(jié)構(gòu),這可能是NULL如果在subdev驅(qū)動程序不支持任何從該類別指針。
               struct v4l2_subdev {
           #if defined(CONFIG_MEDIA_CONTROLLER)
               struct media_entity entity;
           #endif
               struct list_head list;
               struct module *owner;
               u32 flags;
               struct v4l2_device *v4l2_dev;
               const struct v4l2_subdev_ops *ops;
               /* 從驅(qū)動程序中不要調(diào)用這些內(nèi)部操作函數(shù)! */
               const struct v4l2_subdev_internal_ops *internal_ops;
               /*這個subdev控制處理程序??赡苁荖ULL。 */
               struct v4l2_ctrl_handler *ctrl_handler;
               /* 名字必須是唯一 */
               char name[V4L2_SUBDEV_NAME_SIZE];
               /* 可用於到類似subdevs組,值是驅(qū)動程序特定的 */
               u32 grp_id;
               /* 私有數(shù)據(jù)的指針 */
               void *dev_priv;
               void *host_priv;
               /* subdev 設(shè)備節(jié)點*/
               struct video_device devnode;
               /* 事件的數(shù)量在打開的時候被分配 */
               unsigned int nevents;
            };
       

       4.v4l2_buffer

      struct v4l2_buffer {
          __u32            index;
          enum v4l2_buf_type      type;
          __u32            bytesused;
          __u32            flags;
           enum v4l2_field        field;
          struct timeval        timestamp;
           struct v4l2_timecode    timecode;
          __u32            sequence;

          /* memory location */
          enum v4l2_memory        memory;
          union {
              __u32           offset;
              unsigned long   userptr;
          } m;
          __u32            length;
          __u32            input;
          __u32            reserved;
      };

         V4L2核心API提供了一套標(biāo)準(zhǔn)方法的用於處理視頻緩沖器(稱為“videobuf”)。這些方法允許驅(qū)動程序以一致的方式來實現(xiàn)read(),mmap()和overlay()。目前使用的設(shè)備上的視頻緩沖器,支持scatter/gather方法(videobuf-dma-SG),線性存取的DMA的(videobuf-DMA-contig),vmalloc分配的緩沖區(qū),主要用於在USB驅(qū)動程序(DMA緩沖區(qū)的方法videobuf-vmalloc)。

         videobuf層的功能為一種V4L2驅(qū)動和用戶空間之間的粘合層。它可以處理存儲視頻幀緩沖區(qū)的分配和管理。有一組可用於執(zhí)行許多標(biāo)準(zhǔn)的POSIX I / O系統(tǒng)調(diào)用的功能,包括read(),poll()的,happily,mmap()。另一套功能可以用來實現(xiàn)大部分的V4L2的ioctl()調(diào)用相關(guān)的流式I/ O的,包括緩沖區(qū)分配,排隊和dequeueing,流控制。驅(qū)動作者使用videobuf規(guī)定了一些設(shè)計決定,但回收期在驅(qū)動器和一個V4L2的用戶空間API的貫徹實施在減少代碼的形式。

         關(guān)於videobuf的層的更多信息,請參閱Documentation/video4linux/videobuf

      V4l2驅(qū)動架構(gòu)

            驅(qū)動架構(gòu)圖

             

            所有的驅(qū)動程序有以下結(jié)構(gòu):


               1) 每個設(shè)備包含設(shè)備狀態(tài)的實例結(jié)構(gòu)。

               2) 子設(shè)備的初始化和命令方式(如果有).

               3) 創(chuàng)建V4L2的設(shè)備節(jié)點 (/dev/videoX, /dev/vbiX and /dev/radioX)和跟蹤設(shè)備節(jié)點的具體數(shù)據(jù)。

               4)文件句柄特定的結(jié)構(gòu),包含每個文件句柄數(shù)據(jù);

               5) 視頻緩沖處理。


      驅(qū)動源碼分析

              vivi.c 虛擬視頻驅(qū)動程序
                            ----- 此代碼模擬一個真正的視頻設(shè)備V4L2 API (位於drivers/media/video目錄下)

        入口:+int __init vivi_init(void)

                       + vivi_create_instance(i) /*創(chuàng)建設(shè)備*//**/。

                               + 分配一個vivi_dev的結(jié)構(gòu)體 /*它嵌套這結(jié)構(gòu)體v4l2_device 和video_device*/
                               + v4l2_device_register(NULL, &dev->v4l2_dev);/*注冊vivi_dev中的V4l2_device*/
                               + 初始化視頻的DMA隊列
                               + 初始化鎖
                               + video_device_alloc(); 動態(tài)分配video_device結(jié)構(gòu)體
                               + 構(gòu)建一個video_device結(jié)構(gòu)體 vivi_template 並賦給上面分配的video_device

                                      static struct video_device vivi_template = {
                                                . name        = "vivi",
                                                .fops           = &vivi_fops,
                                                .ioctl_ops     = &vivi_ioctl_ops,
                                                .minor        = -1,
                                                .release    = video_device_release,

                                                .tvnorms              = V4L2_STD_525_60,
                                                .current_norm         = V4L2_STD_NTSC_M,
                                       };

                             + video_set_drvdata(vfd, dev);設(shè)置驅(qū)動程序?qū)S袛?shù)據(jù)
                             + 所有控件設(shè)置為其默認(rèn)值
                             + list_add_tail(&dev->vivi_devlist, &vivi_devlist);添加到設(shè)備列表
                + 構(gòu)建 v4l2_file_operations 結(jié)構(gòu)體vivi_fops 並實現(xiàn).open .release .read .poll .mmap函數(shù)
                                  ----- .ioctl 用標(biāo)準(zhǔn)的v4l2控制處理程序
                + 構(gòu)建 v4l2_ioctl_ops結(jié)構(gòu)體 vivi_ioctl_ops

                                   static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
                                              .vidioc_querycap      = vidioc_querycap,
                                              .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
                                              .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
                                              .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
                                              .vidioc_reqbufs       = vidioc_reqbufs,
                                              .vidioc_querybuf      = vidioc_querybuf,
                                              .vidioc_qbuf          = vidioc_qbuf,
                                              .vidioc_dqbuf         = vidioc_dqbuf,
                                              .vidioc_s_std         = vidioc_s_std,
                                              .vidioc_enum_input    = vidioc_enum_input,
                                              .vidioc_g_input       = vidioc_g_input,
                                              .vidioc_s_input       = vidioc_s_input,
                                              .vidioc_queryctrl     = vidioc_queryctrl,
                                              .vidioc_g_ctrl        = vidioc_g_ctrl,
                                              .vidioc_s_ctrl        = vidioc_s_ctrl,
                                              .vidioc_streamon      = vidioc_streamon,
                                              .vidioc_streamoff     = vidioc_streamoff,
                                   #ifdef CONFIG_VIDEO_V4L1_COMPAT
                                             .vidiocgmbuf          = vidiocgmbuf,
                                 #endif
                             };

                 + int vivi_open(struct file *file)
                           + vivi_dev *dev = video_drvdata(file);  訪問驅(qū)動程序?qū)S脭?shù)據(jù)
                           + 分配+初始化句柄(vivi_fh)數(shù)據(jù)
                           + 重置幀計數(shù)器
                           + videobuf_queue_vmalloc_init(); 初始化視頻緩沖隊列
                           + 開啟一個新線程用於開始和暫停
                 + 實現(xiàn)自定義的v4l2_ioctl_ops 函數(shù)

      附:Sub-devices

                         Sub-devices 支持的頭文件 V4l2-subdev.h

      •            子設(shè)備是某種程度上主橋設(shè)備連接的設(shè)備。這些設(shè)備通常是音頻/視頻流 合並器/編碼器/解碼器或傳感器和攝像頭控制器。

                               一般控制這些器件通過I2C總線,但也可用於其他總線。

      •           v4l2_subdev結(jié)構(gòu)提供了一個通用的方式訪問這些設(shè)備, sub-devices支持的大部分操作分為以下幾個類別:

                          核心操作、音頻操作、視頻操作、調(diào)諧器操作,每個類別都可以在實現(xiàn)subdev的驅(qū)動程序時設(shè)置自己的操作。

                                       struct v4l2_subdev_ops {
                                                 const struct v4l2_subdev_core_ops  *core;
                                                 const struct v4l2_subdev_tuner_ops *tuner;
                                                 const struct v4l2_subdev_audio_ops *audio;
                                                 const struct v4l2_subdev_video_ops *video;
                                       };

      •           一個subdev驅(qū)動程序可以設(shè)置不執(zhí)行的操作函數(shù)指針為空(如要產(chǎn)生音頻subdev通常沒有實現(xiàn)視頻類操作)。唯一的例外是核心類:必須始終存在。
      •           這些OPS都在內(nèi)部使用,所以它是沒有必要去更改,添加或刪除它們或從一個移動到另一個類別。目前這些OPS基於原有的控制命令,但OPS不僅限於一個參數(shù),一旦所有的I2C驅(qū)動subdev轉(zhuǎn)換為使用這些OPS,就有改進(jìn)的餘地。

         1. 核心操作 v4l2_subdev_core_ops 

      struct v4l2_subdev_core_ops {
          int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
          int (*log_status)(struct v4l2_subdev *sd);
          int (*s_config)(struct v4l2_subdev *sd, int irq, void *platform_data);
          int (*init)(struct v4l2_subdev *sd, u32 val);
          int (*load_fw)(struct v4l2_subdev *sd);
          int (*reset)(struct v4l2_subdev *sd, u32 val);
          int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
          int (*queryctrl)(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
          int (*g_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
          int (*s_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
          int (*g_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
          int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
          int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls);
          int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm);
          int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm);
          long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
      #ifdef CONFIG_VIDEO_ADV_DEBUG
          int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
          int (*s_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
      #endif
      };

                 我們強(qiáng)烈建議至少實現(xiàn)這些操作:

                              g_chip_ident
                              log_status
                              g_register
                              s_register

                    這些提供了基本的調(diào)試支持。
                     ioctl:是指為仿制的ioctl類的命令。根據(jù)使用情況,它可能是更好地使用特定子設(shè)備操作(目前尚未實施),因為OPS提供適當(dāng)?shù)念愋蜋z查。
       

                     s_config:如果設(shè)置,那麼它總是在v4l2_subdev被注冊後由v4l2_i2c_new_subdev函數(shù)調(diào)用後。它用於將數(shù)據(jù)傳遞到平臺,可用於subdev在初始化過程中。

                     init:一些適當(dāng)?shù)哪J(rèn)值初始化傳感器寄存器。不使用新的驅(qū)動程序時現(xiàn)有的驅(qū)動程序應(yīng)該刪除它。

                     reset:復(fù)位通用的命令。參數(shù)選擇復(fù)位哪一個子系統(tǒng)。傳遞0將復(fù)位整個芯片。使用新的驅(qū)動程序前要先掛載在linux-media 列表上再復(fù)位。

                     s_gpio:設(shè)置GPIO引腳。如果需要的話可能還需要擴(kuò)展方向參數(shù)。


           2.分類操作

                         struct v4l2_subdev_video_ops、

                         struct v4l2_subdev_audio_ops、

                         struct v4l2_subdev_tuner_ops

                   以上結(jié)構(gòu)體都在V4l2-subdev.h 中定義。由於操作函數(shù)太多就沒有必要一一列舉。

          3.v4l2_subdev相關(guān)操作

      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      (1)子設(shè)備驅(qū)動初始化的v4l2_subdev結(jié)構(gòu)使用:

                v4l2_subdev_init(sd, &ops);

            (2)V4l2 i2c子設(shè)備的初始化
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      

                                  void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, const struct v4l2_subdev_ops *ops)

                  

                    (3)裝載一個新的i2c 子設(shè)備

                                  v4l2_i2c_new_subdev_board()

                                 注:如果模塊加載先加載這驅(qū)動程序發(fā)現(xiàn)後設(shè)置client->driver,如果模塊不是先加載的,那麼I2C核心試圖延遲加載的模塊,然後驅(qū)動程序的client->drive 默認(rèn)為 NULL,直到加載模塊。如果其他驅(qū)動程序要使用I2C設(shè)備,使明確的加載模塊是最好的選擇,這延遲加載機(jī)制不起作用。

                  

                   (4)獲取i2c subdev地址

                                short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)  

                               返回I2C v4l2_subdev客戶端地址   

                     


      From:CSDN

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多