AnsweredAssumed Answered

Camera quality and strange line

Question asked by 호영 노 on Mar 4, 2019
Latest reply on Mar 4, 2019 by igorpadykov

Hello, 

I'm using the i.MX6DL with ccd camera.

This ccd camera working well with S3C2440. 

So, I connected this ccd camera with i.MX6DL and setting several things and I can see the camera video to my lcd.

 

It working well as S3C2440, but, when I looking the video in detail, 

it has strange line in top. 

and it has nosie.d

 

(Attacehd picture has filcker. Anyway noise is not a serious level, but it does exist.)

 

How can I adjust this noise level and using full lcd with this camera?

I can not get a sense of what source to test with.

 

Should I check the h/w structure first?? 

I think that this problem is depend on some source code setting.. But I can't be sure.

 

 

Below is what I using for test. ( I attached source code file also.)

Actually I change some values in this sources, but no lucks.

 

/*
* Copyright 2007-2013 Freescale Semiconductor, Inc. All rights reserved.
*/

/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/

/*
* @file mxc_v4l2_tvin.c
*
* @brief Mxc TVIN For Linux 2 driver test application
*
*/

#ifdef __cplusplus
extern "C"{
#endif

/*=======================================================================
INCLUDE FILES
=======================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include <sys/time.h>

#include "mxcfb.h"
#include "mxc_v4l2.h"
#include "ipu.h"

#define TFAIL -1
#define TPASS 0

char v4l_capture_dev[100] = "/dev/video1";
char v4l_output_dev[100] = "/dev/video17";
int fd_capture_v4l = 0;
int fd_output_v4l = 0;
int g_cap_mode = 0;
int g_input = 1;
int g_fmt = V4L2_PIX_FMT_UYVY;
int g_rotate = 0;
int g_vflip = 0;
int g_hflip = 0;
int g_vdi_enable = 0;
int g_vdi_motion = 0;
int g_tb = 0;
int g_output = 3;

int g_output_num_buffers = 4;
int g_capture_num_buffers = 3;

int g_in_width = 0;
int g_in_height = 0;
int g_display_width = 0;
int g_display_height = 0;
int g_display_top = 0;
int g_display_left = 0;
int g_frame_size;
int g_frame_period = 33333;
v4l2_std_id g_current_std = V4L2_STD_NTSC;

struct testbuffer
{
unsigned char *start;
size_t offset;
unsigned int length;
};

struct testbuffer output_buffers[4];
struct testbuffer capture_buffers[3];

int start_capturing(void)
{
unsigned int i;
struct v4l2_buffer buf;
enum v4l2_buf_type type;

for (i = 0; i < g_capture_num_buffers; i++)
{
memset(&buf, 0, sizeof (buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (ioctl(fd_capture_v4l, VIDIOC_QUERYBUF, &buf) < 0)
{
printf("VIDIOC_QUERYBUF error\n");
return TFAIL;
}

capture_buffers[i].length = buf.length;
capture_buffers[i].offset = (size_t) buf.m.offset;
capture_buffers[i].start = mmap (NULL, capture_buffers[i].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
fd_capture_v4l, capture_buffers[i].offset);
memset(capture_buffers[i].start, 0xFF, capture_buffers[i].length);
}

for (i = 0; i < g_capture_num_buffers; i++)
{
memset(&buf, 0, sizeof (buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
buf.m.offset = capture_buffers[i].offset;
if (ioctl (fd_capture_v4l, VIDIOC_QBUF, &buf) < 0) {
printf("VIDIOC_QBUF error\n");
return TFAIL;
}
}

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (fd_capture_v4l, VIDIOC_STREAMON, &type) < 0) {
printf("VIDIOC_STREAMON error\n");
return TFAIL;
}
return 0;
}

int prepare_output(void)
{
int i;
struct v4l2_buffer output_buf;

for (i = 0; i < g_output_num_buffers; i++)
{
memset(&output_buf, 0, sizeof(output_buf));
output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
output_buf.memory = V4L2_MEMORY_MMAP;
output_buf.index = i;
if (ioctl(fd_output_v4l, VIDIOC_QUERYBUF, &output_buf) < 0)
{
printf("VIDIOC_QUERYBUF error\n");
return TFAIL;
}

output_buffers[i].length = output_buf.length;
output_buffers[i].offset = (size_t) output_buf.m.offset;
output_buffers[i].start = mmap (NULL, output_buffers[i].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
fd_output_v4l, output_buffers[i].offset);
if (output_buffers[i].start == NULL) {
printf("v4l2 tvin test: output mmap failed\n");
return TFAIL;
}
}
return 0;
}

int v4l_capture_setup(void)
{

struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
struct v4l2_requestbuffers req;
struct v4l2_dbg_chip_ident chip;
struct v4l2_streamparm parm;
v4l2_std_id id;
unsigned int min;

if (ioctl (fd_capture_v4l, VIDIOC_QUERYCAP, &cap) < 0) {
if (EINVAL == errno) {
fprintf (stderr, "%s is no V4L2 device\n",
v4l_capture_dev);
return TFAIL;
} else {
fprintf (stderr, "%s isn not V4L device,unknow error\n",
v4l_capture_dev);
return TFAIL;
}
}

if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf (stderr, "%s is no video capture device\n",
v4l_capture_dev);
return TFAIL;
}

if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
fprintf (stderr, "%s does not support streaming i/o\n",
v4l_capture_dev);
return TFAIL;
}

if (ioctl(fd_capture_v4l, VIDIOC_DBG_G_CHIP_IDENT, &chip))
{
printf("VIDIOC_DBG_G_CHIP_IDENT failed.\n");
close(fd_capture_v4l);
return TFAIL;
}
printf("TV decoder chip is %s\n", chip.match.name);

if (ioctl(fd_capture_v4l, VIDIOC_S_INPUT, &g_input) < 0)
{
printf("VIDIOC_S_INPUT failed\n");
close(fd_capture_v4l);
return TFAIL;
}

if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id) < 0)
{
printf("VIDIOC_G_STD failed\n");
close(fd_capture_v4l);
return TFAIL;
}
g_current_std = id;

if (ioctl(fd_capture_v4l, VIDIOC_S_STD, &id) < 0)
{
printf("VIDIOC_S_STD failed\n");
close(fd_capture_v4l);
return TFAIL;
}

/* Select video input, video standard and tune here. */

memset(&cropcap, 0, sizeof(cropcap));

cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (ioctl (fd_capture_v4l, VIDIOC_CROPCAP, &cropcap) < 0) {
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; /* reset to default */

if (ioctl (fd_capture_v4l, VIDIOC_S_CROP, &crop) < 0) {
switch (errno) {
case EINVAL:
/* Cropping not supported. */
fprintf (stderr, "%s doesn't support crop\n",
v4l_capture_dev);
break;
default:
/* Errors ignored. */
break;
}
}
} else {
/* Errors ignored. */
}

parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm.parm.capture.timeperframe.numerator = 1;
parm.parm.capture.timeperframe.denominator = 0;
parm.parm.capture.capturemode = 0;
if (ioctl(fd_capture_v4l, VIDIOC_S_PARM, &parm) < 0)
{
printf("VIDIOC_S_PARM failed\n");
close(fd_capture_v4l);
return TFAIL;
}

memset(&fmt, 0, sizeof(fmt));

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 0;
fmt.fmt.pix.height = 0;
fmt.fmt.pix.pixelformat = g_fmt;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;


if (ioctl (fd_capture_v4l, VIDIOC_S_FMT, &fmt) < 0){
fprintf (stderr, "%s iformat not supported \n",
v4l_capture_dev);
return TFAIL;
}

/* Note VIDIOC_S_FMT may change width and height. */

/* Buggy driver paranoia. */
min = fmt.fmt.pix.width * 2;
if (fmt.fmt.pix.bytesperline < min)
fmt.fmt.pix.bytesperline = min;

min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
if (fmt.fmt.pix.sizeimage < min)
fmt.fmt.pix.sizeimage = min;

if (ioctl(fd_capture_v4l, VIDIOC_G_FMT, &fmt) < 0)
{
printf("VIDIOC_G_FMT failed\n");
close(fd_capture_v4l);
return TFAIL;
}

g_in_width = fmt.fmt.pix.width;
g_in_height = fmt.fmt.pix.height;

memset(&req, 0, sizeof (req));

req.count = g_capture_num_buffers;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;

if (ioctl (fd_capture_v4l, VIDIOC_REQBUFS, &req) < 0) {
if (EINVAL == errno) {
fprintf (stderr, "%s does not support "
"memory mapping\n", v4l_capture_dev);
return TFAIL;
} else {
fprintf (stderr, "%s does not support "
"memory mapping, unknow error\n", v4l_capture_dev);
return TFAIL;
}
}

if (req.count < 2) {
fprintf (stderr, "Insufficient buffer memory on %s\n",
v4l_capture_dev);
return TFAIL;
}

return 0;
}

