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