aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-dev.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2008-12-19 19:28:27 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:39:35 -0500
commitdc93a70cc7f92e1dbaf29fa7dfd914b0f618fb31 (patch)
treeec14edc6348b80390a1787e70828b5cd3401fe3c /drivers/media/video/v4l2-dev.c
parentbe49e368fb6e20c3a90c566b040ac3d248e2ce29 (diff)
V4L/DVB (9973): v4l2-dev: use the release callback from device instead of cdev
Instead of relying on the cdev release callback we should rely on the release callback from the device struct. This requires that we use get_device/put_device to do proper refcounting. In order to do this safely v4l2-dev.c now sets up its own file_operations that call out to the driver's ops. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-dev.c')
-rw-r--r--drivers/media/video/v4l2-dev.c356
1 files changed, 263 insertions, 93 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 @@
41static ssize_t show_index(struct device *cd, 41static 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
49static ssize_t show_name(struct device *cd, 49static 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
57static struct device_attribute video_device_attrs[] = { 57static struct device_attribute video_device_attrs[] = {
@@ -73,64 +73,64 @@ struct video_device *video_device_alloc(void)
73} 73}
74EXPORT_SYMBOL(video_device_alloc); 74EXPORT_SYMBOL(video_device_alloc);
75 75
76void video_device_release(struct video_device *vfd) 76void video_device_release(struct video_device *vdev)
77{ 77{
78 kfree(vfd); 78 kfree(vdev);
79} 79}
80EXPORT_SYMBOL(video_device_release); 80EXPORT_SYMBOL(video_device_release);
81 81
82void video_device_release_empty(struct video_device *vfd) 82void 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}
87EXPORT_SYMBOL(video_device_release_empty); 87EXPORT_SYMBOL(video_device_release_empty);
88 88
89/* Called when the last user of the character device is gone. */ 89static inline void video_get(struct video_device *vdev)
90static 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
94static 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. */
100static 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 */
115static 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
119static 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
130static struct class video_class = { 131static 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
136struct video_device *video_devdata(struct file *file) 136struct video_device *video_devdata(struct file *file)
@@ -139,13 +139,163 @@ struct video_device *video_devdata(struct file *file)
139} 139}
140EXPORT_SYMBOL(video_devdata); 140EXPORT_SYMBOL(video_devdata);
141 141
142static 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
154static 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
166static 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
175static 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
187static 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
200static 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
213static 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 */
224static 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 */
249static 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
260static 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
275static 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 */
151static int get_index(struct video_device *vdev, int num) 301static 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
187static const struct file_operations video_fops; 336int video_register_device(struct video_device *vdev, int type, int nr)
188
189int 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}
193EXPORT_SYMBOL(video_register_device); 340EXPORT_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 368int video_register_device_index(struct video_device *vdev, int type, int nr,
222int 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
358del_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
361fail_minor: 523cleanup:
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}
369EXPORT_SYMBOL(video_register_device_index); 533EXPORT_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 542void video_unregister_device(struct video_device *vdev)
379void 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}
383EXPORT_SYMBOL(video_unregister_device); 553EXPORT_SYMBOL(video_unregister_device);
384 554