GNU Linux-libre 4.19.263-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 const 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                 u32 function;
82
83                 v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
84                 strlcpy(entity->subdev.name, entity->name,
85                         sizeof(entity->subdev.name));
86
87                 switch (UVC_ENTITY_TYPE(entity)) {
88                 case UVC_VC_SELECTOR_UNIT:
89                         function = MEDIA_ENT_F_VID_MUX;
90                         break;
91                 case UVC_VC_PROCESSING_UNIT:
92                 case UVC_VC_EXTENSION_UNIT:
93                         /* For lack of a better option. */
94                         function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
95                         break;
96                 case UVC_COMPOSITE_CONNECTOR:
97                 case UVC_COMPONENT_CONNECTOR:
98                         function = MEDIA_ENT_F_CONN_COMPOSITE;
99                         break;
100                 case UVC_SVIDEO_CONNECTOR:
101                         function = MEDIA_ENT_F_CONN_SVIDEO;
102                         break;
103                 case UVC_ITT_CAMERA:
104                         function = MEDIA_ENT_F_CAM_SENSOR;
105                         break;
106                 case UVC_TT_VENDOR_SPECIFIC:
107                 case UVC_ITT_VENDOR_SPECIFIC:
108                 case UVC_ITT_MEDIA_TRANSPORT_INPUT:
109                 case UVC_OTT_VENDOR_SPECIFIC:
110                 case UVC_OTT_DISPLAY:
111                 case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
112                 case UVC_EXTERNAL_VENDOR_SPECIFIC:
113                 default:
114                         function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
115                         break;
116                 }
117
118                 entity->subdev.entity.function = function;
119
120                 ret = media_entity_pads_init(&entity->subdev.entity,
121                                         entity->num_pads, entity->pads);
122
123                 if (ret < 0)
124                         return ret;
125
126                 ret = v4l2_device_register_subdev(&chain->dev->vdev,
127                                                   &entity->subdev);
128         } else if (entity->vdev != NULL) {
129                 ret = media_entity_pads_init(&entity->vdev->entity,
130                                         entity->num_pads, entity->pads);
131                 if (entity->flags & UVC_ENTITY_FLAG_DEFAULT)
132                         entity->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
133         } else
134                 ret = 0;
135
136         return ret;
137 }
138
139 int uvc_mc_register_entities(struct uvc_video_chain *chain)
140 {
141         struct uvc_entity *entity;
142         int ret;
143
144         list_for_each_entry(entity, &chain->entities, chain) {
145                 ret = uvc_mc_init_entity(chain, entity);
146                 if (ret < 0) {
147                         uvc_printk(KERN_INFO, "Failed to initialize entity for "
148                                    "entity %u\n", entity->id);
149                         return ret;
150                 }
151         }
152
153         list_for_each_entry(entity, &chain->entities, chain) {
154                 ret = uvc_mc_create_links(chain, entity);
155                 if (ret < 0) {
156                         uvc_printk(KERN_INFO, "Failed to create links for "
157                                    "entity %u\n", entity->id);
158                         return ret;
159                 }
160         }
161
162         return 0;
163 }