int v4l_output_setup(void)
{
struct v4l2_control ctrl;
struct v4l2_format fmt;
struct v4l2_framebuffer fb;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_capability cap;
struct v4l2_fmtdesc fmtdesc;
struct v4l2_requestbuffers buf_req;

if (!ioctl(fd_output_v4l, VIDIOC_QUERYCAP, &cap)) {
printf("driver=%s, card=%s, bus=%s, \r\n"
"version=0x%08x, "
"capabilities=0x%08x\n",
cap.driver, cap.card, cap.bus_info,
cap.version,
cap.capabilities);
}

fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
while (!ioctl(fd_output_v4l, VIDIOC_ENUM_FMT, &fmtdesc)) {
printf("fmt %s: fourcc = 0x%08x\n",
fmtdesc.description,
fmtdesc.pixelformat);
fmtdesc.index++;
}

memset(&cropcap, 0, sizeof(cropcap));
cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
if (ioctl(fd_output_v4l, VIDIOC_CROPCAP, &cropcap) < 0)
{
printf("get crop capability failed\n");
close(fd_output_v4l);
return TFAIL;
}

crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
crop.c.top = g_display_top;
crop.c.left = g_display_left;
crop.c.width = g_display_width;
crop.c.height = g_display_height;
if (ioctl(fd_output_v4l, VIDIOC_S_CROP, &crop) < 0)
{
printf("set crop failed\n");
close(fd_output_v4l);
return TFAIL;
}

// Set rotation
ctrl.id = V4L2_CID_ROTATE;
ctrl.value = g_rotate;
if (ioctl(fd_output_v4l, VIDIOC_S_CTRL, &ctrl) < 0)
{
printf("set ctrl rotate failed\n");
close(fd_output_v4l);
return TFAIL;
}
ctrl.id = V4L2_CID_VFLIP;
ctrl.value = g_vflip;
if (ioctl(fd_output_v4l, VIDIOC_S_CTRL, &ctrl) < 0)
{
printf("set ctrl vflip failed\n");
close(fd_output_v4l);
return TFAIL;
}
ctrl.id = V4L2_CID_HFLIP;
ctrl.value = g_hflip;
if (ioctl(fd_output_v4l, VIDIOC_S_CTRL, &ctrl) < 0)
{
printf("set ctrl hflip failed\n");
close(fd_output_v4l);
return TFAIL;
}

if (g_vdi_enable) {
ctrl.id = V4L2_CID_MXC_MOTION;
ctrl.value = g_vdi_motion;
//ctrl.value = 0;

if (ioctl(fd_output_v4l, VIDIOC_S_CTRL, &ctrl) < 0)
{
printf("set ctrl motion failed\n");
close(fd_output_v4l);
return TFAIL;
}
}

fb.flags = V4L2_FBUF_FLAG_OVERLAY;
ioctl(fd_output_v4l, VIDIOC_S_FBUF, &fb);

memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
fmt.fmt.pix.width= g_in_width;
fmt.fmt.pix.height= g_in_height;
fmt.fmt.pix.pixelformat = g_fmt;
fmt.fmt.pix.bytesperline = g_in_width;
fmt.fmt.pix.priv = 0;
fmt.fmt.pix.sizeimage = 0;

if (g_tb)
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
else
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED_BT;

if (ioctl(fd_output_v4l, VIDIOC_S_FMT, &fmt) < 0)
{
printf("set format failed\n");
return TFAIL;
}

if (ioctl(fd_output_v4l, VIDIOC_G_FMT, &fmt) < 0)
{
printf("get format failed\n");
return TFAIL;
}
g_frame_size = fmt.fmt.pix.sizeimage;

memset(&buf_req, 0, sizeof(buf_req));
buf_req.count = g_output_num_buffers;
buf_req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
buf_req.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd_output_v4l, VIDIOC_REQBUFS, &buf_req) < 0)
{
printf("request buffers failed\n");
return TFAIL;
}

return 0;
}

int
mxc_v4l_tvin_test(void)
{
struct v4l2_buffer capture_buf, output_buf;
v4l2_std_id id;
int i, j;
enum v4l2_buf_type type;
int total_time;
struct timeval tv_start, tv_current;
int rtn;

if (prepare_output() < 0)
{
printf("prepare_output failed\n");
return TFAIL;
}

if (start_capturing() < 0)
{
printf("start_capturing failed\n");
return TFAIL;
}

gettimeofday(&tv_start, 0);
printf("start time = %d s, %d us\n", (unsigned int) tv_start.tv_sec,
(unsigned int) tv_start.tv_usec);

for (i = 0; ; i++) {
begin:
if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id)) {
printf("VIDIOC_G_STD failed.\n");
return TFAIL;
}

if (id == g_current_std)
{
//printf("goto next\r\n");
goto next;
}
else if (id == V4L2_STD_PAL || id == V4L2_STD_NTSC) {
printf("----------------------------------------------------------------------\r\n");
type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
ioctl(fd_output_v4l, VIDIOC_STREAMOFF, &type);

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd_capture_v4l, VIDIOC_STREAMOFF, &type);

for (j = 0; j < g_output_num_buffers; j++)
{
munmap(output_buffers[j].start, output_buffers[j].length);
}
for (j = 0; j < g_capture_num_buffers; j++)
{
munmap(capture_buffers[j].start, capture_buffers[j].length);
}

if (v4l_capture_setup() < 0) {
printf("Setup v4l capture failed.\n");
return TFAIL;
}

if (v4l_output_setup() < 0) {
printf("Setup v4l output failed.\n");
return TFAIL;
}

if (prepare_output() < 0)
{
printf("prepare_output failed\n");
return TFAIL;
}

if (start_capturing() < 0)
{
printf("start_capturing failed\n");
return TFAIL;
}
i = 0;
printf("TV standard changed\n");
} else {
sleep(1);
/* Try again */
if (ioctl(fd_capture_v4l, VIDIOC_G_STD, &id)) {
printf("VIDIOC_G_STD failed.\n");
return TFAIL;
}

if (id != V4L2_STD_ALL)
goto begin;

printf("Cannot detect TV standard\n");
return 0;
}
next:

/*rtn = poll( (struct pollfd *)&poll_fds, 1, tmout );
if ( rtn < 0 ) return -1;*/

