diff options
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 356 | ||||
-rw-r--r-- | include/media/v4l2-dev.h | 47 |
2 files changed, 295 insertions, 108 deletions
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index c5ca51a9020a..4e0db8845e04 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -41,17 +41,17 @@ | |||
41 | static ssize_t show_index(struct device *cd, | 41 | static ssize_t show_index(struct device *cd, |
42 | struct device_attribute *attr, char *buf) | 42 | struct device_attribute *attr, char *buf) |
43 | { | 43 | { |
44 | struct video_device *vfd = container_of(cd, struct video_device, dev); | 44 | struct video_device *vdev = to_video_device(cd); |
45 | 45 | ||
46 | return sprintf(buf, "%i\n", vfd->index); | 46 | return sprintf(buf, "%i\n", vdev->index); |
47 | } | 47 | } |
48 | 48 | ||
49 | static ssize_t show_name(struct device *cd, | 49 | static ssize_t show_name(struct device *cd, |
50 | struct device_attribute *attr, char *buf) | 50 | struct device_attribute *attr, char *buf) |
51 | { | 51 | { |
52 | struct video_device *vfd = container_of(cd, struct video_device, dev); | 52 | struct video_device *vdev = to_video_device(cd); |
53 | 53 | ||
54 | return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); | 54 | return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name); |
55 | } | 55 | } |
56 | 56 | ||
57 | static struct device_attribute video_device_attrs[] = { | 57 | static struct device_attribute video_device_attrs[] = { |
@@ -73,64 +73,64 @@ struct video_device *video_device_alloc(void) | |||
73 | } | 73 | } |
74 | EXPORT_SYMBOL(video_device_alloc); | 74 | EXPORT_SYMBOL(video_device_alloc); |
75 | 75 | ||
76 | void video_device_release(struct video_device *vfd) | 76 | void video_device_release(struct video_device *vdev) |
77 | { | 77 | { |
78 | kfree(vfd); | 78 | kfree(vdev); |
79 | } | 79 | } |
80 | EXPORT_SYMBOL(video_device_release); | 80 | EXPORT_SYMBOL(video_device_release); |
81 | 81 | ||
82 | void video_device_release_empty(struct video_device *vfd) | 82 | void video_device_release_empty(struct video_device *vdev) |
83 | { | 83 | { |
84 | /* Do nothing */ | 84 | /* Do nothing */ |
85 | /* Only valid when the video_device struct is a static. */ | 85 | /* Only valid when the video_device struct is a static. */ |
86 | } | 86 | } |
87 | EXPORT_SYMBOL(video_device_release_empty); | 87 | EXPORT_SYMBOL(video_device_release_empty); |
88 | 88 | ||
89 | /* Called when the last user of the character device is gone. */ | 89 | static inline void video_get(struct video_device *vdev) |
90 | static void v4l2_chardev_release(struct kobject *kobj) | ||
91 | { | 90 | { |
92 | struct video_device *vfd = container_of(kobj, struct video_device, cdev.kobj); | 91 | get_device(&vdev->dev); |
92 | } | ||
93 | |||
94 | static inline void video_put(struct video_device *vdev) | ||
95 | { | ||
96 | put_device(&vdev->dev); | ||
97 | } | ||
98 | |||
99 | /* Called when the last user of the video device exits. */ | ||
100 | static void v4l2_device_release(struct device *cd) | ||
101 | { | ||
102 | struct video_device *vdev = to_video_device(cd); | ||
93 | 103 | ||
94 | mutex_lock(&videodev_lock); | 104 | mutex_lock(&videodev_lock); |
95 | if (video_device[vfd->minor] != vfd) { | 105 | if (video_device[vdev->minor] != vdev) { |
96 | mutex_unlock(&videodev_lock); | 106 | mutex_unlock(&videodev_lock); |
97 | BUG(); | 107 | /* should not happen */ |
108 | WARN_ON(1); | ||
98 | return; | 109 | return; |
99 | } | 110 | } |
100 | 111 | ||
101 | /* Free up this device for reuse */ | 112 | /* Free up this device for reuse */ |
102 | video_device[vfd->minor] = NULL; | 113 | video_device[vdev->minor] = NULL; |
103 | clear_bit(vfd->num, video_nums[vfd->vfl_type]); | ||
104 | mutex_unlock(&videodev_lock); | ||
105 | 114 | ||
106 | /* Release the character device */ | 115 | /* Delete the cdev on this minor as well */ |
107 | vfd->cdev_release(kobj); | 116 | cdev_del(vdev->cdev); |
108 | /* Release video_device and perform other | 117 | /* Just in case some driver tries to access this from |
109 | cleanups as needed. */ | 118 | the release() callback. */ |
110 | if (vfd->release) | 119 | vdev->cdev = NULL; |
111 | vfd->release(vfd); | ||
112 | } | ||
113 | 120 | ||
114 | /* The new kobj_type for the character device */ | 121 | /* Mark minor as free */ |
115 | static struct kobj_type v4l2_ktype_cdev_default = { | 122 | clear_bit(vdev->num, video_nums[vdev->vfl_type]); |
116 | .release = v4l2_chardev_release, | ||
117 | }; | ||
118 | 123 | ||
119 | static void video_release(struct device *cd) | 124 | mutex_unlock(&videodev_lock); |
120 | { | ||
121 | struct video_device *vfd = container_of(cd, struct video_device, dev); | ||
122 | 125 | ||
123 | /* It's now safe to delete the char device. | 126 | /* Release video_device and perform other |
124 | This will either trigger the v4l2_chardev_release immediately (if | 127 | cleanups as needed. */ |
125 | the refcount goes to 0) or later when the last user of the | 128 | vdev->release(vdev); |
126 | character device closes it. */ | ||
127 | cdev_del(&vfd->cdev); | ||
128 | } | 129 | } |
129 | 130 | ||
130 | static struct class video_class = { | 131 | static struct class video_class = { |
131 | .name = VIDEO_NAME, | 132 | .name = VIDEO_NAME, |
132 | .dev_attrs = video_device_attrs, | 133 | .dev_attrs = video_device_attrs, |
133 | .dev_release = video_release, | ||
134 | }; | 134 | }; |
135 | 135 | ||
136 | struct video_device *video_devdata(struct file *file) | 136 | struct video_device *video_devdata(struct file *file) |
@@ -139,13 +139,163 @@ struct video_device *video_devdata(struct file *file) | |||
139 | } | 139 | } |
140 | EXPORT_SYMBOL(video_devdata); | 140 | EXPORT_SYMBOL(video_devdata); |
141 | 141 | ||
142 | static ssize_t v4l2_read(struct file *filp, char __user *buf, | ||
143 | size_t sz, loff_t *off) | ||
144 | { | ||
145 | struct video_device *vdev = video_devdata(filp); | ||
146 | |||
147 | if (!vdev->fops->read) | ||
148 | return -EINVAL; | ||
149 | if (video_is_unregistered(vdev)) | ||
150 | return -EIO; | ||
151 | return vdev->fops->read(filp, buf, sz, off); | ||
152 | } | ||
153 | |||
154 | static ssize_t v4l2_write(struct file *filp, const char __user *buf, | ||
155 | size_t sz, loff_t *off) | ||
156 | { | ||
157 | struct video_device *vdev = video_devdata(filp); | ||
158 | |||
159 | if (!vdev->fops->write) | ||
160 | return -EINVAL; | ||
161 | if (video_is_unregistered(vdev)) | ||
162 | return -EIO; | ||
163 | return vdev->fops->write(filp, buf, sz, off); | ||
164 | } | ||
165 | |||
166 | static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) | ||
167 | { | ||
168 | struct video_device *vdev = video_devdata(filp); | ||
169 | |||
170 | if (!vdev->fops->poll || video_is_unregistered(vdev)) | ||
171 | return DEFAULT_POLLMASK; | ||
172 | return vdev->fops->poll(filp, poll); | ||
173 | } | ||
174 | |||
175 | static int v4l2_ioctl(struct inode *inode, struct file *filp, | ||
176 | unsigned int cmd, unsigned long arg) | ||
177 | { | ||
178 | struct video_device *vdev = video_devdata(filp); | ||
179 | |||
180 | if (!vdev->fops->ioctl) | ||
181 | return -ENOTTY; | ||
182 | /* Allow ioctl to continue even if the device was unregistered. | ||
183 | Things like dequeueing buffers might still be useful. */ | ||
184 | return vdev->fops->ioctl(inode, filp, cmd, arg); | ||
185 | } | ||
186 | |||
187 | static long v4l2_unlocked_ioctl(struct file *filp, | ||
188 | unsigned int cmd, unsigned long arg) | ||
189 | { | ||
190 | struct video_device *vdev = video_devdata(filp); | ||
191 | |||
192 | if (!vdev->fops->unlocked_ioctl) | ||
193 | return -ENOTTY; | ||
194 | /* Allow ioctl to continue even if the device was unregistered. | ||
195 | Things like dequeueing buffers might still be useful. */ | ||
196 | return vdev->fops->unlocked_ioctl(filp, cmd, arg); | ||
197 | } | ||
198 | |||
199 | #ifdef CONFIG_COMPAT | ||
200 | static long v4l2_compat_ioctl(struct file *filp, | ||
201 | unsigned int cmd, unsigned long arg) | ||
202 | { | ||
203 | struct video_device *vdev = video_devdata(filp); | ||
204 | |||
205 | if (!vdev->fops->compat_ioctl) | ||
206 | return -ENOIOCTLCMD; | ||
207 | /* Allow ioctl to continue even if the device was unregistered. | ||
208 | Things like dequeueing buffers might still be useful. */ | ||
209 | return vdev->fops->compat_ioctl(filp, cmd, arg); | ||
210 | } | ||
211 | #endif | ||
212 | |||
213 | static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) | ||
214 | { | ||
215 | struct video_device *vdev = video_devdata(filp); | ||
216 | |||
217 | if (!vdev->fops->mmap || | ||
218 | video_is_unregistered(vdev)) | ||
219 | return -ENODEV; | ||
220 | return vdev->fops->mmap(filp, vm); | ||
221 | } | ||
222 | |||
223 | /* Override for the open function */ | ||
224 | static int v4l2_open(struct inode *inode, struct file *filp) | ||
225 | { | ||
226 | struct video_device *vdev; | ||
227 | int ret; | ||
228 | |||
229 | /* Check if the video device is available */ | ||
230 | mutex_lock(&videodev_lock); | ||
231 | vdev = video_devdata(filp); | ||
232 | /* return ENODEV if the video device has been removed | ||
233 | already or if it is not registered anymore. */ | ||
234 | if (vdev == NULL || video_is_unregistered(vdev)) { | ||
235 | mutex_unlock(&videodev_lock); | ||
236 | return -ENODEV; | ||
237 | } | ||
238 | /* and increase the device refcount */ | ||
239 | video_get(vdev); | ||
240 | mutex_unlock(&videodev_lock); | ||
241 | ret = vdev->fops->open(inode, filp); | ||
242 | /* decrease the refcount in case of an error */ | ||
243 | if (ret) | ||
244 | video_put(vdev); | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | /* Override for the release function */ | ||
249 | static int v4l2_release(struct inode *inode, struct file *filp) | ||
250 | { | ||
251 | struct video_device *vdev = video_devdata(filp); | ||
252 | int ret = vdev->fops->release(inode, filp); | ||
253 | |||
254 | /* decrease the refcount unconditionally since the release() | ||
255 | return value is ignored. */ | ||
256 | video_put(vdev); | ||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | static const struct file_operations v4l2_unlocked_fops = { | ||
261 | .owner = THIS_MODULE, | ||
262 | .read = v4l2_read, | ||
263 | .write = v4l2_write, | ||
264 | .open = v4l2_open, | ||
265 | .mmap = v4l2_mmap, | ||
266 | .unlocked_ioctl = v4l2_unlocked_ioctl, | ||
267 | #ifdef CONFIG_COMPAT | ||
268 | .compat_ioctl = v4l2_compat_ioctl, | ||
269 | #endif | ||
270 | .release = v4l2_release, | ||
271 | .poll = v4l2_poll, | ||
272 | .llseek = no_llseek, | ||
273 | }; | ||
274 | |||
275 | static const struct file_operations v4l2_fops = { | ||
276 | .owner = THIS_MODULE, | ||
277 | .read = v4l2_read, | ||
278 | .write = v4l2_write, | ||
279 | .open = v4l2_open, | ||
280 | .mmap = v4l2_mmap, | ||
281 | .ioctl = v4l2_ioctl, | ||
282 | #ifdef CONFIG_COMPAT | ||
283 | .compat_ioctl = v4l2_compat_ioctl, | ||
284 | #endif | ||
285 | .release = v4l2_release, | ||
286 | .poll = v4l2_poll, | ||
287 | .llseek = no_llseek, | ||
288 | }; | ||
289 | |||
142 | /** | 290 | /** |
143 | * get_index - assign stream number based on parent device | 291 | * get_index - assign stream number based on parent device |
144 | * @vdev: video_device to assign index number to, vdev->dev should be assigned | 292 | * @vdev: video_device to assign index number to, vdev->parent should be assigned |
145 | * @num: -1 if auto assign, requested number otherwise | 293 | * @num: -1 if auto assign, requested number otherwise |
146 | * | 294 | * |
295 | * Note that when this is called the new device has not yet been registered | ||
296 | * in the video_device array. | ||
147 | * | 297 | * |
148 | * returns -ENFILE if num is already in use, a free index number if | 298 | * Returns -ENFILE if num is already in use, a free index number if |
149 | * successful. | 299 | * successful. |
150 | */ | 300 | */ |
151 | static int get_index(struct video_device *vdev, int num) | 301 | static int get_index(struct video_device *vdev, int num) |
@@ -168,7 +318,6 @@ static int get_index(struct video_device *vdev, int num) | |||
168 | 318 | ||
169 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) { | 319 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) { |
170 | if (video_device[i] != NULL && | 320 | if (video_device[i] != NULL && |
171 | video_device[i] != vdev && | ||
172 | video_device[i]->parent == vdev->parent) { | 321 | video_device[i]->parent == vdev->parent) { |
173 | used |= 1 << video_device[i]->index; | 322 | used |= 1 << video_device[i]->index; |
174 | } | 323 | } |
@@ -184,17 +333,15 @@ static int get_index(struct video_device *vdev, int num) | |||
184 | return i > max_index ? -ENFILE : i; | 333 | return i > max_index ? -ENFILE : i; |
185 | } | 334 | } |
186 | 335 | ||
187 | static const struct file_operations video_fops; | 336 | int video_register_device(struct video_device *vdev, int type, int nr) |
188 | |||
189 | int video_register_device(struct video_device *vfd, int type, int nr) | ||
190 | { | 337 | { |
191 | return video_register_device_index(vfd, type, nr, -1); | 338 | return video_register_device_index(vdev, type, nr, -1); |
192 | } | 339 | } |
193 | EXPORT_SYMBOL(video_register_device); | 340 | EXPORT_SYMBOL(video_register_device); |
194 | 341 | ||
195 | /** | 342 | /** |
196 | * video_register_device_index - register video4linux devices | 343 | * video_register_device_index - register video4linux devices |
197 | * @vfd: video device structure we want to register | 344 | * @vdev: video device structure we want to register |
198 | * @type: type of device to register | 345 | * @type: type of device to register |
199 | * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... | 346 | * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... |
200 | * -1 == first free) | 347 | * -1 == first free) |
@@ -218,8 +365,7 @@ EXPORT_SYMBOL(video_register_device); | |||
218 | * | 365 | * |
219 | * %VFL_TYPE_RADIO - A radio card | 366 | * %VFL_TYPE_RADIO - A radio card |
220 | */ | 367 | */ |
221 | 368 | int video_register_device_index(struct video_device *vdev, int type, int nr, | |
222 | int video_register_device_index(struct video_device *vfd, int type, int nr, | ||
223 | int index) | 369 | int index) |
224 | { | 370 | { |
225 | int i = 0; | 371 | int i = 0; |
@@ -227,14 +373,19 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, | |||
227 | int minor_offset = 0; | 373 | int minor_offset = 0; |
228 | int minor_cnt = VIDEO_NUM_DEVICES; | 374 | int minor_cnt = VIDEO_NUM_DEVICES; |
229 | const char *name_base; | 375 | const char *name_base; |
230 | void *priv = video_get_drvdata(vfd); | 376 | void *priv = video_get_drvdata(vdev); |
231 | 377 | ||
232 | /* the release callback MUST be present */ | 378 | /* A minor value of -1 marks this video device as never |
233 | BUG_ON(!vfd->release); | 379 | having been registered */ |
380 | if (vdev) | ||
381 | vdev->minor = -1; | ||
234 | 382 | ||
235 | if (vfd == NULL) | 383 | /* the release callback MUST be present */ |
384 | WARN_ON(!vdev || !vdev->release); | ||
385 | if (!vdev || !vdev->release) | ||
236 | return -EINVAL; | 386 | return -EINVAL; |
237 | 387 | ||
388 | /* Part 1: check device type */ | ||
238 | switch (type) { | 389 | switch (type) { |
239 | case VFL_TYPE_GRABBER: | 390 | case VFL_TYPE_GRABBER: |
240 | name_base = "video"; | 391 | name_base = "video"; |
@@ -254,8 +405,10 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, | |||
254 | return -EINVAL; | 405 | return -EINVAL; |
255 | } | 406 | } |
256 | 407 | ||
257 | vfd->vfl_type = type; | 408 | vdev->vfl_type = type; |
409 | vdev->cdev = NULL; | ||
258 | 410 | ||
411 | /* Part 2: find a free minor, kernel number and device index. */ | ||
259 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | 412 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES |
260 | /* Keep the ranges for the first four types for historical | 413 | /* Keep the ranges for the first four types for historical |
261 | * reasons. | 414 | * reasons. |
@@ -286,10 +439,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, | |||
286 | } | 439 | } |
287 | #endif | 440 | #endif |
288 | 441 | ||
289 | /* Initialize the character device */ | 442 | /* Pick a minor number */ |
290 | cdev_init(&vfd->cdev, vfd->fops); | ||
291 | vfd->cdev.owner = vfd->fops->owner; | ||
292 | /* pick a minor number */ | ||
293 | mutex_lock(&videodev_lock); | 443 | mutex_lock(&videodev_lock); |
294 | nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr); | 444 | nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr); |
295 | if (nr == minor_cnt) | 445 | if (nr == minor_cnt) |
@@ -313,72 +463,92 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, | |||
313 | return -ENFILE; | 463 | return -ENFILE; |
314 | } | 464 | } |
315 | #endif | 465 | #endif |
316 | vfd->minor = i + minor_offset; | 466 | vdev->minor = i + minor_offset; |
317 | vfd->num = nr; | 467 | vdev->num = nr; |
318 | set_bit(nr, video_nums[type]); | 468 | set_bit(nr, video_nums[type]); |
319 | BUG_ON(video_device[vfd->minor]); | 469 | /* Should not happen since we thought this minor was free */ |
320 | video_device[vfd->minor] = vfd; | 470 | WARN_ON(video_device[vdev->minor] != NULL); |
321 | 471 | ret = vdev->index = get_index(vdev, index); | |
322 | ret = get_index(vfd, index); | ||
323 | vfd->index = ret; | ||
324 | |||
325 | mutex_unlock(&videodev_lock); | 472 | mutex_unlock(&videodev_lock); |
326 | 473 | ||
327 | if (ret < 0) { | 474 | if (ret < 0) { |
328 | printk(KERN_ERR "%s: get_index failed\n", __func__); | 475 | printk(KERN_ERR "%s: get_index failed\n", __func__); |
329 | goto fail_minor; | 476 | goto cleanup; |
330 | } | 477 | } |
331 | 478 | ||
332 | ret = cdev_add(&vfd->cdev, MKDEV(VIDEO_MAJOR, vfd->minor), 1); | 479 | /* Part 3: Initialize the character device */ |
480 | vdev->cdev = cdev_alloc(); | ||
481 | if (vdev->cdev == NULL) { | ||
482 | ret = -ENOMEM; | ||
483 | goto cleanup; | ||
484 | } | ||
485 | if (vdev->fops->unlocked_ioctl) | ||
486 | vdev->cdev->ops = &v4l2_unlocked_fops; | ||
487 | else | ||
488 | vdev->cdev->ops = &v4l2_fops; | ||
489 | vdev->cdev->owner = vdev->fops->owner; | ||
490 | ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); | ||
333 | if (ret < 0) { | 491 | if (ret < 0) { |
334 | printk(KERN_ERR "%s: cdev_add failed\n", __func__); | 492 | printk(KERN_ERR "%s: cdev_add failed\n", __func__); |
335 | goto fail_minor; | 493 | kfree(vdev->cdev); |
494 | vdev->cdev = NULL; | ||
495 | goto cleanup; | ||
336 | } | 496 | } |
337 | /* sysfs class */ | 497 | |
338 | memset(&vfd->dev, 0, sizeof(vfd->dev)); | 498 | /* Part 4: register the device with sysfs */ |
499 | memset(&vdev->dev, 0, sizeof(vdev->dev)); | ||
339 | /* The memset above cleared the device's drvdata, so | 500 | /* The memset above cleared the device's drvdata, so |
340 | put back the copy we made earlier. */ | 501 | put back the copy we made earlier. */ |
341 | video_set_drvdata(vfd, priv); | 502 | video_set_drvdata(vdev, priv); |
342 | vfd->dev.class = &video_class; | 503 | vdev->dev.class = &video_class; |
343 | vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); | 504 | vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); |
344 | if (vfd->parent) | 505 | if (vdev->parent) |
345 | vfd->dev.parent = vfd->parent; | 506 | vdev->dev.parent = vdev->parent; |
346 | dev_set_name(&vfd->dev, "%s%d", name_base, nr); | 507 | dev_set_name(&vdev->dev, "%s%d", name_base, nr); |
347 | ret = device_register(&vfd->dev); | 508 | ret = device_register(&vdev->dev); |
348 | if (ret < 0) { | 509 | if (ret < 0) { |
349 | printk(KERN_ERR "%s: device_register failed\n", __func__); | 510 | printk(KERN_ERR "%s: device_register failed\n", __func__); |
350 | goto del_cdev; | 511 | goto cleanup; |
351 | } | 512 | } |
352 | /* Remember the cdev's release function */ | 513 | /* Register the release callback that will be called when the last |
353 | vfd->cdev_release = vfd->cdev.kobj.ktype->release; | 514 | reference to the device goes away. */ |
354 | /* Install our own */ | 515 | vdev->dev.release = v4l2_device_release; |
355 | vfd->cdev.kobj.ktype = &v4l2_ktype_cdev_default; | ||
356 | return 0; | ||
357 | 516 | ||
358 | del_cdev: | 517 | /* Part 5: Activate this minor. The char device can now be used. */ |
359 | cdev_del(&vfd->cdev); | 518 | mutex_lock(&videodev_lock); |
519 | video_device[vdev->minor] = vdev; | ||
520 | mutex_unlock(&videodev_lock); | ||
521 | return 0; | ||
360 | 522 | ||
361 | fail_minor: | 523 | cleanup: |
362 | mutex_lock(&videodev_lock); | 524 | mutex_lock(&videodev_lock); |
363 | video_device[vfd->minor] = NULL; | 525 | if (vdev->cdev) |
364 | clear_bit(vfd->num, video_nums[type]); | 526 | cdev_del(vdev->cdev); |
527 | clear_bit(vdev->num, video_nums[type]); | ||
365 | mutex_unlock(&videodev_lock); | 528 | mutex_unlock(&videodev_lock); |
366 | vfd->minor = -1; | 529 | /* Mark this video device as never having been registered. */ |
530 | vdev->minor = -1; | ||
367 | return ret; | 531 | return ret; |
368 | } | 532 | } |
369 | EXPORT_SYMBOL(video_register_device_index); | 533 | EXPORT_SYMBOL(video_register_device_index); |
370 | 534 | ||
371 | /** | 535 | /** |
372 | * video_unregister_device - unregister a video4linux device | 536 | * video_unregister_device - unregister a video4linux device |
373 | * @vfd: the device to unregister | 537 | * @vdev: the device to unregister |
374 | * | 538 | * |
375 | * This unregisters the passed device and deassigns the minor | 539 | * This unregisters the passed device. Future open calls will |
376 | * number. Future open calls will be met with errors. | 540 | * be met with errors. |
377 | */ | 541 | */ |
378 | 542 | void video_unregister_device(struct video_device *vdev) | |
379 | void video_unregister_device(struct video_device *vfd) | ||
380 | { | 543 | { |
381 | device_unregister(&vfd->dev); | 544 | /* Check if vdev was ever registered at all */ |
545 | if (!vdev || vdev->minor < 0) | ||
546 | return; | ||
547 | |||
548 | mutex_lock(&videodev_lock); | ||
549 | set_bit(V4L2_FL_UNREGISTERED, &vdev->flags); | ||
550 | mutex_unlock(&videodev_lock); | ||
551 | device_unregister(&vdev->dev); | ||
382 | } | 552 | } |
383 | EXPORT_SYMBOL(video_unregister_device); | 553 | EXPORT_SYMBOL(video_unregister_device); |
384 | 554 | ||
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index a0a6b41c5e09..e0d72d2c6f0e 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h | |||
@@ -26,6 +26,11 @@ | |||
26 | 26 | ||
27 | struct v4l2_ioctl_callbacks; | 27 | struct v4l2_ioctl_callbacks; |
28 | 28 | ||
29 | /* Flag to mark the video_device struct as unregistered. | ||
30 | Drivers can set this flag if they want to block all future | ||
31 | device access. It is set by video_unregister_device. */ | ||
32 | #define V4L2_FL_UNREGISTERED (0) | ||
33 | |||
29 | /* | 34 | /* |
30 | * Newer version of video_device, handled by videodev2.c | 35 | * Newer version of video_device, handled by videodev2.c |
31 | * This version moves redundant code from video device code to | 36 | * This version moves redundant code from video device code to |
@@ -39,15 +44,17 @@ struct video_device | |||
39 | 44 | ||
40 | /* sysfs */ | 45 | /* sysfs */ |
41 | struct device dev; /* v4l device */ | 46 | struct device dev; /* v4l device */ |
42 | struct cdev cdev; /* character device */ | 47 | struct cdev *cdev; /* character device */ |
43 | void (*cdev_release)(struct kobject *kobj); | ||
44 | struct device *parent; /* device parent */ | 48 | struct device *parent; /* device parent */ |
45 | 49 | ||
46 | /* device info */ | 50 | /* device info */ |
47 | char name[32]; | 51 | char name[32]; |
48 | int vfl_type; | 52 | int vfl_type; |
53 | /* 'minor' is set to -1 if the registration failed */ | ||
49 | int minor; | 54 | int minor; |
50 | u16 num; | 55 | u16 num; |
56 | /* use bitops to set/clear/test flags */ | ||
57 | unsigned long flags; | ||
51 | /* attribute to differentiate multiple indices on one physical device */ | 58 | /* attribute to differentiate multiple indices on one physical device */ |
52 | int index; | 59 | int index; |
53 | 60 | ||
@@ -58,7 +65,7 @@ struct video_device | |||
58 | v4l2_std_id current_norm; /* Current tvnorm */ | 65 | v4l2_std_id current_norm; /* Current tvnorm */ |
59 | 66 | ||
60 | /* callbacks */ | 67 | /* callbacks */ |
61 | void (*release)(struct video_device *vfd); | 68 | void (*release)(struct video_device *vdev); |
62 | 69 | ||
63 | /* ioctl callbacks */ | 70 | /* ioctl callbacks */ |
64 | const struct v4l2_ioctl_ops *ioctl_ops; | 71 | const struct v4l2_ioctl_ops *ioctl_ops; |
@@ -67,36 +74,41 @@ struct video_device | |||
67 | /* dev to video-device */ | 74 | /* dev to video-device */ |
68 | #define to_video_device(cd) container_of(cd, struct video_device, dev) | 75 | #define to_video_device(cd) container_of(cd, struct video_device, dev) |
69 | 76 | ||
70 | /* Register and unregister devices. Note that if video_register_device fails, | 77 | /* Register video devices. Note that if video_register_device fails, |
71 | the release() callback of the video_device structure is *not* called, so | 78 | the release() callback of the video_device structure is *not* called, so |
72 | the caller is responsible for freeing any data. Usually that means that | 79 | the caller is responsible for freeing any data. Usually that means that |
73 | you call video_device_release() on failure. */ | 80 | you call video_device_release() on failure. |
74 | int __must_check video_register_device(struct video_device *vfd, int type, int nr); | 81 | |
75 | int __must_check video_register_device_index(struct video_device *vfd, | 82 | Also note that vdev->minor is set to -1 if the registration failed. */ |
83 | int __must_check video_register_device(struct video_device *vdev, int type, int nr); | ||
84 | int __must_check video_register_device_index(struct video_device *vdev, | ||
76 | int type, int nr, int index); | 85 | int type, int nr, int index); |
77 | void video_unregister_device(struct video_device *vfd); | 86 | |
87 | /* Unregister video devices. Will do nothing if vdev == NULL or | ||
88 | vdev->minor < 0. */ | ||
89 | void video_unregister_device(struct video_device *vdev); | ||
78 | 90 | ||
79 | /* helper functions to alloc/release struct video_device, the | 91 | /* helper functions to alloc/release struct video_device, the |
80 | latter can also be used for video_device->release(). */ | 92 | latter can also be used for video_device->release(). */ |
81 | struct video_device * __must_check video_device_alloc(void); | 93 | struct video_device * __must_check video_device_alloc(void); |
82 | 94 | ||
83 | /* this release function frees the vfd pointer */ | 95 | /* this release function frees the vdev pointer */ |
84 | void video_device_release(struct video_device *vfd); | 96 | void video_device_release(struct video_device *vdev); |
85 | 97 | ||
86 | /* this release function does nothing, use when the video_device is a | 98 | /* this release function does nothing, use when the video_device is a |
87 | static global struct. Note that having a static video_device is | 99 | static global struct. Note that having a static video_device is |
88 | a dubious construction at best. */ | 100 | a dubious construction at best. */ |
89 | void video_device_release_empty(struct video_device *vfd); | 101 | void video_device_release_empty(struct video_device *vdev); |
90 | 102 | ||
91 | /* helper functions to access driver private data. */ | 103 | /* helper functions to access driver private data. */ |
92 | static inline void *video_get_drvdata(struct video_device *dev) | 104 | static inline void *video_get_drvdata(struct video_device *vdev) |
93 | { | 105 | { |
94 | return dev_get_drvdata(&dev->dev); | 106 | return dev_get_drvdata(&vdev->dev); |
95 | } | 107 | } |
96 | 108 | ||
97 | static inline void video_set_drvdata(struct video_device *dev, void *data) | 109 | static inline void video_set_drvdata(struct video_device *vdev, void *data) |
98 | { | 110 | { |
99 | dev_set_drvdata(&dev->dev, data); | 111 | dev_set_drvdata(&vdev->dev, data); |
100 | } | 112 | } |
101 | 113 | ||
102 | struct video_device *video_devdata(struct file *file); | 114 | struct video_device *video_devdata(struct file *file); |
@@ -108,4 +120,9 @@ static inline void *video_drvdata(struct file *file) | |||
108 | return video_get_drvdata(video_devdata(file)); | 120 | return video_get_drvdata(video_devdata(file)); |
109 | } | 121 | } |
110 | 122 | ||
123 | static inline int video_is_unregistered(struct video_device *vdev) | ||
124 | { | ||
125 | return test_bit(V4L2_FL_UNREGISTERED, &vdev->flags); | ||
126 | } | ||
127 | |||
111 | #endif /* _V4L2_DEV_H */ | 128 | #endif /* _V4L2_DEV_H */ |