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 + -
显示快捷键?