s5pv210 cmos摄像头驱动(一)

一、环境

     芯片: S5PV210

     kernel:2.6.32

 

二、S5PV210 camera接口介绍

     芯片手册如下描述:

 

             The key application ofthese features is in a folder-type cellular phone.

 

2.2KEY FEATURES OF CAMIF
The keyfeatures of CAMIF include:
• Multipleinput support
− ITU-R BT601/ 656/ 709 mode
− DMA (AXI64-bit interface) mode
− MIPI (CSI)mode
− DirectFIFO (PlayBack) mode
• Multipleoutput support
− DMA (AXI64-bit interface) mode
− DirectFIFO mode
• DigitalZoom In (DZI) capability
• Multiplecamera input
•Programmable polarity of video sync signals
• Supportsmaximum 8192 x 8192 pixels input (Refer to Table 2-1)

•Image mirror and rotation (X-axis mirror, Y-axis mirror, 90°, 180°, and 270°rotation)
• Generatesvarious image formats
• Supportscapture frame control
• Supportsimage effect

    Table 2-1 Maximum Size

三、linux中cmos驱动的实现

1.  cmos控制器驱动

主要文件:

在driver/media/samsung/fimc目录下

arch/arm/mach-s5pv210目录下

arch/arm/plat-s5p目录下

 

因为芯片有3个控制器,所以有三个控制器的代码,在arch/arm/plat-s5p目录下的devs.c中

如下:



#ifdef CONFIG_VIDEO_FIMC
static struct resource s3c_fimc0_resource[] = {
[0] = {
.start = S5P_PA_FIMC0,
.end = S5P_PA_FIMC0 + S5P_SZ_FIMC0 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_FIMC0,
.end = IRQ_FIMC0,
.flags = IORESOURCE_IRQ,
},
};


struct platform_device s3c_device_fimc0 = {
.name = "s3c-fimc",
.id = 0,
.num_resources= ARRAY_SIZE(s3c_fimc0_resource),
.resource = s3c_fimc0_resource,
};


static struct s3c_platform_fimc default_fimc0_data __initdata = {
.default_cam = CAMERA_PAR_A,
.hw_ver = 0x45,
};


void __init s3c_fimc0_set_platdata(struct s3c_platform_fimc *pd)
{
struct s3c_platform_fimc *npd;


if (!pd)
pd = &default_fimc0_data;


npd = kmemdup(pd, sizeof(struct s3c_platform_fimc), GFP_KERNEL);
if (!npd)
printk(KERN_ERR "%s: no memory for platform data\n", __func__);
else {
if (!npd->cfg_gpio)
npd->cfg_gpio = s3c_fimc0_cfg_gpio;


if (!npd->clk_on)
npd->clk_on = s3c_fimc_clk_on;


if (!npd->clk_off)
npd->clk_off = s3c_fimc_clk_off;


npd->hw_ver = 0x45;


/* starting physical address of memory region */
npd->pmem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMC0, 1);
/* size of memory region */
npd->pmem_size = s5p_get_media_memsize_bank(S5P_MDEV_FIMC0, 1);


s3c_device_fimc0.dev.platform_data = npd;
}
}


static struct resource s3c_fimc1_resource[] = {
[0] = {
.start = S5P_PA_FIMC1,
.end = S5P_PA_FIMC1 + S5P_SZ_FIMC1 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_FIMC1,
.end = IRQ_FIMC1,
.flags = IORESOURCE_IRQ,
},
};


struct platform_device s3c_device_fimc1 = {
.name = "s3c-fimc",
.id = 1,
.num_resources= ARRAY_SIZE(s3c_fimc1_resource),
.resource = s3c_fimc1_resource,
};


static struct s3c_platform_fimc default_fimc1_data __initdata = {
.default_cam = CAMERA_PAR_A,
.hw_ver = 0x50,
};


void __init s3c_fimc1_set_platdata(struct s3c_platform_fimc *pd)
{
struct s3c_platform_fimc *npd;


if (!pd)
pd = &default_fimc1_data;


npd = kmemdup(pd, sizeof(struct s3c_platform_fimc), GFP_KERNEL);
if (!npd)
printk(KERN_ERR "%s: no memory for platform data\n", __func__);
else {
if (!npd->cfg_gpio)
npd->cfg_gpio = s3c_fimc1_cfg_gpio;


if (!npd->clk_on)
npd->clk_on = s3c_fimc_clk_on;


if (!npd->clk_off)
npd->clk_off = s3c_fimc_clk_off;


npd->hw_ver = 0x50;


/* starting physical address of memory region */
npd->pmem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMC1, 1);
/* size of memory region */
npd->pmem_size = s5p_get_media_memsize_bank(S5P_MDEV_FIMC1, 1);


s3c_device_fimc1.dev.platform_data = npd;
}
}


static struct resource s3c_fimc2_resource[] = {
[0] = {
.start = S5P_PA_FIMC2,
.end = S5P_PA_FIMC2 + S5P_SZ_FIMC2 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_FIMC2,
.end = IRQ_FIMC2,
.flags = IORESOURCE_IRQ,
},
};


struct platform_device s3c_device_fimc2 = {
.name = "s3c-fimc",
.id = 2,
.num_resources= ARRAY_SIZE(s3c_fimc2_resource),
.resource = s3c_fimc2_resource,
};


static struct s3c_platform_fimc default_fimc2_data __initdata = {
.default_cam = CAMERA_PAR_A,
.hw_ver = 0x45,
};


void __init s3c_fimc2_set_platdata(struct s3c_platform_fimc *pd)
{
struct s3c_platform_fimc *npd;


if (!pd)
pd = &default_fimc2_data;


npd = kmemdup(pd, sizeof(struct s3c_platform_fimc), GFP_KERNEL);
if (!npd)
printk(KERN_ERR "%s: no memory for platform data\n", __func__);
else {
if (!npd->cfg_gpio)
npd->cfg_gpio = s3c_fimc2_cfg_gpio;


if (!npd->clk_on)
npd->clk_on = s3c_fimc_clk_on;


if (!npd->clk_off)
npd->clk_off = s3c_fimc_clk_off;


npd->hw_ver = 0x45;


/* starting physical address of memory region */
npd->pmem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMC2, 1);
/* size of memory region */
npd->pmem_size = s5p_get_media_memsize_bank(S5P_MDEV_FIMC2, 1);


s3c_device_fimc2.dev.platform_data = npd;
}
}



static struct resource s3c_ipc_resource[] = {
[0] = {
.start = S5P_PA_IPC,
.end = S5P_PA_IPC + S5P_SZ_IPC - 1,
.flags = IORESOURCE_MEM,
},
};


struct platform_device s3c_device_ipc = {
.name = "s3c-ipc",
.id = -1,
.num_resources= ARRAY_SIZE(s3c_ipc_resource),
.resource = s3c_ipc_resource,
};
static struct resource s3c_csis_resource[] = {
[0] = {
.start = S5P_PA_CSIS,
.end = S5P_PA_CSIS + S5P_SZ_CSIS - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_MIPICSI,
.end = IRQ_MIPICSI,
.flags = IORESOURCE_IRQ,
},
};


struct platform_device s3c_device_csis = {
.name = "s3c-csis",
.id = -1,
.num_resources= ARRAY_SIZE(s3c_csis_resource),
.resource = s3c_csis_resource,
};


static struct s3c_platform_csis default_csis_data __initdata = {
.srclk_name = "mout_mpll",
.clk_name = "sclk_csis",
.clk_rate = 166000000,
};


void __init s3c_csis_set_platdata(struct s3c_platform_csis *pd)
{
struct s3c_platform_csis *npd;


if (!pd)
pd = &default_csis_data;


npd = kmemdup(pd, sizeof(struct s3c_platform_csis), GFP_KERNEL);
if (!npd) {
printk(KERN_ERR "%s: no memory for platform data\n", __func__);
return;
}


npd->cfg_gpio = s3c_csis_cfg_gpio;
npd->cfg_phy_global = s3c_csis_cfg_phy_global;
npd->clk_on = s3c_csis_clk_on;
npd->clk_off = s3c_csis_clk_off;


s3c_device_csis.dev.platform_data = npd;
}
#endif

将设备添加到系统中,是在arch/arm/mach-s5pv210目录中,

如下:

/* Interface setting */
static struct s3c_platform_fimc fimc_plat_lsi = {
.srclk_name = "mout_mpll",
.clk_name = "sclk_fimc",
.lclk_name = "sclk_fimc_lclk",
.clk_rate = 166750000,
.default_cam = CAMERA_PAR_A,
.camera = {
#ifdef CONFIG_CAMERA_OV3640
&ov3640,
#endif
#if defined(CONFIG_CAMERA_TVP5150_ONBOARD) ||defined(CONFIG_CAMERA_TVP5150_MODULE)
&tvp5150,
#endif
},
.hw_ver = 0x43,
};

 

static struct platform_device*smdkc110_devices[] __initdata = {

 

...

#ifdef CONFIG_VIDEO_FIMC
&s3c_device_fimc0,
&s3c_device_fimc1,
&s3c_device_fimc2,
#endif

...

}

 

static void __initsmdkc110_machine_init(void)

{

...

platform_add_devices(smdkc110_devices,ARRAY_SIZE(smdkc110_devices));

...

#ifdef CONFIG_VIDEO_FIMC
/* fimc */
s3c_fimc0_set_platdata(&fimc_plat_lsi);
s3c_fimc1_set_platdata(&fimc_plat_lsi);
s3c_fimc2_set_platdata(&fimc_plat_lsi);
/* external camera */
/* smdkv210_cam0_power(1); */
/* smdkv210_cam1_power(1); */
#endif

}

platform_add_devices(smdkc110_devices,ARRAY_SIZE(smdkc110_devices));

在系统启动后,会将这三个控制设备加入系统

      s3c_fimc0_set_platdata(&fimc_plat_lsi);
      s3c_fimc1_set_platdata(&fimc_plat_lsi);
      s3c_fimc2_set_platdata(&fimc_plat_lsi);

为3个控制器设置摄像头数据

static struct s3c_platform_fimc fimc_plat_lsi= {
      .srclk_name   = "mout_mpll",
      .clk_name = "sclk_fimc",
      .lclk_name     = "sclk_fimc_lclk",
      .clk_rate   = 166750000,
      .default_cam  = CAMERA_PAR_A,
      .camera         = {
#ifdef CONFIG_CAMERA_OV3640
           &ov3640,
#endif
#if defined(CONFIG_CAMERA_TVP5150_ONBOARD) ||defined(CONFIG_CAMERA_TVP5150_MODULE)
           &tvp5150,
#endif
      },
      .hw_ver          = 0x43,
};

void __init s3c_fimc0_set_platdata(structs3c_platform_fimc *pd)
{
      structs3c_platform_fimc *npd;


      if(!pd)
           pd = &default_fimc0_data;


      npd =kmemdup(pd, sizeof(struct s3c_platform_fimc), GFP_KERNEL);
      if(!npd)
           printk(KERN_ERR "%s: no memory for platformdata\n", __func__);
      else{
           if (!npd->cfg_gpio)
                 npd->cfg_gpio = s3c_fimc0_cfg_gpio;


           if (!npd->clk_on)
                 npd->clk_on = s3c_fimc_clk_on;


           if (!npd->clk_off)
                 npd->clk_off = s3c_fimc_clk_off;


           npd->hw_ver = 0x45;


           /* starting physical address of memory region */
           npd->pmem_start =s5p_get_media_memory_bank(S5P_MDEV_FIMC0, 1);
           /* size of memory region */
           npd->pmem_size =s5p_get_media_memsize_bank(S5P_MDEV_FIMC0, 1);


           s3c_device_fimc0.dev.platform_data = npd;
      }
}

