⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 camera_sensor_if.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
字号:
/*
 *  linux/drivers/media/video/omap/camera_sensor_if.c
 *
 * Copyright (C) 2004 Texas Instruments Inc
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <linux/videodev.h>

#include "camera_sensor_if.h"
#include "camera_core.h"
#include "ov9640.h"

extern int ov9640_configure(enum image_size, enum pixel_format, unsigned char);
extern int ov9640_read_mask(u8, u8);
extern int ov9640_write_mask(u8, u8, u8);
extern int ov9640_init (void);

#define DEF_GAIN         31
#define DEF_AUTOGAIN      1
#define DEF_EXPOSURE    154
#define DEF_AEC           1
#define DEF_FREEZE_AGCAEC 0
#define DEF_BLUE        153
#define DEF_RED         (255 - DEF_BLUE)
#define DEF_AWB           1
#define DEF_HFLIP         0
#define DEF_VFLIP         0

/* Our own specific controls */
#define V4L2_CID_FREEZE_AGCAEC V4L2_CID_PRIVATE_BASE+0
#define V4L2_CID_AUTOEXPOSURE V4L2_CID_PRIVATE_BASE+1
#define V4L2_CID_LAST_PRIV  V4L2_CID_AUTOEXPOSURE

/*  Video controls  */
static struct vcontrol {
        struct v4l2_queryctrl qc;
        int current_value;
        u8 reg;
        u8 mask;
        u8 start_bit;
} control[] = {
        { { V4L2_CID_GAIN, V4L2_CTRL_TYPE_INTEGER, "Gain", 0, 63, 1,
            DEF_GAIN },
          0, OV9640_GAIN, 0x3f, 0 },
        { { V4L2_CID_AUTOGAIN, V4L2_CTRL_TYPE_BOOLEAN, "Auto Gain", 0, 1, 0,
            DEF_AUTOGAIN },
          0, OV9640_COM8, 0x04, 2 },
        { { V4L2_CID_EXPOSURE, V4L2_CTRL_TYPE_INTEGER, "Exposure", 0, 255, 1,
            DEF_EXPOSURE },
          0, OV9640_AECH, 0xff, 0 },
        { { V4L2_CID_AUTOEXPOSURE, V4L2_CTRL_TYPE_BOOLEAN, "Auto Exposure", 0, 1, 0,
            DEF_AEC },
          0, OV9640_COM8, 0x01, 0 },
        { { V4L2_CID_FREEZE_AGCAEC, V4L2_CTRL_TYPE_BOOLEAN, "Freeze AGC/AEC", 0,1,0,
            DEF_FREEZE_AGCAEC },
          0, OV9640_COM9, 0x01, 0 },
        { { V4L2_CID_RED_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Red Balance", 0, 255, 1,
            DEF_RED },
          0, OV9640_RED, 0xff, 0 },
        { { V4L2_CID_BLUE_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Blue Balance", 0, 255, 1,
            DEF_BLUE },
          0, OV9640_BLUE, 0xff, 0 },
        { { V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CTRL_TYPE_BOOLEAN, "Auto White Balance", 0,1,0,
            DEF_AWB },
          0, OV9640_COM8, 0x02, 1 },
        { { V4L2_CID_HFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Mirror Image", 0, 1, 0,
            DEF_HFLIP },
          0, OV9640_MVFP, 0x20, 5 },
        { { V4L2_CID_VFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Vertical Flip", 0, 1, 0,
            DEF_VFLIP },
          0, OV9640_MVFP, 0x10, 4 },
};

#define NUM_CONTROLS (sizeof(control)/sizeof(control[0]))

/* Convert a Video for Linux fourcc pixelformat to an enum pixel_format value.
 */
static enum pixel_format
image_find_format(unsigned long pixelformat)
{	switch (pixelformat) {
		case V4L2_PIX_FMT_YUYV:
		case V4L2_PIX_FMT_UYVY:
		default:
			return YUV;
		case V4L2_PIX_FMT_RGB565:
		case V4L2_PIX_FMT_RGB565X:
			return RGB565;
		case V4L2_PIX_FMT_RGB555:
		case V4L2_PIX_FMT_RGB555X:
			return RGB555;
	}
}