memset(&capture_buf, 0, sizeof(capture_buf));
capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
capture_buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd_capture_v4l, VIDIOC_DQBUF, &capture_buf) < 0) {
printf("VIDIOC_DQBUF failed.\n");
return TFAIL;
}

memset(&output_buf, 0, sizeof(output_buf));
output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
output_buf.memory = V4L2_MEMORY_MMAP;
if (i < g_output_num_buffers) {
output_buf.index = i;
if (ioctl(fd_output_v4l, VIDIOC_QUERYBUF, &output_buf) < 0)
{
printf("VIDIOC_QUERYBUF failed\n");
return TFAIL;
}
} else {
output_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
output_buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd_output_v4l, VIDIOC_DQBUF, &output_buf) < 0)
{
printf("VIDIOC_DQBUF failed\n");
return TFAIL;
}
}

memcpy(output_buffers[output_buf.index].start, capture_buffers[capture_buf.index].start, g_frame_size);

if (ioctl(fd_capture_v4l, VIDIOC_QBUF, &capture_buf) < 0) {
printf("VIDIOC_QBUF failed\n");
return TFAIL;
}

output_buf.timestamp.tv_sec = tv_start.tv_sec;
output_buf.timestamp.tv_usec = tv_start.tv_usec + (g_frame_period * i);
if (g_vdi_enable)
output_buf.field = g_tb ? V4L2_FIELD_INTERLACED_TB :
V4L2_FIELD_INTERLACED_BT;

if (ioctl(fd_output_v4l, VIDIOC_QBUF, &output_buf) < 0)
{
printf("VIDIOC_QBUF failed\n");
return TFAIL;
}
if (i == 1) {
type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
if (ioctl(fd_output_v4l, VIDIOC_STREAMON, &type) < 0) {
printf("Could not start stream\n");
return TFAIL;
}
}

//if(i==4) break;
}
gettimeofday(&tv_current, 0);
total_time = (tv_current.tv_sec - tv_start.tv_sec) * 1000000L;
total_time += tv_current.tv_usec - tv_start.tv_usec;
printf("total time for %u frames = %u us = %lld fps\n", i, total_time, (i * 1000000ULL) / total_time);

return 0;
}

int process_cmdline(int argc, char **argv)
{
int i;

for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-ow") == 0) {
g_display_width = atoi(argv[++i]);
}
else if (strcmp(argv[i], "-oh") == 0) {
g_display_height = atoi(argv[++i]);
}
else if (strcmp(argv[i], "-ot") == 0) {
g_display_top = atoi(argv[++i]);
}
else if (strcmp(argv[i], "-ol") == 0) {
g_display_left = atoi(argv[++i]);
}
else if (strcmp(argv[i], "-r") == 0) {
g_rotate = atoi(argv[++i]);
}
else if (strcmp(argv[i], "-f") == 0) {
i++;
g_fmt = v4l2_fourcc(argv[i][0], argv[i][1],argv[i][2],argv[i][3]);
if ((g_fmt != V4L2_PIX_FMT_NV12) &&
(g_fmt != V4L2_PIX_FMT_UYVY) &&
(g_fmt != V4L2_PIX_FMT_YUYV) &&
(g_fmt != V4L2_PIX_FMT_YUV420)) {
printf("Default format is used: UYVY\n");
}
}
else if (strcmp(argv[i], "-m") == 0) {
g_vdi_enable = 1;
g_vdi_motion = atoi(argv[++i]);
}
else if (strcmp(argv[i], "-tb") == 0) {
g_tb = 1;
}
else if (strcmp(argv[i], "-help") == 0) {
printf("MXC Video4Linux TVin Test\n\n" \
"Syntax: mxc_v4l2_tvin.out\n" \
" -ow <capture display width>\n" \
" -oh <capture display height>\n" \
" -ot <display top>\n" \
" -ol <display left>\n" \
" -r <rotation> -c <capture counter> \n"
" -m <motion> 0:medium 1:low 2:high, 0-default\n"
" -tb top field first, bottom field first-default\n"
" -f <format, only YU12, YUYV, UYVY and NV12 are supported> \n");
return TFAIL;
}
}

if ((g_display_width == 0) || (g_display_height == 0)) {
printf("Zero display width or height\n");
return TFAIL;
}

return 0;
}

int main(int argc, char **argv)
{
#ifdef BUILD_FOR_ANDROID
char fb_device[100] = "/dev/graphics/fb0";
#else
char fb_device[100] = "/dev/fb0";
#endif
int fd_fb = 0, i;
struct mxcfb_gbl_alpha alpha;
enum v4l2_buf_type type;

if (process_cmdline(argc, argv) < 0) {
return TFAIL;
}

if ((fd_capture_v4l = open(v4l_capture_dev, O_RDWR, 0)) < 0)
{
printf("Unable to open %s\n", v4l_capture_dev);
return TFAIL;
}

if ((fd_output_v4l = open(v4l_output_dev, O_RDWR, 0)) < 0)
{
printf("Unable to open %s\n", v4l_output_dev);
return TFAIL;
}

if (v4l_capture_setup() < 0) {
printf("Setup v4l capture failed.\n");
return TFAIL;
}

if (v4l_output_setup() < 0) {
printf("Setup v4l output failed.\n");
close(fd_capture_v4l);
return TFAIL;
}

if ((fd_fb = open(fb_device, O_RDWR )) < 0) {
printf("Unable to open frame buffer\n");
close(fd_capture_v4l);
close(fd_output_v4l);
return TFAIL;
}

/* Overlay setting */
alpha.alpha = 0;
alpha.enable = 1;
if (ioctl(fd_fb, MXCFB_SET_GBL_ALPHA, &alpha) < 0) {
printf("Set global alpha failed\n");
close(fd_fb);
close(fd_capture_v4l);
close(fd_output_v4l);
return TFAIL;
}

mxc_v4l_tvin_test();

type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
ioctl(fd_output_v4l, VIDIOC_STREAMOFF, &type);

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd_capture_v4l, VIDIOC_STREAMOFF, &type);

for (i = 0; i < g_output_num_buffers; i++)
{
munmap(output_buffers[i].start, output_buffers[i].length);
}
for (i = 0; i < g_capture_num_buffers; i++)
{
munmap(capture_buffers[i].start, capture_buffers[i].length);
}

close(fd_capture_v4l);
close(fd_output_v4l);
close(fd_fb);
return 0;
}

 

And this code is tw9900 driver code.

 

/*
* Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/

/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/

/*!
* @file adv7180.c
*
* @brief Analog Device ADV7180 video decoder functions
*
* @ingroup Camera
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/regulator/consumer.h>
#include <linux/fsl_devices.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-int-device.h>
#include "mxc_v4l2_capture.h"


//static struct fsl_mxc_tvin_platform_data *tvin_plat;
static struct fsl_mxc_camera_platform_data *tvin_plat;

extern void gpio_sensor_active(void);
extern void gpio_sensor_inactive(void);

static int tw9900_probe(struct i2c_client *adapter,
const struct i2c_device_id *id);
static int tw9900_detach(struct i2c_client *client);

static const struct i2c_device_id tw9900_id[] = {
{"tw9900", 0},
{},
};

#define TW9900_IDENT 0x00 /* IDENT */
#define TW9900_STATUS_1 0x01
#define TW9900_BRIGHTNESS 0x10 /* Brightness */
#define TW9900_CONTRAST 0x11 /* CONTRAST */
#define TW9900_SD_SATURATION_CB 0x13 /* SD Saturation Cb */
#define TW9900_SD_SATURATION_CR 0x14 /* SD Saturation Cr */

 

#define V4L2_IDENT_TW9900 9900


//#define NTSC_FIX

 


MODULE_DEVICE_TABLE(i2c, tw9900_id);

static struct i2c_driver tw9900_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "tw9900",
},
.probe = tw9900_probe,
.remove = tw9900_detach,
.id_table = tw9900_id,
};

/*!
* Maintains the information on the current state of the sensor.
*/
struct sensor {
struct sensor_data sen;
v4l2_std_id std_id;
} tw9900_data;


/*! List of input video formats supported. The video formats is corresponding
* with v4l2 id in video_fmt_t
*/
typedef enum {
tw9900_NTSC = 0, /*!< Locked on (M) NTSC video signal. */
tw9900_PAL, /*!< (B, G, H, I, N)PAL video signal. */
tw9900_NOT_LOCKED, /*!< Not locked on a signal. */
} video_fmt_idx;

/*! Number of video standards supported (including 'not locked' signal). */
#define tw9900_STD_MAX (tw9900_PAL + 1)

/*! Video format structure. */
typedef struct {
int v4l2_id; /*!< Video for linux ID. */
char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */
u16 raw_width; /*!< Raw width. */
u16 raw_height; /*!< Raw height. */
u16 active_width; /*!< Active width. */
u16 active_height; /*!< Active height. */
u16 active_top; /*!< Active top. */
u16 active_left; /*!< Active left. */
} video_fmt_t;

/*! Description of video formats supported.
*
* PAL: raw=720x625, active=720x576.
* NTSC: raw=720x525, active=720x480.
*/
static video_fmt_t video_fmts[] = {
{ /*! NTSC */
.v4l2_id = V4L2_STD_NTSC,
.name = "NTSC",
.raw_width = 720, /* SENS_FRM_WIDTH */
.raw_height = 525, /* SENS_FRM_HEIGHT */
.active_width = 720, /* ACT_FRM_WIDTH plus 1 */
.active_height = 480, /* ACT_FRM_WIDTH plus 1 */
.active_top = 13,
.active_left = 0,
},
{ /*! (B, G, H, I, N) PAL */
.v4l2_id = V4L2_STD_PAL,
.name = "PAL",
.raw_width = 720,
.raw_height = 625,
.active_width = 720,
.active_height = 576,
},
{ /*! Unlocked standard */
.v4l2_id = V4L2_STD_ALL,
.name = "Autodetect",
.raw_width = 720,
.raw_height = 625,
.active_width = 720,
.active_height = 576,
},
};

#ifdef NTSC_FIX
static video_fmt_idx video_idx = tw9900_NTSC;
#else
static video_fmt_idx video_idx = tw9900_PAL;
#endif

/*! @brief This mutex is used to provide mutual exclusion.
*
* Create a mutex that can be used to provide mutually exclusive
* read/write access to the globally accessible data structures
* and variables that were defined above.
*/
static DEFINE_MUTEX(mutex);

#define IF_NAME "tw9900"


/* supported controls */
/* This hasn't been fully implemented yet.
* This is how it should work, though. */
static struct v4l2_queryctrl tw9900_qctrl[] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0, /* check this value */
.maximum = 255, /* check this value */
.step = 1, /* check this value */
.default_value = 127, /* check this value */
.flags = 0,
}, {
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Saturation",
.minimum = 0, /* check this value */
.maximum = 255, /* check this value */
.step = 0x1, /* check this value */
.default_value = 127, /* check this value */
.flags = 0,
}
};

/***********************************************************************
* I2C transfert.
***********************************************************************/

/*! Read one register from a ADV7180 i2c slave device.
*
* @param *reg register in the device we wish to access.
*
* @return 0 if success, an error code otherwise.
*/
static inline int tw9900_read(u8 reg)
{
int val;
val = i2c_smbus_read_byte_data(tw9900_data.sen.i2c_client, reg);
if (val < 0) {
dev_dbg(&tw9900_data.sen.i2c_client->dev,
"%s:read reg error: reg=%2x\n", __func__, reg);
return -1;
}
return val;
}

/*! Write one register of a ADV7180 i2c slave device.
*
* @param *reg register in the device we wish to access.
*
* @return 0 if success, an error code otherwise.
*/
static int tw9900_write_reg(u8 reg,u8 val)
{
s32 ret;

ret = i2c_smbus_write_byte_data(tw9900_data.sen.i2c_client, reg, val);
if (ret < 0) {
dev_dbg(&tw9900_data.sen.i2c_client->dev,
"%s:write reg error:reg=%2x,val=%2x\n", __func__,
reg, val);
return -1;
}
return 0;
}

/***********************************************************************
* mxc_v4l2_capture interface.
***********************************************************************/

/*!
* Return attributes of current video standard.
* Since this device autodetects the current standard, this function also
* sets the values that need to be changed if the standard changes.
* There is no set std equivalent function.
*
* @return None.
*/
//static void adv7180_get_std(v4l2_std_id *std)
//{
// int tmp;
// int idx;

// dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_get_std\n");

/* Read the AD_RESULT to get the detect output video standard */
// tmp = adv7180_read(ADV7180_STATUS_1) & 0x70;

// mutex_lock(&mutex);
// if (tmp == 0x40) {
/* PAL */
// *std = V4L2_STD_PAL;
// idx = ADV7180_PAL;
// } else if (tmp == 0) {
/*NTSC*/
// *std = V4L2_STD_NTSC;
// idx = ADV7180_NTSC;
// } else {
// *std = V4L2_STD_ALL;
// idx = ADV7180_NOT_LOCKED;
// dev_dbg(&adv7180_data.sen.i2c_client->dev,
// "Got invalid video standard!\n");
// }
// mutex_unlock(&mutex);

/* This assumes autodetect which this device uses. */
// if (*std != adv7180_data.std_id) {
// video_idx = idx;
// adv7180_data.std_id = *std;
// adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width;
// adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height;
// }
//}
static void tw9900_get_std(v4l2_std_id *std)
{
int status_1, standard, idx;
bool locked;

dev_dbg(&tw9900_data.sen.i2c_client->dev, "In tw9900_get_std\n");
status_1 = tw9900_read(TW9900_STATUS_1);
#if 0
status_1 = tw9912_read(TW9912_STATUS_1);
locked = status_1 & 0x1;
standard = status_1 & 0x70;
#endif
mutex_lock(&mutex);
*std = V4L2_STD_ALL;
idx = tw9900_NOT_LOCKED;

standard = 0;
locked = 1;
if (locked) {
if (standard == 0x40) {
*std = V4L2_STD_PAL;
idx = tw9900_PAL;
} else if (standard == 0) {
*std = V4L2_STD_NTSC;
idx = tw9900_NTSC;
}
}
mutex_unlock(&mutex);

/* This assumes autodetect which this device uses. */
if (*std != tw9900_data.std_id) {
video_idx = idx;
tw9900_data.std_id = *std;
tw9900_data.sen.pix.width = video_fmts[video_idx].raw_width;
tw9900_data.sen.pix.height = video_fmts[video_idx].raw_height;
}
}


/***********************************************************************
* IOCTL Functions from v4l2_int_ioctl_desc.
***********************************************************************/

/*!
* ioctl_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_ifparm_num
* s: pointer to standard V4L2 device structure
* p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
*
* Gets slave interface parameters.
* Calculates the required xclk value to support the requested
* clock parameters in p. This value is returned in the p
* parameter.
*
* vidioc_int_g_ifparm returns platform-specific information about the
* interface settings used by the sensor.
*
* Called on open.
*/
static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
{
//dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_ifparm\n");
//printk("ioctl g ifparm is ==================================================\n");
if (s == NULL) {
pr_err(" ERROR!! no slave device set!\n");
return -1;
}

/* Initialize structure to 0s then set any non-0 values. */
memset(p, 0, sizeof(*p));
p->if_type = V4L2_IF_TYPE_BT656; /* This is the only possibility. */
p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
p->u.bt656.nobt_hs_inv = 1;
p->u.bt656.bt_sync_correct = 1;

/* ADV7180 has a dedicated clock so no clock settings needed. */

return 0;
}

