[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
2 changed files with 33 additions and 7 deletions
|
@ -21,6 +21,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#if defined(CONFIG_SPI)
|
||||
#include <linux/spi/spi.h>
|
||||
#endif
|
||||
|
@ -193,6 +194,13 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
|
|||
}
|
||||
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)
|
||||
{
|
||||
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))
|
||||
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));
|
||||
vdev->v4l2_dev = v4l2_dev;
|
||||
vdev->fops = &v4l2_subdev_fops;
|
||||
vdev->release = video_device_release_empty;
|
||||
vdev->release = v4l2_device_release_subdev_node;
|
||||
vdev->ctrl_handler = sd->ctrl_handler;
|
||||
err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
|
||||
sd->owner);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err < 0) {
|
||||
kfree(vdev);
|
||||
goto clean_up;
|
||||
}
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
sd->entity.v4l.major = VIDEO_MAJOR;
|
||||
sd->entity.v4l.minor = vdev->minor;
|
||||
#endif
|
||||
sd->devnode = vdev;
|
||||
}
|
||||
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);
|
||||
|
||||
|
@ -247,7 +273,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
|
|||
if (v4l2_dev->mdev)
|
||||
media_device_unregister_entity(&sd->entity);
|
||||
#endif
|
||||
video_unregister_device(&sd->devnode);
|
||||
video_unregister_device(sd->devnode);
|
||||
module_put(sd->owner);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
|
||||
|
|
|
@ -534,13 +534,13 @@ struct v4l2_subdev {
|
|||
void *dev_priv;
|
||||
void *host_priv;
|
||||
/* subdev device node */
|
||||
struct video_device devnode;
|
||||
struct video_device *devnode;
|
||||
};
|
||||
|
||||
#define media_entity_to_v4l2_subdev(ent) \
|
||||
container_of(ent, struct v4l2_subdev, entity)
|
||||
#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
|
||||
|
|
Loading…
Reference in a new issue