/* Returns the index of the requested ID from the control structure array */
static int
find_vctrl(int id)
{
	int i;

	if (id < V4L2_CID_BASE)
		return -EDOM;

	for (i = NUM_CONTROLS - 1; i >= 0; i--)
		if (control[i].qc.id == id)
			break;
	if (i < 0)
		i = -EINVAL;
	return i;
}

/* Implement the 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.
 */
static int/*void*/
sensor_try_fmt(struct v4l2_pix_format *pix)
{
	enum image_size isize;
	int ifmt;

	isize = image_find_size(pix->width, pix->height);
	pix->width = image_sizes[isize].width;
	pix->height = image_sizes[isize].height;
	for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
		if (pix->pixelformat == image_formats[ifmt].pixelformat)
			break;
	}
	if (ifmt == NUM_CAPTURE_FORMATS)
		ifmt = 0;
	pix->pixelformat = image_formats[ifmt].pixelformat;
	pix->field = V4L2_FIELD_NONE;
	pix->bytesperline = pix->width*2;
	pix->sizeimage = pix->bytesperline*pix->height;
	pix->priv = 0;
	switch (pix->pixelformat) {
		case V4L2_PIX_FMT_YUYV:
		case V4L2_PIX_FMT_UYVY:
		default:
			pix->colorspace = V4L2_COLORSPACE_JPEG;
			break;
		case V4L2_PIX_FMT_RGB565:
		case V4L2_PIX_FMT_RGB565X:
		case V4L2_PIX_FMT_RGB555:
		case V4L2_PIX_FMT_RGB555X:
			pix->colorspace = V4L2_COLORSPACE_SRGB;
			break;
	}
	return 0;
}

/* Calculate the internal clock divisor (value of the CLKRC register) of the
 * OV9640 given the image size, the frequency (in Hz) of its XCLK input and a
 * desired frame period (in seconds).  The frame period 'fper' is expressed as
 * a fraction.  The frame period is an input/output parameter.
 * Returns the value of the OV9640 CLKRC register that will yield the frame
 * period returned in 'fper' at the specified xclk frequency.  The
 * returned period will be as close to the requested period as possible.
 */
unsigned char
sensor_clkrc(enum image_size isize, unsigned long xclk, struct v4l2_fract *fper)
{
        unsigned long fpm, fpm_max;     /* frames per minute */
        unsigned long divisor;
        const unsigned long divisor_max = 64;
        const static unsigned long clks_per_frame[] =
                { 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };
        /*         QQCIF   QQVGA    QCIF    QVGA     CIF     VGA     SXGA
         *actually 199680,400000, 199680, 400000, 399360, 800000, 3200000
         */

        if (fper->numerator > 0)
                fpm = (fper->denominator*60)/fper->numerator;
        else
                fpm = 0xffffffff;
        fpm_max = (xclk*60)/clks_per_frame[isize];
        if (fpm_max == 0)
                fpm_max = 1;
        if (fpm > fpm_max)
                fpm = fpm_max;
        if (fpm == 0)
                fpm = 1;
        divisor = fpm_max/fpm;
        if (divisor > divisor_max)
                divisor = divisor_max;
        fper->numerator = divisor*60;
        fper->denominator = fpm_max;

        /* try to reduce the fraction */
        while (!(fper->denominator % 5) && !(fper->numerator % 5)) {
                fper->numerator /= 5;
                fper->denominator /= 5;
        }
        while (!(fper->denominator % 3) && !(fper->numerator % 3)) {
                fper->numerator /= 3;
                fper->denominator /= 3;
        }
        while (!(fper->denominator % 2) && !(fper->numerator % 2)) {
                fper->numerator /= 2;
                fper->denominator /= 2;
        }
        if (fper->numerator < fper->denominator) {
                if (!(fper->denominator % fper->numerator)) {
                        fper->denominator /= fper->numerator;
                        fper->numerator = 1;
                }
        }
        else {
                if (!(fper->numerator % fper->denominator)) {
                        fper->numerator /= fper->denominator;
                        fper->denominator = 1;
                }
        }

        return (0x80 | (divisor - 1));
}


