diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2009-12-09 06:38:49 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-21 19:32:42 -0400 |
commit | 2096a5dcf9704f5a86ecba37169eb813aaf0431c (patch) | |
tree | 21e7d870302a7c6748667a785b465a7a84805228 /drivers/media/video/v4l2-device.c | |
parent | 0070d91e5b5ae594116202ab7d62d8264830b1cd (diff) |
[media] v4l: subdev: Add device node support
Create a device node named subdevX for every registered subdev.
As the device node is registered before the subdev core::s_config
function is called, return -EGAIN on open until initialization
completes.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@gmail.com>
Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-device.c')
-rw-r--r-- | drivers/media/video/v4l2-device.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index ce64fe16bc60..8c0ad8b372d8 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c | |||
@@ -124,16 +124,20 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
124 | /* Check for valid input */ | 124 | /* Check for valid input */ |
125 | if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) | 125 | if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) |
126 | return -EINVAL; | 126 | return -EINVAL; |
127 | |||
127 | /* Warn if we apparently re-register a subdev */ | 128 | /* Warn if we apparently re-register a subdev */ |
128 | WARN_ON(sd->v4l2_dev != NULL); | 129 | WARN_ON(sd->v4l2_dev != NULL); |
130 | |||
129 | if (!try_module_get(sd->owner)) | 131 | if (!try_module_get(sd->owner)) |
130 | return -ENODEV; | 132 | return -ENODEV; |
133 | |||
131 | sd->v4l2_dev = v4l2_dev; | 134 | sd->v4l2_dev = v4l2_dev; |
132 | if (sd->internal_ops && sd->internal_ops->registered) { | 135 | if (sd->internal_ops && sd->internal_ops->registered) { |
133 | err = sd->internal_ops->registered(sd); | 136 | err = sd->internal_ops->registered(sd); |
134 | if (err) | 137 | if (err) |
135 | return err; | 138 | return err; |
136 | } | 139 | } |
140 | |||
137 | /* This just returns 0 if either of the two args is NULL */ | 141 | /* This just returns 0 if either of the two args is NULL */ |
138 | err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); | 142 | err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); |
139 | if (err) { | 143 | if (err) { |
@@ -141,24 +145,57 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
141 | sd->internal_ops->unregistered(sd); | 145 | sd->internal_ops->unregistered(sd); |
142 | return err; | 146 | return err; |
143 | } | 147 | } |
148 | |||
144 | spin_lock(&v4l2_dev->lock); | 149 | spin_lock(&v4l2_dev->lock); |
145 | list_add_tail(&sd->list, &v4l2_dev->subdevs); | 150 | list_add_tail(&sd->list, &v4l2_dev->subdevs); |
146 | spin_unlock(&v4l2_dev->lock); | 151 | spin_unlock(&v4l2_dev->lock); |
152 | |||
147 | return 0; | 153 | return 0; |
148 | } | 154 | } |
149 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); | 155 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); |
150 | 156 | ||
157 | int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | ||
158 | { | ||
159 | struct video_device *vdev; | ||
160 | struct v4l2_subdev *sd; | ||
161 | int err; | ||
162 | |||
163 | /* Register a device node for every subdev marked with the | ||
164 | * V4L2_SUBDEV_FL_HAS_DEVNODE flag. | ||
165 | */ | ||
166 | list_for_each_entry(sd, &v4l2_dev->subdevs, list) { | ||
167 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) | ||
168 | continue; | ||
169 | |||
170 | vdev = &sd->devnode; | ||
171 | strlcpy(vdev->name, sd->name, sizeof(vdev->name)); | ||
172 | vdev->v4l2_dev = v4l2_dev; | ||
173 | vdev->fops = &v4l2_subdev_fops; | ||
174 | vdev->release = video_device_release_empty; | ||
175 | err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, | ||
176 | sd->owner); | ||
177 | if (err < 0) | ||
178 | return err; | ||
179 | } | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); | ||
184 | |||
151 | void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) | 185 | void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) |
152 | { | 186 | { |
153 | /* return if it isn't registered */ | 187 | /* return if it isn't registered */ |
154 | if (sd == NULL || sd->v4l2_dev == NULL) | 188 | if (sd == NULL || sd->v4l2_dev == NULL) |
155 | return; | 189 | return; |
190 | |||
156 | spin_lock(&sd->v4l2_dev->lock); | 191 | spin_lock(&sd->v4l2_dev->lock); |
157 | list_del(&sd->list); | 192 | list_del(&sd->list); |
158 | spin_unlock(&sd->v4l2_dev->lock); | 193 | spin_unlock(&sd->v4l2_dev->lock); |
159 | if (sd->internal_ops && sd->internal_ops->unregistered) | 194 | if (sd->internal_ops && sd->internal_ops->unregistered) |
160 | sd->internal_ops->unregistered(sd); | 195 | sd->internal_ops->unregistered(sd); |
161 | sd->v4l2_dev = NULL; | 196 | sd->v4l2_dev = NULL; |
197 | |||
198 | video_unregister_device(&sd->devnode); | ||
162 | module_put(sd->owner); | 199 | module_put(sd->owner); |
163 | } | 200 | } |
164 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); | 201 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); |