[media] v4l2-core: create MC interfaces for devnodes
authorMauro Carvalho Chehab <mchehab@osg.samsung.com>
Mon, 24 Aug 2015 11:47:54 +0000 (08:47 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Mon, 11 Jan 2016 14:18:57 +0000 (12:18 -0200)
V4L2 device (and subdevice) nodes should create an interface, if the
Media Controller support is enabled.

Please notice that radio devices should not create an entity, as radio
input/output is either via wires or via ALSA.

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-device.c
include/media/v4l2-dev.h

index 2297571a0568a8fa13a5e125a169b1c79427d291..077cdc92778cd054a08f9771223e64d8d1803953 100644 (file)
@@ -194,9 +194,12 @@ static void v4l2_device_release(struct device *cd)
        mutex_unlock(&videodev_lock);
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
-       if (v4l2_dev->mdev &&
-           vdev->vfl_type != VFL_TYPE_SUBDEV)
-               media_device_unregister_entity(&vdev->entity);
+       if (v4l2_dev->mdev) {
+               /* Remove interfaces and interface links */
+               media_devnode_remove(vdev->intf_devnode);
+               if (vdev->entity.type != MEDIA_ENT_T_UNKNOWN)
+                       media_device_unregister_entity(&vdev->entity);
+       }
 #endif
 
        /* Do not call v4l2_device_put if there is no release callback set.
@@ -723,6 +726,91 @@ static void determine_valid_ioctls(struct video_device *vdev)
                        BASE_VIDIOC_PRIVATE);
 }
 
+static int video_register_media_controller(struct video_device *vdev, int type)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       u32 intf_type;
+       int ret;
+
+       if (!vdev->v4l2_dev->mdev)
+               return 0;
+
+       vdev->entity.type = MEDIA_ENT_T_UNKNOWN;
+
+       switch (type) {
+       case VFL_TYPE_GRABBER:
+               intf_type = MEDIA_INTF_T_V4L_VIDEO;
+               vdev->entity.type = MEDIA_ENT_T_V4L2_VIDEO;
+               break;
+       case VFL_TYPE_VBI:
+               intf_type = MEDIA_INTF_T_V4L_VBI;
+               vdev->entity.type = MEDIA_ENT_T_V4L2_VBI;
+               break;
+       case VFL_TYPE_SDR:
+               intf_type = MEDIA_INTF_T_V4L_SWRADIO;
+               vdev->entity.type = MEDIA_ENT_T_V4L2_SWRADIO;
+               break;
+       case VFL_TYPE_RADIO:
+               intf_type = MEDIA_INTF_T_V4L_RADIO;
+               /*
+                * Radio doesn't have an entity at the V4L2 side to represent
+                * radio input or output. Instead, the audio input/output goes
+                * via either physical wires or ALSA.
+                */
+               break;
+       case VFL_TYPE_SUBDEV:
+               intf_type = MEDIA_INTF_T_V4L_SUBDEV;
+               /* Entity will be created via v4l2_device_register_subdev() */
+               break;
+       default:
+               return 0;
+       }
+
+       if (vdev->entity.type != MEDIA_ENT_T_UNKNOWN) {
+               vdev->entity.name = vdev->name;
+
+               /* Needed just for backward compatibility with legacy MC API */
+               vdev->entity.info.dev.major = VIDEO_MAJOR;
+               vdev->entity.info.dev.minor = vdev->minor;
+
+               ret = media_device_register_entity(vdev->v4l2_dev->mdev,
+                                                  &vdev->entity);
+               if (ret < 0) {
+                       printk(KERN_WARNING
+                               "%s: media_device_register_entity failed\n",
+                               __func__);
+                       return ret;
+               }
+       }
+
+       vdev->intf_devnode = media_devnode_create(vdev->v4l2_dev->mdev,
+                                                 intf_type,
+                                                 0, VIDEO_MAJOR,
+                                                 vdev->minor,
+                                                 GFP_KERNEL);
+       if (!vdev->intf_devnode) {
+               media_device_unregister_entity(&vdev->entity);
+               return -ENOMEM;
+       }
+
+       if (vdev->entity.type != MEDIA_ENT_T_UNKNOWN) {
+               struct media_link *link;
+
+               link = media_create_intf_link(&vdev->entity,
+                                             &vdev->intf_devnode->intf, 0);
+               if (!link) {
+                       media_devnode_remove(vdev->intf_devnode);
+                       media_device_unregister_entity(&vdev->entity);
+                       return -ENOMEM;
+               }
+       }
+
+       /* FIXME: how to create the other interface links? */
+
+#endif
+       return 0;
+}
+
 /**
  *     __video_register_device - register video4linux devices
  *     @vdev: video device structure we want to register
@@ -918,22 +1006,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
        /* Increase v4l2_device refcount */
        v4l2_device_get(vdev->v4l2_dev);
 
-#if defined(CONFIG_MEDIA_CONTROLLER)
        /* Part 5: Register the entity. */
-       if (vdev->v4l2_dev->mdev &&
-           vdev->vfl_type != VFL_TYPE_SUBDEV) {
-               vdev->entity.type = MEDIA_ENT_T_V4L2_VIDEO;
-               vdev->entity.name = vdev->name;
-               vdev->entity.info.dev.major = VIDEO_MAJOR;
-               vdev->entity.info.dev.minor = vdev->minor;
-               ret = media_device_register_entity(vdev->v4l2_dev->mdev,
-                       &vdev->entity);
-               if (ret < 0)
-                       printk(KERN_WARNING
-                              "%s: media_device_register_entity failed\n",
-                              __func__);
-       }
-#endif
+       ret = video_register_media_controller(vdev, type);
+
        /* Part 6: Activate this minor. The char device can now be used. */
        set_bit(V4L2_FL_REGISTERED, &vdev->flags);
 
index 7129e438f29e776fa7ff2a72a0ee4873ababdc94..3c87307e56f08ecffdda2f320416178b4b7ae5b2 100644 (file)
@@ -258,6 +258,17 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
 #if defined(CONFIG_MEDIA_CONTROLLER)
                sd->entity.info.dev.major = VIDEO_MAJOR;
                sd->entity.info.dev.minor = vdev->minor;
+
+               /* Interface is created by __video_register_device() */
+               if (vdev->v4l2_dev->mdev) {
+                       struct media_link *link;
+
+                       link = media_create_intf_link(&sd->entity,
+                                                     &vdev->intf_devnode->intf,
+                                                     0);
+                       if (!link)
+                               goto clean_up;
+               }
 #endif
                sd->devnode = vdev;
        }
@@ -294,7 +305,10 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
        if (v4l2_dev->mdev) {
-               media_entity_remove_links(&sd->entity);
+               /*
+                * No need to explicitly remove links, as both pads and
+                * links are removed by the function below, in the right order
+                */
                media_device_unregister_entity(&sd->entity);
        }
 #endif
index acbcd2f5fe7f8167b053ac5d6c7fa747f1cbef9b..eeabf20e87a66d5c4306e059c15d277d17cea9a7 100644 (file)
@@ -86,6 +86,7 @@ struct video_device
 {
 #if defined(CONFIG_MEDIA_CONTROLLER)
        struct media_entity entity;
+       struct media_intf_devnode *intf_devnode;
 #endif
        /* device ops */
        const struct v4l2_file_operations *fops;