/*!
* Sets the camera power.
*
* s pointer to the camera device
* on if 1, power is to be turned on. 0 means power is to be turned off
*
* ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
* @s: pointer to standard V4L2 device structure
* @on: power state to which device is to be set
*
* Sets devices power state to requrested state, if possible.
* This is called on open, close, suspend and resume.
*/
static int ioctl_s_power(struct v4l2_int_device *s, int on)
{

//printk("ioctl s power is =======================================\n");
struct sensor *sensor = s->priv;
sensor->sen.on = on;

return 0;
}

/*!
* ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
* @s: pointer to standard V4L2 device structure
* @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
*
* Returns the sensor's video CAPTURE parameters.
*/
static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
{
struct sensor *sensor = s->priv;
struct v4l2_captureparm *cparm = &a->parm.capture;

dev_dbg(&tw9900_data.sen.i2c_client->dev, "In tw9900:ioctl_g_parm\n");

switch (a->type) {
/* These are all the possible cases. */
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
memset(a, 0, sizeof(*a));
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cparm->capability = sensor->sen.streamcap.capability;
cparm->timeperframe = sensor->sen.streamcap.timeperframe;
cparm->capturemode = sensor->sen.streamcap.capturemode;
break;

case V4L2_BUF_TYPE_VIDEO_OUTPUT:
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
break;

default:
pr_debug("ioctl_g_parm:type is unknown %d\n", a->type);
break;
}

return 0;
}

/*!
* ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
* @s: pointer to standard V4L2 device structure
* @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
*
* Configures the sensor to use the input parameters, if possible. If
* not possible, reverts to the old parameters and returns the
* appropriate error code.
*
* This driver cannot change these settings.
*/
static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
{
dev_dbg(&tw9900_data.sen.i2c_client->dev, "In tw9900:ioctl_s_parm\n");

switch (a->type) {
/* These are all the possible cases. */
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
break;

default:
pr_debug(" type is unknown - %d\n", a->type);
break;
}

return 0;
}

/*!
* ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
* @s: pointer to standard V4L2 device structure
* @f: pointer to standard V4L2 v4l2_format structure
*
* Returns the sensor's current pixel format in the v4l2_format
* parameter.
*/
static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
{
struct sensor *sensor = s->priv;
int val=0;

//dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_fmt_cap\n");

switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
pr_debug(" Returning size of %dx%d\n",
sensor->sen.pix.width, sensor->sen.pix.height);
f->fmt.pix = sensor->sen.pix;
break;

case V4L2_BUF_TYPE_PRIVATE: {
v4l2_std_id std;
tw9900_get_std(&std);
f->fmt.pix.pixelformat = (u32)std;
}
break;

// case V4L2_BUF_TYPE_BRIGHTNESS:
// val = tw9900_read(TW9900_BRIGHTNESS);
// f->fmt.pix.pixelformat = (u32)val;
// //vc->value = tw9900_data.sen.brightness;
// break;
// case V4L2_BUF_TYPE_CONTRAST:
// val = tw9900_read(TW9900_CONTRAST);
// f->fmt.pix.pixelformat = (u32)val;
// break;


default:
f->fmt.pix = sensor->sen.pix;
break;
}

return 0;
}

/*!
* ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
* @s: pointer to standard V4L2 device structure
* @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure
*
* If the requested control is supported, returns the control information
* from the video_control[] array. Otherwise, returns -EINVAL if the
* control is not supported.
*/
static int ioctl_queryctrl(struct v4l2_int_device *s,
struct v4l2_queryctrl *qc)
{
int i;

dev_dbg(&tw9900_data.sen.i2c_client->dev, "adv7180:ioctl_queryctrl\n");

for (i = 0; i < ARRAY_SIZE(tw9900_qctrl); i++)
if (qc->id && qc->id == tw9900_qctrl[i].id) {
memcpy(qc, &(tw9900_qctrl[i]),
sizeof(*qc));
return 0;
}

return -EINVAL;
}

/*!
* ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
* @s: pointer to standard V4L2 device structure
* @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
*
* If the requested control is supported, returns the control's current
* value from the video_control[] array. Otherwise, returns -EINVAL
* if the control is not supported.
*/
static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
{
int ret = 0;
int sat = 0;

dev_dbg(&tw9900_data.sen.i2c_client->dev, "In tw9900:ioctl_g_ctrl\n");

switch (vc->id) {
case V4L2_CID_BRIGHTNESS:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_BRIGHTNESS\n");
tw9900_data.sen.brightness = tw9900_read(TW9900_BRIGHTNESS);
vc->value = tw9900_data.sen.brightness;
break;
case V4L2_CID_CONTRAST://add contrast - yongseok
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_CONTRAST\n");
tw9900_data.sen.contrast = tw9900_read(TW9900_CONTRAST);
vc->value = tw9900_data.sen.contrast;

break;
case V4L2_CID_SATURATION:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_SATURATION\n");
sat = tw9900_read(TW9900_SD_SATURATION_CB);
tw9900_data.sen.saturation = sat;
vc->value = tw9900_data.sen.saturation;
break;
case V4L2_CID_HUE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_HUE\n");
vc->value = tw9900_data.sen.hue;
break;
case V4L2_CID_AUTO_WHITE_BALANCE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_AUTO_WHITE_BALANCE\n");
break;
case V4L2_CID_DO_WHITE_BALANCE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_DO_WHITE_BALANCE\n");
break;
case V4L2_CID_RED_BALANCE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_RED_BALANCE\n");
vc->value = tw9900_data.sen.red;
break;
case V4L2_CID_BLUE_BALANCE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_BLUE_BALANCE\n");
vc->value = tw9900_data.sen.blue;
break;
case V4L2_CID_GAMMA:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_GAMMA\n");
break;
case V4L2_CID_EXPOSURE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_EXPOSURE\n");
vc->value = tw9900_data.sen.ae_mode;
break;
case V4L2_CID_AUTOGAIN:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_AUTOGAIN\n");
break;
case V4L2_CID_GAIN:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_GAIN\n");
break;
case V4L2_CID_HFLIP:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_HFLIP\n");
break;
case V4L2_CID_VFLIP:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_VFLIP\n");
break;
default:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" Default case\n");
vc->value = 0;
ret = -EPERM;
break;
}

return ret;
}

/*!
* ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
* @s: pointer to standard V4L2 device structure
* @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
*
* If the requested control is supported, sets the control's current
* value in HW (and updates the video_control[] array). Otherwise,
* returns -EINVAL if the control is not supported.
*/
static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
{
int retval = 0;
u8 tmp;

dev_dbg(&tw9900_data.sen.i2c_client->dev, "In tw9900:ioctl_s_ctrl\n");

switch (vc->id) {
case V4L2_CID_BRIGHTNESS:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_BRIGHTNESS\n");
tmp = vc->value;
tw9900_write_reg(TW9900_BRIGHTNESS, tmp);
tw9900_data.sen.brightness = vc->value;
break;
case V4L2_CID_CONTRAST: // add contrast - yongseok
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_CONTRAST\n");
tmp = vc->value;
tw9900_write_reg(TW9900_CONTRAST, tmp);
tw9900_data.sen.contrast = vc->value;

 


break;
case V4L2_CID_SATURATION:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_SATURATION\n");
tmp = vc->value;
tw9900_write_reg(TW9900_SD_SATURATION_CB, tmp);
tw9900_write_reg(TW9900_SD_SATURATION_CR, tmp);
tw9900_data.sen.saturation = vc->value;
break;
case V4L2_CID_HUE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_HUE\n");
break;
case V4L2_CID_AUTO_WHITE_BALANCE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_AUTO_WHITE_BALANCE\n");
break;
case V4L2_CID_DO_WHITE_BALANCE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_DO_WHITE_BALANCE\n");
break;
case V4L2_CID_RED_BALANCE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_RED_BALANCE\n");
break;
case V4L2_CID_BLUE_BALANCE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_BLUE_BALANCE\n");
break;
case V4L2_CID_GAMMA:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_GAMMA\n");
break;
case V4L2_CID_EXPOSURE:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_EXPOSURE\n");
break;
case V4L2_CID_AUTOGAIN:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_AUTOGAIN\n");
break;
case V4L2_CID_GAIN:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_GAIN\n");
break;
case V4L2_CID_HFLIP:
printk("____________________________________________________________ \n");
printk("_________________________ TW9900 ___________________________ \n");
printk("----------------- case V4L2_CID_HFLIP: --------------------- \n");
printk("____________________________________________________________ \n");
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_HFLIP\n");
break;
case V4L2_CID_VFLIP:
printk("____________________________________________________________ \n");
printk("_________________________ TW9900 ___________________________ \n");
printk("----------------- case V4L2_CID_VFLIP: --------------------- \n");
printk("____________________________________________________________ \n");
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" V4L2_CID_VFLIP\n");
break;
default:
dev_dbg(&tw9900_data.sen.i2c_client->dev,
" Default case\n");
retval = -EPERM;
break;
}

return retval;
}

/*!
* ioctl_enum_framesizes - V4L2 sensor interface handler for
* VIDIOC_ENUM_FRAMESIZES ioctl
* @s: pointer to standard V4L2 device structure
* @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
*
* Return 0 if successful, otherwise -EINVAL.
*/
static int ioctl_enum_framesizes(struct v4l2_int_device *s,
struct v4l2_frmsizeenum *fsize)
{
if (fsize->index >= 1)
return -EINVAL;

fsize->discrete.width = video_fmts[video_idx].active_width;
fsize->discrete.height = video_fmts[video_idx].active_height;

return 0;
}

/*!
* ioctl_g_chip_ident - V4L2 sensor interface handler for
* VIDIOC_DBG_G_CHIP_IDENT ioctl
* @s: pointer to standard V4L2 device structure
* @id: pointer to int
*
* Return 0.
*/
static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
{
((struct v4l2_dbg_chip_ident *)id)->match.type =
V4L2_CHIP_MATCH_I2C_DRIVER;
strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name,
"tw9900_decoder");
((struct v4l2_dbg_chip_ident *)id)->ident = V4L2_IDENT_TW9900;

return 0;
}

/*!
* ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
* @s: pointer to standard V4L2 device structure
*/
static int ioctl_init(struct v4l2_int_device *s)
{
//dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_init\n");

//printk("ioctl init is ================================================\n");
return 0;
}

/*!
* ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
* @s: pointer to standard V4L2 device structure
*
* Initialise the device when slave attaches to the master.
*/
static int ioctl_dev_init(struct v4l2_int_device *s)
{

//printk("ioctl dev init====================================================\n");
//dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_dev_init\n");
return 0;
}

/*!
* This structure defines all the ioctls for this module.
*/
static struct v4l2_int_ioctl_desc tw9900_ioctl_desc[] = {

{vidioc_int_dev_init_num, (v4l2_int_ioctl_func*)ioctl_dev_init},

/*!
* Delinitialise the dev. at slave detach.
* The complement of ioctl_dev_init.
*/
/* {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func *)ioctl_dev_exit}, */

{vidioc_int_s_power_num, (v4l2_int_ioctl_func*)ioctl_s_power},
{vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*)ioctl_g_ifparm},
/* {vidioc_int_g_needs_reset_num,
(v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
{vidioc_int_init_num, (v4l2_int_ioctl_func*)ioctl_init},

/*!
* VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
*/
/* {vidioc_int_enum_fmt_cap_num,
(v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */

/*!
* VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.
* This ioctl is used to negotiate the image capture size and
* pixel format without actually making it take effect.
*/
/* {vidioc_int_try_fmt_cap_num,
(v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */

{vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_g_fmt_cap},

/*!
* If the requested format is supported, configures the HW to use that
* format, returns error code if format not supported or HW can't be
* correctly configured.
*/
/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */

{vidioc_int_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm},
{vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm},
{vidioc_int_queryctrl_num, (v4l2_int_ioctl_func*)ioctl_queryctrl},
{vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func*)ioctl_g_ctrl},
{vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func*)ioctl_s_ctrl},
{vidioc_int_enum_framesizes_num,
(v4l2_int_ioctl_func *) ioctl_enum_framesizes},
{vidioc_int_g_chip_ident_num,
(v4l2_int_ioctl_func *)ioctl_g_chip_ident},
};

static struct v4l2_int_slave tw9900_slave = {
.ioctls = tw9900_ioctl_desc,
.num_ioctls = ARRAY_SIZE(tw9900_ioctl_desc),
};

static struct v4l2_int_device tw9900_int_device = {
.module = THIS_MODULE,
.name = "tw9900",
.type = v4l2_int_type_slave,
.u = {
.slave = &tw9900_slave,
},
};


/***********************************************************************
* I2C client and driver.
***********************************************************************/

