Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2096a5dc authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarVimarsh Zutshi <vimarsh.zutshi@gmail.com>
Acked-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0070d91e
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -319,6 +319,22 @@ controlled through GPIO pins. This distinction is only relevant when setting
up the device, but once the subdev is registered it is completely transparent.


V4L2 sub-device userspace API
-----------------------------

Beside exposing a kernel API through the v4l2_subdev_ops structure, V4L2
sub-devices can also be controlled directly by userspace applications.

Device nodes named v4l-subdevX can be created in /dev to access sub-devices
directly. If a sub-device supports direct userspace configuration it must set
the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered.

After registering sub-devices, the v4l2_device driver can create device nodes
for all registered sub-devices marked with V4L2_SUBDEV_FL_HAS_DEVNODE by calling
v4l2_device_register_subdev_nodes(). Those device nodes will be automatically
removed when sub-devices are unregistered.


I2C sub-device drivers
----------------------

+1 −1
Original line number Diff line number Diff line
@@ -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

+11 −16
Original line number Diff line number Diff line
@@ -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 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
	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
+37 −0
Original line number Diff line number Diff line
@@ -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);
+60 −0
Original line number Diff line number Diff line
/*
 *  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,
};
Loading