第一个if,如果没有传入摄像头信息,就用默认的,如果传入了,就用npd = kmemdup(pd, sizeof(struct s3c_platform_fimc),GFP_KERNEL);该函数申请一个空间并把传过来的数值赋值过去。最终使用s3c_device_fimc0.dev.platform_data = npd;保存到私有数据

 

void __init s3c_fimc0_set_platdata(structs3c_platform_fimc *pd)

{
      structs3c_platform_fimc *npd;


      if(!pd)
           pd = &default_fimc0_data;


      npd =kmemdup(pd, sizeof(struct s3c_platform_fimc), GFP_KERNEL);
      if(!npd)
           printk(KERN_ERR "%s: no memory for platformdata\n", __func__);
      else{
           if (!npd->cfg_gpio)
                 npd->cfg_gpio = s3c_fimc0_cfg_gpio;


           if (!npd->clk_on)
                 npd->clk_on = s3c_fimc_clk_on;


           if (!npd->clk_off)
                 npd->clk_off = s3c_fimc_clk_off;


           npd->hw_ver = 0x45;


           /* starting physical address of memory region */
           npd->pmem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMC0,1);
           /* size of memory region */
           npd->pmem_size =s5p_get_media_memsize_bank(S5P_MDEV_FIMC0, 1);


           s3c_device_fimc0.dev.platform_data = npd;
      }
}

这些数据将在驱动匹配上后取出来并设置

    s3c_fimc0_set_platdata(&fimc_plat_lsi);
    s3c_fimc1_set_platdata(&fimc_plat_lsi);
    s3c_fimc2_set_platdata(&fimc_plat_lsi);

这三个函数就是设置控制器的操作函数并赋值一些摄像头数据,最终赋给平台设备的私有数据,在驱动匹配到后取出来。

该结构图原型如下:

structs3c_platform_fimc {
    const char        srclk_name[16];        /* source of interface clock name */
    const char        clk_name[16];       /* interface clock name */
    const char        lclk_name[16];      /* interface clock name */
    u32              clk_rate;       /* clockrate for interface clock */
    enum fimc_cam_index      default_cam;     /* indexof default cam */
    struct s3c_platform_camera  *camera[5];       /*FIXME */
    int            hw_ver;
    phys_addr_t         pmem_start;     /* starting physical address of memoryregion */
    size_t               pmem_size;      /* size of memory region */


    void              (*cfg_gpio)(structplatform_device *pdev);
    int            (*clk_on)(structplatform_device *pdev, struct clk *clk);
    int            (*clk_off)(structplatform_device *pdev, struct clk *clk);
};

在driver/media/samsung/fimc目录下fimc_dev.c

static struct platform_driver fimc_driver = {
      .probe       = fimc_probe,
      .remove         = fimc_remove,
      .suspend  = fimc_suspend,
      .resume         = fimc_resume,
      .driver       = {
           .name = FIMC_NAME,
           .owner = THIS_MODULE,
      },
};


static int fimc_register(void)
{
      platform_driver_register(&fimc_driver);


      return0;
}

.name   = FIMC_NAME,

其中,#define FIMC_NAME        "s3c-fimc"

通过名字匹配,因为设备的id=0,没有用id_table

在probe函数中,将设备信息提取出来,并设置

static int __devinit fimc_probe(structplatform_device *pdev)
{
      structs3c_platform_fimc *pdata;
      structfimc_control *ctrl;
      structclk *srclk;
      intret;


      if(!fimc_dev) {
           fimc_dev = kzalloc(sizeof(*fimc_dev), GFP_KERNEL);
           if (!fimc_dev) {
                 dev_err(&pdev->dev, "%s: not enoughmemory\n",
                      __func__);
                 return -ENOMEM;
           }
      }


      ctrl= fimc_register_controller(pdev);
      if(!ctrl) {
           printk(KERN_ERR "%s: cannot register fimc\n",__func__);
           goto err_alloc;
      }


      pdata= to_fimc_plat(&pdev->dev);
      if(pdata->cfg_gpio)
           pdata->cfg_gpio(pdev);


      /*Get fimc power domain regulator */
      ctrl->regulator= regulator_get(&pdev->dev, "pd");
      if(IS_ERR(ctrl->regulator)) {
           fimc_err("%s: failed to get resource %s\n",
                      __func__, "s3c-fimc");
           return PTR_ERR(ctrl->regulator);
      }


      /*fimc source clock */
      srclk= clk_get(&pdev->dev, pdata->srclk_name);
      if(IS_ERR(srclk)) {
           fimc_err("%s: failed to get source clock offimc\n",
                      __func__);
           goto err_v4l2;
      }


      /*fimc clock */
      ctrl->clk= clk_get(&pdev->dev, pdata->clk_name);
      if(IS_ERR(ctrl->clk)) {
           fimc_err("%s: failed to get fimc clocksource\n",
                 __func__);
           goto err_v4l2;
      }


      /*set parent for mclk */
      clk_set_parent(ctrl->clk,srclk);


      /*set rate for mclk */
      clk_set_rate(ctrl->clk,pdata->clk_rate);


      /*V4L2 device-subdev registration */
      ret =v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev);
      if(ret) {
           fimc_err("%s: v4l2 device register failed\n",__func__);
           goto err_fimc;
      }


      /*things to initialize once */
      if (!fimc_dev->initialized){
           ret = fimc_init_global(pdev);
           if (ret)
                 goto err_v4l2;
      }


      /*video device register */
      ret =video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);
      if(ret) {
           fimc_err("%s: cannot register video driver\n",__func__);
           goto err_v4l2;
      }


      video_set_drvdata(ctrl->vd,ctrl);


      ret =device_create_file(&(pdev->dev), &dev_attr_log_level);
      if(ret < 0) {
           fimc_err("failed to add sysfs entries\n");
           goto err_global;
      }
      printk(KERN_INFO"FIMC%d registered successfully\n", ctrl->id);


      return0;


err_global:
      video_unregister_device(ctrl->vd);


err_v4l2:
      v4l2_device_unregister(&ctrl->v4l2_dev);


err_fimc:
      fimc_unregister_controller(pdev);


err_alloc:
      kfree(fimc_dev);
      return-EINVAL;


}

      if(!fimc_dev) {
           fimc_dev = kzalloc(sizeof(*fimc_dev), GFP_KERNEL);
           if (!fimc_dev) {
                 dev_err(&pdev->dev, "%s: not enoughmemory\n",
                      __func__);
                 return -ENOMEM;
           }
      }

fimc_dev是一个全局指针,如果没有申请,就申请个

定义如下

structfimc_global {
    struct fimc_control    ctrl[FIMC_DEVICES];
    struct s3c_platform_camera  camera[FIMC_MAXCAMS];
    int            camera_isvalid[FIMC_MAXCAMS];
    int            active_camera;
    int            initialized;
};

整个驱动围绕着这个来转

struct fimc_control *ctrl;

定义如下:

struct fimc_control {
      int                   id;       /* controller id */
      char                     name[16];
      atomic_t              in_use;
      void__iomem                 *regs;       /* register i/o */
      structclk              *clk;          /* interface clock */
      structregulator    *regulator;           /* pd regulator */
      structfimc_meminfo       mem;        /* for reserved mem */


      /*kernel helpers */
      structmutex              lock;         /* controller lock */
      structmutex              alloc_lock;
      structmutex              v4l2_lock;
      wait_queue_head_t        wq;
      structdevice             *dev;
      int                   irq;


      /*v4l2 related */
      structvideo_device        *vd;
      structv4l2_device          v4l2_dev;


      /*fimc specific */
      structfimc_limit         *limit;        /* H/W limitation */
      structs3c_platform_camera *cam;        /* activated camera */
      structfimc_capinfo         *cap;         /* capture dev info */
      structfimc_outinfo          *out;         /* output dev info */
      structfimc_fbinfo      fb;       /* fimd info */
      structfimc_scaler           sc;       /* scaler info */
      structfimc_effect      fe;       /* fimc effect info */


      enumfimc_status           status;
      enumfimc_log                log;


      u32                      ctx_busy[FIMC_MAX_CTXS];
};
在函数ctrl = fimc_register_controller(pdev);中将设备的信息赋值给它,并将video信息和v2里



static  struct fimc_control *fimc_register_controller(structplatform_device *pdev)
{
      structs3c_platform_fimc *pdata;
      structfimc_control *ctrl;
      structresource *res;
      intid, mdev_id;


      id =pdev->id;
      mdev_id= S5P_MDEV_FIMC0 + id;
      pdata= to_fimc_plat(&pdev->dev);


      ctrl= get_fimc_ctrl(id);
      ctrl->id= id;
      ctrl->dev= &pdev->dev;
      ctrl->vd= &fimc_video_device[id];
      ctrl->vd->minor= id;


      /*alloc from bank1 as default */
      ctrl->mem.base= pdata->pmem_start;
      ctrl->mem.size= pdata->pmem_size;
      ctrl->mem.curr= ctrl->mem.base;


      ctrl->status= FIMC_STREAMOFF;
      switch(pdata->hw_ver) {
      case0x40:
           ctrl->limit = &fimc40_limits[id];
           break;
      case0x43:
      case0x45:
           ctrl->limit = &fimc43_limits[id];
           break;
      case0x50:
           ctrl->limit = &fimc50_limits[id];
           break;
      }


      ctrl->log= FIMC_LOG_DEFAULT;


      sprintf(ctrl->name,"%s%d", FIMC_NAME, id);
      strcpy(ctrl->vd->name,ctrl->name);


      atomic_set(&ctrl->in_use,0);
      mutex_init(&ctrl->lock);
      mutex_init(&ctrl->alloc_lock);
      mutex_init(&ctrl->v4l2_lock);
      init_waitqueue_head(&ctrl->wq);


      /*get resource for io memory */
      res =platform_get_resource(pdev, IORESOURCE_MEM, 0);
      if(!res) {
           fimc_err("%s: failed to get io memory region\n",__func__);
           return NULL;
      }


      /*request mem region */
      res =request_mem_region(res->start, res->end - res->start + 1,
                 pdev->name);
      if(!res) {
           fimc_err("%s: failed to request io memoryregion\n", __func__);
           return NULL;
      }


      /*ioremap for register block */
      ctrl->regs= ioremap(res->start, res->end - res->start + 1);
      if(!ctrl->regs) {
           fimc_err("%s: failed to remap io region\n",__func__);
           return NULL;
      }


      /*irq */
      ctrl->irq= platform_get_irq(pdev, 0);
      if(request_irq(ctrl->irq, fimc_irq, IRQF_DISABLED, ctrl->name, ctrl))
           fimc_err("%s: request_irq failed\n", __func__);


      fimc_hwset_reset(ctrl);


      returnctrl;
}

 

通过控制器的id号获取ctrl指针,在上面已经申请好了的

ctrl = get_fimc_ctrl(id);

static inline struct fimc_control*get_fimc_ctrl(int id)
{
      return&fimc_dev->ctrl[id];
}

后面就是赋值

ctrl->vd = &fimc_video_device[id];

关键的操作集合,摄像头的操作都集中在这里

struct video_devicefimc_video_device[FIMC_DEVICES] = {
      [0] ={
           .fops = &fimc_fops,
           .ioctl_ops = &fimc_v4l2_ops,
           .release = fimc_vdev_release,
      },
      [1] ={
           .fops = &fimc_fops,
           .ioctl_ops = &fimc_v4l2_ops,
           .release = fimc_vdev_release,
      },
      [2] ={
           .fops = &fimc_fops,
           .ioctl_ops = &fimc_v4l2_ops,
           .release = fimc_vdev_release,
      },
};

