aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/v4l2-device.c')
-rw-r--r--drivers/media/video/v4l2-device.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index e6a2c3b302d..0edd618b9dd 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -20,7 +20,9 @@
20 20
21#include <linux/types.h> 21#include <linux/types.h>
22#include <linux/ioctl.h> 22#include <linux/ioctl.h>
23#include <linux/module.h>
23#include <linux/i2c.h> 24#include <linux/i2c.h>
25#include <linux/slab.h>
24#if defined(CONFIG_SPI) 26#if defined(CONFIG_SPI)
25#include <linux/spi/spi.h> 27#include <linux/spi/spi.h>
26#endif 28#endif
@@ -193,6 +195,13 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
193} 195}
194EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); 196EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
195 197
198static void v4l2_device_release_subdev_node(struct video_device *vdev)
199{
200 struct v4l2_subdev *sd = video_get_drvdata(vdev);
201 sd->devnode = NULL;
202 kfree(vdev);
203}
204
196int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) 205int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
197{ 206{
198 struct video_device *vdev; 207 struct video_device *vdev;
@@ -206,22 +215,40 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
206 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) 215 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
207 continue; 216 continue;
208 217
209 vdev = &sd->devnode; 218 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
219 if (!vdev) {
220 err = -ENOMEM;
221 goto clean_up;
222 }
223
224 video_set_drvdata(vdev, sd);
210 strlcpy(vdev->name, sd->name, sizeof(vdev->name)); 225 strlcpy(vdev->name, sd->name, sizeof(vdev->name));
211 vdev->v4l2_dev = v4l2_dev; 226 vdev->v4l2_dev = v4l2_dev;
212 vdev->fops = &v4l2_subdev_fops; 227 vdev->fops = &v4l2_subdev_fops;
213 vdev->release = video_device_release_empty; 228 vdev->release = v4l2_device_release_subdev_node;
214 vdev->ctrl_handler = sd->ctrl_handler; 229 vdev->ctrl_handler = sd->ctrl_handler;
215 err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, 230 err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
216 sd->owner); 231 sd->owner);
217 if (err < 0) 232 if (err < 0) {
218 return err; 233 kfree(vdev);
234 goto clean_up;
235 }
219#if defined(CONFIG_MEDIA_CONTROLLER) 236#if defined(CONFIG_MEDIA_CONTROLLER)
220 sd->entity.v4l.major = VIDEO_MAJOR; 237 sd->entity.v4l.major = VIDEO_MAJOR;
221 sd->entity.v4l.minor = vdev->minor; 238 sd->entity.v4l.minor = vdev->minor;
222#endif 239#endif
240 sd->devnode = vdev;
223 } 241 }
224 return 0; 242 return 0;
243
244clean_up:
245 list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
246 if (!sd->devnode)
247 break;
248 video_unregister_device(sd->devnode);
249 }
250
251 return err;
225} 252}
226EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); 253EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
227 254
@@ -247,7 +274,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
247 if (v4l2_dev->mdev) 274 if (v4l2_dev->mdev)
248 media_device_unregister_entity(&sd->entity); 275 media_device_unregister_entity(&sd->entity);
249#endif 276#endif
250 video_unregister_device(&sd->devnode); 277 video_unregister_device(sd->devnode);
251 module_put(sd->owner); 278 module_put(sd->owner);
252} 279}
253EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); 280EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);