diff options
Diffstat (limited to 'drivers/media/video/v4l2-device.c')
-rw-r--r-- | drivers/media/video/v4l2-device.c | 37 |
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 | } |
194 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); | 196 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); |
195 | 197 | ||
198 | static 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 | |||
196 | int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | 205 | int 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 | |||
244 | clean_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 | } |
226 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); | 253 | EXPORT_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 | } |
253 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); | 280 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); |