camera_core.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,174 行 · 第 1/3 页

C
1,174
字号
			return -EINVAL;
		}

		default:
		{
			/* unrecognized ioctl */
			return -ENOIOCTLCMD;
		}
	}
	return 0;
}

/*
 *  file operations
 */

static unsigned
int camera_core_poll(struct file *file, struct poll_table_struct *wait)
{
	return -EINVAL;
}

/* ------------------------------------------------------------ */
/* callback routine for read DMA completion. We just start another DMA
 * transfer unless overlay has been turned off
 */
static void
camera_core_capture_callback(struct camera_device *cam, void *arg)
{
	int err;
	unsigned long irqflags;
	static int done = 0;

		spin_lock_irqsave(&cam->capture_lock, irqflags);
		if (capture_abort)
		{
			done = 0;
			cam->capture_started = 0;
			spin_unlock_irqrestore(&cam->capture_lock, irqflags);
			return;
		}
	if (done < 14) {
		++done;
		sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
		sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
		err = camera_core_sg_dma_queue(cam, &cam->capture_sglist, 1,
			camera_core_capture_callback, NULL);
		
	} else {
		camera_dev->capture_completed = 1;
		if(!capture_abort)
		{

		/* Wake up any process which are waiting for the 
		** DMA to complete */
		wake_up_interruptible (&camera_dev->new_video_frame);
		sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
		sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
		err = camera_core_sg_dma_queue(cam, &cam->capture_sglist, 1,
			camera_core_capture_callback, NULL);
		}
	}
		spin_unlock_irqrestore(&cam->capture_lock, irqflags);

}

 
static ssize_t
camera_core_read(struct file *file, char *data, size_t count, loff_t *ppos)
{
	struct camera_fh *fh = file->private_data;
	struct camera_device *cam = fh->cam;
	int err;
	unsigned long irqflags;
	long timeout;

	
	if (!cam->capture_base){
	cam->capture_base = (unsigned long) dma_alloc_coherent(NULL,
				cam->pix.sizeimage,
				(dma_addr_t *) &cam->capture_base_phys,
				GFP_KERNEL | GFP_DMA);
	}
	if (!cam->capture_base){
		printk(KERN_ERR CAM_NAME
			": cannot allocate overlay framebuffer \n");
		return 0;
	}
	spin_lock_irqsave(&cam->capture_lock, irqflags);
	capture_abort = 0;
	cam->capture_started = 1;
	sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
	sg_dma_len(&cam->capture_sglist)= cam->pix.sizeimage;
	spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
	err = camera_core_sg_dma_queue(cam, &cam->capture_sglist, 1,
			camera_core_capture_callback, NULL);
	/* Wait till DMA is completed */
	timeout = HZ * 10;
	cam->capture_completed = 0;
	while (cam->capture_completed == 0) {
		timeout = interruptible_sleep_on_timeout 
				(&cam->new_video_frame, timeout);
		if (timeout == 0){
			printk("TIMEOUT");	
			return 0; /* time out */
		}
	}
	/* copy the data to the user buffer */
	err = copy_to_user (data, (void *)cam->capture_base, cam->pix.sizeimage);
	return (cam->pix.sizeimage - err);
	
}

static int
camera_core_mmap(struct file *file, struct vm_area_struct *vma)
{
        struct camera_fh *fh = file->private_data;

        return videobuf_mmap_mapper(vma, &fh->vbq);
}

static int
camera_core_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 
		  unsigned long arg)
{

	return video_usercopy(inode, file, cmd, arg, camera_core_do_ioctl);
}

static int
camera_core_release(struct inode *inode, struct file *file)
{
	struct camera_fh *fh = file->private_data;
	struct camera_device *cam = fh->cam;
	

	file->private_data = NULL;
	kfree(fh);

	spin_lock(&cam->img_lock);
	if (cam->previewing == fh) {
		cam->previewing = NULL;
	}
	spin_unlock(&cam->img_lock);

	capture_abort = 1;
	while(cam->free_dmach < 2)
		mdelay(5);

	if(cam->capture_base) {
		dma_free_coherent(NULL, cam->pix.sizeimage, 
					(void *)cam->capture_base, 
					cam->capture_base_phys);
		cam->capture_base = 0;
		cam->capture_base_phys = 0;
	}
	if (fh->vbq.read_buf) {
		camera_core_vbq_release(file, fh->vbq.read_buf);
		kfree(fh->vbq.read_buf);
	}
	camera_dev->cam_if->close ();
	return 0;
}

static int
camera_core_open(struct inode *inode, struct file *file)
{
	int minor = iminor(inode);
	struct camera_device *cam = camera_dev;
	struct camera_fh *fh;

	if (!cam || !cam->vfd || (cam->vfd->minor != minor))
		return -ENODEV;

	/* allocate per-filehandle data */
	fh = kmalloc(sizeof(*fh), GFP_KERNEL);
	if (NULL == fh)
		return -ENOMEM;
	file->private_data = fh;
	fh->cam = cam;
	fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	videobuf_queue_init(&fh->vbq, &cam->vbq_ops, NULL, &cam->vbq_lock,
                fh->type, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer));

	cam->capture_completed = 0;
	cam->capture_started = 0;

	cam->cam_if->open (cam);
        /* program the sensor for the default capture format and rate */
        if (cam->cam_sensor->set_format (&cam->pix, cam->xclk, 
				&cam->cparm.timeperframe))
        {
                printk ("\nCamera sensor configuration failed");
                return -ENODEV;
        }


	return 0;
}

static struct file_operations camera_core_fops = 
{
	.owner			= THIS_MODULE,
	.llseek			= no_llseek,
	.read			= camera_core_read,
	.poll			= camera_core_poll,
	.ioctl			= camera_core_ioctl,
	.mmap			= camera_core_mmap,
	.open			= camera_core_open,
	.release		= camera_core_release,
};

