diff options
Diffstat (limited to 'drivers/media/video/v4l2-device.c')
-rw-r--r-- | drivers/media/video/v4l2-device.c | 101 |
1 files changed, 92 insertions, 9 deletions
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index ce64fe16bc60..5aeaf876ba9b 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c | |||
@@ -36,6 +36,8 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) | |||
36 | INIT_LIST_HEAD(&v4l2_dev->subdevs); | 36 | INIT_LIST_HEAD(&v4l2_dev->subdevs); |
37 | spin_lock_init(&v4l2_dev->lock); | 37 | spin_lock_init(&v4l2_dev->lock); |
38 | mutex_init(&v4l2_dev->ioctl_lock); | 38 | mutex_init(&v4l2_dev->ioctl_lock); |
39 | v4l2_prio_init(&v4l2_dev->prio); | ||
40 | kref_init(&v4l2_dev->ref); | ||
39 | v4l2_dev->dev = dev; | 41 | v4l2_dev->dev = dev; |
40 | if (dev == NULL) { | 42 | if (dev == NULL) { |
41 | /* If dev == NULL, then name must be filled in by the caller */ | 43 | /* If dev == NULL, then name must be filled in by the caller */ |
@@ -47,13 +49,27 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) | |||
47 | if (!v4l2_dev->name[0]) | 49 | if (!v4l2_dev->name[0]) |
48 | snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s", | 50 | snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s", |
49 | dev->driver->name, dev_name(dev)); | 51 | dev->driver->name, dev_name(dev)); |
50 | if (dev_get_drvdata(dev)) | 52 | if (!dev_get_drvdata(dev)) |
51 | v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n"); | 53 | dev_set_drvdata(dev, v4l2_dev); |
52 | dev_set_drvdata(dev, v4l2_dev); | ||
53 | return 0; | 54 | return 0; |
54 | } | 55 | } |
55 | EXPORT_SYMBOL_GPL(v4l2_device_register); | 56 | EXPORT_SYMBOL_GPL(v4l2_device_register); |
56 | 57 | ||
58 | static void v4l2_device_release(struct kref *ref) | ||
59 | { | ||
60 | struct v4l2_device *v4l2_dev = | ||
61 | container_of(ref, struct v4l2_device, ref); | ||
62 | |||
63 | if (v4l2_dev->release) | ||
64 | v4l2_dev->release(v4l2_dev); | ||
65 | } | ||
66 | |||
67 | int v4l2_device_put(struct v4l2_device *v4l2_dev) | ||
68 | { | ||
69 | return kref_put(&v4l2_dev->ref, v4l2_device_release); | ||
70 | } | ||
71 | EXPORT_SYMBOL_GPL(v4l2_device_put); | ||
72 | |||
57 | int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, | 73 | int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, |
58 | atomic_t *instance) | 74 | atomic_t *instance) |
59 | { | 75 | { |
@@ -72,10 +88,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_set_name); | |||
72 | 88 | ||
73 | void v4l2_device_disconnect(struct v4l2_device *v4l2_dev) | 89 | void v4l2_device_disconnect(struct v4l2_device *v4l2_dev) |
74 | { | 90 | { |
75 | if (v4l2_dev->dev) { | 91 | if (v4l2_dev->dev == NULL) |
92 | return; | ||
93 | |||
94 | if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev) | ||
76 | dev_set_drvdata(v4l2_dev->dev, NULL); | 95 | dev_set_drvdata(v4l2_dev->dev, NULL); |
77 | v4l2_dev->dev = NULL; | 96 | v4l2_dev->dev = NULL; |
78 | } | ||
79 | } | 97 | } |
80 | EXPORT_SYMBOL_GPL(v4l2_device_disconnect); | 98 | EXPORT_SYMBOL_GPL(v4l2_device_disconnect); |
81 | 99 | ||
@@ -117,23 +135,30 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) | |||
117 | EXPORT_SYMBOL_GPL(v4l2_device_unregister); | 135 | EXPORT_SYMBOL_GPL(v4l2_device_unregister); |
118 | 136 | ||
119 | int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | 137 | int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, |
120 | struct v4l2_subdev *sd) | 138 | struct v4l2_subdev *sd) |
121 | { | 139 | { |
140 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
141 | struct media_entity *entity = &sd->entity; | ||
142 | #endif | ||
122 | int err; | 143 | int err; |
123 | 144 | ||
124 | /* Check for valid input */ | 145 | /* Check for valid input */ |
125 | if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) | 146 | if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) |
126 | return -EINVAL; | 147 | return -EINVAL; |
148 | |||
127 | /* Warn if we apparently re-register a subdev */ | 149 | /* Warn if we apparently re-register a subdev */ |
128 | WARN_ON(sd->v4l2_dev != NULL); | 150 | WARN_ON(sd->v4l2_dev != NULL); |
151 | |||
129 | if (!try_module_get(sd->owner)) | 152 | if (!try_module_get(sd->owner)) |
130 | return -ENODEV; | 153 | return -ENODEV; |
154 | |||
131 | sd->v4l2_dev = v4l2_dev; | 155 | sd->v4l2_dev = v4l2_dev; |
132 | if (sd->internal_ops && sd->internal_ops->registered) { | 156 | if (sd->internal_ops && sd->internal_ops->registered) { |
133 | err = sd->internal_ops->registered(sd); | 157 | err = sd->internal_ops->registered(sd); |
134 | if (err) | 158 | if (err) |
135 | return err; | 159 | return err; |
136 | } | 160 | } |
161 | |||
137 | /* This just returns 0 if either of the two args is NULL */ | 162 | /* 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); | 163 | err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); |
139 | if (err) { | 164 | if (err) { |
@@ -141,24 +166,82 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
141 | sd->internal_ops->unregistered(sd); | 166 | sd->internal_ops->unregistered(sd); |
142 | return err; | 167 | return err; |
143 | } | 168 | } |
169 | |||
170 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
171 | /* Register the entity. */ | ||
172 | if (v4l2_dev->mdev) { | ||
173 | err = media_device_register_entity(v4l2_dev->mdev, entity); | ||
174 | if (err < 0) { | ||
175 | if (sd->internal_ops && sd->internal_ops->unregistered) | ||
176 | sd->internal_ops->unregistered(sd); | ||
177 | module_put(sd->owner); | ||
178 | return err; | ||
179 | } | ||
180 | } | ||
181 | #endif | ||
182 | |||
144 | spin_lock(&v4l2_dev->lock); | 183 | spin_lock(&v4l2_dev->lock); |
145 | list_add_tail(&sd->list, &v4l2_dev->subdevs); | 184 | list_add_tail(&sd->list, &v4l2_dev->subdevs); |
146 | spin_unlock(&v4l2_dev->lock); | 185 | spin_unlock(&v4l2_dev->lock); |
186 | |||
147 | return 0; | 187 | return 0; |
148 | } | 188 | } |
149 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); | 189 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); |
150 | 190 | ||
191 | int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | ||
192 | { | ||
193 | struct video_device *vdev; | ||
194 | struct v4l2_subdev *sd; | ||
195 | int err; | ||
196 | |||
197 | /* Register a device node for every subdev marked with the | ||
198 | * V4L2_SUBDEV_FL_HAS_DEVNODE flag. | ||
199 | */ | ||
200 | list_for_each_entry(sd, &v4l2_dev->subdevs, list) { | ||
201 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) | ||
202 | continue; | ||
203 | |||
204 | vdev = &sd->devnode; | ||
205 | strlcpy(vdev->name, sd->name, sizeof(vdev->name)); | ||
206 | vdev->v4l2_dev = v4l2_dev; | ||
207 | vdev->fops = &v4l2_subdev_fops; | ||
208 | vdev->release = video_device_release_empty; | ||
209 | err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, | ||
210 | sd->owner); | ||
211 | if (err < 0) | ||
212 | return err; | ||
213 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
214 | sd->entity.v4l.major = VIDEO_MAJOR; | ||
215 | sd->entity.v4l.minor = vdev->minor; | ||
216 | #endif | ||
217 | } | ||
218 | return 0; | ||
219 | } | ||
220 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); | ||
221 | |||
151 | void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) | 222 | void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) |
152 | { | 223 | { |
224 | struct v4l2_device *v4l2_dev; | ||
225 | |||
153 | /* return if it isn't registered */ | 226 | /* return if it isn't registered */ |
154 | if (sd == NULL || sd->v4l2_dev == NULL) | 227 | if (sd == NULL || sd->v4l2_dev == NULL) |
155 | return; | 228 | return; |
156 | spin_lock(&sd->v4l2_dev->lock); | 229 | |
230 | v4l2_dev = sd->v4l2_dev; | ||
231 | |||
232 | spin_lock(&v4l2_dev->lock); | ||
157 | list_del(&sd->list); | 233 | list_del(&sd->list); |
158 | spin_unlock(&sd->v4l2_dev->lock); | 234 | spin_unlock(&v4l2_dev->lock); |
235 | |||
159 | if (sd->internal_ops && sd->internal_ops->unregistered) | 236 | if (sd->internal_ops && sd->internal_ops->unregistered) |
160 | sd->internal_ops->unregistered(sd); | 237 | sd->internal_ops->unregistered(sd); |
161 | sd->v4l2_dev = NULL; | 238 | sd->v4l2_dev = NULL; |
239 | |||
240 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
241 | if (v4l2_dev->mdev) | ||
242 | media_device_unregister_entity(&sd->entity); | ||
243 | #endif | ||
244 | video_unregister_device(&sd->devnode); | ||
162 | module_put(sd->owner); | 245 | module_put(sd->owner); |
163 | } | 246 | } |
164 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); | 247 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); |