.fops= &fimc_fops,为控制器的操作集合

.ioctl_ops= &fimc_v4l2_ops,为v4l2的操作集合

这这里赋值,后面会用到

    switch (pdata->hw_ver) {
    case 0x40:
        ctrl->limit = &fimc40_limits[id];
        break;
    case 0x43:
    case 0x45:
        ctrl->limit = &fimc43_limits[id];
        break;
    case 0x50:
        ctrl->limit = &fimc50_limits[id];
        break;
    }

这三个与控制器相关,在设备的那里赋值为0x45,所以看这个

ctrl->limit= &fimc43_limits[id];

structfimc_limit fimc43_limits[FIMC_DEVICES] = {
    {
        .pre_dst_w   = 4224,
        .bypass_w    = 8192,
        .trg_h_no_rot    = 4224,
        .trg_h_rot = 1920,
        .real_w_no_rot  = 8192,
        .real_h_rot    = 1920,
    }, {
        .pre_dst_w   = 4224,
        .bypass_w    = 8192,
        .trg_h_no_rot    = 4224,
        .trg_h_rot = 1920,
        .real_w_no_rot  = 8192,
        .real_h_rot    = 1920,
    }, {
        .pre_dst_w   = 1920,
        .bypass_w    = 8192,
        .trg_h_no_rot    = 1920,
        .trg_h_rot = 1280,
        .real_w_no_rot  = 8192,
        .real_h_rot    = 1280,
    },
};

这几个与硬件相关,数据手册有写,如下:


后面是申请io内存并映射,申请中断

最后调用fimc_hwset_reset(ctrl);设置寄存器

int fimc_hwset_reset(struct fimc_control*ctrl)
{
      u32cfg = 0;


      cfg =readl(ctrl->regs + S3C_CISRCFMT);
      cfg|= S3C_CISRCFMT_ITU601_8BIT;
      writel(cfg,ctrl->regs + S3C_CISRCFMT);


      /*s/w reset */
      cfg =readl(ctrl->regs + S3C_CIGCTRL);
      cfg|= (S3C_CIGCTRL_SWRST);
      writel(cfg,ctrl->regs + S3C_CIGCTRL);
      mdelay(1);


      cfg =readl(ctrl->regs + S3C_CIGCTRL);
      cfg&= ~S3C_CIGCTRL_SWRST;
      writel(cfg,ctrl->regs + S3C_CIGCTRL);


      /* incase of ITU656, CISRCFMT[31] should be 0 */
      if((ctrl->cap != NULL) && (ctrl->cam->fmt ==ITU_656_YCBCR422_8BIT)) {
           cfg = readl(ctrl->regs + S3C_CISRCFMT);
           cfg &= ~S3C_CISRCFMT_ITU601_8BIT;
           writel(cfg, ctrl->regs + S3C_CISRCFMT);
      }


      fimc_reset_cfg(ctrl);


      return0;

}

static void fimc_reset_cfg(structfimc_control *ctrl)
{
      inti;
      u32cfg[][2] = {
           { 0x018, 0x00000000 }, { 0x01c, 0x00000000 },
           { 0x020, 0x00000000 }, { 0x024, 0x00000000 },
           { 0x028, 0x00000000 }, { 0x02c, 0x00000000 },
           { 0x030, 0x00000000 }, { 0x034, 0x00000000 },
           { 0x038, 0x00000000 }, { 0x03c, 0x00000000 },
           { 0x040, 0x00000000 }, { 0x044, 0x00000000 },
           { 0x048, 0x00000000 }, { 0x04c, 0x00000000 },
           { 0x050, 0x00000000 }, { 0x054, 0x00000000 },
           { 0x058, 0x18000000 }, { 0x05c, 0x00000000 },
           { 0x0c0, 0x00000000 }, { 0x0c4, 0xffffffff },
           { 0x0d0, 0x00100080 }, { 0x0d4, 0x00000000 },
           { 0x0d8, 0x00000000 }, { 0x0dc, 0x00000000 },
           { 0x0f8, 0x00000000 }, { 0x0fc, 0x04000000 },
           { 0x168, 0x00000000 }, { 0x16c, 0x00000000 },
           { 0x170, 0x00000000 }, { 0x174, 0x00000000 },
           { 0x178, 0x00000000 }, { 0x17c, 0x00000000 },
           { 0x180, 0x00000000 }, { 0x184, 0x00000000 },
           { 0x188, 0x00000000 }, { 0x18c, 0x00000000 },
           { 0x194, 0x0000001e },
      };


      for(i = 0; i < sizeof(cfg) / 8; i++)
           writel(cfg[i][1], ctrl->regs + cfg[i][0]);

}

设置完后,返回到fimc_probe,结下了设置gpio,设置电源,设置时钟。

结下来ret =v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev);就是一些赋值

int v4l2_device_register(struct device *dev,struct v4l2_device *v4l2_dev)
{
      if(v4l2_dev == NULL)
           return -EINVAL;


      INIT_LIST_HEAD(&v4l2_dev->subdevs);
      spin_lock_init(&v4l2_dev->lock);
      v4l2_dev->dev= dev;
      if(dev == NULL) {
           /* If dev == NULL, then name must be filled in by thecaller */
           WARN_ON(!v4l2_dev->name[0]);
           return 0;
      }


      /*Set name to driver name + device name if it is empty. */
      if(!v4l2_dev->name[0])
           snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),"%s %s",
                 dev->driver->name, dev_name(dev));
      if(dev_get_drvdata(dev))
           v4l2_warn(v4l2_dev, "Non-NULL drvdata onregister\n");
      dev_set_drvdata(dev,v4l2_dev);
      return0;
}

dev_set_drvdata(dev,v4l2_dev);将v4l2_dev放到dev的私数据中,以便后面用

      if(!fimc_dev->initialized) {
           ret = fimc_init_global(pdev);
           if (ret)
                 goto err_v4l2;
      }

判断摄头是否初始化了,如果初始化了,就跳过,没有初始化就初始化

static int fimc_init_global(structplatform_device *pdev)
{
      structs3c_platform_fimc *pdata;
      structs3c_platform_camera *cam;
      inti;


      pdata= to_fimc_plat(&pdev->dev);


      /*Registering external camera modules. re-arrange order to be sure */
      for(i = 0; i < FIMC_MAXCAMS; i++) {
           cam = pdata->camera[i];
           if (!cam)
                 break;


           cam->srclk = clk_get(&pdev->dev,cam->srclk_name);
           if (IS_ERR(cam->srclk)) {
                 dev_err(&pdev->dev,
                      "%s: failed to get mclk src(srclk_name:%s)\n",
                      __func__, cam->srclk_name);
                 return -EINVAL;
           }


           /* mclk */
           cam->clk = clk_get(&pdev->dev,cam->clk_name);
           if (IS_ERR(cam->clk)) {
                 dev_err(&pdev->dev,
                      "%s: failed to get mclk src(clk_name:%s)\n",
                      __func__, cam->clk_name);
                 clk_put(cam->srclk);
                 return -EINVAL;
           }



           clk_set_parent(cam->clk, cam->srclk);
           clk_put(cam->clk);
           clk_put(cam->srclk);


           /* Assign camera device to fimc */
           memcpy(&fimc_dev->camera[i], cam, sizeof(*cam));
           fimc_dev->camera_isvalid[i] = 1;
           fimc_dev->camera[i].initialized = 0;
      }


      fimc_dev->active_camera= -1;
      fimc_dev->initialized= 1;


      return0;
}

fimc_dev->initialized= 1;初始化完后这个值赋为1,表明已经初始化

    ret = video_register_device(ctrl->vd,VFL_TYPE_GRABBER, ctrl->id);
    if (ret) {
        fimc_err("%s: cannot register videodriver\n", __func__);
        goto err_v4l2;
    }


    video_set_drvdata(ctrl->vd, ctrl);

注册video设备并将ctrl存入video的私有数据中

int video_register_device(struct video_device*vdev, int type, int nr)
{
      return__video_register_device(vdev, type, nr, 1);
}

static int __video_register_device(structvideo_device *vdev, int type, int nr,
           int warn_if_nr_in_use)
{
      int i= 0;
      intret;
      intminor_offset = 0;
      intminor_cnt = VIDEO_NUM_DEVICES;
      constchar *name_base;
      void*priv = video_get_drvdata(vdev);


      /* Aminor value of -1 marks this video device as never
         having been registered */
      vdev->minor= -1;


      /*the release callback MUST be present */
      WARN_ON(!vdev->release);
      if(!vdev->release)
           return -EINVAL;


      /*v4l2_fh support */
      spin_lock_init(&vdev->fh_lock);
      INIT_LIST_HEAD(&vdev->fh_list);


      /*Part 1: check device type */
      switch(type) {
      caseVFL_TYPE_GRABBER:
           name_base = "video";
           break;
      caseVFL_TYPE_VTX:
           name_base = "vtx";
           break;
      caseVFL_TYPE_VBI:
           name_base = "vbi";
           break;
      caseVFL_TYPE_RADIO:
           name_base = "radio";
           break;
      default:
           printk(KERN_ERR "%s called with unknown type:%d\n",
                  __func__, type);
           return -EINVAL;
      }


      vdev->vfl_type= type;
      vdev->cdev= NULL;
      if(vdev->v4l2_dev && vdev->v4l2_dev->dev)
           vdev->parent = vdev->v4l2_dev->dev;


      /*Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
      /*Keep the ranges for the first four types for historical
       * reasons.
       * Newer devices (not yet in place) should use the range
       * of 128-191 and just pick the first free minor there
       * (new style). */
      switch(type) {
      caseVFL_TYPE_GRABBER:
           minor_offset = 0;
           minor_cnt = 64;
           break;
      caseVFL_TYPE_RADIO:
           minor_offset = 64;
           minor_cnt = 64;
           break;
      caseVFL_TYPE_VTX:
           minor_offset = 192;
           minor_cnt = 32;
           break;
      caseVFL_TYPE_VBI:
           minor_offset = 224;
           minor_cnt = 32;
           break;
      default:
           minor_offset = 128;
           minor_cnt = 64;
           break;
      }
#endif


      /*Pick a device node number */
      mutex_lock(&videodev_lock);
      nr =devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
      if(nr == minor_cnt)
           nr = devnode_find(vdev, 0, minor_cnt);
      if(nr == minor_cnt) {
           printk(KERN_ERR "could not get a free device nodenumber\n");
           mutex_unlock(&videodev_lock);
           return -ENFILE;
      }
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
      /*1-on-1 mapping of device node number to minor number */
      i =nr;
#else
      /*The device node number and minor numbers are independent, so
         we just find the first free minor number. */
      for(i = 0; i < VIDEO_NUM_DEVICES; i++)
           if (video_device[i] == NULL)
                 break;
      if (i== VIDEO_NUM_DEVICES) {
           mutex_unlock(&videodev_lock);
           printk(KERN_ERR "could not get a freeminor\n");
           return -ENFILE;
      }
#endif
      vdev->minor= i + minor_offset;
      vdev->num= nr;
      devnode_set(vdev);


      /*Should not happen since we thought this minor was free */
      WARN_ON(video_device[vdev->minor]!= NULL);
      vdev->index= get_index(vdev);
      mutex_unlock(&videodev_lock);


      /*Part 3: Initialize the character device */
      vdev->cdev= cdev_alloc();
      if(vdev->cdev == NULL) {
           ret = -ENOMEM;
           goto cleanup;
      }
      if(vdev->fops->unlocked_ioctl)
           vdev->cdev->ops = &v4l2_unlocked_fops;
      else
           vdev->cdev->ops = &v4l2_fops;
      vdev->cdev->owner= vdev->fops->owner;
      ret =cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
      if(ret < 0) {
           printk(KERN_ERR "%s: cdev_add failed\n",__func__);
           kfree(vdev->cdev);
           vdev->cdev = NULL;
           goto cleanup;
      }


      /*Part 4: register the device with sysfs */
      memset(&vdev->dev,0, sizeof(vdev->dev));
      /*The memset above cleared the device's drvdata, so
         put back the copy we made earlier. */
      video_set_drvdata(vdev,priv);
      vdev->dev.class= &video_class;
      vdev->dev.devt= MKDEV(VIDEO_MAJOR, vdev->minor);
      if(vdev->parent)
           vdev->dev.parent = vdev->parent;
      dev_set_name(&vdev->dev,"%s%d", name_base, vdev->num);
      ret =device_register(&vdev->dev);
      if(ret < 0) {
           printk(KERN_ERR "%s: device_register failed\n",__func__);
           goto cleanup;
      }
      /*Register the release callback that will be called when the last
         reference to the device goes away. */
      vdev->dev.release= v4l2_device_release;


      if(nr != -1 && nr != vdev->num && warn_if_nr_in_use)
           printk(KERN_WARNING "%s: requested %s%d, got%s\n", __func__,
                 name_base, nr, video_device_node_name(vdev));


      /* Part5: Activate this minor. The char device can now be used. */
      set_bit(V4L2_FL_REGISTERED,&vdev->flags);
      mutex_lock(&videodev_lock);
      video_device[vdev->minor]= vdev;
      mutex_unlock(&videodev_lock);
      return0;


cleanup:
      mutex_lock(&videodev_lock);
      if(vdev->cdev)
           cdev_del(vdev->cdev);
      devnode_clear(vdev);
      mutex_unlock(&videodev_lock);
      /*Mark this video device as never having been registered. */
      vdev->minor= -1;
      returnret;
}
主要工作就是确定video类型并注册字符设备和创建节点
      if(vdev->fops->unlocked_ioctl)
           vdev->cdev->ops = &v4l2_unlocked_fops;
      else
           vdev->cdev->ops = &v4l2_fops;
      vdev->cdev->owner= vdev->fops->owner;
      ret =cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
