summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2009-12-09 08:38:49 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 20:32:42 -0300
commit2096a5dcf9704f5a86ecba37169eb813aaf0431c (patch)
tree21e7d870302a7c6748667a785b465a7a84805228 /drivers/media
parent0070d91e5b5ae594116202ab7d62d8264830b1cd (diff)
[media] v4l: subdev: Add device node support
Create a device node named subdevX for every registered subdev. As the device node is registered before the subdev core::s_config function is called, return -EGAIN on open until initialization completes. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@gmail.com> Acked-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/v4l2-dev.c27
-rw-r--r--drivers/media/video/v4l2-device.c37
-rw-r--r--drivers/media/video/v4l2-subdev.c60
4 files changed, 109 insertions, 17 deletions
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ac54652396e3..7ea65163090e 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -11,7 +11,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
- v4l2-event.o v4l2-ctrls.o
+ v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
# V4L2 core modules
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 341764a3a990..abe04ef38066 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -408,13 +408,14 @@ static int get_index(struct video_device *vdev)
}
/**
- * video_register_device - register video4linux devices
+ * __video_register_device - register video4linux devices
* @vdev: video device structure we want to register
* @type: type of device to register
* @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ...
* -1 == first free)
* @warn_if_nr_in_use: warn if the desired device node number
* was already in use and another number was chosen instead.
+ * @owner: module that owns the video device node
*
* The registration code assigns minor numbers and device node numbers
* based on the requested type and registers the new device node with
@@ -435,9 +436,11 @@ static int get_index(struct video_device *vdev)
* %VFL_TYPE_VBI - Vertical blank data (undecoded)
*
* %VFL_TYPE_RADIO - A radio card
+ *
+ * %VFL_TYPE_SUBDEV - A subdevice
*/
-static int __video_register_device(struct video_device *vdev, int type, int nr,
- int warn_if_nr_in_use)
+int __video_register_device(struct video_device *vdev, int type, int nr,
+ int warn_if_nr_in_use, struct module *owner)
{
int i = 0;
int ret;
@@ -469,6 +472,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
case VFL_TYPE_RADIO:
name_base = "radio";
break;
+ case VFL_TYPE_SUBDEV:
+ name_base = "v4l-subdev";
+ break;
default:
printk(KERN_ERR "%s called with unknown type: %d\n",
__func__, type);
@@ -552,7 +558,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
goto cleanup;
}
vdev->cdev->ops = &v4l2_fops;
- vdev->cdev->owner = vdev->fops->owner;
+ vdev->cdev->owner = owner;
ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
if (ret < 0) {
printk(KERN_ERR "%s: cdev_add failed\n", __func__);
@@ -597,18 +603,7 @@ cleanup:
vdev->minor = -1;
return ret;
}
-
-int video_register_device(struct video_device *vdev, int type, int nr)
-{
- return __video_register_device(vdev, type, nr, 1);
-}
-EXPORT_SYMBOL(video_register_device);
-
-int video_register_device_no_warn(struct video_device *vdev, int type, int nr)
-{
- return __video_register_device(vdev, type, nr, 0);
-}
-EXPORT_SYMBOL(video_register_device_no_warn);
+EXPORT_SYMBOL(__video_register_device);
/**
* video_unregister_device - unregister a video4linux device
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index ce64fe16bc60..8c0ad8b372d8 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -124,16 +124,20 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
/* Check for valid input */
if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
return -EINVAL;
+
/* Warn if we apparently re-register a subdev */
WARN_ON(sd->v4l2_dev != NULL);
+
if (!try_module_get(sd->owner))
return -ENODEV;
+
sd->v4l2_dev = v4l2_dev;
if (sd->internal_ops && sd->internal_ops->registered) {
err = sd->internal_ops->registered(sd);
if (err)
return err;
}
+
/* This just returns 0 if either of the two args is NULL */
err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
if (err) {
@@ -141,24 +145,57 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
sd->internal_ops->unregistered(sd);
return err;
}
+
spin_lock(&v4l2_dev->lock);
list_add_tail(&sd->list, &v4l2_dev->subdevs);
spin_unlock(&v4l2_dev->lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
+{
+ struct video_device *vdev;
+ struct v4l2_subdev *sd;
+ int err;
+
+ /* Register a device node for every subdev marked with the
+ * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+ */
+ list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+ continue;
+
+ vdev = &sd->devnode;
+ strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+ vdev->v4l2_dev = v4l2_dev;
+ vdev->fops = &v4l2_subdev_fops;
+ vdev->release = video_device_release_empty;
+ err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+ sd->owner);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
+
void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
{
/* return if it isn't registered */
if (sd == NULL || sd->v4l2_dev == NULL)
return;
+
spin_lock(&sd->v4l2_dev->lock);
list_del(&sd->list);
spin_unlock(&sd->v4l2_dev->lock);
if (sd->internal_ops && sd->internal_ops->unregistered)
sd->internal_ops->unregistered(sd);
sd->v4l2_dev = NULL;
+
+ video_unregister_device(&sd->devnode);
module_put(sd->owner);
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
new file mode 100644
index 000000000000..037aa28a5ed1
--- /dev/null
+++ b/drivers/media/video/v4l2-subdev.c
@@ -0,0 +1,60 @@
+/*
+ * V4L2 subdevice support.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+static int subdev_open(struct file *file)
+{
+ return 0;
+}
+
+static int subdev_close(struct file *file)
+{
+ return 0;
+}
+
+static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static long subdev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(file, cmd, arg, subdev_do_ioctl);
+}
+
+const struct v4l2_file_operations v4l2_subdev_fops = {
+ .owner = THIS_MODULE,
+ .open = subdev_open,
+ .unlocked_ioctl = subdev_ioctl,
+ .release = subdev_close,
+};