camera_core.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,174 行 · 第 1/3 页
C
1,174 行
vb->state = STATE_QUEUED;
err = camera_core_sg_dma_queue (cam, vb->dma.sglist, vb->dma.sglen,
camera_core_vbq_complete, vb);
if (err) {
/* Oops. We're not supposed to get any errors here. The only
* way we could get an error is if we ran out of scatter-gather
* DMA slots, but we are supposed to have at least as many
* scatter-gather DMA slots as video buffers so that can't
* happen.
*/
printk(KERN_DEBUG CAM_NAME
": Failed to queue a video buffer for DMA!\n");
vb->state = state;
}
}
/* ------------------ videobuf_queue_ops ---------------------------------------- */
/* Find the best match for a requested image capture size. The best match
* is chosen as the nearest match that has the same number or fewer pixels
* as the requested size, or the smallest image size if the requested size
* has fewer pixels than the smallest image.
*/
enum image_size
image_find_size(unsigned int width, unsigned int height)
{
enum image_size isize;
unsigned long pixels = width*height;
for (isize = QQCIF; isize < SXGA; isize++) {
if (image_sizes[isize + 1].height*
image_sizes[isize + 1].width > pixels) {
return isize;
}
}
return SXGA;
}
/* Given the image capture format in cam->pix, the nominal frame period in
* cam->nominal_timeperframe, and the frequency of the camera interface
* functional clock (cam->ocp_clk), calculate the required xclk frequency
* (cam->xclk) and the actual frame period (cam->cparm.timeperframe).
* xclk is obtained by dividing ocp_clk with a divisor in the range 1 to 30.
* The nominal xclk input frequency of the OV9640 is 24MHz, maximum
* frequency is 48MHz, and minimum frequency is 10MHz.
*/
static void
camera_core_sensor_timeperframe(struct camera_device *cam)
{
unsigned long tgt_xclk; /* target xclk */
unsigned long tgt_fps; /* target frames per minute */
enum image_size isize;
/* We use arbitrary rules to select the xclk frequency. If the
* capture size is VGA and the frame rate is greater than 900
* frames per minute, or if the capture size is SXGA and the
* frame rate is greater than 450 frames per minutes, then the
* xclk frequency will be set to 48MHz. Otherwise, the xclk
* frequency will be set to 24MHz. If the ocp_clk frequency
* is such that
* the target xclk frequency is not achievable, then xclk will be set
* as close as to the target as possible.
*/
if ((cam->nominal_timeperframe.numerator == 0)
|| (cam->nominal_timeperframe.denominator == 0))
{
/* supply a default nominal_timeperframe of 15 fps */
cam->nominal_timeperframe.numerator = 1;
cam->nominal_timeperframe.denominator = 15;
}
tgt_fps = (cam->nominal_timeperframe.denominator)
/ cam->nominal_timeperframe.numerator;
tgt_xclk = 24000000;
isize = image_find_size(cam->pix.width, cam->pix.height);
switch (isize) {
case SXGA:
if( tgt_fps >7)
tgt_xclk = 48000000;
break;
case VGA:
if (tgt_fps > 15)
tgt_xclk = 48000000;
break;
case CIF:
if (tgt_fps > 30)
tgt_xclk = 24000000;
break;
case QVGA:
if (tgt_fps > 30)
tgt_xclk = 24000000;
break;
case QCIF:
if (tgt_fps > 60)
tgt_xclk = 24000000;
break;
case QQVGA:
if (tgt_fps > 30)
tgt_xclk = 24000000;
break;
case QQCIF:
if (tgt_fps > 60)
tgt_xclk = 24000000;
break;
default:
break;
}
cam->xclk = tgt_xclk;
cam->cparm.timeperframe = cam->nominal_timeperframe;
}
static int
camera_core_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
void *arg)
{
struct camera_fh *fh = file->private_data;
struct camera_device *cam = fh->cam;
int err;
switch (cmd) {
case VIDIOC_ENUMINPUT:
{
/* default handler assumes 1 video input (the camera) */
struct v4l2_input *input = (struct v4l2_input *) arg;
int index = input->index;
memset(input, 0, sizeof(*input));
input->index = index;
if (index > 0)
return -EINVAL;
strlcpy(input->name, "camera", sizeof(input->name));
input->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
}
case VIDIOC_G_INPUT:
{
unsigned int *input = arg;
*input = 0;
return 0;
}
case VIDIOC_S_INPUT:
{
unsigned int *input = arg;
if (*input > 0)
return -EINVAL;
return 0;
}
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc *fmt = arg;
return cam->cam_sensor->enum_pixformat(fmt);
}
case VIDIOC_TRY_FMT:
{
struct v4l2_pix_format *fmt = arg;
return cam->cam_sensor->try_format(fmt);
}
case VIDIOC_G_FMT:
{
struct v4l2_format *fmt = arg;
/* get the current format */
memset (&fmt->fmt.pix, 0, sizeof (fmt->fmt.pix));
fmt->fmt.pix = cam->pix;
return 0;
}
case VIDIOC_S_FMT:
{
struct v4l2_format *fmt = arg;
unsigned int temp_sizeimage = 0;
unsigned int clk = 0;
temp_sizeimage = cam->pix.sizeimage;
cam->cam_sensor->try_format(&fmt->fmt.pix);
cam->pix = fmt->fmt.pix;
camera_core_sensor_timeperframe (cam);
clk = cam->cam_if->set_xclk(cam->xclk, cam->ocp_clk);
return cam->cam_sensor->set_format((struct v4l2_pix_format*)fmt, clk, &cam->cparm.timeperframe);
}
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
return cam->cam_sensor->query_control(qc);
}
case VIDIOC_G_CTRL:
{
struct v4l2_control *vc = arg;
return cam->cam_sensor->get_control(vc);
}
case VIDIOC_S_CTRL:
{
struct v4l2_control *vc = arg;
return cam->cam_sensor->set_control (vc);
}
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap =
(struct v4l2_capability *) arg;
memset(cap, 0, sizeof(*cap));
strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
cap->bus_info[0] = '\0';
cap->version = KERNEL_VERSION(0, 0, 0);
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
return 0;
}
case VIDIOC_G_FBUF: /* Get the frame buffer parameters */
{
struct v4l2_framebuffer *fbuf =
(struct v4l2_framebuffer *) arg;
spin_lock(&cam->img_lock);
*fbuf = cam->fbuf;
spin_unlock(&cam->img_lock);
return 0;
}
case VIDIOC_S_FBUF: /* set the frame buffer parameters */
{
struct v4l2_framebuffer *fbuf =
(struct v4l2_framebuffer *) arg;
spin_lock(&cam->img_lock);
if (cam->previewing) {
spin_unlock(&cam->img_lock);
return -EBUSY;
}
cam->fbuf.base = fbuf->base;
cam->fbuf.fmt = fbuf->fmt;
spin_unlock(&cam->img_lock);
return 0;
}
case VIDIOC_OVERLAY:
{
int enable = *((int *) arg);
/*
* check whether the capture format and
** the display format matches
* return failure if they are different
*/
if (cam->pix.pixelformat != cam->fbuf.fmt.pixelformat)
{
printk("VIDIOC_OVERLAY: Format is not matching\n");
return -EINVAL;
}
/* If the camera image size is greater
** than LCD size return failure */
if ((cam->pix.width > cam->fbuf.fmt.height) ||
(cam->pix.height > cam->fbuf.fmt.width))
{
printk ("VIDIOC_OVERLAY: size of the LCD is less\n");
return -EINVAL;
}
if ( !cam->previewing && enable)
{
cam->previewing = fh;
cam->overlay_cnt = 0;
camera_core_start_overlay_dma(cam);
}
else if (!enable)
{
cam->previewing = NULL;
}
return 0;
}
case VIDIOC_REQBUFS:
return videobuf_reqbufs(file, &fh->vbq, arg);
case VIDIOC_QUERYBUF:
return videobuf_querybuf(&fh->vbq, arg);
case VIDIOC_QBUF:
return videobuf_qbuf(file, &fh->vbq, arg);
case VIDIOC_DQBUF:
return videobuf_dqbuf(file, &fh->vbq, arg);
case VIDIOC_STREAMON:
{
spin_lock(&cam->img_lock);
if (cam->streaming || cam->reading) {
spin_unlock(&cam->img_lock);
return -EBUSY;
}
else {
cam->streaming = fh;
/* FIXME: start camera interface */
}
spin_unlock(&cam->img_lock);
return videobuf_streamon(file, &fh->vbq);
}
case VIDIOC_STREAMOFF:
{
err = videobuf_streamoff(file, &fh->vbq);
if (err < 0)
return err;
spin_lock(&cam->img_lock);
if (cam->streaming == fh) {
cam->streaming = NULL;
/* FIXME: stop camera interface */
}
spin_unlock(&cam->img_lock);
return 0;
}
case VIDIOC_ENUMSTD:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_QUERYSTD:
{
/* Digital cameras don't have an analog video standard,
* so we don't need to implement these ioctls.
*/
return -EINVAL;
}
case VIDIOC_G_AUDIO:
case VIDIOC_S_AUDIO:
case VIDIOC_G_AUDOUT:
case VIDIOC_S_AUDOUT:
{
/* we don't have any audio inputs or outputs */
return -EINVAL;
}
case VIDIOC_G_JPEGCOMP:
case VIDIOC_S_JPEGCOMP:
{
/* JPEG compression is not supported */
return -EINVAL;
}
case VIDIOC_G_TUNER:
case VIDIOC_S_TUNER:
case VIDIOC_G_MODULATOR:
case VIDIOC_S_MODULATOR:
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
{
/* we don't have a tuner or modulator */
return -EINVAL;
}
case VIDIOC_ENUMOUTPUT:
case VIDIOC_G_OUTPUT:
case VIDIOC_S_OUTPUT:
{
/* we don't have any video outputs */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?