/*! ADV7180 Reset function.
*
* @return None.
*/
static void tw9900_hard_reset()
{

tw9900_write_reg(0x00, 0x00);
tw9900_write_reg(0x01, 0x78);
tw9900_write_reg(0x02, 0x40);
tw9900_write_reg(0x03, 0xA2);
tw9900_write_reg(0x04, 0x00);
tw9900_write_reg(0x05, 0x01);
tw9900_write_reg(0x06, 0x00);
tw9900_write_reg(0x07, 0x02);
tw9900_write_reg(0x08, 0x12);
tw9900_write_reg(0x09, 0xf4);
tw9900_write_reg(0x0A, 0x10);
tw9900_write_reg(0x0B, 0xD0);
tw9900_write_reg(0x0C, 0xCC);
tw9900_write_reg(0x0D, 0x00);
tw9900_write_reg(0x0E, 0x11);
tw9900_write_reg(0x0F, 0x00);
tw9900_write_reg(0x10, 0x00);
tw9900_write_reg(0x11, 0x64);
tw9900_write_reg(0x12, 0x11);
tw9900_write_reg(0x13, 0x80);
tw9900_write_reg(0x14, 0x80);
tw9900_write_reg(0x15, 0x00);
tw9900_write_reg(0x16, 0x00);
tw9900_write_reg(0x17, 0x30);
tw9900_write_reg(0x18, 0x44);
tw9900_write_reg(0x19, 0x57);
tw9900_write_reg(0x1A, 0x0F);
tw9900_write_reg(0x1B, 0x00);
tw9900_write_reg(0x1C, 0x07);
tw9900_write_reg(0x1D, 0x7F);
tw9900_write_reg(0x1E, 0x08);
tw9900_write_reg(0x1F, 0x00);
tw9900_write_reg(0x20, 0x50);
tw9900_write_reg(0x21, 0x42);
tw9900_write_reg(0x22, 0xF0);
tw9900_write_reg(0x23, 0xD8);
tw9900_write_reg(0x24, 0xBC);
tw9900_write_reg(0x25, 0xB8);
tw9900_write_reg(0x26, 0x44);
tw9900_write_reg(0x27, 0x2A);
tw9900_write_reg(0x28, 0x00);
tw9900_write_reg(0x29, 0x03);
tw9900_write_reg(0x2A, 0x78);
tw9900_write_reg(0x2B, 0x44);
tw9900_write_reg(0x2C, 0x30);
tw9900_write_reg(0x2D, 0x07);
tw9900_write_reg(0x2E, 0xA5);
tw9900_write_reg(0x2F, 0xE0);
tw9900_write_reg(0x30, 0x00);
tw9900_write_reg(0x31, 0x10);
tw9900_write_reg(0x32, 0xFF);
tw9900_write_reg(0x33, 0x05);
tw9900_write_reg(0x34, 0x1A);
tw9900_write_reg(0x35, 0x80);
tw9900_write_reg(0x36, 0x00);
tw9900_write_reg(0x37, 0x00);
tw9900_write_reg(0x38, 0x00);
tw9900_write_reg(0x39, 0x00);
tw9900_write_reg(0x3A, 0x00);
tw9900_write_reg(0x3B, 0x00);
tw9900_write_reg(0x3C, 0x00);
tw9900_write_reg(0x3D, 0x00);
tw9900_write_reg(0x3E, 0x00);
tw9900_write_reg(0x3F, 0x00);
tw9900_write_reg(0x40, 0x00);
tw9900_write_reg(0x41, 0x00);
tw9900_write_reg(0x42, 0x00);
tw9900_write_reg(0x43, 0x00);
tw9900_write_reg(0x44, 0x00);
tw9900_write_reg(0x45, 0x00);
tw9900_write_reg(0x46, 0x00);
tw9900_write_reg(0x47, 0x00);
tw9900_write_reg(0x48, 0x00);
tw9900_write_reg(0x49, 0x00);
tw9900_write_reg(0x4A, 0x00);
tw9900_write_reg(0x4B, 0x00);
tw9900_write_reg(0x4C, 0x05);
tw9900_write_reg(0x4D, 0x40);
tw9900_write_reg(0x4E, 0x00);
tw9900_write_reg(0x4F, 0x00);
tw9900_write_reg(0x50, 0xA0);
tw9900_write_reg(0x51, 0x22);
tw9900_write_reg(0x52, 0x31);
tw9900_write_reg(0x53, 0x80);
tw9900_write_reg(0x54, 0x00);
tw9900_write_reg(0x55, 0x00);
tw9900_write_reg(0x56, 0x00);
tw9900_write_reg(0x57, 0x00);
tw9900_write_reg(0x58, 0x00);
tw9900_write_reg(0x59, 0x00);
tw9900_write_reg(0x5A, 0x00);
tw9900_write_reg(0x5B, 0x00);
tw9900_write_reg(0x5C, 0x00);
tw9900_write_reg(0x5D, 0x00);
tw9900_write_reg(0x5E, 0x00);
tw9900_write_reg(0x5F, 0x00);
tw9900_write_reg(0x60, 0x00);
tw9900_write_reg(0x61, 0x00);
tw9900_write_reg(0x62, 0x00);
tw9900_write_reg(0x63, 0x00);
tw9900_write_reg(0x64, 0x00);
tw9900_write_reg(0x65, 0x00);
tw9900_write_reg(0x66, 0x00);
tw9900_write_reg(0x67, 0x00);
tw9900_write_reg(0x68, 0x00);
tw9900_write_reg(0x69, 0x00);
tw9900_write_reg(0x6A, 0x00);
tw9900_write_reg(0x6B, 0x09);
tw9900_write_reg(0x6C, 0x19);
tw9900_write_reg(0x6D, 0x0A);
tw9900_write_reg(0x6E, 0x20);
tw9900_write_reg(0x6F, 0x13);
tw9900_write_reg(0x70, 0x00);
tw9900_write_reg(0x71, 0x00);
tw9900_write_reg(0x72, 0x00);
tw9900_write_reg(0x73, 0x00);
tw9900_write_reg(0x74, 0x00);
tw9900_write_reg(0x75, 0x00);
tw9900_write_reg(0x76, 0x00);
tw9900_write_reg(0x77, 0x00);
tw9900_write_reg(0x78, 0x00);
tw9900_write_reg(0x79, 0x00);
tw9900_write_reg(0x7A, 0x00);
tw9900_write_reg(0x7B, 0x00);
tw9900_write_reg(0x7C, 0x00);
tw9900_write_reg(0x7D, 0x00);
tw9900_write_reg(0x7E, 0x00);
tw9900_write_reg(0x7F, 0x00);
tw9900_write_reg(0x80, 0x00);
tw9900_write_reg(0x81, 0x00);
tw9900_write_reg(0x82, 0x00);
tw9900_write_reg(0x83, 0x00);
tw9900_write_reg(0x84, 0x00);
tw9900_write_reg(0x85, 0x00);
tw9900_write_reg(0x86, 0x00);
tw9900_write_reg(0x87, 0x00);
tw9900_write_reg(0x88, 0x00);
tw9900_write_reg(0x89, 0x00);
tw9900_write_reg(0x8A, 0x00);
tw9900_write_reg(0x8B, 0x00);
tw9900_write_reg(0x8C, 0x00);
tw9900_write_reg(0x8D, 0x00);
tw9900_write_reg(0x8E, 0x00);
tw9900_write_reg(0x8F, 0x00);
tw9900_write_reg(0x90, 0x00);
tw9900_write_reg(0x91, 0x00);
tw9900_write_reg(0x92, 0x00);
tw9900_write_reg(0x93, 0x00);
tw9900_write_reg(0x94, 0x00);
tw9900_write_reg(0x95, 0x00);
tw9900_write_reg(0x96, 0x00);
tw9900_write_reg(0x97, 0x00);
tw9900_write_reg(0x98, 0x00);
tw9900_write_reg(0x99, 0x00);
tw9900_write_reg(0x9A, 0x00);
tw9900_write_reg(0x9B, 0x00);
tw9900_write_reg(0x9C, 0x00);
tw9900_write_reg(0x9D, 0x00);
tw9900_write_reg(0x9E, 0x00);
tw9900_write_reg(0x9F, 0x00);
tw9900_write_reg(0xA0, 0x00);
tw9900_write_reg(0xA1, 0x00);
tw9900_write_reg(0xA2, 0x00);
tw9900_write_reg(0xA3, 0x00);
tw9900_write_reg(0xA4, 0x00);
tw9900_write_reg(0xA5, 0x00);
tw9900_write_reg(0xA6, 0x00);
tw9900_write_reg(0xA7, 0x00);
tw9900_write_reg(0xA8, 0x00);
tw9900_write_reg(0xA9, 0x00);
tw9900_write_reg(0xAA, 0x00);
tw9900_write_reg(0xAB, 0x00);
tw9900_write_reg(0xAC, 0x00);
tw9900_write_reg(0xAD, 0x00);
tw9900_write_reg(0xAE, 0x1A);
tw9900_write_reg(0xAF, 0x80);
tw9900_write_reg(0xB0, 0x00);
tw9900_write_reg(0xB1, 0x00);
tw9900_write_reg(0xB2, 0x00);
tw9900_write_reg(0xB3, 0x00);
tw9900_write_reg(0xB4, 0x00);
tw9900_write_reg(0xB5, 0x00);
tw9900_write_reg(0xB6, 0x00);
tw9900_write_reg(0xB7, 0x06);
tw9900_write_reg(0xB8, 0x00);
tw9900_write_reg(0xB9, 0x00);
tw9900_write_reg(0xBA, 0x57);
tw9900_write_reg(0xBB, 0x00);
tw9900_write_reg(0xBC, 0x00);
tw9900_write_reg(0xBD, 0x80);
tw9900_write_reg(0xBE, 0x80);
tw9900_write_reg(0xBF, 0x80);
tw9900_write_reg(0xC0, 0x80);
tw9900_write_reg(0xC1, 0x00);
tw9900_write_reg(0xC2, 0x00);
tw9900_write_reg(0xC3, 0x00);
tw9900_write_reg(0xC4, 0x00);
tw9900_write_reg(0xC5, 0x00);
tw9900_write_reg(0xC6, 0x00);
tw9900_write_reg(0xC7, 0x00);
tw9900_write_reg(0xC8, 0x00);
tw9900_write_reg(0xC9, 0x00);
tw9900_write_reg(0xCA, 0x00);
tw9900_write_reg(0xCB, 0x00);
tw9900_write_reg(0xCC, 0x00);
tw9900_write_reg(0xCD, 0x00);
tw9900_write_reg(0xCE, 0x00);
tw9900_write_reg(0xCF, 0x00);
tw9900_write_reg(0xD0, 0x00);
tw9900_write_reg(0xD1, 0x00);
tw9900_write_reg(0xD2, 0x00);
tw9900_write_reg(0xD3, 0x00);
tw9900_write_reg(0xD4, 0x00);
tw9900_write_reg(0xD5, 0x00);
tw9900_write_reg(0xD6, 0x00);
tw9900_write_reg(0xD7, 0x00);
tw9900_write_reg(0xD8, 0x00);
tw9900_write_reg(0xD9, 0x00);
tw9900_write_reg(0xDA, 0x00);
tw9900_write_reg(0xDB, 0x00);
tw9900_write_reg(0xDC, 0x00);
tw9900_write_reg(0xDD, 0x00);
tw9900_write_reg(0xDE, 0x00);
tw9900_write_reg(0xDF, 0x00);
tw9900_write_reg(0xE0, 0x00);
tw9900_write_reg(0xE1, 0x00);
tw9900_write_reg(0xE2, 0x00);
tw9900_write_reg(0xE3, 0x00);
tw9900_write_reg(0xE4, 0x00);
tw9900_write_reg(0xE5, 0x00);
tw9900_write_reg(0xE6, 0x00);
tw9900_write_reg(0xE7, 0x00);
tw9900_write_reg(0xE8, 0x00);
tw9900_write_reg(0xE9, 0x00);
tw9900_write_reg(0xEA, 0x00);
tw9900_write_reg(0xEB, 0x00);
tw9900_write_reg(0xEC, 0x00);
tw9900_write_reg(0xED, 0x00);
tw9900_write_reg(0xEE, 0x00);
tw9900_write_reg(0xEF, 0x00);
tw9900_write_reg(0xF0, 0x00);
tw9900_write_reg(0xF1, 0x00);
tw9900_write_reg(0xF2, 0x00);
tw9900_write_reg(0xF3, 0x00);
tw9900_write_reg(0xF4, 0x00);
tw9900_write_reg(0xF5, 0x00);
tw9900_write_reg(0xF6, 0x00);
tw9900_write_reg(0xF7, 0x00);
tw9900_write_reg(0xF8, 0x00);
tw9900_write_reg(0xF9, 0x00);
tw9900_write_reg(0xFA, 0x00);
tw9900_write_reg(0xFB, 0x00);
tw9900_write_reg(0xFC, 0x00);
tw9900_write_reg(0xFD, 0x00);
tw9900_write_reg(0xFE, 0x00);
tw9900_write_reg(0xFF, 0x00);

}