static const struct file_operations v4l2_fops = {
      .owner= THIS_MODULE,
      .read= v4l2_read,
      .write= v4l2_write,
      .open= v4l2_open,
      .get_unmapped_area= v4l2_get_unmapped_area,
      .mmap= v4l2_mmap,
      .ioctl= v4l2_ioctl,
#ifdef CONFIG_COMPAT
      .compat_ioctl= v4l2_compat_ioctl32,
#endif
      .release= v4l2_release,
      .poll= v4l2_poll,
      .llseek= no_llseek,
};
该操作集合都是回调上层video的fop

static int v4l2_open(struct inode *inode,struct file *filp)
{
      structvideo_device *vdev;
      intret = 0;


      /*Check if the video device is available */
      mutex_lock(&videodev_lock);
      vdev= video_devdata(filp);
      /*return ENODEV if the video device has been removed
         already or if it is not registered anymore. */
      if(vdev == NULL || !video_is_registered(vdev)) {
           mutex_unlock(&videodev_lock);
           return -ENODEV;
      }
      /*and increase the device refcount */
      video_get(vdev);
      mutex_unlock(&videodev_lock);
      if(vdev->fops->open)
           ret = vdev->fops->open(filp);


      /*decrease the refcount in case of an error */
      if(ret)
           video_put(vdev);
      returnret;
}
其中重要的.ioctl = v4l2_ioctl,

//是针对v4l2操作的接口,最终调用与硬件相关的v4l2操作

static int v4l2_ioctl(struct inode *inode,struct file *filp,

                   unsignedint cmd, unsigned long arg)

{

         structvideo_device *vdev = video_devdata(filp);

 

 

         if(!vdev->fops->ioctl)

                   return-ENOTTY;

         /*Allow ioctl to continue even if the device was unregistered.

            Things like dequeueing buffers might stillbe useful. */

         returnvdev->fops->ioctl(filp, cmd, arg);

}

 

//调用上层ioctl

long video_ioctl2(struct file *file,

                unsigned int cmd, unsigned long arg)

{

         char sbuf[128];

         void    *mbuf = NULL;

         void  *parg = (void *)arg;

         long err  =-EINVAL;

         int     is_ext_ctrl;

         size_t  ctrls_size = 0;

         void__user *user_ptr = NULL;

 

 

#ifdef __OLD_VIDIOC_

         cmd= video_fix_command(cmd);

#endif

         is_ext_ctrl= (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||

                          cmd == VIDIOC_TRY_EXT_CTRLS);

 

 

         /*  Copy arguments into temp kernel buffer  */

         if(_IOC_DIR(cmd) != _IOC_NONE) {

                   if(_IOC_SIZE(cmd) <= sizeof(sbuf)) {

                            parg= sbuf;

                   }else {

                            /*too big to allocate from stack */

                            mbuf= kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);

                            if(NULL == mbuf)

                                     return-ENOMEM;

                            parg= mbuf;

                   }

 

 

                   err= -EFAULT;

                   if(_IOC_DIR(cmd) & _IOC_WRITE) {

                            unsignedlong n = cmd_input_size(cmd);

 

 

                            if (copy_from_user(parg, (void __user*)arg, n))

                                     gotoout;

 

 

                            /*zero out anything we don't copy from userspace */

                            if(n < _IOC_SIZE(cmd))

                                     memset((u8*)parg + n, 0, _IOC_SIZE(cmd) - n);

                   }else {

                            /*read-only ioctl */

                            memset(parg,0, _IOC_SIZE(cmd));

                   }

         }

 

 

         if(is_ext_ctrl) {

                   structv4l2_ext_controls *p = parg;

 

 

                   /*In case of an error, tell the caller that it wasn't

                      a specific control that caused it. */

                   p->error_idx= p->count;

                   user_ptr= (void __user *)p->controls;

                   if(p->count) {

                            ctrls_size= sizeof(struct v4l2_ext_control) * p->count;

                            /*Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */

                            mbuf= kmalloc(ctrls_size, GFP_KERNEL);

                            err= -ENOMEM;

                            if(NULL == mbuf)

                                     gotoout_ext_ctrl;

                            err= -EFAULT;

                            if(copy_from_user(mbuf, user_ptr, ctrls_size))

                                     gotoout_ext_ctrl;

                            p->controls= mbuf;

                   }

         }

 

 

         /*Handles IOCTL */

         err= __video_do_ioctl(file, cmd, parg);

         if(err == -ENOIOCTLCMD)

                   err= -EINVAL;

         if(is_ext_ctrl) {

                   structv4l2_ext_controls *p = parg;

 

 

                   p->controls= (void *)user_ptr;

                   if(p->count && err == 0 && copy_to_user(user_ptr, mbuf,ctrls_size))

                            err= -EFAULT;

                   gotoout_ext_ctrl;

         }

         if(err < 0)

                   gotoout;

 

 

out_ext_ctrl:

         /*  Copy results into user buffer  */

         switch(_IOC_DIR(cmd)) {

         case_IOC_READ:

         case(_IOC_WRITE | _IOC_READ):

                   if(copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))

                            err= -EFAULT;

                   break;

         }

 

 

out:

         kfree(mbuf);

         returnerr;

}

 

最后调用执行的ioctl

err = __video_do_ioctl(file, cmd, parg);

 

//这个函数很长

static long __video_do_ioctl(struct file*file,

                   unsignedint cmd, void *arg)