int camera_sensor_enum_pixformat(struct v4l2_fmtdesc *fmt)
{
	int index = fmt->index;
	enum v4l2_buf_type type = fmt->type;

	memset(fmt, 0, sizeof(*fmt));
	fmt->index = index;
	fmt->type = type;

	switch (fmt->type) {
		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		if (index >= NUM_CAPTURE_FORMATS)
			return -EINVAL;
		break;

		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
		if (index >= NUM_OVERLAY_FORMATS)
			return -EINVAL;
		break;

		default:
			return -EINVAL;
	}

	fmt->flags = image_formats[index].flags;
	strlcpy(fmt->description, image_formats[index].description, sizeof(fmt->description));
	fmt->pixelformat = image_formats[index].pixelformat;
	return 0;
}

int camera_sensor_set_format( struct v4l2_pix_format* fmt, unsigned long xclk, struct v4l2_fract *fper)
{
        enum image_size isize;
        enum pixel_format pfmt;
        unsigned char clkrc;
        int err = 0;

        isize = image_find_size(fmt->width, fmt->height);
        pfmt = image_find_format(fmt->pixelformat);

        clkrc = sensor_clkrc (isize, xclk, fper);
        err = ov9640_configure(isize, pfmt, clkrc);

        return err;
}

int camera_sensor_query_control(struct v4l2_queryctrl *qc)
{

	int i;
	i = find_vctrl (qc->id);
	if (i == -EINVAL) {
		qc->flags = V4L2_CTRL_FLAG_DISABLED;
		return 0;
	}

	if (i < 0)
		return -EINVAL;

	*qc = control[i].qc;
	return 0;
}

int camera_sensor_get_control(struct v4l2_control *vc)
{
	int i, val;
	struct vcontrol * lvc;
	
	i = find_vctrl(vc->id);
	if (i < 0)
		return -EINVAL;

	lvc = &control[i];
	
	val = ov9640_read_mask(lvc->reg, lvc->mask) >> lvc->start_bit;
	
	if (val >= 0) {
		vc->value = lvc->current_value = val;
		return 0;
	} else
		return val;
}

int camera_sensor_set_control(struct v4l2_control *vc)
{
	struct vcontrol * lvc;
	int val = vc->value;
	int i;

	i = find_vctrl(vc->id);
	if (i < 0)
		return -EINVAL;

	lvc = &control[i];

	val = ov9640_write_mask(lvc->reg,
			    val << lvc->start_bit,
			    lvc->mask) >> lvc->start_bit;

	if (val >= 0) {
		lvc->current_value = val;
		return 0;
	} else
		return val;

}

/* Initialize the OV9640 sensor.
 * This routine allocates and initializes the data structure for the sensor, 
 * powers up the sensor, registers the I2C driver, and sets a default image 
 * capture format in cam->pix.  The capture format is not actually programmed 
 * into the OV9640 sensor by this routine.
 * This function must set cam->sensor to a non-NULL value to indicate that 
 * initialization is successful.  cam->sensor must be set to NULL to indicate 
 * failure.
 */
static int
camera_sensor_init(struct v4l2_pix_format *pix)
{
	/* Call Ov9640 init function */
	ov9640_init ();

   	/* Make the default capture format QVGA YUYV */
	pix->width = image_sizes[QCIF].width;
	pix->height = image_sizes[QCIF].height;
        pix->bytesperline = pix->width*2;
        pix->sizeimage = pix->bytesperline*pix->height;

	pix->pixelformat = V4L2_PIX_FMT_RGB565;
	sensor_try_fmt(pix);

	return 0;
}

/* Function pointers exported to the core module */
struct camera_sensor camera_sensor_if = {
        version: 	0x01,
        init: 		camera_sensor_init,
	enum_pixformat:	camera_sensor_enum_pixformat,
	try_format:	sensor_try_fmt,
	set_format:	camera_sensor_set_format,
	query_control:	camera_sensor_query_control,
	get_control:	camera_sensor_get_control,
	set_control:	camera_sensor_set_control
};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -