[Home] dummy isp ccdc driver

Goal

Create a simple dummy driver (called fsr172x) for the OMAP3530 that bypasses almost all extra functionality just to get the RAW data from the 12 data lines to a v4l2buf.

Overview

Note: The file contents shown are not complete but rather snippets that give content to the changes. Note: The FSR172X is a stripped down version of the MT9T111. I recommend viewing the V4L2 Example Capture application as well.

Pre-reqs

Hacking V4L2

Our dummy driver will use a special formats for

These are created from enums and #defines that are completely arbitrary. The caveat is that any application or driver that depends on these settings must include this special modified version of the of videodev2.h.

drivers/media/video/isp/isp.c

This is a patch showing changes I've made for the fsr172x. Once I have this figured out I'll refactor it down into understandable chunks

diff --git a/drivers/media/video/isp/isp.c b/drivers/media/video/isp/isp.c
index 29dd005..2369f54 100644
--- a/drivers/media/video/isp/isp.c
+++ b/drivers/media/video/isp/isp.c
@@ -930,7 +930,7 @@ static irqreturn_t omap34xx_isp_isr(int irq, void *_pdev)
    return IRQ_HANDLED;

  spin_lock_irqsave(&bufs->lock, flags);
- wait_hs_vs = bufs->wait_hs_vs;
+ wait_hs_vs = 0; //bufs->wait_hs_vs; For FSR
  if (irqstatus & HS_VS) {
    if (bufs->wait_hs_vs) {
      bufs->wait_hs_vs--;
@@ -978,12 +978,23 @@ static irqreturn_t omap34xx_isp_isr(int irq, void *_pdev)
  }

  if (irqstatus & CCDC_VD0) {
+   DPRINTK_ISPCTRL("VD0 interupt\n");    
    if (isp->pipeline.pix.field == V4L2_FIELD_INTERLACED) {
      /* Skip even fields, and process only odd fields */
      if (isp->current_field != 0)
        if (RAW_CAPTURE(isp))
          isp_buf_process(dev, bufs);
    }
+   else // For FSR - progressive scan, process every field
+   {
+     //DPRINTK_ISPCTRL("Not interlaced\n");
+     if (RAW_CAPTURE(isp))
+     {
+       DPRINTK_ISPCTRL("Processing buff\n");
+       isp_buf_process(dev, bufs);
+     }
+   }
+   
    if (!ispccdc_busy(&isp->isp_ccdc))
      ispccdc_config_shadow_registers(&isp->isp_ccdc);
  }
@@ -1363,7 +1374,10 @@ static void isp_set_buf(struct device *dev, struct isp_buf *buf)
      && is_ispresizer_enabled())
    ispresizer_set_outaddr(&isp->isp_res, buf->isp_addr);
  else if (isp->pipeline.modules & OMAP_ISP_CCDC)
+ {
+   printk("SDR Address set to 0x%08X\n",buf->isp_addr);
    ispccdc_set_outaddr(&isp->isp_ccdc, buf->isp_addr);
+ }

 }

@@ -1412,7 +1426,10 @@ static int isp_try_pipeline(struct device *dev,
    pipe->prv_out = PREVIEW_MEM;
    pipe->rsz_in = RSZ_MEM_YUV;
  } else {
+    printk("ARRIVED IN: ISP_CCDC\n");
    pipe->modules = OMAP_ISP_CCDC;
+   // TODO if this is set in fsr172x, we shouldn't need this here
+   //pix_input->pixelformat = V4L2_PIX_FMT_FSR172X; // Added for FSR 
    if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
        pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8 ||
        pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10 ||
@@ -1431,12 +1448,17 @@ static int isp_try_pipeline(struct device *dev,
    } else if (pix_input->pixelformat == V4L2_PIX_FMT_YUYV ||
         pix_input->pixelformat == V4L2_PIX_FMT_UYVY) {
      if (isp->bt656ifen)
-       pipe->ccdc_in = CCDC_YUV_BT;
+       pipe->ccdc_in = CCDC_YUV_BT;
      else
-       pipe->ccdc_in = CCDC_YUV_SYNC;
+       pipe->ccdc_in = CCDC_YUV_SYNC;
      pipe->ccdc_out = CCDC_OTHERS_MEM;
-   } else
+   } else if (pix_input->pixelformat == V4L2_PIX_FMT_FSR172X) { // Added for FSR
+      printk("ARRIVED IN: PIPELINE FSR\n");
+     pipe->ccdc_in = CCDC_RAW_FSR;
+     pipe->ccdc_out = CCDC_FSR_MEM;
+    } else {
      return -EINVAL;
+    }
  }

  if (pipe->modules & OMAP_ISP_CCDC) {
@@ -1652,7 +1674,8 @@ static int isp_buf_process(struct device *dev, struct isp_bufs *bufs)
  if (ISP_BUFS_IS_EMPTY(bufs))
    goto out;

- if (RAW_CAPTURE(isp) && ispccdc_sbl_wait_idle(&isp->isp_ccdc, 1000)) {
+  // We keep getting wait errors... this seems to fix the problem (originally 1000)
+ if (RAW_CAPTURE(isp) && ispccdc_sbl_wait_idle(&isp->isp_ccdc, 2e6)) {
    dev_err(dev, "ccdc %d won't become idle!\n",
           RAW_CAPTURE(isp));
    goto out;

drivers/media/video/isp/ispccdc.c

diff --git a/drivers/media/video/isp/ispccdc.c b/drivers/media/video/isp/ispccdc.c
index 137a5e6..df7c15d 100644
--- a/drivers/media/video/isp/ispccdc.c
+++ b/drivers/media/video/isp/ispccdc.c
@@ -631,6 +631,23 @@ static int ispccdc_config_datapath(struct isp_ccdc_device *isp_ccdc,
    ispccdc_config_vp(isp_ccdc, vpcfg);
    ispccdc_enable_vp(isp_ccdc, 1);
    break;
+
+  case CCDC_FSR_MEM:
+    printk("ARRIVED IN: CCDC_FSR_MEM\n");
+   syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+   syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+   syn_mode |= ISPCCDC_SYN_MODE_WEN;
+   syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
+    isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
+        ISPCCDC_CFG, ~ISPCCDC_CFG_WENLOG);
+
+    // TODO aren't these 0 by default?
+   vpcfg.bitshift_sel = 0;
+   vpcfg.freq_sel = 0;
+   ispccdc_config_vp(isp_ccdc, vpcfg);
+   ispccdc_enable_vp(isp_ccdc, 0);
+    break;
+
  default:
    DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Output\n");
    return -EINVAL;
@@ -700,6 +717,33 @@ static int ispccdc_config_datapath(struct isp_ccdc_device *isp_ccdc,
    blkcfg.dcsubval = 0;
    ispccdc_config_black_clamp(isp_ccdc, blkcfg);
    break;
+  case CCDC_RAW_FSR: // what values do we need here?
+    printk("ARRIVED IN: CCDC_RAW_FSR\n");
+    syncif.ccdc_mastermode = 1; // p1461 1 ==hs/vs output
+    syncif.datapol = 0; // 0 == normal, not one's complement
+    syncif.datsz = DAT12; // 12 lines
+    syncif.fldmode = 0; // 0 == progressive scan, not interlaced
+    syncif.fldout = 0; // (cam_fld) not used when 0 == fldmode
+    syncif.fldpol = 0; // not used when 0 == fldmode
+    syncif.fldstat = 0; // not used when 0 == fldmode, otherwise marks current frame as odd/even
+    syncif.hdpol = 0; // cam_hs polarity 0 == positive
+    syncif.ipmod = RAW; // aka inpmod p1553 should be 0 for raw
+    syncif.vdpol = 0; // cam_vs polarity 0 == positive
+    syncif.bt_r656_en = 0; // 1 == ITU enabled
+
+    // These should next four should always be set when mastermode is enabled
+    syncif.hs_width = 0; // aka hd_vd_wid p1554
+    syncif.vs_width = 0; // aka hd_vd_wid
+    syncif.ppln = (u8) 0x7D01; // 32001 Maybe should be 16001(?) p1555 pixels per line
+    syncif.hlprf = 128; // half line per field or frame
+
+    // isp modules
+    ispccdc_config_imgattr(isp_ccdc, 0); // mosiac filter??, probably should be all 0's
+    ispccdc_config_sync_if(isp_ccdc, syncif); // commit these values to the registers
+
+    // black clamp
+    blkcfg.dcsubval = 0; // black clamp substraction value, probably should be 0
+    ispccdc_config_black_clamp(isp_ccdc, blkcfg);
  case CCDC_OTHERS:
    break;
  default:
@@ -1202,6 +1246,8 @@ int ispccdc_try_pipeline(struct isp_ccdc_device *isp_ccdc,
  pipe->ccdc_in_v_st = 0;
  pipe->ccdc_out_w = pipe->ccdc_in_w;
  pipe->ccdc_out_h = pipe->ccdc_in_h;
+ 
+ printk("Out pixel height %d\n",pipe->ccdc_out_h);

  if (!isp_ccdc->refmt_en
      && pipe->ccdc_out != CCDC_OTHERS_MEM
@@ -1348,6 +1394,7 @@ int ispccdc_s_pipeline(struct isp_ccdc_device *isp_ccdc,
          OMAP3_ISP_IOMEM_CCDC,
          ISPCCDC_VDINT);
    } else {
+       printk("Arrived in vp out mem\n");
      ispccdc_config_outlineoffset(isp_ccdc,
          pipe->ccdc_out_w * 2, EVENEVEN, 1);
      ispccdc_config_outlineoffset(isp_ccdc,
@@ -1367,6 +1414,7 @@ int ispccdc_s_pipeline(struct isp_ccdc_device *isp_ccdc,
    }

  } else if (pipe->ccdc_out == CCDC_OTHERS_VP_MEM) {
+   printk("Arrived in vp out mem\n");
    isp_reg_writel(isp_ccdc->dev,
             (pipe->ccdc_in_h_st << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
             ((pipe->ccdc_in_w - pipe->ccdc_in_h_st) <<

drivers/media/video/isp/ispccdc.h

The FSR uses a type of RAW capture and has particular memory requirements not currently supported by the ISP. These new enums allow us to cleanly create new conditional branches in the ISP/CCDC code.

/* Enumeration constants for CCDC input output format */
enum ccdc_input {
  CCDC_RAW_GRBG,
  CCDC_RAW_RGGB,
  CCDC_RAW_BGGR,
  CCDC_RAW_GBRG,
  CCDC_RAW_FSR, // FSR
  CCDC_YUV_SYNC,
  CCDC_YUV_BT,
  CCDC_OTHERS
};

enum ccdc_output {
  CCDC_YUV_RSZ,
  CCDC_YUV_MEM_RSZ,
  CCDC_FSR_MEM, // FSR
  CCDC_OTHERS_VP,
  CCDC_OTHERS_MEM,
  CCDC_OTHERS_VP_MEM
};

arch/arm/mach-omap2/board-overo-camera.c

#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/mm.h>
#include <linux/videodev2.h>
#include <linux/delay.h>
#include <linux/platform_device.h>

#include <plat/mux.h>
#include <plat/board.h>
#include <plat/control.h>

#include <media/v4l2-int-device.h>
#include <media/fsr172x.h>

/* Include V4L2 ISP-Camera driver related header file */
#include <../drivers/media/video/omap34xxcam.h>
#include <../drivers/media/video/isp/ispreg.h>

#include "mux.h"
#include "board-overo-camera.h"

#define MODULE_NAME     "omap3beaglelmb"

#define CAM_USE_XCLKA       0

#define ISP_FSR172X_MCLK    216000000

#define LEOPARD_RESET_GPIO    98

#if defined(CONFIG_VIDEO_FSR172X) || defined(CONFIG_VIDEO_FSR172X_MODULE)

/* Arbitrary memory handling limit */
#define FSR172X_BIGGEST_FRAME_BYTE_SIZE PAGE_ALIGN(2048 * 1536 * 4)

// TODO can this be moved to fsr driver?
static struct isp_interface_config fsr172x_if_config = {
  .ccdc_par_ser   = ISP_PARLL,
  .dataline_shift   = 0x0,
  .hsvs_syncdetect  = ISPCTRL_SYNC_DETECT_VSRISE,
  .strobe     = 0x0,
  .prestrobe    = 0x0,
  .shutter    = 0x0,
  .cam_mclk   = ISP_FSR172X_MCLK, // 216MHz
  .wenlog     = ISPCCDC_CFG_WENLOG_AND, // (0 << 8)
  .wait_hs_vs   = 2,
  .u.par.par_bridge = 0x0, // no bridge
  .u.par.par_clk_pol  = 0x0,
};

static struct v4l2_ifparm fsr172x_ifparm_s = {
  .if_type = V4L2_IF_TYPE_RAW,
  .u   = {
    .raw = {
      .frame_start_on_rising_vs = 1,
      .bt_sync_correct  = 0,
      .swap     = 0,
      .latch_clk_inv    = 0,
      .nobt_hs_inv    = 0,  /* active high */
      .nobt_vs_inv    = 0,  /* active high */
      .clock_min    = FSR172X_CLK_MIN, // 2.048MHz
      .clock_max    = FSR172X_CLK_MAX, // 2.048MHz
    },
  },
};

/**
 * @brief fsr172x_ifparm - Returns the fsr172x interface parameters
 *
 * @param p - pointer to v4l2_ifparm structure
 *
 * @return result of operation - 0 is success
 */
static int fsr172x_ifparm(struct v4l2_ifparm *p)
{
  if (p == NULL)
    return -EINVAL;

  *p = fsr172x_ifparm_s;
  return 0;
}

#if defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE)
static struct omap34xxcam_hw_config fsr172x_hwc = {
  .dev_index    = 0,
  .dev_minor    = 0,
  .dev_type   = OMAP34XXCAM_SLAVE_SENSOR,
  .u.sensor.sensor_isp  = 1,
  .u.sensor.capture_mem = FSR172X_BIGGEST_FRAME_BYTE_SIZE * 2,
  .u.sensor.ival_default  = { 1, 10 },
};
#endif

/**
 * @brief fsr172x_set_prv_data - Returns fsr172x omap34xx driver private data
 *
 * @param priv - pointer to omap34xxcam_hw_config structure
 *
 * @return result of operation - 0 is success
 */
static int fsr172x_set_prv_data(void *priv)
{
#if defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE)
  struct omap34xxcam_hw_config *hwc = priv;

  if (priv == NULL)
    return -EINVAL;

  hwc->u.sensor = fsr172x_hwc.u.sensor;
  hwc->dev_index = fsr172x_hwc.dev_index;
  hwc->dev_minor = fsr172x_hwc.dev_minor;
  hwc->dev_type = fsr172x_hwc.dev_type;
  return 0;
#else
  return -EINVAL;
#endif
}

/**
 * @brief fsr172x_power_set - Power-on or power-off TVP5146 device
 *
 * @param power - enum, Power on/off, resume/standby
 *
 * @return result of operation - 0 is success
 */
static int fsr172x_power_set(struct v4l2_int_device *s, enum v4l2_power power)
{
  struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;

  switch (power) {
  case V4L2_POWER_OFF:
  case V4L2_POWER_STANDBY:
    isp_set_xclk(vdev->cam->isp, 0, CAM_USE_XCLKA);
    break;

  case V4L2_POWER_ON:
#if defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE)
    isp_configure_interface(vdev->cam->isp, &fsr172x_if_config);
#endif
    break;

  default:
    return -ENODEV;
    break;
  }
  return 0;
}

struct fsr172x_platform_data fsr172x_pdata = {
  .master   = "omap34xxcam",
  .power_set  = fsr172x_power_set,
  .priv_data_set  = fsr172x_set_prv_data,
  .ifparm   = fsr172x_ifparm,
  /* Some interface dependent params */
  .clk_polarity = 0, /* data clocked out on falling edge */
  .hs_polarity  = 1, /* 0 - Active low, 1- Active high */
  .vs_polarity  = 1, /* 0 - Active low, 1- Active high */
};

#endif        /* #ifdef CONFIG_VIDEO_FSR172X */


static int beagle_cam_probe(struct platform_device *pdev)
{
  printk(KERN_INFO MODULE_NAME ": Driver registration complete \n");
  return 0;
}

static int beagle_cam_remove(struct platform_device *pdev)
{
  // FSR_COMMENT -  mux init on remove, but not on insert?
  /* MUX init */
  omap_ctrl_writew(OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
       0x10C); /* CAM_HS */
  omap_ctrl_writew(OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
       0x10E); /* CAM_VS */
  omap_ctrl_writew(OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
       0x110); /* CAM_XCLKA */
  omap_ctrl_writew(OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
       0x112); /* CAM_PCLK */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x116); /* CAM_D0 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x118); /* CAM_D1 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x11A); /* CAM_D2 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x11C); /* CAM_D3 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x11E); /* CAM_D4 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x120); /* CAM_D5 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x122); /* CAM_D6 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x124); /* CAM_D7 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x126); /* CAM_D8 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x128); /* CAM_D9 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x12A); /* CAM_D10 */
  omap_ctrl_writew(OMAP_PIN_INPUT | OMAP_MUX_MODE0,
       0x12C); /* CAM_D11 */

  return 0;
}

static int beagle_cam_suspend(struct device *dev)
{
  return 0;
}

static int beagle_cam_resume(struct device *dev)
{
  return 0;
}

static struct dev_pm_ops beagle_cam_pm_ops = {
  .suspend = beagle_cam_suspend,
  .resume  = beagle_cam_resume,
};

static struct platform_driver beagle_cam_driver = {
  .probe    = beagle_cam_probe,
  .remove   = beagle_cam_remove,
  .driver   = {
    .name = "beagle_cam",
    .pm = &beagle_cam_pm_ops,
  },
};

/**
 * @brief omap3beaglelmb_init - module init function. Should be called before any
 *                          client driver init call
 *
 * @return result of operation - 0 is success
 */
int __init omap3beaglelmb_init(void)
{
  platform_driver_register(&beagle_cam_driver);
  return 0;
}

late_initcall(omap3beaglelmb_init);

include/linux/videodev2.h

Note: Although these #defines are arbitrary, they must match between the file included with the driver and the file included in the application.

// Our own special colorspace goes in a section like this
enum v4l2_colorspace {
  /* ITU-R 601 -- broadcast NTSC/PAL */
  V4L2_COLORSPACE_SMPTE170M     = 1,

  /* 1125-Line (US) HDTV */
  V4L2_COLORSPACE_SMPTE240M     = 2,

  //
  // SEVERAL LINES SKIPPED FOR BREVITY IN THIS EXAMPLE
  //

  /* For RGB colourspaces, this is probably a good start. */
  V4L2_COLORSPACE_SRGB          = 8,

  /* For colourspaces not in the normal range (FSR172X). */
  V4L2_COLORSPACE_FSR172X       = 9,
};


// Our own special pixel format goes in a section like this
/*
 *  V I D E O   I M A G E   F O R M A T
 */

//
// SEVERAL LINES SKIPPED FOR BREVITY IN THIS EXAMPLE
//

/*  Vendor-specific formats   */
#define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
#define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */

//
// SEVERAL LINES SKIPPED FOR BREVITY IN THIS EXAMPLE
//

#define V4L2_PIX_FMT_STV0680  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
#define V4L2_PIX_FMT_FSR172X  v4l2_fourcc('F', 'S', 'R', '0') /* 12bit raw fsr172x */

include/linux/v4l2-int-device.h

Nothing is changed here, but it's worth noting that we'll be using the predefined RAW mode...

/* Slave interface type. */
enum v4l2_if_type {
  /*
   * Parallel 8-, 10- or 12-bit interface, used by for example
   * on certain image sensors.
   */
  V4L2_IF_TYPE_BT656,
  V4L2_IF_TYPE_YCbCr,
  V4L2_IF_TYPE_RAW,
};

... and its associated struct

struct v4l2_if_type_raw {
  /*
   * 0: Frame begins when vsync is high.
   * 1: Frame begins when vsync changes from low to high.
   */
  unsigned frame_start_on_rising_vs:1;
  /* Use Bt synchronisation codes for sync correction. */
  unsigned bt_sync_correct:1;
  /* Swap every two adjacent image data elements. */
  unsigned swap:1;
  /* Inverted latch clock polarity from slave. */
  unsigned latch_clk_inv:1;
  /* Hs polarity. 0 is active high, 1 active low. */
  unsigned nobt_hs_inv:1;
  /* Vs polarity. 0 is active high, 1 active low. */
  unsigned nobt_vs_inv:1;
  /* Minimum accepted bus clock for slave (in Hz). */
  u32 clock_min;
  /* Maximum accepted bus clock for slave. */
  u32 clock_max;
  /*
   * Current wish of the slave. May only change in response to
   * ioctls that affect image capture.
   */
  u32 clock_curr;
};

If we were to create our own, we would need to modify this v4l2 struct:

struct v4l2_ifparm {
  enum v4l2_if_type if_type;
  union {
    struct v4l2_if_type_bt656 bt656;
    struct v4l2_if_type_ycbcr ycbcr;
    struct v4l2_if_type_raw raw;
  } u;
};

In our driver code we will access these settings as v4l2_ifparm.

arch/arm/mach-omap2/board-overo-camera.c

This board file and its header are the exact same as board-omap3beagle-camera with the exception that every occurrance of beagle has been replaced with overo and every occurance of mt9t111 has been replaced with fsr172x.

Again, we'll just use RAW, but if we had created our own FSR standard, we would need to add to this list:

static struct v4l2_ifparm fsr172x_ifparm_s = {
#if 1
  .if_type = V4L2_IF_TYPE_RAW,
  .u   = {
    .raw = {
      .frame_start_on_rising_vs = 1,
      .bt_sync_correct  = 0,
      .swap     = 0,
      .latch_clk_inv    = 0,
      .nobt_hs_inv    = 0,  /* active high */
      .nobt_vs_inv    = 0,  /* active high */
      .clock_min    = FSR172X_CLK_MIN,
      .clock_max    = FSR172X_CLK_MAX,
    },
  },
#else
  .if_type = V4L2_IF_TYPE_YCbCr,
  // REMOVED FOR BREVITY
  },
#endif
};

scratchspace

Linux Kernel vs TRM

where stuff is

which v4l2 calls must we implement?

what is this mess?

drivers/media/video/fsr172x.c

// Creating a map between VIDIOC_X_YZ and our internal functions
static struct v4l2_int_ioctl_desc fsr172x_ioctl_desc[] = {
  { .num = vidioc_int_enum_framesizes_num,
    .func = (v4l2_int_ioctl_func *)ioctl_enum_framesizes },
  { .num = vidioc_int_enum_frameintervals_num,
    .func = (v4l2_int_ioctl_func *)ioctl_enum_frameintervals },
  { .num = vidioc_int_dev_init_num,
    .func = (v4l2_int_ioctl_func *)ioctl_dev_init },
  { .num = vidioc_int_dev_exit_num,
    .func = (v4l2_int_ioctl_func *)ioctl_dev_exit },
  { .num = vidioc_int_s_power_num,
    .func = (v4l2_int_ioctl_func *)ioctl_s_power },
  { .num = vidioc_int_g_priv_num,
    .func = (v4l2_int_ioctl_func *)ioctl_g_priv },
  { .num = vidioc_int_g_ifparm_num,
    .func = (v4l2_int_ioctl_func *)ioctl_g_ifparm },
  { .num = vidioc_int_init_num,
    .func = (v4l2_int_ioctl_func *)ioctl_init },
  { .num = vidioc_int_enum_fmt_cap_num,
    .func = (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
  { .num = vidioc_int_try_fmt_cap_num,
    .func = (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
  { .num = vidioc_int_g_fmt_cap_num,
    .func = (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
  { .num = vidioc_int_s_fmt_cap_num,
    .func = (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
  { .num = vidioc_int_g_parm_num,
    .func = (v4l2_int_ioctl_func *)ioctl_g_parm },
  { .num = vidioc_int_s_parm_num,
    .func = (v4l2_int_ioctl_func *)ioctl_s_parm },
  { .num = vidioc_int_queryctrl_num,
    .func = (v4l2_int_ioctl_func *)ioctl_queryctrl },
  { .num = vidioc_int_g_ctrl_num,
    .func = (v4l2_int_ioctl_func *)ioctl_g_ctrl },
  { .num = vidioc_int_s_ctrl_num,
    .func = (v4l2_int_ioctl_func *)ioctl_s_ctrl },
  { .num = vidioc_int_s_video_routing_num,
    .func = (v4l2_int_ioctl_func *)ioctl_s_routing },
};


static struct v4l2_int_slave fsr172x_slave = {
  .ioctls = fsr172x_ioctl_desc,
  .num_ioctls = ARRAY_SIZE(fsr172x_ioctl_desc),
};

static struct v4l2_int_device fsr172x_int_device = {
  .module = THIS_MODULE,
  .name = "fsr172x",
  .priv = &fsr172x,
  .type = v4l2_int_type_slave,
  .u = {
    .slave = &fsr172x_slave,
  },
};

Note: Most of the ioctl_x_yz functions refer to V4L2s VIDIOC_X_YZ #defines.

Appendix

Updated at 2010-08-24
blog comments powered by Disqus