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