diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2016-03-15 06:48:28 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2016-03-15 06:48:28 -0400 |
commit | 8331c055b23c4155b896a2c3791704ae68992d2b (patch) | |
tree | 7b8055caa7363b2194dd33de8ba27ee96a9d2505 /drivers/media/media-device.c | |
parent | b562e44f507e863c6792946e4e1b1449fbbac85d (diff) | |
parent | 840f5b0572ea9ddaca2bf5540a171013e92c97bd (diff) |
Merge commit '840f5b0572ea' into v4l_for_linus
* commit '840f5b0572ea': (381 commits)
media: au0828 disable tuner to demod link in au0828_media_device_register()
[media] touptek: cast char types on %x printk
[media] touptek: don't DMA at the stack
[media] mceusb: use %*ph for small buffer dumps
[media] v4l: exynos4-is: Drop unneeded check when setting up fimc-lite links
[media] v4l: vsp1: Check if an entity is a subdev with the right function
[media] hide unused functions for !MEDIA_CONTROLLER
[media] em28xx: fix Terratec Grabby AC97 codec detection
[media] media: add prefixes to interface types
[media] media: rc: nuvoton: switch attribute wakeup_data to text
[media] v4l2-ioctl: fix YUV422P pixel format description
[media] media: fix null pointer dereference in v4l_vb2q_enable_media_source()
[media] v4l2-mc.h: fix yet more compiler errors
[media] staging/media: add missing TODO files
[media] media.h: always start with 1 for the audio entities
[media] sound/usb: Use meaninful names for goto labels
[media] v4l2-mc.h: fix compiler warnings
[media] media: au0828 audio mixer isn't connected to decoder
[media] sound/usb: Use Media Controller API to share media resources
[media] dw2102: add support for TeVii S662
...
Diffstat (limited to 'drivers/media/media-device.c')
-rw-r--r-- | drivers/media/media-device.c | 145 |
1 files changed, 134 insertions, 11 deletions
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index e9219f528d7e..6e43c95629ea 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include <linux/media.h> | 30 | #include <linux/media.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/pci.h> | ||
34 | #include <linux/usb.h> | ||
33 | 35 | ||
34 | #include <media/media-device.h> | 36 | #include <media/media-device.h> |
35 | #include <media/media-devnode.h> | 37 | #include <media/media-devnode.h> |
@@ -41,6 +43,11 @@ | |||
41 | * Userspace API | 43 | * Userspace API |
42 | */ | 44 | */ |
43 | 45 | ||
46 | static inline void __user *media_get_uptr(__u64 arg) | ||
47 | { | ||
48 | return (void __user *)(uintptr_t)arg; | ||
49 | } | ||
50 | |||
44 | static int media_device_open(struct file *filp) | 51 | static int media_device_open(struct file *filp) |
45 | { | 52 | { |
46 | return 0; | 53 | return 0; |
@@ -58,7 +65,11 @@ static int media_device_get_info(struct media_device *dev, | |||
58 | 65 | ||
59 | memset(&info, 0, sizeof(info)); | 66 | memset(&info, 0, sizeof(info)); |
60 | 67 | ||
61 | strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver)); | 68 | if (dev->driver_name[0]) |
69 | strlcpy(info.driver, dev->driver_name, sizeof(info.driver)); | ||
70 | else | ||
71 | strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver)); | ||
72 | |||
62 | strlcpy(info.model, dev->model, sizeof(info.model)); | 73 | strlcpy(info.model, dev->model, sizeof(info.model)); |
63 | strlcpy(info.serial, dev->serial, sizeof(info.serial)); | 74 | strlcpy(info.serial, dev->serial, sizeof(info.serial)); |
64 | strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info)); | 75 | strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info)); |
@@ -257,7 +268,6 @@ static long media_device_setup_link(struct media_device *mdev, | |||
257 | return ret; | 268 | return ret; |
258 | } | 269 | } |
259 | 270 | ||
260 | #if 0 /* Let's postpone it to Kernel 4.6 */ | ||
261 | static long __media_device_get_topology(struct media_device *mdev, | 271 | static long __media_device_get_topology(struct media_device *mdev, |
262 | struct media_v2_topology *topo) | 272 | struct media_v2_topology *topo) |
263 | { | 273 | { |
@@ -265,10 +275,10 @@ static long __media_device_get_topology(struct media_device *mdev, | |||
265 | struct media_interface *intf; | 275 | struct media_interface *intf; |
266 | struct media_pad *pad; | 276 | struct media_pad *pad; |
267 | struct media_link *link; | 277 | struct media_link *link; |
268 | struct media_v2_entity kentity, *uentity; | 278 | struct media_v2_entity kentity, __user *uentity; |
269 | struct media_v2_interface kintf, *uintf; | 279 | struct media_v2_interface kintf, __user *uintf; |
270 | struct media_v2_pad kpad, *upad; | 280 | struct media_v2_pad kpad, __user *upad; |
271 | struct media_v2_link klink, *ulink; | 281 | struct media_v2_link klink, __user *ulink; |
272 | unsigned int i; | 282 | unsigned int i; |
273 | int ret = 0; | 283 | int ret = 0; |
274 | 284 | ||
@@ -413,7 +423,6 @@ static long media_device_get_topology(struct media_device *mdev, | |||
413 | 423 | ||
414 | return 0; | 424 | return 0; |
415 | } | 425 | } |
416 | #endif | ||
417 | 426 | ||
418 | static long media_device_ioctl(struct file *filp, unsigned int cmd, | 427 | static long media_device_ioctl(struct file *filp, unsigned int cmd, |
419 | unsigned long arg) | 428 | unsigned long arg) |
@@ -447,14 +456,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, | |||
447 | mutex_unlock(&dev->graph_mutex); | 456 | mutex_unlock(&dev->graph_mutex); |
448 | break; | 457 | break; |
449 | 458 | ||
450 | #if 0 /* Let's postpone it to Kernel 4.6 */ | ||
451 | case MEDIA_IOC_G_TOPOLOGY: | 459 | case MEDIA_IOC_G_TOPOLOGY: |
452 | mutex_lock(&dev->graph_mutex); | 460 | mutex_lock(&dev->graph_mutex); |
453 | ret = media_device_get_topology(dev, | 461 | ret = media_device_get_topology(dev, |
454 | (struct media_v2_topology __user *)arg); | 462 | (struct media_v2_topology __user *)arg); |
455 | mutex_unlock(&dev->graph_mutex); | 463 | mutex_unlock(&dev->graph_mutex); |
456 | break; | 464 | break; |
457 | #endif | 465 | |
458 | default: | 466 | default: |
459 | ret = -ENOIOCTLCMD; | 467 | ret = -ENOIOCTLCMD; |
460 | } | 468 | } |
@@ -503,9 +511,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, | |||
503 | case MEDIA_IOC_DEVICE_INFO: | 511 | case MEDIA_IOC_DEVICE_INFO: |
504 | case MEDIA_IOC_ENUM_ENTITIES: | 512 | case MEDIA_IOC_ENUM_ENTITIES: |
505 | case MEDIA_IOC_SETUP_LINK: | 513 | case MEDIA_IOC_SETUP_LINK: |
506 | #if 0 /* Let's postpone it to Kernel 4.6 */ | ||
507 | case MEDIA_IOC_G_TOPOLOGY: | 514 | case MEDIA_IOC_G_TOPOLOGY: |
508 | #endif | ||
509 | return media_device_ioctl(filp, cmd, arg); | 515 | return media_device_ioctl(filp, cmd, arg); |
510 | 516 | ||
511 | case MEDIA_IOC_ENUM_LINKS32: | 517 | case MEDIA_IOC_ENUM_LINKS32: |
@@ -564,6 +570,7 @@ static void media_device_release(struct media_devnode *mdev) | |||
564 | int __must_check media_device_register_entity(struct media_device *mdev, | 570 | int __must_check media_device_register_entity(struct media_device *mdev, |
565 | struct media_entity *entity) | 571 | struct media_entity *entity) |
566 | { | 572 | { |
573 | struct media_entity_notify *notify, *next; | ||
567 | unsigned int i; | 574 | unsigned int i; |
568 | int ret; | 575 | int ret; |
569 | 576 | ||
@@ -603,8 +610,33 @@ int __must_check media_device_register_entity(struct media_device *mdev, | |||
603 | media_gobj_create(mdev, MEDIA_GRAPH_PAD, | 610 | media_gobj_create(mdev, MEDIA_GRAPH_PAD, |
604 | &entity->pads[i].graph_obj); | 611 | &entity->pads[i].graph_obj); |
605 | 612 | ||
613 | /* invoke entity_notify callbacks */ | ||
614 | list_for_each_entry_safe(notify, next, &mdev->entity_notify, list) { | ||
615 | (notify)->notify(entity, notify->notify_data); | ||
616 | } | ||
617 | |||
606 | spin_unlock(&mdev->lock); | 618 | spin_unlock(&mdev->lock); |
607 | 619 | ||
620 | mutex_lock(&mdev->graph_mutex); | ||
621 | if (mdev->entity_internal_idx_max | ||
622 | >= mdev->pm_count_walk.ent_enum.idx_max) { | ||
623 | struct media_entity_graph new = { .top = 0 }; | ||
624 | |||
625 | /* | ||
626 | * Initialise the new graph walk before cleaning up | ||
627 | * the old one in order not to spoil the graph walk | ||
628 | * object of the media device if graph walk init fails. | ||
629 | */ | ||
630 | ret = media_entity_graph_walk_init(&new, mdev); | ||
631 | if (ret) { | ||
632 | mutex_unlock(&mdev->graph_mutex); | ||
633 | return ret; | ||
634 | } | ||
635 | media_entity_graph_walk_cleanup(&mdev->pm_count_walk); | ||
636 | mdev->pm_count_walk = new; | ||
637 | } | ||
638 | mutex_unlock(&mdev->graph_mutex); | ||
639 | |||
608 | return 0; | 640 | return 0; |
609 | } | 641 | } |
610 | EXPORT_SYMBOL_GPL(media_device_register_entity); | 642 | EXPORT_SYMBOL_GPL(media_device_register_entity); |
@@ -636,6 +668,8 @@ static void __media_device_unregister_entity(struct media_entity *entity) | |||
636 | /* Remove the entity */ | 668 | /* Remove the entity */ |
637 | media_gobj_destroy(&entity->graph_obj); | 669 | media_gobj_destroy(&entity->graph_obj); |
638 | 670 | ||
671 | /* invoke entity_notify callbacks to handle entity removal?? */ | ||
672 | |||
639 | entity->graph_obj.mdev = NULL; | 673 | entity->graph_obj.mdev = NULL; |
640 | } | 674 | } |
641 | 675 | ||
@@ -668,6 +702,7 @@ void media_device_init(struct media_device *mdev) | |||
668 | INIT_LIST_HEAD(&mdev->interfaces); | 702 | INIT_LIST_HEAD(&mdev->interfaces); |
669 | INIT_LIST_HEAD(&mdev->pads); | 703 | INIT_LIST_HEAD(&mdev->pads); |
670 | INIT_LIST_HEAD(&mdev->links); | 704 | INIT_LIST_HEAD(&mdev->links); |
705 | INIT_LIST_HEAD(&mdev->entity_notify); | ||
671 | spin_lock_init(&mdev->lock); | 706 | spin_lock_init(&mdev->lock); |
672 | mutex_init(&mdev->graph_mutex); | 707 | mutex_init(&mdev->graph_mutex); |
673 | ida_init(&mdev->entity_internal_idx); | 708 | ida_init(&mdev->entity_internal_idx); |
@@ -680,6 +715,7 @@ void media_device_cleanup(struct media_device *mdev) | |||
680 | { | 715 | { |
681 | ida_destroy(&mdev->entity_internal_idx); | 716 | ida_destroy(&mdev->entity_internal_idx); |
682 | mdev->entity_internal_idx_max = 0; | 717 | mdev->entity_internal_idx_max = 0; |
718 | media_entity_graph_walk_cleanup(&mdev->pm_count_walk); | ||
683 | mutex_destroy(&mdev->graph_mutex); | 719 | mutex_destroy(&mdev->graph_mutex); |
684 | } | 720 | } |
685 | EXPORT_SYMBOL_GPL(media_device_cleanup); | 721 | EXPORT_SYMBOL_GPL(media_device_cleanup); |
@@ -713,11 +749,40 @@ int __must_check __media_device_register(struct media_device *mdev, | |||
713 | } | 749 | } |
714 | EXPORT_SYMBOL_GPL(__media_device_register); | 750 | EXPORT_SYMBOL_GPL(__media_device_register); |
715 | 751 | ||
752 | int __must_check media_device_register_entity_notify(struct media_device *mdev, | ||
753 | struct media_entity_notify *nptr) | ||
754 | { | ||
755 | spin_lock(&mdev->lock); | ||
756 | list_add_tail(&nptr->list, &mdev->entity_notify); | ||
757 | spin_unlock(&mdev->lock); | ||
758 | return 0; | ||
759 | } | ||
760 | EXPORT_SYMBOL_GPL(media_device_register_entity_notify); | ||
761 | |||
762 | /* | ||
763 | * Note: Should be called with mdev->lock held. | ||
764 | */ | ||
765 | static void __media_device_unregister_entity_notify(struct media_device *mdev, | ||
766 | struct media_entity_notify *nptr) | ||
767 | { | ||
768 | list_del(&nptr->list); | ||
769 | } | ||
770 | |||
771 | void media_device_unregister_entity_notify(struct media_device *mdev, | ||
772 | struct media_entity_notify *nptr) | ||
773 | { | ||
774 | spin_lock(&mdev->lock); | ||
775 | __media_device_unregister_entity_notify(mdev, nptr); | ||
776 | spin_unlock(&mdev->lock); | ||
777 | } | ||
778 | EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); | ||
779 | |||
716 | void media_device_unregister(struct media_device *mdev) | 780 | void media_device_unregister(struct media_device *mdev) |
717 | { | 781 | { |
718 | struct media_entity *entity; | 782 | struct media_entity *entity; |
719 | struct media_entity *next; | 783 | struct media_entity *next; |
720 | struct media_interface *intf, *tmp_intf; | 784 | struct media_interface *intf, *tmp_intf; |
785 | struct media_entity_notify *notify, *nextp; | ||
721 | 786 | ||
722 | if (mdev == NULL) | 787 | if (mdev == NULL) |
723 | return; | 788 | return; |
@@ -734,6 +799,10 @@ void media_device_unregister(struct media_device *mdev) | |||
734 | list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) | 799 | list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) |
735 | __media_device_unregister_entity(entity); | 800 | __media_device_unregister_entity(entity); |
736 | 801 | ||
802 | /* Remove all entity_notify callbacks from the media device */ | ||
803 | list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) | ||
804 | __media_device_unregister_entity_notify(mdev, notify); | ||
805 | |||
737 | /* Remove all interfaces from the media device */ | 806 | /* Remove all interfaces from the media device */ |
738 | list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, | 807 | list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, |
739 | graph_obj.list) { | 808 | graph_obj.list) { |
@@ -777,4 +846,58 @@ struct media_device *media_device_find_devres(struct device *dev) | |||
777 | } | 846 | } |
778 | EXPORT_SYMBOL_GPL(media_device_find_devres); | 847 | EXPORT_SYMBOL_GPL(media_device_find_devres); |
779 | 848 | ||
849 | void media_device_pci_init(struct media_device *mdev, | ||
850 | struct pci_dev *pci_dev, | ||
851 | const char *name) | ||
852 | { | ||
853 | #ifdef CONFIG_PCI | ||
854 | mdev->dev = &pci_dev->dev; | ||
855 | |||
856 | if (name) | ||
857 | strlcpy(mdev->model, name, sizeof(mdev->model)); | ||
858 | else | ||
859 | strlcpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model)); | ||
860 | |||
861 | sprintf(mdev->bus_info, "PCI:%s", pci_name(pci_dev)); | ||
862 | |||
863 | mdev->hw_revision = (pci_dev->subsystem_vendor << 16) | ||
864 | | pci_dev->subsystem_device; | ||
865 | |||
866 | mdev->driver_version = LINUX_VERSION_CODE; | ||
867 | |||
868 | media_device_init(mdev); | ||
869 | #endif | ||
870 | } | ||
871 | EXPORT_SYMBOL_GPL(media_device_pci_init); | ||
872 | |||
873 | void __media_device_usb_init(struct media_device *mdev, | ||
874 | struct usb_device *udev, | ||
875 | const char *board_name, | ||
876 | const char *driver_name) | ||
877 | { | ||
878 | #ifdef CONFIG_USB | ||
879 | mdev->dev = &udev->dev; | ||
880 | |||
881 | if (driver_name) | ||
882 | strlcpy(mdev->driver_name, driver_name, | ||
883 | sizeof(mdev->driver_name)); | ||
884 | |||
885 | if (board_name) | ||
886 | strlcpy(mdev->model, board_name, sizeof(mdev->model)); | ||
887 | else if (udev->product) | ||
888 | strlcpy(mdev->model, udev->product, sizeof(mdev->model)); | ||
889 | else | ||
890 | strlcpy(mdev->model, "unknown model", sizeof(mdev->model)); | ||
891 | if (udev->serial) | ||
892 | strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial)); | ||
893 | usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info)); | ||
894 | mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); | ||
895 | mdev->driver_version = LINUX_VERSION_CODE; | ||
896 | |||
897 | media_device_init(mdev); | ||
898 | #endif | ||
899 | } | ||
900 | EXPORT_SYMBOL_GPL(__media_device_usb_init); | ||
901 | |||
902 | |||
780 | #endif /* CONFIG_MEDIA_CONTROLLER */ | 903 | #endif /* CONFIG_MEDIA_CONTROLLER */ |