diff options
Diffstat (limited to 'drivers/media/video/v4l2-dev.c')
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 152 |
1 files changed, 133 insertions, 19 deletions
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 341764a3a990..498e6742579e 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -143,6 +143,7 @@ static inline void video_put(struct video_device *vdev) | |||
143 | static void v4l2_device_release(struct device *cd) | 143 | static void v4l2_device_release(struct device *cd) |
144 | { | 144 | { |
145 | struct video_device *vdev = to_video_device(cd); | 145 | struct video_device *vdev = to_video_device(cd); |
146 | struct v4l2_device *v4l2_dev = vdev->v4l2_dev; | ||
146 | 147 | ||
147 | mutex_lock(&videodev_lock); | 148 | mutex_lock(&videodev_lock); |
148 | if (video_device[vdev->minor] != vdev) { | 149 | if (video_device[vdev->minor] != vdev) { |
@@ -169,6 +170,10 @@ static void v4l2_device_release(struct device *cd) | |||
169 | /* Release video_device and perform other | 170 | /* Release video_device and perform other |
170 | cleanups as needed. */ | 171 | cleanups as needed. */ |
171 | vdev->release(vdev); | 172 | vdev->release(vdev); |
173 | |||
174 | /* Decrease v4l2_device refcount */ | ||
175 | if (v4l2_dev) | ||
176 | v4l2_device_put(v4l2_dev); | ||
172 | } | 177 | } |
173 | 178 | ||
174 | static struct class video_class = { | 179 | static struct class video_class = { |
@@ -182,6 +187,70 @@ struct video_device *video_devdata(struct file *file) | |||
182 | } | 187 | } |
183 | EXPORT_SYMBOL(video_devdata); | 188 | EXPORT_SYMBOL(video_devdata); |
184 | 189 | ||
190 | |||
191 | /* Priority handling */ | ||
192 | |||
193 | static inline bool prio_is_valid(enum v4l2_priority prio) | ||
194 | { | ||
195 | return prio == V4L2_PRIORITY_BACKGROUND || | ||
196 | prio == V4L2_PRIORITY_INTERACTIVE || | ||
197 | prio == V4L2_PRIORITY_RECORD; | ||
198 | } | ||
199 | |||
200 | void v4l2_prio_init(struct v4l2_prio_state *global) | ||
201 | { | ||
202 | memset(global, 0, sizeof(*global)); | ||
203 | } | ||
204 | EXPORT_SYMBOL(v4l2_prio_init); | ||
205 | |||
206 | int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, | ||
207 | enum v4l2_priority new) | ||
208 | { | ||
209 | if (!prio_is_valid(new)) | ||
210 | return -EINVAL; | ||
211 | if (*local == new) | ||
212 | return 0; | ||
213 | |||
214 | atomic_inc(&global->prios[new]); | ||
215 | if (prio_is_valid(*local)) | ||
216 | atomic_dec(&global->prios[*local]); | ||
217 | *local = new; | ||
218 | return 0; | ||
219 | } | ||
220 | EXPORT_SYMBOL(v4l2_prio_change); | ||
221 | |||
222 | void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local) | ||
223 | { | ||
224 | v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT); | ||
225 | } | ||
226 | EXPORT_SYMBOL(v4l2_prio_open); | ||
227 | |||
228 | void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local) | ||
229 | { | ||
230 | if (prio_is_valid(local)) | ||
231 | atomic_dec(&global->prios[local]); | ||
232 | } | ||
233 | EXPORT_SYMBOL(v4l2_prio_close); | ||
234 | |||
235 | enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global) | ||
236 | { | ||
237 | if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0) | ||
238 | return V4L2_PRIORITY_RECORD; | ||
239 | if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0) | ||
240 | return V4L2_PRIORITY_INTERACTIVE; | ||
241 | if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0) | ||
242 | return V4L2_PRIORITY_BACKGROUND; | ||
243 | return V4L2_PRIORITY_UNSET; | ||
244 | } | ||
245 | EXPORT_SYMBOL(v4l2_prio_max); | ||
246 | |||
247 | int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local) | ||
248 | { | ||
249 | return (local < v4l2_prio_max(global)) ? -EBUSY : 0; | ||
250 | } | ||
251 | EXPORT_SYMBOL(v4l2_prio_check); | ||
252 | |||
253 | |||
185 | static ssize_t v4l2_read(struct file *filp, char __user *buf, | 254 | static ssize_t v4l2_read(struct file *filp, char __user *buf, |
186 | size_t sz, loff_t *off) | 255 | size_t sz, loff_t *off) |
187 | { | 256 | { |
@@ -303,6 +372,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) | |||
303 | static int v4l2_open(struct inode *inode, struct file *filp) | 372 | static int v4l2_open(struct inode *inode, struct file *filp) |
304 | { | 373 | { |
305 | struct video_device *vdev; | 374 | struct video_device *vdev; |
375 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
376 | struct media_entity *entity = NULL; | ||
377 | #endif | ||
306 | int ret = 0; | 378 | int ret = 0; |
307 | 379 | ||
308 | /* Check if the video device is available */ | 380 | /* Check if the video device is available */ |
@@ -316,6 +388,16 @@ static int v4l2_open(struct inode *inode, struct file *filp) | |||
316 | /* and increase the device refcount */ | 388 | /* and increase the device refcount */ |
317 | video_get(vdev); | 389 | video_get(vdev); |
318 | mutex_unlock(&videodev_lock); | 390 | mutex_unlock(&videodev_lock); |
391 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
392 | if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { | ||
393 | entity = media_entity_get(&vdev->entity); | ||
394 | if (!entity) { | ||
395 | ret = -EBUSY; | ||
396 | video_put(vdev); | ||
397 | return ret; | ||
398 | } | ||
399 | } | ||
400 | #endif | ||
319 | if (vdev->fops->open) { | 401 | if (vdev->fops->open) { |
320 | if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { | 402 | if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { |
321 | ret = -ERESTARTSYS; | 403 | ret = -ERESTARTSYS; |
@@ -331,8 +413,13 @@ static int v4l2_open(struct inode *inode, struct file *filp) | |||
331 | 413 | ||
332 | err: | 414 | err: |
333 | /* decrease the refcount in case of an error */ | 415 | /* decrease the refcount in case of an error */ |
334 | if (ret) | 416 | if (ret) { |
417 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
418 | if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) | ||
419 | media_entity_put(entity); | ||
420 | #endif | ||
335 | video_put(vdev); | 421 | video_put(vdev); |
422 | } | ||
336 | return ret; | 423 | return ret; |
337 | } | 424 | } |
338 | 425 | ||
@@ -349,7 +436,10 @@ static int v4l2_release(struct inode *inode, struct file *filp) | |||
349 | if (vdev->lock) | 436 | if (vdev->lock) |
350 | mutex_unlock(vdev->lock); | 437 | mutex_unlock(vdev->lock); |
351 | } | 438 | } |
352 | 439 | #if defined(CONFIG_MEDIA_CONTROLLER) | |
440 | if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) | ||
441 | media_entity_put(&vdev->entity); | ||
442 | #endif | ||
353 | /* decrease the refcount unconditionally since the release() | 443 | /* decrease the refcount unconditionally since the release() |
354 | return value is ignored. */ | 444 | return value is ignored. */ |
355 | video_put(vdev); | 445 | video_put(vdev); |
@@ -408,13 +498,14 @@ static int get_index(struct video_device *vdev) | |||
408 | } | 498 | } |
409 | 499 | ||
410 | /** | 500 | /** |
411 | * video_register_device - register video4linux devices | 501 | * __video_register_device - register video4linux devices |
412 | * @vdev: video device structure we want to register | 502 | * @vdev: video device structure we want to register |
413 | * @type: type of device to register | 503 | * @type: type of device to register |
414 | * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... | 504 | * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... |
415 | * -1 == first free) | 505 | * -1 == first free) |
416 | * @warn_if_nr_in_use: warn if the desired device node number | 506 | * @warn_if_nr_in_use: warn if the desired device node number |
417 | * was already in use and another number was chosen instead. | 507 | * was already in use and another number was chosen instead. |
508 | * @owner: module that owns the video device node | ||
418 | * | 509 | * |
419 | * The registration code assigns minor numbers and device node numbers | 510 | * The registration code assigns minor numbers and device node numbers |
420 | * based on the requested type and registers the new device node with | 511 | * based on the requested type and registers the new device node with |
@@ -435,9 +526,11 @@ static int get_index(struct video_device *vdev) | |||
435 | * %VFL_TYPE_VBI - Vertical blank data (undecoded) | 526 | * %VFL_TYPE_VBI - Vertical blank data (undecoded) |
436 | * | 527 | * |
437 | * %VFL_TYPE_RADIO - A radio card | 528 | * %VFL_TYPE_RADIO - A radio card |
529 | * | ||
530 | * %VFL_TYPE_SUBDEV - A subdevice | ||
438 | */ | 531 | */ |
439 | static int __video_register_device(struct video_device *vdev, int type, int nr, | 532 | int __video_register_device(struct video_device *vdev, int type, int nr, |
440 | int warn_if_nr_in_use) | 533 | int warn_if_nr_in_use, struct module *owner) |
441 | { | 534 | { |
442 | int i = 0; | 535 | int i = 0; |
443 | int ret; | 536 | int ret; |
@@ -469,6 +562,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | |||
469 | case VFL_TYPE_RADIO: | 562 | case VFL_TYPE_RADIO: |
470 | name_base = "radio"; | 563 | name_base = "radio"; |
471 | break; | 564 | break; |
565 | case VFL_TYPE_SUBDEV: | ||
566 | name_base = "v4l-subdev"; | ||
567 | break; | ||
472 | default: | 568 | default: |
473 | printk(KERN_ERR "%s called with unknown type: %d\n", | 569 | printk(KERN_ERR "%s called with unknown type: %d\n", |
474 | __func__, type); | 570 | __func__, type); |
@@ -482,6 +578,10 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | |||
482 | vdev->parent = vdev->v4l2_dev->dev; | 578 | vdev->parent = vdev->v4l2_dev->dev; |
483 | if (vdev->ctrl_handler == NULL) | 579 | if (vdev->ctrl_handler == NULL) |
484 | vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; | 580 | vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; |
581 | /* If the prio state pointer is NULL, then use the v4l2_device | ||
582 | prio state. */ | ||
583 | if (vdev->prio == NULL) | ||
584 | vdev->prio = &vdev->v4l2_dev->prio; | ||
485 | } | 585 | } |
486 | 586 | ||
487 | /* Part 2: find a free minor, device node number and device index. */ | 587 | /* Part 2: find a free minor, device node number and device index. */ |
@@ -552,7 +652,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | |||
552 | goto cleanup; | 652 | goto cleanup; |
553 | } | 653 | } |
554 | vdev->cdev->ops = &v4l2_fops; | 654 | vdev->cdev->ops = &v4l2_fops; |
555 | vdev->cdev->owner = vdev->fops->owner; | 655 | vdev->cdev->owner = owner; |
556 | ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); | 656 | ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); |
557 | if (ret < 0) { | 657 | if (ret < 0) { |
558 | printk(KERN_ERR "%s: cdev_add failed\n", __func__); | 658 | printk(KERN_ERR "%s: cdev_add failed\n", __func__); |
@@ -580,11 +680,31 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | |||
580 | printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__, | 680 | printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__, |
581 | name_base, nr, video_device_node_name(vdev)); | 681 | name_base, nr, video_device_node_name(vdev)); |
582 | 682 | ||
583 | /* Part 5: Activate this minor. The char device can now be used. */ | 683 | /* Increase v4l2_device refcount */ |
684 | if (vdev->v4l2_dev) | ||
685 | v4l2_device_get(vdev->v4l2_dev); | ||
686 | |||
687 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
688 | /* Part 5: Register the entity. */ | ||
689 | if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { | ||
690 | vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; | ||
691 | vdev->entity.name = vdev->name; | ||
692 | vdev->entity.v4l.major = VIDEO_MAJOR; | ||
693 | vdev->entity.v4l.minor = vdev->minor; | ||
694 | ret = media_device_register_entity(vdev->v4l2_dev->mdev, | ||
695 | &vdev->entity); | ||
696 | if (ret < 0) | ||
697 | printk(KERN_WARNING | ||
698 | "%s: media_device_register_entity failed\n", | ||
699 | __func__); | ||
700 | } | ||
701 | #endif | ||
702 | /* Part 6: Activate this minor. The char device can now be used. */ | ||
584 | set_bit(V4L2_FL_REGISTERED, &vdev->flags); | 703 | set_bit(V4L2_FL_REGISTERED, &vdev->flags); |
585 | mutex_lock(&videodev_lock); | 704 | mutex_lock(&videodev_lock); |
586 | video_device[vdev->minor] = vdev; | 705 | video_device[vdev->minor] = vdev; |
587 | mutex_unlock(&videodev_lock); | 706 | mutex_unlock(&videodev_lock); |
707 | |||
588 | return 0; | 708 | return 0; |
589 | 709 | ||
590 | cleanup: | 710 | cleanup: |
@@ -597,18 +717,7 @@ cleanup: | |||
597 | vdev->minor = -1; | 717 | vdev->minor = -1; |
598 | return ret; | 718 | return ret; |
599 | } | 719 | } |
600 | 720 | EXPORT_SYMBOL(__video_register_device); | |
601 | int video_register_device(struct video_device *vdev, int type, int nr) | ||
602 | { | ||
603 | return __video_register_device(vdev, type, nr, 1); | ||
604 | } | ||
605 | EXPORT_SYMBOL(video_register_device); | ||
606 | |||
607 | int video_register_device_no_warn(struct video_device *vdev, int type, int nr) | ||
608 | { | ||
609 | return __video_register_device(vdev, type, nr, 0); | ||
610 | } | ||
611 | EXPORT_SYMBOL(video_register_device_no_warn); | ||
612 | 721 | ||
613 | /** | 722 | /** |
614 | * video_unregister_device - unregister a video4linux device | 723 | * video_unregister_device - unregister a video4linux device |
@@ -623,6 +732,11 @@ void video_unregister_device(struct video_device *vdev) | |||
623 | if (!vdev || !video_is_registered(vdev)) | 732 | if (!vdev || !video_is_registered(vdev)) |
624 | return; | 733 | return; |
625 | 734 | ||
735 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
736 | if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) | ||
737 | media_device_unregister_entity(&vdev->entity); | ||
738 | #endif | ||
739 | |||
626 | mutex_lock(&videodev_lock); | 740 | mutex_lock(&videodev_lock); |
627 | /* This must be in a critical section to prevent a race with v4l2_open. | 741 | /* This must be in a critical section to prevent a race with v4l2_open. |
628 | * Once this bit has been cleared video_get may never be called again. | 742 | * Once this bit has been cleared video_get may never be called again. |