camera_core.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,206 行 · 第 1/2 页
C
1,206 行
{ 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 */ return -EINVAL; } default: { /* unrecognized ioctl */ return -ENOIOCTLCMD; } } return 0;}/* * file operations */static unsignedint 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 voidcamera_core_capture_callback(void *arg1, void *arg){ struct camera_device *cam = (struct camera_device *)arg1; int err; unsigned long irqflags; static int done = 0; spin_lock_irqsave(&cam->capture_lock, irqflags); if (!cam->reading) { 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_sgdma_queue(cam, &cam->capture_sglist, 1, camera_core_capture_callback, NULL); } else { cam->capture_completed = 1; if (cam->reading) { /* 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_sgdma_queue(cam, &cam->capture_sglist, 1, camera_core_capture_callback, NULL); } } spin_unlock_irqrestore(&cam->capture_lock, irqflags);} static ssize_tcamera_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 0 /* use video_buf to do capture */ int i; for (i = 0; i < 14; i++) videobuf_read_one(file, &fh->vbq, data, count, ppos); i = videobuf_read_one(file, &fh->vbq, data, count, ppos); return i;#endif 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 capture buffer\n"); return 0; } spin_lock_irqsave(&cam->capture_lock, irqflags); cam->reading = fh; 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->capture_lock, irqflags); err = camera_core_sgdma_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(KERN_ERR CAM_NAME ": timeout waiting video frame\n"); return -EIO; /* 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 intcamera_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 intcamera_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 intcamera_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; } if (cam->streaming == fh) { cam->streaming = NULL; } if (cam->reading == fh) { cam->reading = NULL; } cam->busy--; spin_unlock(&cam->img_lock); camera_dev->cam_hardware->finish_dma(cam->hardware_data); 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); } cam->cam_hardware->close(cam->hardware_data); return 0;}static intcamera_core_open(struct inode *inode, struct file *file){ int minor = iminor(inode); struct camera_device *cam = camera_dev; struct camera_fh *fh; spin_lock(&cam->img_lock); if (cam->power_state != 0 || cam->busy){ spin_unlock(&cam->img_lock); return -EPERM; } cam->busy++; spin_unlock(&cam->img_lock); 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; if (cam->cam_hardware->open(cam->hardware_data)) { printk (KERN_ERR CAM_NAME ": Camera IF configuration failed\n"); cam->cam_hardware->close(cam->hardware_data); return -ENODEV; } cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data); /* program the sensor for the capture format and rate */ if (cam->cam_sensor->configure(&cam->pix, cam->xclk, &cam->cparm.timeperframe, cam->sensor_data)) { printk (KERN_ERR CAM_NAME ": Camera sensor configuration failed\n"); cam->cam_sensor->power_off(cam->sensor_data); cam->cam_hardware->close(cam->hardware_data); 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,};/* Ideally, we want to do all init work in probe() and all cleanup work in * remove(). We do them in module init() and cleanup() now. */ static intomap_camera_driver_probe(struct device *dev){ return 0;}static intomap_camera_driver_remove(struct device *dev){ return 0;}static intomap_camera_driver_suspend(struct device *dev, u32 state, u32 level){ int ret = 0;#ifdef CONFIG_PM struct camera_device *cam = dev_get_drvdata(dev); if (level != 3) return ret; spin_lock(&cam->img_lock); if (cam->power_state == 3) { spin_unlock(&cam->img_lock); return ret; } if (cam->busy) { spin_unlock(&cam->img_lock); printk(KERN_ERR "Camera device Active, Cannot Suspend\n"); return -EPERM; } cam->power_state = level; /* camera I/F is enabled on open() and disabled on release() */ cam->cam_sensor->power_off(cam->sensor_data); spin_unlock(&cam->img_lock);#endif return ret;}static intomap_camera_driver_resume(struct device *dev, u32 level){ int ret = 0;#ifdef CONFIG_PM struct camera_device *cam = dev_get_drvdata(dev); if (level != 0) return 0; spin_lock(&cam->img_lock); if (cam->power_state == 0) { spin_unlock(&cam->img_lock); return ret; } /* camera I/F is enabled on open() and disabled on release() */ cam->cam_sensor->power_on(cam->sensor_data); cam->power_state = level; spin_unlock(&cam->img_lock);#endif return ret;}/* Driver information */static struct device_driver omap_camera_driver = { .name = CAM_NAME, .bus = &platform_bus_type, .probe = omap_camera_driver_probe, .remove = omap_camera_driver_remove, .suspend = omap_camera_driver_suspend, .resume = omap_camera_driver_resume,};static void omap_camera_device_release(struct device *dev){}/* Device Information */static struct platform_device omap_camera_device = { .name = CAM_NAME, .id = 0, .dev = { .release = omap_camera_device_release, },};static voidcamera_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_sensor->cleanup(cam->sensor_data); cam->cam_hardware->cleanup(cam->hardware_data); kfree(cam); camera_dev = NULL; driver_unregister(&omap_camera_driver); platform_device_unregister(&omap_camera_device); return;}static 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; dev_set_drvdata(&omap_camera_device.dev, (void *)cam); if (platform_device_register(&omap_camera_device)) { printk(KERN_ERR CAM_NAME ": could not register device\n"); goto init_error; } if (driver_register(&omap_camera_driver)){ printk(KERN_ERR CAM_NAME ": could not register driver\n"); goto init_error; } /* 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. Revisit when adding PM code. */ 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; /* initilize the overlay interface */ 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); spin_lock_init(&cam->overlay_lock); /*Initialise the pointer to the sensor interface and camera interface */ cam->cam_sensor = &camera_sensor_if; cam->cam_hardware = &camera_hardware_if; /* initialize the camera interface */ cam->hardware_data = cam->cam_hardware->init(); if (!cam->hardware_data) { printk(KERN_ERR CAM_NAME ": cannot initialize interface hardware\n"); goto init_error; } /* 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; cam->cparm.readbuffers = 1; /* 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 */ cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data); /* initialize the sensor and define a default capture format cam->pix */ cam->sensor_data = cam->cam_sensor->init(&cam->pix); if (!cam->sensor_data) { printk(KERN_ERR CAM_NAME ": cannot initialize sensor\n"); goto init_error; } printk(KERN_INFO CAM_NAME ": %s interface with %s sensor\n", cam->cam_hardware->name, cam->cam_sensor->name); /* select an arbitrary default capture frame rate of 15fps */ cam->nominal_timeperframe.numerator = 1; cam->nominal_timeperframe.denominator = 15; /* calculate xclk based on the default capture format and default * frame rate */ cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix, &cam->nominal_timeperframe, cam->sensor_data); cam->cparm.timeperframe = cam->nominal_timeperframe; /* initialise the wait queue */ init_waitqueue_head(&cam->new_video_frame); /* Initialise the DMA structures */ camera_core_sgdma_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 + -
显示快捷键?