⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 soc_camera.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * camera image capture (abstract) bus driver * * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> * * This driver provides an interface between platform-specific camera * busses and camera devices. It should be used if the camera is * connected not over a "proper" bus like PCI or USB, but over a * special bus, like, for example, the Quick Capture interface on PXA270 * SoCs. Later it should also be used for i.MX31 SoCs from Freescale. * It can handle multiple cameras and / or multiple busses, which can * be used, e.g., in stereo-vision applications. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/module.h>#include <linux/init.h>#include <linux/device.h>#include <linux/list.h>#include <linux/err.h>#include <linux/mutex.h>#include <linux/vmalloc.h>#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#include <media/v4l2-dev.h>#include <media/videobuf-core.h>#include <media/soc_camera.h>static LIST_HEAD(hosts);static LIST_HEAD(devices);static DEFINE_MUTEX(list_lock);static DEFINE_MUTEX(video_lock);const static struct soc_camera_data_format*format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc){	unsigned int i;	for (i = 0; i < icd->num_formats; i++)		if (icd->formats[i].fourcc == fourcc)			return icd->formats + i;	return NULL;}static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,				  struct v4l2_format *f){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	struct soc_camera_host *ici =		to_soc_camera_host(icd->dev.parent);	enum v4l2_field field;	const struct soc_camera_data_format *fmt;	int ret;	WARN_ON(priv != file->private_data);	fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);	if (!fmt) {		dev_dbg(&icd->dev, "invalid format 0x%08x\n",			f->fmt.pix.pixelformat);		return -EINVAL;	}	dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);	field = f->fmt.pix.field;	if (field == V4L2_FIELD_ANY) {		field = V4L2_FIELD_NONE;	} else if (V4L2_FIELD_NONE != field) {		dev_err(&icd->dev, "Field type invalid.\n");		return -EINVAL;	}	/* test physical bus parameters */	ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat);	if (ret)		return ret;	/* limit format to hardware capabilities */	ret = ici->ops->try_fmt_cap(icd, f);	/* calculate missing fields */	f->fmt.pix.field = field;	f->fmt.pix.bytesperline =		(f->fmt.pix.width * fmt->depth) >> 3;	f->fmt.pix.sizeimage =		f->fmt.pix.height * f->fmt.pix.bytesperline;	return ret;}static int soc_camera_enum_input(struct file *file, void *priv,				 struct v4l2_input *inp){	if (inp->index != 0)		return -EINVAL;	inp->type = V4L2_INPUT_TYPE_CAMERA;	inp->std = V4L2_STD_UNKNOWN;	strcpy(inp->name, "Camera");	return 0;}static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i){	*i = 0;	return 0;}static int soc_camera_s_input(struct file *file, void *priv, unsigned int i){	if (i > 0)		return -EINVAL;	return 0;}static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a){	return 0;}static int soc_camera_reqbufs(struct file *file, void *priv,			      struct v4l2_requestbuffers *p){	int ret;	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	struct soc_camera_host *ici =		to_soc_camera_host(icd->dev.parent);	WARN_ON(priv != file->private_data);	dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory);	ret = videobuf_reqbufs(&icf->vb_vidq, p);	if (ret < 0)		return ret;	return ici->ops->reqbufs(icf, p);}static int soc_camera_querybuf(struct file *file, void *priv,			       struct v4l2_buffer *p){	struct soc_camera_file *icf = file->private_data;	WARN_ON(priv != file->private_data);	return videobuf_querybuf(&icf->vb_vidq, p);}static int soc_camera_qbuf(struct file *file, void *priv,			   struct v4l2_buffer *p){	struct soc_camera_file *icf = file->private_data;	WARN_ON(priv != file->private_data);	return videobuf_qbuf(&icf->vb_vidq, p);}static int soc_camera_dqbuf(struct file *file, void *priv,			    struct v4l2_buffer *p){	struct soc_camera_file *icf = file->private_data;	WARN_ON(priv != file->private_data);	return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);}static int soc_camera_open(struct inode *inode, struct file *file){	struct video_device *vdev;	struct soc_camera_device *icd;	struct soc_camera_host *ici;	struct soc_camera_file *icf;	int ret;	icf = vmalloc(sizeof(*icf));	if (!icf)		return -ENOMEM;	/* Protect against icd->remove() until we module_get() both drivers. */	mutex_lock(&video_lock);	vdev = video_devdata(file);	icd = container_of(vdev->parent, struct soc_camera_device, dev);	ici = to_soc_camera_host(icd->dev.parent);	if (!try_module_get(icd->ops->owner)) {		dev_err(&icd->dev, "Couldn't lock sensor driver.\n");		ret = -EINVAL;		goto emgd;	}	if (!try_module_get(ici->ops->owner)) {		dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");		ret = -EINVAL;		goto emgi;	}	icf->icd = icd;	icd->use_count++;	/* Now we really have to activate the camera */	if (icd->use_count == 1) {		ret = ici->ops->add(icd);		if (ret < 0) {			dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);			icd->use_count--;			goto eiciadd;		}	}	mutex_unlock(&video_lock);	file->private_data = icf;	dev_dbg(&icd->dev, "camera device open\n");	ici->ops->init_videobuf(&icf->vb_vidq, icd);	return 0;	/* All errors are entered with the video_lock held */eiciadd:	module_put(ici->ops->owner);emgi:	module_put(icd->ops->owner);emgd:	mutex_unlock(&video_lock);	vfree(icf);	return ret;}static int soc_camera_close(struct inode *inode, struct file *file){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);	struct video_device *vdev = icd->vdev;	mutex_lock(&video_lock);	icd->use_count--;	if (!icd->use_count)		ici->ops->remove(icd);	module_put(icd->ops->owner);	module_put(ici->ops->owner);	mutex_unlock(&video_lock);	vfree(icf);	dev_dbg(vdev->parent, "camera device close\n");	return 0;}static ssize_t soc_camera_read(struct file *file, char __user *buf,			   size_t count, loff_t *ppos){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	struct video_device *vdev = icd->vdev;	int err = -EINVAL;	dev_err(vdev->parent, "camera device read not implemented\n");	return err;}static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	int err;	dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);	err = videobuf_mmap_mapper(&icf->vb_vidq, vma);	dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",		(unsigned long)vma->vm_start,		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start,		err);	return err;}static unsigned int soc_camera_poll(struct file *file, poll_table *pt){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	struct soc_camera_host *ici =		to_soc_camera_host(icd->dev.parent);	if (list_empty(&icf->vb_vidq.stream)) {		dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");		return POLLERR;	}	return ici->ops->poll(file, pt);}static struct file_operations soc_camera_fops = {	.owner		= THIS_MODULE,	.open		= soc_camera_open,	.release	= soc_camera_close,	.ioctl		= video_ioctl2,	.read		= soc_camera_read,	.mmap		= soc_camera_mmap,	.poll		= soc_camera_poll,	.llseek		= no_llseek,};static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,				struct v4l2_format *f){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	struct soc_camera_host *ici =		to_soc_camera_host(icd->dev.parent);	int ret;	struct v4l2_rect rect;	const static struct soc_camera_data_format *data_fmt;	WARN_ON(priv != file->private_data);	data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);	if (!data_fmt)		return -EINVAL;	/* buswidth may be further adjusted by the ici */	icd->buswidth = data_fmt->depth;	ret = soc_camera_try_fmt_vid_cap(file, icf, f);	if (ret < 0)		return ret;	rect.left	= icd->x_current;	rect.top	= icd->y_current;	rect.width	= f->fmt.pix.width;	rect.height	= f->fmt.pix.height;	ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);	if (ret < 0)		return ret;	icd->current_fmt	= data_fmt;	icd->width		= rect.width;	icd->height		= rect.height;	icf->vb_vidq.field	= f->fmt.pix.field;	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)		dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",			 f->type);	dev_dbg(&icd->dev, "set width: %d height: %d\n",		icd->width, icd->height);	/* set physical bus parameters */	return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);}static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,				   struct v4l2_fmtdesc *f){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	const struct soc_camera_data_format *format;	WARN_ON(priv != file->private_data);	if (f->index >= icd->num_formats)		return -EINVAL;	format = &icd->formats[f->index];	strlcpy(f->description, format->name, sizeof(f->description));	f->pixelformat = format->fourcc;	return 0;}static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,				struct v4l2_format *f){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	WARN_ON(priv != file->private_data);	f->fmt.pix.width	= icd->width;	f->fmt.pix.height	= icd->height;	f->fmt.pix.field	= icf->vb_vidq.field;	f->fmt.pix.pixelformat	= icd->current_fmt->fourcc;	f->fmt.pix.bytesperline	=		(f->fmt.pix.width * icd->current_fmt->depth) >> 3;	f->fmt.pix.sizeimage	=		f->fmt.pix.height * f->fmt.pix.bytesperline;	dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",		icd->current_fmt->fourcc);	return 0;}static int soc_camera_querycap(struct file *file, void  *priv,			       struct v4l2_capability *cap){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	struct soc_camera_host *ici =		to_soc_camera_host(icd->dev.parent);	WARN_ON(priv != file->private_data);	strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));	return ici->ops->querycap(ici, cap);}static int soc_camera_streamon(struct file *file, void *priv,			       enum v4l2_buf_type i){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	WARN_ON(priv != file->private_data);	dev_dbg(&icd->dev, "%s\n", __func__);	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	icd->ops->start_capture(icd);	/* This calls buf_queue from host driver's videobuf_queue_ops */	return videobuf_streamon(&icf->vb_vidq);}static int soc_camera_streamoff(struct file *file, void *priv,				enum v4l2_buf_type i){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	WARN_ON(priv != file->private_data);	dev_dbg(&icd->dev, "%s\n", __func__);	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	/* This calls buf_release from host driver's videobuf_queue_ops for all	 * remaining buffers. When the last buffer is freed, stop capture */	videobuf_streamoff(&icf->vb_vidq);	icd->ops->stop_capture(icd);	return 0;}static int soc_camera_queryctrl(struct file *file, void *priv,				struct v4l2_queryctrl *qc){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	int i;	WARN_ON(priv != file->private_data);	if (!qc->id)		return -EINVAL;	for (i = 0; i < icd->ops->num_controls; i++)		if (qc->id == icd->ops->controls[i].id) {			memcpy(qc, &(icd->ops->controls[i]),				sizeof(*qc));			return 0;		}	return -EINVAL;}static int soc_camera_g_ctrl(struct file *file, void *priv,			     struct v4l2_control *ctrl){	struct soc_camera_file *icf = file->private_data;	struct soc_camera_device *icd = icf->icd;	WARN_ON(priv != file->private_data);	switch (ctrl->id) {	case V4L2_CID_GAIN:		if (icd->gain == (unsigned short)~0)			return -EINVAL;		ctrl->value = icd->gain;		return 0;

⌨️ 快捷键说明

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