void
camera_core_cleanup(void)
{
	struct camera_device *cam = camera_dev;
	struct video_device *vfd;
	if (!cam)
		return;
	vfd = cam->vfd;
	if(vfd){
		if(vfd->minor == -1) {
			/* The device never got registered, so release the 
			** video_device struct directly
			*/
			video_device_release(vfd);
		} else {
			/* The unregister function will release the video_device
			** struct as well as unregistering it.
			*/
			video_unregister_device(vfd);
		}
		cam->vfd = NULL;
	}
	if(cam->overlay_base) {
		dma_free_coherent(NULL, cam->overlay_size,
					(void *)cam->overlay_base, 
					cam->overlay_base_phys);
		cam->overlay_base = 0;
	}	
	cam->overlay_base_phys = 0;
	cam->cam_if->cleanup(cam);
	cam->iobase_phys = 0;
	kfree(cam);
	camera_dev=NULL;

	return;
}


int __init 
camera_core_init(void)
{
	struct camera_device *cam;
	struct video_device *vfd;

	cam = kmalloc(sizeof(struct camera_device), GFP_KERNEL);
	if (!cam) {
		printk(KERN_ERR CAM_NAME ": could not allocate memory\n");
		goto init_error;
	}
	memset(cam, 0, sizeof(struct camera_device));
	
	/* Save the pointer to camera device in a global variable */
	camera_dev = cam;

	/* initialize the video_device struct */
	vfd = cam->vfd = video_device_alloc();
	if (!vfd) {
		printk(KERN_ERR CAM_NAME 
			": could not allocate video device struct\n");
		goto init_error;
	}
	
 	vfd->release = video_device_release;
#if FIXME_FIXME   
/*  If the dev fields are not initlized (parent and such) sysfs will crash you
 *  when it tries to set you up....most drivers seem to chain in the info their 
 *  parent bus gave them.  Getting this associated right is likely necessary 
 * for power mangement.
 */
 	vfd->dev = &cam->dev;
#endif
 	strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
 	vfd->type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
 	
 	/* need to register for a VID_HARDWARE_* ID in videodev.h */
 	vfd->hardware = 0;
 	vfd->fops = &camera_core_fops;
 	video_set_drvdata(vfd, cam);
 	vfd->minor = -1;

        /* initialize the videobuf queue ops */
        cam->vbq_ops.buf_setup = camera_core_vbq_setup;
        cam->vbq_ops.buf_prepare = camera_core_vbq_prepare;
        cam->vbq_ops.buf_queue = camera_core_vbq_queue;
        cam->vbq_ops.buf_release = camera_core_vbq_release;

	cam->overlay_size = overlay_mem;
	if(cam->overlay_size >0)
	{
		cam->overlay_base = (unsigned long) dma_alloc_coherent(NULL,
					cam->overlay_size,
					(dma_addr_t *) &cam->overlay_base_phys,
					GFP_KERNEL | GFP_DMA);
		if (!cam->overlay_base){
			printk(KERN_ERR CAM_NAME
				": cannot allocate overlay framebuffer \n");
			goto init_error;
		}
	}
	memset ((void*)cam->overlay_base, 0, cam->overlay_size);
	/* initilize the overlay interface */
	spin_lock_init(&cam->overlay_lock);

 	/*Initialise the pointer to the sensor interface and camera interface */
 	cam->cam_sensor = &camera_sensor_if;
 	cam->cam_if = &omap_camera_if;

	/* initialize the camera interface */
	if( (cam->cam_if->init (NULL, cam)) < 0)
		goto init_error;
	
	/* initialise the camera sensor interface */
	cam->cam_sensor->init (&cam->pix);

	/* initialize the spinlock used to serialize access to the image 
	 * parameters
	 */
	spin_lock_init(&cam->img_lock);

	/* initialize the streaming capture parameters */
	cam->cparm.capability = V4L2_CAP_TIMEPERFRAME;

	/* get the input clock value to camera interface and store it */
	cam->ocp_clk= clk_get_rate(clk_get(0, "armper_ck"));

	/* Enable the xclk output.  The sensor may (and does, in the case of 
	 * the OV9640) require an xclk input in order for its initialization 
	 * routine to work.
	 */
	cam->xclk = 21000000;	/* choose an arbitrary xclk frequency */

	/* select an arbitrary default capture frame rate of 15fps */
	cam->nominal_timeperframe.numerator = 1;
	cam->nominal_timeperframe.denominator = 15;
	camera_core_sensor_timeperframe(cam);

	/* disable overlay */
	cam->overlay = 0;

	/* initialise the wait queue */
	init_waitqueue_head (&cam->new_video_frame);

	/* Initialise the DMA structures */
	camera_core_dma_init (cam);

	if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
		printk(KERN_ERR CAM_NAME 
			": could not register Video for Linux device\n");
		vfd->minor = -1;
		goto init_error;
	}

	printk(KERN_INFO CAM_NAME 
		": registered device video%d [v4l2]\n", vfd->minor);

	return 0;

init_error:
	camera_core_cleanup();
	return -ENODEV;
}

MODULE_AUTHOR("Texas Instruments.");
MODULE_DESCRIPTION("OMAP Video for Linux camera driver");
MODULE_LICENSE("GPL");
module_param(video_nr, int, 0);
MODULE_PARM_DESC(video_nr, 
		"Minor number for video device (-1 ==> auto assign)");
module_param(capture_mem, int, 0);
MODULE_PARM_DESC(capture_mem,
        "Maximum amount of memory for capture buffers (default 4800KB)");

module_init(camera_core_init);
module_exit(camera_core_cleanup);


⌨️ 快捷键说明

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