[media] V4L: dynamically allocate video_device nodes in subdevices
Currently only very few drivers actually use video_device nodes, embedded in struct v4l2_subdev. Allocate these nodes dynamically for those drivers to save memory for the rest. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Tested-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
2fbdc9bd42
commit
3e0ec41c5c
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/ioctl.h>
|
#include <linux/ioctl.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#if defined(CONFIG_SPI)
|
#if defined(CONFIG_SPI)
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -193,6 +194,13 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
|
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
|
||||||
|
|
||||||
|
static void v4l2_device_release_subdev_node(struct video_device *vdev)
|
||||||
|
{
|
||||||
|
struct v4l2_subdev *sd = video_get_drvdata(vdev);
|
||||||
|
sd->devnode = NULL;
|
||||||
|
kfree(vdev);
|
||||||
|
}
|
||||||
|
|
||||||
int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
|
int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
|
||||||
{
|
{
|
||||||
struct video_device *vdev;
|
struct video_device *vdev;
|
||||||
|
@ -206,22 +214,40 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
|
||||||
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
|
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
vdev = &sd->devnode;
|
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
|
||||||
|
if (!vdev) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
|
|
||||||
|
video_set_drvdata(vdev, sd);
|
||||||
strlcpy(vdev->name, sd->name, sizeof(vdev->name));
|
strlcpy(vdev->name, sd->name, sizeof(vdev->name));
|
||||||
vdev->v4l2_dev = v4l2_dev;
|
vdev->v4l2_dev = v4l2_dev;
|
||||||
vdev->fops = &v4l2_subdev_fops;
|
vdev->fops = &v4l2_subdev_fops;
|
||||||
vdev->release = video_device_release_empty;
|
vdev->release = v4l2_device_release_subdev_node;
|
||||||
vdev->ctrl_handler = sd->ctrl_handler;
|
vdev->ctrl_handler = sd->ctrl_handler;
|
||||||
err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
|
err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
|
||||||
sd->owner);
|
sd->owner);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
return err;
|
kfree(vdev);
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||||
sd->entity.v4l.major = VIDEO_MAJOR;
|
sd->entity.v4l.major = VIDEO_MAJOR;
|
||||||
sd->entity.v4l.minor = vdev->minor;
|
sd->entity.v4l.minor = vdev->minor;
|
||||||
#endif
|
#endif
|
||||||
|
sd->devnode = vdev;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
clean_up:
|
||||||
|
list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
|
||||||
|
if (!sd->devnode)
|
||||||
|
break;
|
||||||
|
video_unregister_device(sd->devnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
|
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
|
||||||
|
|
||||||
|
@ -247,7 +273,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
|
||||||
if (v4l2_dev->mdev)
|
if (v4l2_dev->mdev)
|
||||||
media_device_unregister_entity(&sd->entity);
|
media_device_unregister_entity(&sd->entity);
|
||||||
#endif
|
#endif
|
||||||
video_unregister_device(&sd->devnode);
|
video_unregister_device(sd->devnode);
|
||||||
module_put(sd->owner);
|
module_put(sd->owner);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
|
EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
|
||||||
|
|
|
@ -534,13 +534,13 @@ struct v4l2_subdev {
|
||||||
void *dev_priv;
|
void *dev_priv;
|
||||||
void *host_priv;
|
void *host_priv;
|
||||||
/* subdev device node */
|
/* subdev device node */
|
||||||
struct video_device devnode;
|
struct video_device *devnode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define media_entity_to_v4l2_subdev(ent) \
|
#define media_entity_to_v4l2_subdev(ent) \
|
||||||
container_of(ent, struct v4l2_subdev, entity)
|
container_of(ent, struct v4l2_subdev, entity)
|
||||||
#define vdev_to_v4l2_subdev(vdev) \
|
#define vdev_to_v4l2_subdev(vdev) \
|
||||||
container_of(vdev, struct v4l2_subdev, devnode)
|
video_get_drvdata(vdev)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used for storing subdev information per file handle
|
* Used for storing subdev information per file handle
|
||||||
|
|
Loading…
Reference in New Issue