{

         structvideo_device *vfd = video_devdata(file);

         conststruct v4l2_ioctl_ops *ops = vfd->ioctl_ops;

         void*fh = file->private_data;

         longret = -EINVAL;

 

 

         if(ops == NULL) {

                   printk(KERN_WARNING"videodev: \"%s\" has no ioctl_ops.\n",

                                     vfd->name);

                   return-EINVAL;

         }

 

 

#ifdef CONFIG_VIDEO_V4L1_COMPAT

         /********************************************************

          All other V4L1 calls are handled by v4l1_compatmodule.

          Those calls will be translated into V4L2calls, and

          __video_do_ioctl will be called again, withone or more

          V4L2 ioctls.

          ********************************************************/

         if(_IOC_TYPE(cmd) == 'v' && cmd != VIDIOCGMBUF &&

                                     _IOC_NR(cmd)< BASE_VIDIOCPRIVATE) {

                   returnv4l_compat_translate_ioctl(file, cmd, arg,

                                                        __video_do_ioctl);

         }

#endif

 

 

         if((vfd->debug & V4L2_DEBUG_IOCTL) &&

                                     !(vfd->debug& V4L2_DEBUG_IOCTL_ARG)) {

                   v4l_print_ioctl(vfd->name,cmd);

                   printk(KERN_CONT"\n");

         }

 

 

         switch(cmd) {

 

 

#ifdef CONFIG_VIDEO_V4L1_COMPAT

         /***********************************************************

          Handles calls to the obsoleted V4L1 API

          Due to the nature of VIDIOCGMBUF, each driverthat supports

          V4L1 should implement its own handler for thisioctl.

          ***********************************************************/

 

 

         /*--- streaming capture ------------------------------------- */

         caseVIDIOCGMBUF:

         {

                   structvideo_mbuf *p = arg;

 

 

                   if(!ops->vidiocgmbuf)

                            break;

                   ret= ops->vidiocgmbuf(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"size=%d, frames=%d, offsets=0x%08lx\n",

                                                        p->size,p->frames,

                                                        (unsignedlong)p->offsets);

                   break;

         }

#endif

 

 

         /*--- capabilities ------------------------------------------ */

         caseVIDIOC_QUERYCAP:

         {

                   structv4l2_capability *cap = (struct v4l2_capability *)arg;

 

 

                   if(!ops->vidioc_querycap)

                            break;

 

 

                   ret= ops->vidioc_querycap(file, fh, cap);

                   if(!ret)

                            dbgarg(cmd,"driver=%s, card=%s, bus=%s, "

                                               "version=0x%08x,"

                                               "capabilities=0x%08x\n",

                                               cap->driver,cap->card, cap->bus_info,

                                               cap->version,

                                               cap->capabilities);

                   break;

         }

 

 

         /*--- priority ------------------------------------------ */

         caseVIDIOC_G_PRIORITY:

         {

                   enumv4l2_priority *p = arg;

 

 

                   if(!ops->vidioc_g_priority)

                            break;

                   ret= ops->vidioc_g_priority(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"priority is %d\n", *p);

                   break;

         }

         caseVIDIOC_S_PRIORITY:

         {

                   enumv4l2_priority *p = arg;

 

 

                   if(!ops->vidioc_s_priority)

                            break;

                   dbgarg(cmd,"setting priority to %d\n", *p);

                   ret= ops->vidioc_s_priority(file, fh, *p);

                   break;

         }

 

 

         /*--- capture ioctls ---------------------------------------- */

         caseVIDIOC_ENUM_FMT:

         {

                   structv4l2_fmtdesc *f = arg;

 

 

                   switch(f->type) {

                   caseV4L2_BUF_TYPE_VIDEO_CAPTURE:

                            if(ops->vidioc_enum_fmt_vid_cap)

                                     ret= ops->vidioc_enum_fmt_vid_cap(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OVERLAY:

                            if(ops->vidioc_enum_fmt_vid_overlay)

                                     ret= ops->vidioc_enum_fmt_vid_overlay(file,

                                               fh,f);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OUTPUT:

                            if(ops->vidioc_enum_fmt_vid_out)

                                     ret= ops->vidioc_enum_fmt_vid_out(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_PRIVATE:

                            if(ops->vidioc_enum_fmt_type_private)

                                     ret= ops->vidioc_enum_fmt_type_private(file,

                                                                           fh,f);

                            break;

                   default:

                            break;

                   }

                   if(!ret)

                            dbgarg(cmd,"index=%d, type=%d, flags=%d, "

                                     "pixelformat=%c%c%c%c,description='%s'\n",

                                     f->index,f->type, f->flags,

                                     (f->pixelformat& 0xff),

                                     (f->pixelformat>>  8) & 0xff,

                                     (f->pixelformat>> 16) & 0xff,

                                     (f->pixelformat>> 24) & 0xff,

                                     f->description);

                   break;

         }

         caseVIDIOC_G_FMT:

         {

                   structv4l2_format *f = (struct v4l2_format *)arg;

 

 

                   /*FIXME: Should be one dump per type */

                   dbgarg(cmd,"type=%s\n", prt_names(f->type, v4l2_type_names));

 

 

                   switch(f->type) {

                   caseV4L2_BUF_TYPE_VIDEO_CAPTURE:

                            if(ops->vidioc_g_fmt_vid_cap)

                                     ret= ops->vidioc_g_fmt_vid_cap(file, fh, f);

                            if(!ret)

                                     v4l_print_pix_fmt(vfd,&f->fmt.pix);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OVERLAY:

                            if(ops->vidioc_g_fmt_vid_overlay)

                                     ret= ops->vidioc_g_fmt_vid_overlay(file,

                                                                               fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OUTPUT:

                            if(ops->vidioc_g_fmt_vid_out)

                                     ret= ops->vidioc_g_fmt_vid_out(file, fh, f);

                            if(!ret)

                                     v4l_print_pix_fmt(vfd,&f->fmt.pix);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:

                            if(ops->vidioc_g_fmt_vid_out_overlay)

                                     ret= ops->vidioc_g_fmt_vid_out_overlay(file,

                                            fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VBI_CAPTURE:

                            if(ops->vidioc_g_fmt_vbi_cap)

                                     ret= ops->vidioc_g_fmt_vbi_cap(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VBI_OUTPUT:

                            if(ops->vidioc_g_fmt_vbi_out)

                                     ret= ops->vidioc_g_fmt_vbi_out(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_SLICED_VBI_CAPTURE:

                            if(ops->vidioc_g_fmt_sliced_vbi_cap)

                                     ret= ops->vidioc_g_fmt_sliced_vbi_cap(file,

                                                                                    fh,f);

                            break;

                   caseV4L2_BUF_TYPE_SLICED_VBI_OUTPUT:

                            if(ops->vidioc_g_fmt_sliced_vbi_out)

                                     ret= ops->vidioc_g_fmt_sliced_vbi_out(file,

                                                                                    fh,f);

                            break;

                   caseV4L2_BUF_TYPE_PRIVATE:

                            if(ops->vidioc_g_fmt_type_private)

                                     ret= ops->vidioc_g_fmt_type_private(file,

                                                                           fh,f);

                            break;

                   }

 

 

                   break;

         }

         caseVIDIOC_S_FMT:

         {

                   structv4l2_format *f = (struct v4l2_format *)arg;

 

 

                   /*FIXME: Should be one dump per type */

                   dbgarg(cmd,"type=%s\n", prt_names(f->type, v4l2_type_names));

 

 

                   switch(f->type) {

                   caseV4L2_BUF_TYPE_VIDEO_CAPTURE:

                            CLEAR_AFTER_FIELD(f,fmt.pix);

                            v4l_print_pix_fmt(vfd,&f->fmt.pix);

                            if(ops->vidioc_s_fmt_vid_cap)

                                     ret= ops->vidioc_s_fmt_vid_cap(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OVERLAY:

                            CLEAR_AFTER_FIELD(f,fmt.win);

                            if(ops->vidioc_s_fmt_vid_overlay)

                                     ret= ops->vidioc_s_fmt_vid_overlay(file,

                                                                               fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OUTPUT:

                            CLEAR_AFTER_FIELD(f,fmt.pix);

                            v4l_print_pix_fmt(vfd,&f->fmt.pix);

                            if(ops->vidioc_s_fmt_vid_out)

                                     ret= ops->vidioc_s_fmt_vid_out(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:

                            CLEAR_AFTER_FIELD(f,fmt.win);

                            if(ops->vidioc_s_fmt_vid_out_overlay)

                                     ret= ops->vidioc_s_fmt_vid_out_overlay(file,

                                               fh,f);

                            break;

                   caseV4L2_BUF_TYPE_VBI_CAPTURE:

                            CLEAR_AFTER_FIELD(f,fmt.vbi);

                            if(ops->vidioc_s_fmt_vbi_cap)

                                     ret= ops->vidioc_s_fmt_vbi_cap(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VBI_OUTPUT:

                            CLEAR_AFTER_FIELD(f,fmt.vbi);

                            if(ops->vidioc_s_fmt_vbi_out)

                                     ret= ops->vidioc_s_fmt_vbi_out(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_SLICED_VBI_CAPTURE:

                            CLEAR_AFTER_FIELD(f,fmt.sliced);

                            if(ops->vidioc_s_fmt_sliced_vbi_cap)

                                     ret= ops->vidioc_s_fmt_sliced_vbi_cap(file,

                                                                                    fh,f);

                            break;

                   caseV4L2_BUF_TYPE_SLICED_VBI_OUTPUT:

                            CLEAR_AFTER_FIELD(f,fmt.sliced);

                            if(ops->vidioc_s_fmt_sliced_vbi_out)

                                     ret= ops->vidioc_s_fmt_sliced_vbi_out(file,

                                                                                    fh,f);

                            break;

                   caseV4L2_BUF_TYPE_PRIVATE:

                            /*CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */

                            if(ops->vidioc_s_fmt_type_private)

                                     ret =ops->vidioc_s_fmt_type_private(file,

                                                                           fh,f);

                            break;

                   }

                   break;

         }

         caseVIDIOC_TRY_FMT:

         {

                   structv4l2_format *f = (struct v4l2_format *)arg;

 

 

                   /*FIXME: Should be one dump per type */

                   dbgarg(cmd,"type=%s\n", prt_names(f->type,

                                                        v4l2_type_names));

                   switch(f->type) {

                   caseV4L2_BUF_TYPE_VIDEO_CAPTURE:

                            CLEAR_AFTER_FIELD(f,fmt.pix);

                            if(ops->vidioc_try_fmt_vid_cap)

                                     ret= ops->vidioc_try_fmt_vid_cap(file, fh, f);

                            if(!ret)

                                     v4l_print_pix_fmt(vfd,&f->fmt.pix);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OVERLAY:

                            CLEAR_AFTER_FIELD(f,fmt.win);

                            if(ops->vidioc_try_fmt_vid_overlay)

                                     ret= ops->vidioc_try_fmt_vid_overlay(file,

                                               fh,f);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OUTPUT:

                            CLEAR_AFTER_FIELD(f,fmt.pix);

                            if(ops->vidioc_try_fmt_vid_out)

                                     ret= ops->vidioc_try_fmt_vid_out(file, fh, f);

                            if(!ret)

                                     v4l_print_pix_fmt(vfd,&f->fmt.pix);

                            break;

                   caseV4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:

                            CLEAR_AFTER_FIELD(f,fmt.win);

                            if(ops->vidioc_try_fmt_vid_out_overlay)

                                     ret= ops->vidioc_try_fmt_vid_out_overlay(file,

                                            fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VBI_CAPTURE:

                            CLEAR_AFTER_FIELD(f,fmt.vbi);

                            if(ops->vidioc_try_fmt_vbi_cap)

                                     ret= ops->vidioc_try_fmt_vbi_cap(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_VBI_OUTPUT:

                            CLEAR_AFTER_FIELD(f,fmt.vbi);

                            if(ops->vidioc_try_fmt_vbi_out)

                                     ret= ops->vidioc_try_fmt_vbi_out(file, fh, f);

                            break;

                   caseV4L2_BUF_TYPE_SLICED_VBI_CAPTURE:

                            CLEAR_AFTER_FIELD(f,fmt.sliced);

                            if(ops->vidioc_try_fmt_sliced_vbi_cap)

                                     ret= ops->vidioc_try_fmt_sliced_vbi_cap(file,

                                                                           fh,f);

                            break;

                   caseV4L2_BUF_TYPE_SLICED_VBI_OUTPUT:

                            CLEAR_AFTER_FIELD(f,fmt.sliced);

                            if(ops->vidioc_try_fmt_sliced_vbi_out)

                                     ret= ops->vidioc_try_fmt_sliced_vbi_out(file,

                                                                           fh,f);

                            break;

                   caseV4L2_BUF_TYPE_PRIVATE:

                            /*CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */

                            if(ops->vidioc_try_fmt_type_private)

                                     ret= ops->vidioc_try_fmt_type_private(file,

                                                                           fh,f);

                            break;

                   }

 

 

                   break;

         }

         /*FIXME: Those buf reqs could be handled here,

            with some changes on videobuf to allow itsheader to be included at

            videodev2.h or being merged at videodev2.

          */

         caseVIDIOC_REQBUFS:

         {

                   structv4l2_requestbuffers *p = arg;

 

 

                   if(!ops->vidioc_reqbufs)

                            break;

                   ret= check_fmt(ops, p->type);

                   if(ret)

                            break;

 

 

                   if(p->type < V4L2_BUF_TYPE_PRIVATE)

                            CLEAR_AFTER_FIELD(p,memory);

 

 

                   ret= ops->vidioc_reqbufs(file, fh, p);

                   dbgarg(cmd,"count=%d, type=%s, memory=%s\n",

                                     p->count,

                                     prt_names(p->type,v4l2_type_names),

                                     prt_names(p->memory,v4l2_memory_names));

                   break;

         }

         caseVIDIOC_QUERYBUF:

         {

                   structv4l2_buffer *p = arg;

 

 

                   if(!ops->vidioc_querybuf)

                            break;

                   ret= check_fmt(ops, p->type);

                   if(ret)

                            break;

 

 

                   ret= ops->vidioc_querybuf(file, fh, p);

                   if(!ret)

                            dbgbuf(cmd,vfd, p);

                   break;

         }

         caseVIDIOC_QBUF:

         {

                   structv4l2_buffer *p = arg;

 

 

                   if(!ops->vidioc_qbuf)

                            break;

                   ret= check_fmt(ops, p->type);

                   if(ret)

                            break;

 

 

                   ret= ops->vidioc_qbuf(file, fh, p);

                   if(!ret)

                            dbgbuf(cmd,vfd, p);

                   break;

         }

         caseVIDIOC_DQBUF:

         {

                   structv4l2_buffer *p = arg;

 

 

                   if(!ops->vidioc_dqbuf)

                            break;

                   ret= check_fmt(ops, p->type);

                   if(ret)

                            break;

 

 

                   ret= ops->vidioc_dqbuf(file, fh, p);

                   if(!ret)

                            dbgbuf(cmd,vfd, p);

                   break;

         }

         caseVIDIOC_OVERLAY:

         {

                   int*i = arg;

 

 

                   if(!ops->vidioc_overlay)

                            break;

                   dbgarg(cmd,"value=%d\n", *i);

                   ret= ops->vidioc_overlay(file, fh, *i);

                   break;

         }

         caseVIDIOC_G_FBUF:

         {

                   structv4l2_framebuffer *p = arg;

 

 

                   if(!ops->vidioc_g_fbuf)

                            break;

                   ret= ops->vidioc_g_fbuf(file, fh, arg);

                   if(!ret) {

                            dbgarg(cmd,"capability=0x%x, flags=%d, base=0x%08lx\n",

                                               p->capability,p->flags,

                                               (unsignedlong)p->base);

                            v4l_print_pix_fmt(vfd,&p->fmt);

                   }

                   break;

         }

         caseVIDIOC_S_FBUF:

         {

                   structv4l2_framebuffer *p = arg;

 

 

                   if(!ops->vidioc_s_fbuf)

                            break;

                   dbgarg(cmd,"capability=0x%x, flags=%d, base=0x%08lx\n",

                            p->capability,p->flags, (unsigned long)p->base);

                   v4l_print_pix_fmt(vfd,&p->fmt);

                   ret= ops->vidioc_s_fbuf(file, fh, arg);

                   break;

         }

         caseVIDIOC_STREAMON:

         {

                   enumv4l2_buf_type i = *(int *)arg;

 

 

                   if(!ops->vidioc_streamon)

                            break;

                   dbgarg(cmd,"type=%s\n", prt_names(i, v4l2_type_names));

                   ret= ops->vidioc_streamon(file, fh, i);

                   break;

         }

         caseVIDIOC_STREAMOFF:

         {

                   enumv4l2_buf_type i = *(int *)arg;

 

 

                   if(!ops->vidioc_streamoff)

                            break;

                   dbgarg(cmd,"type=%s\n", prt_names(i, v4l2_type_names));

                   ret= ops->vidioc_streamoff(file, fh, i);

                   break;

         }

         /*---------- tv norms ---------- */

         caseVIDIOC_ENUMSTD:

         {

                   structv4l2_standard *p = arg;

                   v4l2_std_idid = vfd->tvnorms, curr_id = 0;

                   unsignedint index = p->index, i, j = 0;

                   constchar *descr = "";

 

 

                   /*Return norm array in a canonical way */

                   for(i = 0; i <= index && id; i++) {

                            /*last std value in the standards array is 0, so this

                               while always ends there since (id & 0)== 0. */

                            while((id & standards[j].std) != standards[j].std)

                                     j++;

                            curr_id= standards[j].std;

                            descr= standards[j].descr;

                            j++;

                            if(curr_id == 0)

                                     break;

                            if(curr_id != V4L2_STD_PAL &&

                                curr_id != V4L2_STD_SECAM &&

                                curr_id != V4L2_STD_NTSC)

                                     id&= ~curr_id;

                   }

                   if(i <= index)

                            break;

 

 

                   v4l2_video_std_construct(p,curr_id, descr);

 

 

                   dbgarg(cmd,"index=%d, id=0x%Lx, name=%s, fps=%d/%d, "

                                     "framelines=%d\n",p->index,

                                     (unsignedlong long)p->id, p->name,

                                     p->frameperiod.numerator,

                                     p->frameperiod.denominator,

                                     p->framelines);

 

 

                   ret= 0;

                   break;

         }

         caseVIDIOC_G_STD:

         {

                   v4l2_std_id*id = arg;

 

 

                   ret= 0;

                   /*Calls the specific handler */

                   if(ops->vidioc_g_std)

                            ret= ops->vidioc_g_std(file, fh, id);

                   elseif (vfd->current_norm)

                            *id= vfd->current_norm;

                   else

                            ret = -EINVAL;

 

 

                   if(!ret)

                            dbgarg(cmd,"std=0x%08Lx\n", (long long unsigned)*id);

                   break;

         }

         caseVIDIOC_S_STD:

         {

                   v4l2_std_id*id = arg, norm;

 

 

                   dbgarg(cmd,"std=%08Lx\n", (long long unsigned)*id);

 

 

                   norm= (*id) & vfd->tvnorms;

                   if(vfd->tvnorms && !norm)     /*Check if std is supported */

                            break;

 

 

                   /*Calls the specific handler */

                   if(ops->vidioc_s_std)

                            ret= ops->vidioc_s_std(file, fh, &norm);

                   else

                            ret= -EINVAL;

 

 

                   /*Updates standard information */

                   if(ret >= 0)

                            vfd->current_norm= norm;

                   break;

         }

         caseVIDIOC_QUERYSTD:

         {

                   v4l2_std_id*p = arg;

 

 

                   if(!ops->vidioc_querystd)

                            break;

                   ret= ops->vidioc_querystd(file, fh, arg);

                   if(!ret)

                            dbgarg(cmd,"detected std=%08Lx\n",

                                                        (unsignedlong long)*p);

                   break;

         }

         /*------ input switching ---------- */

         /*FIXME: Inputs can be handled inside videodev2 */

         caseVIDIOC_ENUMINPUT:

         {

                   structv4l2_input *p = arg;

 

 

                   /*

                    * We set the flags for CAP_PRESETS,CAP_CUSTOM_TIMINGS &

                    * CAP_STD here based on ioctl handler providedby the

                    * driver. If the driver doesn't support these

                    * for a specific input, it must override theseflags.

                    */

                   if(ops->vidioc_s_std)

                            p->capabilities|= V4L2_IN_CAP_STD;

                   if(ops->vidioc_s_dv_preset)

                            p->capabilities|= V4L2_IN_CAP_PRESETS;

                   if(ops->vidioc_s_dv_timings)

                            p->capabilities|= V4L2_IN_CAP_CUSTOM_TIMINGS;

 

 

                   if(!ops->vidioc_enum_input)

                            break;

 

 

                   ret= ops->vidioc_enum_input(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"index=%d, name=%s, type=%d, "

                                     "audioset=%d,"

                                     "tuner=%d,std=%08Lx, status=%d\n",

                                     p->index,p->name, p->type, p->audioset,

                                     p->tuner,

                                     (unsignedlong long)p->std,

                                     p->status);

                   break;

         }

         caseVIDIOC_G_INPUT:

         {

                   unsignedint *i = arg;

 

 

                   if(!ops->vidioc_g_input)

                            break;

                   ret= ops->vidioc_g_input(file, fh, i);

                   if(!ret)

                            dbgarg(cmd,"value=%d\n", *i);

                   break;

         }

         caseVIDIOC_S_INPUT:

         {

                   unsignedint *i = arg;

 

 

                   if(!ops->vidioc_s_input)

                            break;

                   dbgarg(cmd,"value=%d\n", *i);

                   ret= ops->vidioc_s_input(file, fh, *i);

                   break;

         }

 

 

         /*------ output switching ---------- */

         caseVIDIOC_ENUMOUTPUT:

         {

                   structv4l2_output *p = arg;

 

 

                   if(!ops->vidioc_enum_output)

                            break;

 

 

                   /*

                    * We set the flags for CAP_PRESETS,CAP_CUSTOM_TIMINGS &

                    * CAP_STD here based on ioctl handler providedby the

                    * driver. If the driver doesn't support these

                    * for a specific output, it must overridethese flags.

                    */

                   if(ops->vidioc_s_std)

                            p->capabilities|= V4L2_OUT_CAP_STD;

                   if(ops->vidioc_s_dv_preset)

                            p->capabilities|= V4L2_OUT_CAP_PRESETS;

                   if(ops->vidioc_s_dv_timings)

                            p->capabilities|= V4L2_OUT_CAP_CUSTOM_TIMINGS;

 

 

                   ret= ops->vidioc_enum_output(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"index=%d, name=%s, type=%d, "

                                     "audioset=0x%x,"

                                     "modulator=%d,std=0x%08Lx\n",

                                     p->index,p->name, p->type, p->audioset,

                                     p->modulator,(unsigned long long)p->std);

                   break;

         }

         caseVIDIOC_G_OUTPUT:

         {

                   unsignedint *i = arg;

 

 

                   if(!ops->vidioc_g_output)

                            break;

                   ret= ops->vidioc_g_output(file, fh, i);

                   if(!ret)

                            dbgarg(cmd,"value=%d\n", *i);

                   break;

         }

         caseVIDIOC_S_OUTPUT:

         {

                   unsignedint *i = arg;

 

 

                   if(!ops->vidioc_s_output)

                            break;

                   dbgarg(cmd,"value=%d\n", *i);

                   ret= ops->vidioc_s_output(file, fh, *i);

                   break;

         }

 

 

         /*--- controls ---------------------------------------------- */

         caseVIDIOC_QUERYCTRL:

         {

                   structv4l2_queryctrl *p = arg;

 

 

                   if(!ops->vidioc_queryctrl)

                            break;

                   ret= ops->vidioc_queryctrl(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"id=0x%x, type=%d, name=%s, min/max=%d/%d, "

                                               "step=%d,default=%d, flags=0x%08x\n",

                                               p->id,p->type, p->name,

                                               p->minimum,p->maximum,

                                               p->step,p->default_value, p->flags);

                   else

                            dbgarg(cmd,"id=0x%x\n", p->id);

                   break;

         }

         caseVIDIOC_G_CTRL:

         {

                   structv4l2_control *p = arg;

 

 

                   if(ops->vidioc_g_ctrl)

                            ret= ops->vidioc_g_ctrl(file, fh, p);

                   elseif (ops->vidioc_g_ext_ctrls) {

                            structv4l2_ext_controls ctrls;

                            structv4l2_ext_control ctrl;

 

 

                            ctrls.ctrl_class= V4L2_CTRL_ID2CLASS(p->id);

                            ctrls.count = 1;

                            ctrls.controls= &ctrl;

                            ctrl.id= p->id;

                            ctrl.value= p->value;

                            if(check_ext_ctrls(&ctrls, 1)) {

                                     ret= ops->vidioc_g_ext_ctrls(file, fh, &ctrls);

                                     if(ret == 0)

                                               p->value= ctrl.value;

                            }

                   }else

                            break;

                   if(!ret)

                            dbgarg(cmd,"id=0x%x, value=%d\n", p->id, p->value);

                   else

                            dbgarg(cmd,"id=0x%x\n", p->id);

                   break;

         }

         caseVIDIOC_S_CTRL:

         {

                   structv4l2_control *p = arg;

                   structv4l2_ext_controls ctrls;

                   structv4l2_ext_control ctrl;

 

 

                   if(!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)

                            break;

 

 

                   dbgarg(cmd,"id=0x%x, value=%d\n", p->id, p->value);

 

 

                   if(ops->vidioc_s_ctrl) {

                            ret= ops->vidioc_s_ctrl(file, fh, p);

                            break;

                   }

                   if(!ops->vidioc_s_ext_ctrls)

                            break;

 

 

                   ctrls.ctrl_class= V4L2_CTRL_ID2CLASS(p->id);

                   ctrls.count= 1;

                   ctrls.controls= &ctrl;

                   ctrl.id= p->id;

                   ctrl.value= p->value;

                   if(check_ext_ctrls(&ctrls, 1))

                            ret= ops->vidioc_s_ext_ctrls(file, fh, &ctrls);

                   break;

         }

         caseVIDIOC_G_EXT_CTRLS:

         {

                   structv4l2_ext_controls *p = arg;

 

 

                   p->error_idx= p->count;

                   if(!ops->vidioc_g_ext_ctrls)

                            break;

                   if(check_ext_ctrls(p, 0))

                            ret= ops->vidioc_g_ext_ctrls(file, fh, p);

                   v4l_print_ext_ctrls(cmd,vfd, p, !ret);

                   break;

         }

         caseVIDIOC_S_EXT_CTRLS:

         {

                   structv4l2_ext_controls *p = arg;

 

 

                   p->error_idx= p->count;

                   if(!ops->vidioc_s_ext_ctrls)

                            break;

                   v4l_print_ext_ctrls(cmd,vfd, p, 1);

                   if(check_ext_ctrls(p, 0))

                            ret= ops->vidioc_s_ext_ctrls(file, fh, p);

                   break;

         }

         caseVIDIOC_TRY_EXT_CTRLS:

         {

                   structv4l2_ext_controls *p = arg;

 

 

                   p->error_idx= p->count;

                   if(!ops->vidioc_try_ext_ctrls)

                            break;

                   v4l_print_ext_ctrls(cmd,vfd, p, 1);

                   if(check_ext_ctrls(p, 0))

                            ret= ops->vidioc_try_ext_ctrls(file, fh, p);

                   break;

         }

         caseVIDIOC_QUERYMENU:

         {

                   structv4l2_querymenu *p = arg;

 

 

                   if(!ops->vidioc_querymenu)

                            break;

                   ret= ops->vidioc_querymenu(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"id=0x%x, index=%d, name=%s\n",

                                     p->id,p->index, p->name);

                   else

                            dbgarg(cmd,"id=0x%x, index=%d\n",

                                     p->id,p->index);

                   break;

         }

         /*--- audio ---------------------------------------------- */

         caseVIDIOC_ENUMAUDIO:

         {

                   structv4l2_audio *p = arg;

 

 

                   if(!ops->vidioc_enumaudio)

                            break;

                   ret= ops->vidioc_enumaudio(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"index=%d, name=%s, capability=0x%x, "

                                               "mode=0x%x\n",p->index, p->name,

                                               p->capability,p->mode);

                   else

                            dbgarg(cmd,"index=%d\n", p->index);

                   break;

         }

         caseVIDIOC_G_AUDIO:

         {

                   structv4l2_audio *p = arg;

 

 

                   if(!ops->vidioc_g_audio)

                            break;

 

 

                   ret= ops->vidioc_g_audio(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"index=%d, name=%s, capability=0x%x, "

                                               "mode=0x%x\n",p->index,

                                               p->name,p->capability, p->mode);

                   else

                            dbgarg(cmd,"index=%d\n", p->index);

                   break;

         }

         caseVIDIOC_S_AUDIO:

         {

                   structv4l2_audio *p = arg;

 

 

                   if(!ops->vidioc_s_audio)

                            break;

                   dbgarg(cmd,"index=%d, name=%s, capability=0x%x, "

                                               "mode=0x%x\n",p->index, p->name,

                                               p->capability,p->mode);

                   ret= ops->vidioc_s_audio(file, fh, p);

                   break;

         }

         caseVIDIOC_ENUMAUDOUT:

         {

                   structv4l2_audioout *p = arg;

 

 

                   if(!ops->vidioc_enumaudout)

                            break;

                   dbgarg(cmd,"Enum for index=%d\n", p->index);

                   ret= ops->vidioc_enumaudout(file, fh, p);

                   if(!ret)

                            dbgarg2("index=%d,name=%s, capability=%d, "

                                               "mode=%d\n",p->index, p->name,

                                               p->capability,p->mode);

                   break;

         }

         caseVIDIOC_G_AUDOUT:

         {

                   structv4l2_audioout *p = arg;

 

 

                   if(!ops->vidioc_g_audout)

                            break;

 

 

                   ret= ops->vidioc_g_audout(file, fh, p);

                   if(!ret)

                            dbgarg2("index=%d,name=%s, capability=%d, "

                                               "mode=%d\n",p->index, p->name,

                                               p->capability,p->mode);

                   break;

         }

         caseVIDIOC_S_AUDOUT:

         {

                   structv4l2_audioout *p = arg;

 

 

                   if(!ops->vidioc_s_audout)

                            break;

                   dbgarg(cmd,"index=%d, name=%s, capability=%d, "

                                               "mode=%d\n",p->index, p->name,

                                               p->capability,p->mode);

 

 

                   ret= ops->vidioc_s_audout(file, fh, p);

                   break;

         }

         caseVIDIOC_G_MODULATOR:

         {

                   structv4l2_modulator *p = arg;

 

 

                   if(!ops->vidioc_g_modulator)

                            break;

                   ret= ops->vidioc_g_modulator(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"index=%d, name=%s, "

                                               "capability=%d,rangelow=%d,"

                                               "rangehigh=%d, txsubchans=%d\n",

                                               p->index,p->name, p->capability,

                                               p->rangelow,p->rangehigh,

                                               p->txsubchans);

                   break;

         }

         caseVIDIOC_S_MODULATOR:

         {

                   structv4l2_modulator *p = arg;

 

 

                   if(!ops->vidioc_s_modulator)

                            break;

                   dbgarg(cmd,"index=%d, name=%s, capability=%d, "

                                     "rangelow=%d,rangehigh=%d, txsubchans=%d\n",

                                     p->index,p->name, p->capability, p->rangelow,

                                     p->rangehigh,p->txsubchans);

                            ret= ops->vidioc_s_modulator(file, fh, p);

                   break;

         }

         caseVIDIOC_G_CROP:

         {

                   structv4l2_crop *p = arg;

 

 

                   if(!ops->vidioc_g_crop)

                            break;

 

 

                   dbgarg(cmd,"type=%s\n", prt_names(p->type, v4l2_type_names));

                   ret= ops->vidioc_g_crop(file, fh, p);

                   if(!ret)

                            dbgrect(vfd,"", &p->c);

                   break;

         }

         caseVIDIOC_S_CROP:

         {

                   structv4l2_crop *p = arg;

 

 

                   if(!ops->vidioc_s_crop)

                            break;

                   dbgarg(cmd,"type=%s\n", prt_names(p->type, v4l2_type_names));

                   dbgrect(vfd,"", &p->c);

                   ret= ops->vidioc_s_crop(file, fh, p);

                   break;

         }

         caseVIDIOC_CROPCAP:

         {

                   structv4l2_cropcap *p = arg;

 

 

                   /*FIXME:Should also show v4l2_fract pixelaspect */

                   if(!ops->vidioc_cropcap)

                            break;

 

 

                   dbgarg(cmd,"type=%s\n", prt_names(p->type, v4l2_type_names));

                   ret= ops->vidioc_cropcap(file, fh, p);

                   if(!ret) {

                            dbgrect(vfd,"bounds ", &p->bounds);

                            dbgrect(vfd,"defrect ", &p->defrect);

                   }

                   break;

         }

         caseVIDIOC_G_JPEGCOMP:

         {

                   structv4l2_jpegcompression *p = arg;

 

 

                   if(!ops->vidioc_g_jpegcomp)

                            break;

 

 

                   ret= ops->vidioc_g_jpegcomp(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"quality=%d, APPn=%d, "

                                               "APP_len=%d,COM_len=%d, "

                                               "jpeg_markers=%d\n",

                                               p->quality,p->APPn, p->APP_len,

                                               p->COM_len,p->jpeg_markers);

                   break;

         }

         caseVIDIOC_S_JPEGCOMP:

         {

                   structv4l2_jpegcompression *p = arg;

 

 

                   if(!ops->vidioc_g_jpegcomp)

                            break;

                   dbgarg(cmd,"quality=%d, APPn=%d, APP_len=%d, "

                                               "COM_len=%d,jpeg_markers=%d\n",

                                               p->quality,p->APPn, p->APP_len,

                                               p->COM_len,p->jpeg_markers);

                            ret= ops->vidioc_s_jpegcomp(file, fh, p);

                   break;

         }

         caseVIDIOC_G_ENC_INDEX:

         {

                   structv4l2_enc_idx *p = arg;

 

 

                   if(!ops->vidioc_g_enc_index)

                            break;

                   ret= ops->vidioc_g_enc_index(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"entries=%d, entries_cap=%d\n",

                                               p->entries,p->entries_cap);

                   break;

         }

         caseVIDIOC_ENCODER_CMD:

         {

                   structv4l2_encoder_cmd *p = arg;

 

 

                   if(!ops->vidioc_encoder_cmd)

                            break;

                   ret= ops->vidioc_encoder_cmd(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"cmd=%d, flags=%x\n", p->cmd, p->flags);

                   break;

         }

         caseVIDIOC_TRY_ENCODER_CMD:

         {

                   structv4l2_encoder_cmd *p = arg;

 

 

                   if(!ops->vidioc_try_encoder_cmd)

                            break;

                   ret= ops->vidioc_try_encoder_cmd(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"cmd=%d, flags=%x\n", p->cmd, p->flags);

                   break;

         }

         caseVIDIOC_G_PARM:

         {

                   structv4l2_streamparm *p = arg;

 

 

                   if(ops->vidioc_g_parm) {

                            ret= check_fmt(ops, p->type);

                            if(ret)

                                     break;

                            ret= ops->vidioc_g_parm(file, fh, p);

                   }else {

                            v4l2_std_idstd = vfd->current_norm;

 

 

                            if(p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)

                                     break;

 

 

                            ret= 0;

                            if(ops->vidioc_g_std)

                                     ret= ops->vidioc_g_std(file, fh, &std);

                            elseif (std == 0)

                                      ret = -EINVAL;

                            if(ret == 0)

                                     v4l2_video_std_frame_period(std,

                                                            &p->parm.capture.timeperframe);

                   }

 

 

                   dbgarg(cmd,"type=%d\n", p->type);

                   break;

         }

         caseVIDIOC_S_PARM:

         {

                   structv4l2_streamparm *p = arg;

 

 

                   if(!ops->vidioc_s_parm)

                            break;

                   ret= check_fmt(ops, p->type);

                   if(ret)

                            break;

 

 

                   dbgarg(cmd,"type=%d\n", p->type);

                   ret= ops->vidioc_s_parm(file, fh, p);

                   break;

         }

         caseVIDIOC_G_TUNER:

         {

                   structv4l2_tuner *p = arg;

 

 

                   if(!ops->vidioc_g_tuner)

                            break;

 

 

                   ret= ops->vidioc_g_tuner(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"index=%d, name=%s, type=%d, "

                                               "capability=0x%x,rangelow=%d, "

                                               "rangehigh=%d,signal=%d, afc=%d, "

                                               "rxsubchans=0x%x,audmode=%d\n",

                                               p->index,p->name, p->type,

                                               p->capability,p->rangelow,

                                               p->rangehigh,p->signal, p->afc,

                                               p->rxsubchans,p->audmode);

                   break;

         }

         caseVIDIOC_S_TUNER:

         {

                   structv4l2_tuner *p = arg;

 

 

                   if(!ops->vidioc_s_tuner)

                            break;

                   dbgarg(cmd,"index=%d, name=%s, type=%d, "

                                     "capability=0x%x,rangelow=%d, "

                                     "rangehigh=%d,signal=%d, afc=%d, "

                                     "rxsubchans=0x%x,audmode=%d\n",

                                     p->index,p->name, p->type,

                                     p->capability,p->rangelow,

                                     p->rangehigh,p->signal, p->afc,

                                     p->rxsubchans,p->audmode);

                   ret= ops->vidioc_s_tuner(file, fh, p);

                   break;

         }

         caseVIDIOC_G_FREQUENCY:

         {

                   structv4l2_frequency *p = arg;

 

 

                   if(!ops->vidioc_g_frequency)

                            break;

 

 

                   ret= ops->vidioc_g_frequency(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"tuner=%d, type=%d, frequency=%d\n",

                                              p->tuner,p->type, p->frequency);

                   break;

         }

         caseVIDIOC_S_FREQUENCY:

         {

                   structv4l2_frequency *p = arg;

 

 

                   if(!ops->vidioc_s_frequency)

                            break;

                   dbgarg(cmd,"tuner=%d, type=%d, frequency=%d\n",

                                     p->tuner,p->type, p->frequency);

                   ret= ops->vidioc_s_frequency(file, fh, p);

                   break;

         }

         caseVIDIOC_G_SLICED_VBI_CAP:

         {

                   structv4l2_sliced_vbi_cap *p = arg;

 

 

                   if(!ops->vidioc_g_sliced_vbi_cap)

                            break;

 

 

                   /*Clear up to type, everything after type is zerod already */

                   memset(p,0, offsetof(struct v4l2_sliced_vbi_cap, type));

 

 

                   dbgarg(cmd,"type=%s\n", prt_names(p->type, v4l2_type_names));

                   ret= ops->vidioc_g_sliced_vbi_cap(file, fh, p);

                   if(!ret)

                            dbgarg2("service_set=%d\n",p->service_set);

                   break;

         }

         caseVIDIOC_LOG_STATUS:

         {

                   if(!ops->vidioc_log_status)

                            break;

                   ret= ops->vidioc_log_status(file, fh);

                   break;

         }

#ifdef CONFIG_VIDEO_ADV_DEBUG

         caseVIDIOC_DBG_G_REGISTER:

         {

                   structv4l2_dbg_register *p = arg;

 

 

                   if(!capable(CAP_SYS_ADMIN))

                            ret= -EPERM;

                   elseif (ops->vidioc_g_register)

                            ret= ops->vidioc_g_register(file, fh, p);

                   break;

         }

         caseVIDIOC_DBG_S_REGISTER:

         {

                   structv4l2_dbg_register *p = arg;

 

 

                   if(!capable(CAP_SYS_ADMIN))

                            ret= -EPERM;

                   elseif (ops->vidioc_s_register)

                            ret= ops->vidioc_s_register(file, fh, p);

                   break;

         }

#endif

         caseVIDIOC_DBG_G_CHIP_IDENT:

         {

                   structv4l2_dbg_chip_ident *p = arg;

 

 

                   if(!ops->vidioc_g_chip_ident)

                            break;

                   p->ident= V4L2_IDENT_NONE;

                   p->revision= 0;

                   ret= ops->vidioc_g_chip_ident(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"chip_ident=%u, revision=0x%x\n", p->ident, p->revision);

                   break;

         }

         caseVIDIOC_S_HW_FREQ_SEEK:

         {

                   structv4l2_hw_freq_seek *p = arg;

 

 

                   if(!ops->vidioc_s_hw_freq_seek)

                            break;

                   dbgarg(cmd,

                            "tuner=%d,type=%d, seek_upward=%d, wrap_around=%d\n",

                            p->tuner,p->type, p->seek_upward, p->wrap_around);

                   ret= ops->vidioc_s_hw_freq_seek(file, fh, p);

                   break;

         }

         caseVIDIOC_ENUM_FRAMESIZES:

         {

                   structv4l2_frmsizeenum *p = arg;

 

 

                   if(!ops->vidioc_enum_framesizes)

                            break;

 

 

                   ret= ops->vidioc_enum_framesizes(file, fh, p);

                   dbgarg(cmd,

                            "index=%d,pixelformat=%c%c%c%c, type=%d ",

                            p->index,

                            (p->pixel_format& 0xff),

                            (p->pixel_format>>  8) & 0xff,

                            (p->pixel_format>> 16) & 0xff,

                            (p->pixel_format>> 24) & 0xff,

                            p->type);

                   switch(p->type) {

                   caseV4L2_FRMSIZE_TYPE_DISCRETE:

                            dbgarg3("width= %d, height=%d\n",

                                     p->discrete.width,p->discrete.height);

                            break;

                   caseV4L2_FRMSIZE_TYPE_STEPWISE:

                            dbgarg3("min%dx%d, max %dx%d, step %dx%d\n",

                                     p->stepwise.min_width,  p->stepwise.min_height,

                                     p->stepwise.step_width,p->stepwise.step_height,

                                     p->stepwise.max_width,  p->stepwise.max_height);

                            break;

                   caseV4L2_FRMSIZE_TYPE_CONTINUOUS:

                            dbgarg3("continuous\n");

                            break;

                   default:

                            dbgarg3("-Unknown type!\n");

                   }

 

 

                   break;

         }

         caseVIDIOC_ENUM_FRAMEINTERVALS:

         {

                   structv4l2_frmivalenum *p = arg;

 

 

                   if(!ops->vidioc_enum_frameintervals)

                            break;

 

 

                   ret= ops->vidioc_enum_frameintervals(file, fh, p);

                   dbgarg(cmd,

                            "index=%d,pixelformat=%d, width=%d, height=%d, type=%d ",

                            p->index,p->pixel_format,

                            p->width,p->height, p->type);

                   switch(p->type) {

                   caseV4L2_FRMIVAL_TYPE_DISCRETE:

                            dbgarg2("fps=%d/%d\n",

                                     p->discrete.numerator,

                                     p->discrete.denominator);

                            break;

                   caseV4L2_FRMIVAL_TYPE_STEPWISE:

                            dbgarg2("min=%d/%d,max=%d/%d, step=%d/%d\n",

                                     p->stepwise.min.numerator,

                                     p->stepwise.min.denominator,

                                     p->stepwise.max.numerator,

                                     p->stepwise.max.denominator,

                                     p->stepwise.step.numerator,

                                     p->stepwise.step.denominator);

                            break;

                   caseV4L2_FRMIVAL_TYPE_CONTINUOUS:

                            dbgarg2("continuous\n");

                            break;

                   default:

                            dbgarg2("-Unknown type!\n");

                   }

                   break;

         }

         caseVIDIOC_ENUM_DV_PRESETS:

         {

                   structv4l2_dv_enum_preset *p = arg;

 

 

                   if(!ops->vidioc_enum_dv_presets)

                            break;

 

 

                   ret= ops->vidioc_enum_dv_presets(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,

                                     "index=%d,preset=%d, name=%s, width=%d,"

                                     "height=%d ",

                                     p->index,p->preset, p->name, p->width,

                                     p->height);

                   break;

         }

         caseVIDIOC_S_DV_PRESET:

         {

                   structv4l2_dv_preset *p = arg;

 

 

                   if(!ops->vidioc_s_dv_preset)

                            break;

 

 

                   dbgarg(cmd,"preset=%d\n", p->preset);

                   ret= ops->vidioc_s_dv_preset(file, fh, p);

                   break;

         }

         caseVIDIOC_G_DV_PRESET:

         {

                   structv4l2_dv_preset *p = arg;

 

 

                   if(!ops->vidioc_g_dv_preset)

                            break;

 

 

                   ret= ops->vidioc_g_dv_preset(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"preset=%d\n", p->preset);

                   break;

         }

         caseVIDIOC_QUERY_DV_PRESET:

         {

                   structv4l2_dv_preset *p = arg;

 

 

                   if(!ops->vidioc_query_dv_preset)

                            break;

 

 

                   ret= ops->vidioc_query_dv_preset(file, fh, p);

                   if(!ret)

                            dbgarg(cmd,"preset=%d\n", p->preset);

                   break;

         }

         caseVIDIOC_S_DV_TIMINGS:

         {

                   structv4l2_dv_timings *p = arg;

 

 

                   if(!ops->vidioc_s_dv_timings)

                            break;

 

 

                   switch(p->type) {

                   caseV4L2_DV_BT_656_1120:

                            dbgarg2("bt-656/1120:interlaced=%d,pixelclock=%lld,"

                                     "width=%d, height=%d, polarities=%x,"

                                     "hfrontporch=%d, hsync=%d, hbackporch=%d,"

                                     "vfrontporch=%d, vsync=%d, vbackporch=%d,"

                                      " il_vfrontporch=%d,il_vsync=%d,"

                                     "il_vbackporch=%d\n",

                                     p->bt.interlaced,p->bt.pixelclock,

                                     p->bt.width,p->bt.height, p->bt.polarities,

                                     p->bt.hfrontporch,p->bt.hsync,

                                     p->bt.hbackporch,p->bt.vfrontporch,

                                     p->bt.vsync,p->bt.vbackporch,

                                     p->bt.il_vfrontporch,p->bt.il_vsync,

                                     p->bt.il_vbackporch);

                            ret= ops->vidioc_s_dv_timings(file, fh, p);

                            break;

                   default:

                            dbgarg2("Unknowntype %d!\n", p->type);

                            break;

                   }

                   break;

         }

         caseVIDIOC_G_DV_TIMINGS:

         {

                   structv4l2_dv_timings *p = arg;

 

 

                   if(!ops->vidioc_g_dv_timings)

                            break;

 

 

                   ret= ops->vidioc_g_dv_timings(file, fh, p);

                   if(!ret) {

                            switch(p->type) {

                            caseV4L2_DV_BT_656_1120:

                                     dbgarg2("bt-656/1120:interlaced=%d,"

                                               "pixelclock=%lld,"

                                               "width=%d, height=%d, polarities=%x,"

                                               "hfrontporch=%d, hsync=%d,"

                                               "hbackporch=%d, vfrontporch=%d,"

                                               "vsync=%d, vbackporch=%d,"

                                               "il_vfrontporch=%d, il_vsync=%d,"

                                               "il_vbackporch=%d\n",

                                               p->bt.interlaced,p->bt.pixelclock,

                                              p->bt.width, p->bt.height,

                                               p->bt.polarities,p->bt.hfrontporch,

                                               p->bt.hsync,p->bt.hbackporch,

                                               p->bt.vfrontporch,p->bt.vsync,

                                               p->bt.vbackporch,p->bt.il_vfrontporch,

                                               p->bt.il_vsync,p->bt.il_vbackporch);

                                     break;

                            default:

                                      dbgarg2("Unknown type%d!\n", p->type);

                                     break;

                            }

                   }

                   break;

         }

         caseVIDIOC_DQEVENT:

         {

                   structv4l2_event *ev = arg;

 

 

                   if(!ops->vidioc_subscribe_event)

                            break;

 

 

                   ret= v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK);

                   if(ret < 0) {

                            dbgarg(cmd,"no pending events?");

                            break;

                   }

                   dbgarg(cmd,

                          "pending=%d, type=0x%8.8x,sequence=%d, "

                          "timestamp=%lu.%9.9lu ",

                          ev->pending, ev->type,ev->sequence,

                          ev->timestamp.tv_sec,ev->timestamp.tv_nsec);

                   break;

         }

         caseVIDIOC_SUBSCRIBE_EVENT:

         {

                   structv4l2_event_subscription *sub = arg;

 

 

                   if(!ops->vidioc_subscribe_event)

                            break;

 

 

                   ret= ops->vidioc_subscribe_event(fh, sub);

                   if(ret < 0) {

                            dbgarg(cmd,"failed, ret=%ld", ret);

                            break;

                   }

                   dbgarg(cmd,"type=0x%8.8x", sub->type);

                   break;

         }

         caseVIDIOC_UNSUBSCRIBE_EVENT:

         {

                   structv4l2_event_subscription *sub = arg;

 

 

                   if(!ops->vidioc_unsubscribe_event)

                            break;

 

 

                   ret= ops->vidioc_unsubscribe_event(fh, sub);

                   if(ret < 0) {

                            dbgarg(cmd,"failed, ret=%ld", ret);

                            break;

                   }

                   dbgarg(cmd,"type=0x%8.8x", sub->type);

                   break;

         }

         default:

         {

                   if(!ops->vidioc_default)

                            break;

                   ret= ops->vidioc_default(file, fh, cmd, arg);

                   break;

         }

         }/* switch */

 

 

         if(vfd->debug & V4L2_DEBUG_IOCTL_ARG) {

                   if(ret < 0) {

                            v4l_print_ioctl(vfd->name,cmd);

                            printk(KERN_CONT" error %ld\n", ret);

                   }

         }

 

 

         returnret;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值