#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 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)
+const struct soc_camera_data_format *soc_camera_format_by_fourcc(
+ struct soc_camera_device *icd, unsigned int fourcc)
{
unsigned int i;
return icd->formats + i;
return NULL;
}
+EXPORT_SYMBOL(soc_camera_format_by_fourcc);
-static int soc_camera_try_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+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);
-
+ /*
+ * TODO: this might also have to migrate to host-drivers, if anyone
+ * wishes to support other fields
+ */
field = f->fmt.pix.field;
if (field == V4L2_FIELD_ANY) {
- field = V4L2_FIELD_NONE;
- } else if (V4L2_FIELD_NONE != field) {
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ } else if (field != V4L2_FIELD_NONE) {
dev_err(&icd->dev, "Field type invalid.\n");
return -EINVAL;
}
- /* test physical bus parameters */
- ret = ici->try_bus_param(icd, f->fmt.pix.pixelformat);
- if (ret)
- return ret;
-
/* limit format to hardware capabilities */
- ret = ici->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;
+ ret = ici->ops->try_fmt_cap(icd, f);
return ret;
}
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s: %d\n", __FUNCTION__, p->memory);
+ dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory);
ret = videobuf_reqbufs(&icf->vb_vidq, p);
if (ret < 0)
return ret;
- return ici->reqbufs(icf, p);
-
- return ret;
+ return ici->ops->reqbufs(icf, p);
}
static int soc_camera_querybuf(struct file *file, void *priv,
mutex_lock(&video_lock);
vdev = video_devdata(file);
- icd = container_of(vdev->dev, struct soc_camera_device, dev);
+ 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)) {
goto emgd;
}
- if (!try_module_get(ici->owner)) {
+ if (!try_module_get(ici->ops->owner)) {
dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
ret = -EINVAL;
goto emgi;
}
- icd->use_count++;
-
icf->icd = icd;
+ icd->use_count++;
/* Now we really have to activate the camera */
if (icd->use_count == 1) {
- ret = ici->add(icd);
+ ret = ici->ops->add(icd);
if (ret < 0) {
dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
icd->use_count--;
file->private_data = icf;
dev_dbg(&icd->dev, "camera device open\n");
- /* We must pass NULL as dev pointer, then all pci_* dma operations
- * transform to normal dma_* ones. Do we need an irqlock? */
- videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, NULL,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- ici->msize, icd);
+ ici->ops->init_videobuf(&icf->vb_vidq, icd);
return 0;
/* All errors are entered with the video_lock held */
eiciadd:
- module_put(ici->owner);
+ module_put(ici->ops->owner);
emgi:
module_put(icd->ops->owner);
emgd:
mutex_lock(&video_lock);
icd->use_count--;
if (!icd->use_count)
- ici->remove(icd);
+ ici->ops->remove(icd);
module_put(icd->ops->owner);
- module_put(ici->owner);
+ module_put(ici->ops->owner);
mutex_unlock(&video_lock);
- vfree(file->private_data);
+ vfree(icf);
- dev_dbg(vdev->dev, "camera device close\n");
+ 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)
+ 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->dev, "camera device read not implemented\n");
+ dev_err(vdev->parent, "camera device read not implemented\n");
return err;
}
return POLLERR;
}
- return ici->poll(file, pt);
+ return ici->ops->poll(file, pt);
}
-
static struct file_operations soc_camera_fops = {
.owner = THIS_MODULE,
.open = soc_camera_open,
.llseek = no_llseek,
};
-
-static int soc_camera_s_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+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;
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_cap(file, icf, f);
+ ret = soc_camera_try_fmt_vid_cap(file, priv, f);
if (ret < 0)
return ret;
rect.top = icd->y_current;
rect.width = f->fmt.pix.width;
rect.height = f->fmt.pix.height;
- ret = ici->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
- if (ret < 0)
+ ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
+ if (ret < 0) {
return ret;
+ } else if (!icd->current_fmt ||
+ icd->current_fmt->fourcc != f->fmt.pix.pixelformat) {
+ dev_err(&ici->dev, "Host driver hasn't set up current "
+ "format correctly!\n");
+ return -EINVAL;
+ }
- icd->current_fmt = data_fmt;
+ /* buswidth may be further adjusted by the ici */
+ icd->buswidth = icd->current_fmt->depth;
icd->width = rect.width;
icd->height = rect.height;
icf->vb_vidq.field = f->fmt.pix.field;
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
f->type);
icd->width, icd->height);
/* set physical bus parameters */
- return ici->set_bus_param(icd, f->fmt.pix.pixelformat);
+ return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
}
-static int soc_camera_enum_fmt_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+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;
return 0;
}
-static int soc_camera_g_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+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;
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;
+ f->fmt.pix.bytesperline = f->fmt.pix.width *
+ DIV_ROUND_UP(icd->current_fmt->depth, 8);
+ 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;
WARN_ON(priv != file->private_data);
strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
- return ici->querycap(ici, cap);
+ return ici->ops->querycap(ici, cap);
}
static int soc_camera_streamon(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s\n", __func__);
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s\n", __func__);
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- ret = ici->set_fmt_cap(icd, 0, &a->c);
+ ret = ici->ops->set_fmt_cap(icd, 0, &a->c);
if (!ret) {
icd->width = a->c.width;
icd->height = a->c.height;
/* We only call ->add() here to activate and probe the camera.
* We shall ->remove() and deactivate it immediately afterwards. */
- ret = ici->add(icd);
+ ret = ici->ops->add(icd);
if (ret < 0)
return ret;
icd->exposure = qctrl ? qctrl->default_value :
(unsigned short)~0;
}
- ici->remove(icd);
+ ici->ops->remove(icd);
return ret;
}
return 0;
}
+static int soc_camera_suspend(struct device *dev, pm_message_t state)
+{
+ struct soc_camera_device *icd = to_soc_camera_dev(dev);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int ret = 0;
+
+ if (ici->ops->suspend)
+ ret = ici->ops->suspend(icd, state);
+
+ return ret;
+}
+
+static int soc_camera_resume(struct device *dev)
+{
+ struct soc_camera_device *icd = to_soc_camera_dev(dev);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int ret = 0;
+
+ if (ici->ops->resume)
+ ret = ici->ops->resume(icd);
+
+ return ret;
+}
+
static struct bus_type soc_camera_bus_type = {
.name = "soc-camera",
.probe = soc_camera_probe,
.remove = soc_camera_remove,
+ .suspend = soc_camera_suspend,
+ .resume = soc_camera_resume,
};
static struct device_driver ic_drv = {
.owner = THIS_MODULE,
};
-/*
- * Image capture host - this is a host device, not a bus device, so,
- * no bus reference, no probing.
- */
-static struct class soc_camera_host_class = {
- .owner = THIS_MODULE,
- .name = "camera_host",
-};
-
static void dummy_release(struct device *dev)
{
}
-int soc_camera_host_register(struct soc_camera_host *ici, struct module *owner)
+int soc_camera_host_register(struct soc_camera_host *ici)
{
int ret;
struct soc_camera_host *ix;
- if (!ici->vbq_ops || !ici->add || !ici->remove || !owner)
+ if (!ici->ops->init_videobuf || !ici->ops->add || !ici->ops->remove)
return -EINVAL;
/* Number might be equal to the platform device ID */
- sprintf(ici->dev.bus_id, "camera_host%d", ici->nr);
- ici->dev.class = &soc_camera_host_class;
+ dev_set_name(&ici->dev, "camera_host%d", ici->nr);
mutex_lock(&list_lock);
list_for_each_entry(ix, &hosts, list) {
list_add_tail(&ici->list, &hosts);
mutex_unlock(&list_lock);
- ici->owner = owner;
ici->dev.release = dummy_release;
ret = device_register(&ici->dev);
if (icd->dev.parent == &ici->dev) {
device_unregister(&icd->dev);
/* Not before device_unregister(), .remove
- * needs parent to call ici->remove() */
+ * needs parent to call ici->ops->remove() */
icd->dev.parent = NULL;
memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
}
icd->devnum = num;
icd->dev.bus = &soc_camera_bus_type;
- snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id),
- "%u-%u", icd->iface, icd->devnum);
+ dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
icd->dev.release = dummy_release;
}
EXPORT_SYMBOL(soc_camera_device_unregister);
+static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
+ .vidioc_querycap = soc_camera_querycap,
+ .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,
+ .vidioc_enum_input = soc_camera_enum_input,
+ .vidioc_g_input = soc_camera_g_input,
+ .vidioc_s_input = soc_camera_s_input,
+ .vidioc_s_std = soc_camera_s_std,
+ .vidioc_reqbufs = soc_camera_reqbufs,
+ .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,
+ .vidioc_querybuf = soc_camera_querybuf,
+ .vidioc_qbuf = soc_camera_qbuf,
+ .vidioc_dqbuf = soc_camera_dqbuf,
+ .vidioc_streamon = soc_camera_streamon,
+ .vidioc_streamoff = soc_camera_streamoff,
+ .vidioc_queryctrl = soc_camera_queryctrl,
+ .vidioc_g_ctrl = soc_camera_g_ctrl,
+ .vidioc_s_ctrl = soc_camera_s_ctrl,
+ .vidioc_cropcap = soc_camera_cropcap,
+ .vidioc_g_crop = soc_camera_g_crop,
+ .vidioc_s_crop = soc_camera_s_crop,
+ .vidioc_g_chip_ident = soc_camera_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = soc_camera_g_register,
+ .vidioc_s_register = soc_camera_s_register,
+#endif
+};
+
int soc_camera_video_start(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
/* Maybe better &ici->dev */
- vdev->dev = &icd->dev;
- vdev->type = VID_TYPE_CAPTURE;
+ vdev->parent = &icd->dev;
vdev->current_norm = V4L2_STD_UNKNOWN;
vdev->fops = &soc_camera_fops;
+ vdev->ioctl_ops = &soc_camera_ioctl_ops;
vdev->release = video_device_release;
vdev->minor = -1;
vdev->tvnorms = V4L2_STD_UNKNOWN,
- vdev->vidioc_querycap = soc_camera_querycap;
- vdev->vidioc_g_fmt_cap = soc_camera_g_fmt_cap;
- vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap;
- vdev->vidioc_s_fmt_cap = soc_camera_s_fmt_cap;
- vdev->vidioc_enum_input = soc_camera_enum_input;
- vdev->vidioc_g_input = soc_camera_g_input;
- vdev->vidioc_s_input = soc_camera_s_input;
- vdev->vidioc_s_std = soc_camera_s_std;
- vdev->vidioc_reqbufs = soc_camera_reqbufs;
- vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap;
- vdev->vidioc_querybuf = soc_camera_querybuf;
- vdev->vidioc_qbuf = soc_camera_qbuf;
- vdev->vidioc_dqbuf = soc_camera_dqbuf;
- vdev->vidioc_streamon = soc_camera_streamon;
- vdev->vidioc_streamoff = soc_camera_streamoff;
- vdev->vidioc_queryctrl = soc_camera_queryctrl;
- vdev->vidioc_g_ctrl = soc_camera_g_ctrl;
- vdev->vidioc_s_ctrl = soc_camera_s_ctrl;
- vdev->vidioc_cropcap = soc_camera_cropcap;
- vdev->vidioc_g_crop = soc_camera_g_crop;
- vdev->vidioc_s_crop = soc_camera_s_crop;
- vdev->vidioc_g_chip_ident = soc_camera_g_chip_ident;
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- vdev->vidioc_g_register = soc_camera_g_register;
- vdev->vidioc_s_register = soc_camera_s_register;
-#endif
icd->current_fmt = &icd->formats[0];
err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
if (err < 0) {
- dev_err(vdev->dev, "video_register_device failed\n");
+ dev_err(vdev->parent, "video_register_device failed\n");
goto evidregd;
}
icd->vdev = vdev;
{
struct video_device *vdev = icd->vdev;
- dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s\n", __func__);
if (!icd->dev.parent || !vdev)
return;
ret = driver_register(&ic_drv);
if (ret)
goto edrvr;
- ret = class_register(&soc_camera_host_class);
- if (ret)
- goto eclr;
return 0;
-eclr:
- driver_unregister(&ic_drv);
edrvr:
bus_unregister(&soc_camera_bus_type);
return ret;
static void __exit soc_camera_exit(void)
{
- class_unregister(&soc_camera_host_class);
driver_unregister(&ic_drv);
bus_unregister(&soc_camera_bus_type);
}