Commit 3e0ec41c authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

[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: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Tested-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 2fbdc9bd
...@@ -21,6 +21,7 @@ ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment