GNU Linux-libre 4.9.294-gnu1
[releases.git] / drivers / media / usb / uvc / uvc_entity.c
1 /*
2  *      uvc_entity.c  --  USB Video Class driver
3  *
4  *      Copyright (C) 2005-2011
5  *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
6  *
7  *      This program is free software; you can redistribute it and/or modify
8  *      it under the terms of the GNU General Public License as published by
9  *      the Free Software Foundation; either version 2 of the License, or
10  *      (at your option) any later version.
11  *
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/list.h>
16 #include <linux/videodev2.h>
17
18 #include <media/v4l2-common.h>
19
20 #include "uvcvideo.h"
21
22 static int uvc_mc_create_links(struct uvc_video_chain *chain,
23                                     struct uvc_entity *entity)
24 {
25         const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
26         struct media_entity *sink;
27         unsigned int i;
28         int ret;
29
30         sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
31              ? (entity->vdev ? &entity->vdev->entity : NULL)
32              : &entity->subdev.entity;
33         if (sink == NULL)
34                 return 0;
35
36         for (i = 0; i < entity->num_pads; ++i) {
37                 struct media_entity *source;
38                 struct uvc_entity *remote;
39                 u8 remote_pad;
40
41                 if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK))
42                         continue;
43
44                 remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]);
45                 if (remote == NULL)
46                         return -EINVAL;
47
48                 source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
49                        ? (remote->vdev ? &remote->vdev->entity : NULL)
50                        : &remote->subdev.entity;
51                 if (source == NULL)
52                         continue;
53
54                 remote_pad = remote->num_pads - 1;
55                 ret = media_create_pad_link(source, remote_pad,
56                                                sink, i, flags);
57                 if (ret < 0)
58                         return ret;
59         }
60
61         return 0;
62 }
63
64 static struct v4l2_subdev_ops uvc_subdev_ops = {
65 };
66
67 void uvc_mc_cleanup_entity(struct uvc_entity *entity)
68 {
69         if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
70                 media_entity_cleanup(&entity->subdev.entity);
71         else if (entity->vdev != NULL)
72                 media_entity_cleanup(&entity->vdev->entity);
73 }
74
75 static int uvc_mc_init_entity(struct uvc_video_chain *chain,
76                               struct uvc_entity *entity)
77 {
78         int ret;
79
80         if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
81                 v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
82                 strlcpy(entity->subdev.name, entity->name,
83                         sizeof(entity->subdev.name));
84
85                 ret = media_entity_pads_init(&entity->subdev.entity,
86                                         entity->num_pads, entity->pads);
87
88                 if (ret < 0)
89                         return ret;
90
91                 ret = v4l2_device_register_subdev(&chain->dev->vdev,
92                                                   &entity->subdev);
93         } else if (entity->vdev != NULL) {
94                 ret = media_entity_pads_init(&entity->vdev->entity,
95                                         entity->num_pads, entity->pads);
96                 if (entity->flags & UVC_ENTITY_FLAG_DEFAULT)
97                         entity->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
98         } else
99                 ret = 0;
100
101         return ret;
102 }
103
104 int uvc_mc_register_entities(struct uvc_video_chain *chain)
105 {
106         struct uvc_entity *entity;
107         int ret;
108
109         list_for_each_entry(entity, &chain->entities, chain) {
110                 ret = uvc_mc_init_entity(chain, entity);
111                 if (ret < 0) {
112                         uvc_printk(KERN_INFO, "Failed to initialize entity for "
113                                    "entity %u\n", entity->id);
114                         return ret;
115                 }
116         }
117
118         list_for_each_entry(entity, &chain->entities, chain) {
119                 ret = uvc_mc_create_links(chain, entity);
120                 if (ret < 0) {
121                         uvc_printk(KERN_INFO, "Failed to create links for "
122                                    "entity %u\n", entity->id);
123                         return ret;
124                 }
125         }
126
127         return 0;
128 }