diff options
Diffstat (limited to 'drivers/media/video/v4l2-dev.c')
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 154 |
1 files changed, 96 insertions, 58 deletions
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index a7f1b69a7dab..500cbe9891ac 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -66,7 +66,49 @@ static struct device_attribute video_device_attrs[] = { | |||
66 | */ | 66 | */ |
67 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; | 67 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; |
68 | static DEFINE_MUTEX(videodev_lock); | 68 | static DEFINE_MUTEX(videodev_lock); |
69 | static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); | 69 | static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); |
70 | |||
71 | /* Device node utility functions */ | ||
72 | |||
73 | /* Note: these utility functions all assume that vfl_type is in the range | ||
74 | [0, VFL_TYPE_MAX-1]. */ | ||
75 | |||
76 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | ||
77 | /* Return the bitmap corresponding to vfl_type. */ | ||
78 | static inline unsigned long *devnode_bits(int vfl_type) | ||
79 | { | ||
80 | /* Any types not assigned to fixed minor ranges must be mapped to | ||
81 | one single bitmap for the purposes of finding a free node number | ||
82 | since all those unassigned types use the same minor range. */ | ||
83 | int idx = (vfl_type > VFL_TYPE_VTX) ? VFL_TYPE_MAX - 1 : vfl_type; | ||
84 | |||
85 | return devnode_nums[idx]; | ||
86 | } | ||
87 | #else | ||
88 | /* Return the bitmap corresponding to vfl_type. */ | ||
89 | static inline unsigned long *devnode_bits(int vfl_type) | ||
90 | { | ||
91 | return devnode_nums[vfl_type]; | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | /* Mark device node number vdev->num as used */ | ||
96 | static inline void devnode_set(struct video_device *vdev) | ||
97 | { | ||
98 | set_bit(vdev->num, devnode_bits(vdev->vfl_type)); | ||
99 | } | ||
100 | |||
101 | /* Mark device node number vdev->num as unused */ | ||
102 | static inline void devnode_clear(struct video_device *vdev) | ||
103 | { | ||
104 | clear_bit(vdev->num, devnode_bits(vdev->vfl_type)); | ||
105 | } | ||
106 | |||
107 | /* Try to find a free device node number in the range [from, to> */ | ||
108 | static inline int devnode_find(struct video_device *vdev, int from, int to) | ||
109 | { | ||
110 | return find_next_zero_bit(devnode_bits(vdev->vfl_type), to, from); | ||
111 | } | ||
70 | 112 | ||
71 | struct video_device *video_device_alloc(void) | 113 | struct video_device *video_device_alloc(void) |
72 | { | 114 | { |
@@ -119,8 +161,8 @@ static void v4l2_device_release(struct device *cd) | |||
119 | the release() callback. */ | 161 | the release() callback. */ |
120 | vdev->cdev = NULL; | 162 | vdev->cdev = NULL; |
121 | 163 | ||
122 | /* Mark minor as free */ | 164 | /* Mark device node number as free */ |
123 | clear_bit(vdev->num, video_nums[vdev->vfl_type]); | 165 | devnode_clear(vdev); |
124 | 166 | ||
125 | mutex_unlock(&videodev_lock); | 167 | mutex_unlock(&videodev_lock); |
126 | 168 | ||
@@ -299,32 +341,28 @@ static const struct file_operations v4l2_fops = { | |||
299 | }; | 341 | }; |
300 | 342 | ||
301 | /** | 343 | /** |
302 | * get_index - assign stream number based on parent device | 344 | * get_index - assign stream index number based on parent device |
303 | * @vdev: video_device to assign index number to, vdev->parent should be assigned | 345 | * @vdev: video_device to assign index number to, vdev->parent should be assigned |
304 | * @num: -1 if auto assign, requested number otherwise | ||
305 | * | 346 | * |
306 | * Note that when this is called the new device has not yet been registered | 347 | * Note that when this is called the new device has not yet been registered |
307 | * in the video_device array. | 348 | * in the video_device array, but it was able to obtain a minor number. |
349 | * | ||
350 | * This means that we can always obtain a free stream index number since | ||
351 | * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in | ||
352 | * use of the video_device array. | ||
308 | * | 353 | * |
309 | * Returns -ENFILE if num is already in use, a free index number if | 354 | * Returns a free index number. |
310 | * successful. | ||
311 | */ | 355 | */ |
312 | static int get_index(struct video_device *vdev, int num) | 356 | static int get_index(struct video_device *vdev) |
313 | { | 357 | { |
314 | /* This can be static since this function is called with the global | 358 | /* This can be static since this function is called with the global |
315 | videodev_lock held. */ | 359 | videodev_lock held. */ |
316 | static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES); | 360 | static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES); |
317 | int i; | 361 | int i; |
318 | 362 | ||
319 | if (num >= VIDEO_NUM_DEVICES) { | 363 | /* Some drivers do not set the parent. In that case always return 0. */ |
320 | printk(KERN_ERR "videodev: %s num is too large\n", __func__); | ||
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | /* Some drivers do not set the parent. In that case always return | ||
325 | num or 0. */ | ||
326 | if (vdev->parent == NULL) | 364 | if (vdev->parent == NULL) |
327 | return num >= 0 ? num : 0; | 365 | return 0; |
328 | 366 | ||
329 | bitmap_zero(used, VIDEO_NUM_DEVICES); | 367 | bitmap_zero(used, VIDEO_NUM_DEVICES); |
330 | 368 | ||
@@ -335,35 +373,23 @@ static int get_index(struct video_device *vdev, int num) | |||
335 | } | 373 | } |
336 | } | 374 | } |
337 | 375 | ||
338 | if (num >= 0) { | 376 | return find_first_zero_bit(used, VIDEO_NUM_DEVICES); |
339 | if (test_bit(num, used)) | ||
340 | return -ENFILE; | ||
341 | return num; | ||
342 | } | ||
343 | |||
344 | i = find_first_zero_bit(used, VIDEO_NUM_DEVICES); | ||
345 | return i == VIDEO_NUM_DEVICES ? -ENFILE : i; | ||
346 | } | 377 | } |
347 | 378 | ||
348 | int video_register_device(struct video_device *vdev, int type, int nr) | ||
349 | { | ||
350 | return video_register_device_index(vdev, type, nr, -1); | ||
351 | } | ||
352 | EXPORT_SYMBOL(video_register_device); | ||
353 | |||
354 | /** | 379 | /** |
355 | * video_register_device_index - register video4linux devices | 380 | * video_register_device - register video4linux devices |
356 | * @vdev: video device structure we want to register | 381 | * @vdev: video device structure we want to register |
357 | * @type: type of device to register | 382 | * @type: type of device to register |
358 | * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... | 383 | * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... |
359 | * -1 == first free) | 384 | * -1 == first free) |
360 | * @index: stream number based on parent device; | 385 | * @warn_if_nr_in_use: warn if the desired device node number |
361 | * -1 if auto assign, requested number otherwise | 386 | * was already in use and another number was chosen instead. |
362 | * | 387 | * |
363 | * The registration code assigns minor numbers based on the type | 388 | * The registration code assigns minor numbers and device node numbers |
364 | * requested. -ENFILE is returned in all the device slots for this | 389 | * based on the requested type and registers the new device node with |
365 | * category are full. If not then the minor field is set and the | 390 | * the kernel. |
366 | * driver initialize function is called (if non %NULL). | 391 | * An error is returned if no free minor or device node number could be |
392 | * found, or if the registration of the device node failed. | ||
367 | * | 393 | * |
368 | * Zero is returned on success. | 394 | * Zero is returned on success. |
369 | * | 395 | * |
@@ -377,8 +403,8 @@ EXPORT_SYMBOL(video_register_device); | |||
377 | * | 403 | * |
378 | * %VFL_TYPE_RADIO - A radio card | 404 | * %VFL_TYPE_RADIO - A radio card |
379 | */ | 405 | */ |
380 | int video_register_device_index(struct video_device *vdev, int type, int nr, | 406 | static int __video_register_device(struct video_device *vdev, int type, int nr, |
381 | int index) | 407 | int warn_if_nr_in_use) |
382 | { | 408 | { |
383 | int i = 0; | 409 | int i = 0; |
384 | int ret; | 410 | int ret; |
@@ -421,7 +447,7 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
421 | if (vdev->v4l2_dev && vdev->v4l2_dev->dev) | 447 | if (vdev->v4l2_dev && vdev->v4l2_dev->dev) |
422 | vdev->parent = vdev->v4l2_dev->dev; | 448 | vdev->parent = vdev->v4l2_dev->dev; |
423 | 449 | ||
424 | /* Part 2: find a free minor, kernel number and device index. */ | 450 | /* Part 2: find a free minor, device node number and device index. */ |
425 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | 451 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES |
426 | /* Keep the ranges for the first four types for historical | 452 | /* Keep the ranges for the first four types for historical |
427 | * reasons. | 453 | * reasons. |
@@ -452,21 +478,22 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
452 | } | 478 | } |
453 | #endif | 479 | #endif |
454 | 480 | ||
455 | /* Pick a minor number */ | 481 | /* Pick a device node number */ |
456 | mutex_lock(&videodev_lock); | 482 | mutex_lock(&videodev_lock); |
457 | nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr); | 483 | nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt); |
458 | if (nr == minor_cnt) | 484 | if (nr == minor_cnt) |
459 | nr = find_first_zero_bit(video_nums[type], minor_cnt); | 485 | nr = devnode_find(vdev, 0, minor_cnt); |
460 | if (nr == minor_cnt) { | 486 | if (nr == minor_cnt) { |
461 | printk(KERN_ERR "could not get a free kernel number\n"); | 487 | printk(KERN_ERR "could not get a free device node number\n"); |
462 | mutex_unlock(&videodev_lock); | 488 | mutex_unlock(&videodev_lock); |
463 | return -ENFILE; | 489 | return -ENFILE; |
464 | } | 490 | } |
465 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | 491 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES |
466 | /* 1-on-1 mapping of kernel number to minor number */ | 492 | /* 1-on-1 mapping of device node number to minor number */ |
467 | i = nr; | 493 | i = nr; |
468 | #else | 494 | #else |
469 | /* The kernel number and minor numbers are independent */ | 495 | /* The device node number and minor numbers are independent, so |
496 | we just find the first free minor number. */ | ||
470 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) | 497 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) |
471 | if (video_device[i] == NULL) | 498 | if (video_device[i] == NULL) |
472 | break; | 499 | break; |
@@ -478,17 +505,13 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
478 | #endif | 505 | #endif |
479 | vdev->minor = i + minor_offset; | 506 | vdev->minor = i + minor_offset; |
480 | vdev->num = nr; | 507 | vdev->num = nr; |
481 | set_bit(nr, video_nums[type]); | 508 | devnode_set(vdev); |
509 | |||
482 | /* Should not happen since we thought this minor was free */ | 510 | /* Should not happen since we thought this minor was free */ |
483 | WARN_ON(video_device[vdev->minor] != NULL); | 511 | WARN_ON(video_device[vdev->minor] != NULL); |
484 | ret = vdev->index = get_index(vdev, index); | 512 | vdev->index = get_index(vdev); |
485 | mutex_unlock(&videodev_lock); | 513 | mutex_unlock(&videodev_lock); |
486 | 514 | ||
487 | if (ret < 0) { | ||
488 | printk(KERN_ERR "%s: get_index failed\n", __func__); | ||
489 | goto cleanup; | ||
490 | } | ||
491 | |||
492 | /* Part 3: Initialize the character device */ | 515 | /* Part 3: Initialize the character device */ |
493 | vdev->cdev = cdev_alloc(); | 516 | vdev->cdev = cdev_alloc(); |
494 | if (vdev->cdev == NULL) { | 517 | if (vdev->cdev == NULL) { |
@@ -517,7 +540,7 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
517 | vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); | 540 | vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); |
518 | if (vdev->parent) | 541 | if (vdev->parent) |
519 | vdev->dev.parent = vdev->parent; | 542 | vdev->dev.parent = vdev->parent; |
520 | dev_set_name(&vdev->dev, "%s%d", name_base, nr); | 543 | dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); |
521 | ret = device_register(&vdev->dev); | 544 | ret = device_register(&vdev->dev); |
522 | if (ret < 0) { | 545 | if (ret < 0) { |
523 | printk(KERN_ERR "%s: device_register failed\n", __func__); | 546 | printk(KERN_ERR "%s: device_register failed\n", __func__); |
@@ -527,6 +550,10 @@ int video_register_device_index(struct video_device *vdev, int type, int nr, | |||
527 | reference to the device goes away. */ | 550 | reference to the device goes away. */ |
528 | vdev->dev.release = v4l2_device_release; | 551 | vdev->dev.release = v4l2_device_release; |
529 | 552 | ||
553 | if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) | ||
554 | printk(KERN_WARNING "%s: requested %s%d, got %s%d\n", | ||
555 | __func__, name_base, nr, name_base, vdev->num); | ||
556 | |||
530 | /* Part 5: Activate this minor. The char device can now be used. */ | 557 | /* Part 5: Activate this minor. The char device can now be used. */ |
531 | mutex_lock(&videodev_lock); | 558 | mutex_lock(&videodev_lock); |
532 | video_device[vdev->minor] = vdev; | 559 | video_device[vdev->minor] = vdev; |
@@ -537,13 +564,24 @@ cleanup: | |||
537 | mutex_lock(&videodev_lock); | 564 | mutex_lock(&videodev_lock); |
538 | if (vdev->cdev) | 565 | if (vdev->cdev) |
539 | cdev_del(vdev->cdev); | 566 | cdev_del(vdev->cdev); |
540 | clear_bit(vdev->num, video_nums[type]); | 567 | devnode_clear(vdev); |
541 | mutex_unlock(&videodev_lock); | 568 | mutex_unlock(&videodev_lock); |
542 | /* Mark this video device as never having been registered. */ | 569 | /* Mark this video device as never having been registered. */ |
543 | vdev->minor = -1; | 570 | vdev->minor = -1; |
544 | return ret; | 571 | return ret; |
545 | } | 572 | } |
546 | EXPORT_SYMBOL(video_register_device_index); | 573 | |
574 | int video_register_device(struct video_device *vdev, int type, int nr) | ||
575 | { | ||
576 | return __video_register_device(vdev, type, nr, 1); | ||
577 | } | ||
578 | EXPORT_SYMBOL(video_register_device); | ||
579 | |||
580 | int video_register_device_no_warn(struct video_device *vdev, int type, int nr) | ||
581 | { | ||
582 | return __video_register_device(vdev, type, nr, 0); | ||
583 | } | ||
584 | EXPORT_SYMBOL(video_register_device_no_warn); | ||
547 | 585 | ||
548 | /** | 586 | /** |
549 | * video_unregister_device - unregister a video4linux device | 587 | * video_unregister_device - unregister a video4linux device |