/*! ADV7180 I2C attach function.
*
* @param *adapter struct i2c_adapter *.
*
* @return Error code indicating success or failure.
*/

/*!
* ADV7180 I2C probe function.
* Function set in i2c_driver struct.
* Called by insmod.
*
* @param *adapter I2C adapter descriptor.
*
* @return Error code indicating success or failure.
*/
static int tw9900_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rev_id;
int ret = 0;
int regfcnt = 0;

tvin_plat = client->dev.platform_data;

//printk(KERN_ERR"DBG sensor data is at %p\n", &adv7180_data);

//printk("In tw9900_probe new =========================================\n");


//printk("enter into tvin plat io init==============\n");
if (tvin_plat->io_init){
tvin_plat->io_init();
printk("end into io init==============================\n");
}

//printk("out into tvin plat io init============================\n");

//if (tvin_plat->reset)
//tvin_plat->reset();

//if (tvin_plat->pwdn)
//tvin_plat->pwdn(0); //\D7\EE\BA\F3\D0޸\B4ƽ̨\CA\FD\BE\DD

msleep(1);

/* Set initial values for the sensor struct. */
memset(&tw9900_data, 0, sizeof(tw9900_data));
tw9900_data.sen.i2c_client = client;
tw9900_data.sen.streamcap.timeperframe.denominator = 60;
tw9900_data.sen.streamcap.timeperframe.numerator = 1;
tw9900_data.std_id = V4L2_STD_ALL;
#ifdef NTSC_FIX
video_idx = tw9900_NTSC;
#else
video_idx = tw9900_NOT_LOCKED;
#endif
tw9900_data.sen.pix.width = video_fmts[video_idx].raw_width;
tw9900_data.sen.pix.height = video_fmts[video_idx].raw_height;
tw9900_data.sen.pix.pixelformat = V4L2_PIX_FMT_UYVY; /* YUV422 */
tw9900_data.sen.pix.priv = 1; /* 1 is used to indicate TV in */
tw9900_data.sen.on = true;
gpio_sensor_active();

/*! Read the revision ID of the tvin chip */
rev_id = tw9900_read(TW9900_IDENT);
//dev_dbg(dev,
// "%s:Analog Device TW99%d detected!\n", __func__,
// GET_ID(rev_id));

/*! ADV7180 initialization. */
tw9900_hard_reset();

/* This function attaches this structure to the /dev/video0 device.
* The pointer in priv points to the mt9v111_data structure here.*/
tw9900_int_device.priv = &tw9900_data;
ret = v4l2_int_device_register(&tw9900_int_device);

return ret;
}

/*!
* ADV7180 I2C detach function.
* Called on rmmod.
*
* @param *client struct i2c_client*.
*
* @return Error code indicating success or failure.
*/
static int tw9900_detach(struct i2c_client *client)
{
v4l2_int_device_unregister(&tw9900_int_device);

return 0;
}

/*!
* ADV7180 init function.
* Called on insmod.
*
* @return Error code indicating success or failure.
*/
static __init int tw9900_init(void)
{
u8 err = 0;

pr_debug("In tw9900_init\n");

/* Tells the i2c driver what functions to call for this driver. */
err = i2c_add_driver(&tw9900_i2c_driver);
if (err != 0)
pr_err("%s:driver registration failed, error=%d \n",
__func__, err);

return err;
}

/*!
* ADV7180 cleanup function.
* Called on rmmod.
*
* @return Error code indicating success or failure.
*/
static void __exit tw9900_clean(void)
{
dev_dbg(&tw9900_data.sen.i2c_client->dev, "In adv7180_clean\n");
i2c_del_driver(&tw9900_i2c_driver);
gpio_sensor_inactive();
}

module_init(tw9900_init);
module_exit(tw9900_clean);

MODULE_AUTHOR("Freescale Semiconductor");
MODULE_DESCRIPTION("Anolog Device ADV7180 video decoder driver");
MODULE_LICENSE("GPL");

Attachments

Outcomes