643686d405514e51bf92702fe034870e1882ae3a
[deliverable/linux.git] / drivers / media / v4l2-core / v4l2-mc.c
1 /*
2 * Media Controller ancillary functions
3 *
4 * Copyright (c) 2016 Mauro Carvalho Chehab <mchehab@osg.samsung.com>
5 * Copyright (C) 2016 Shuah Khan <shuahkh@osg.samsung.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 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18 #include <linux/module.h>
19 #include <media/media-entity.h>
20 #include <media/media-device.h>
21 #include <media/v4l2-fh.h>
22 #include <media/v4l2-mc.h>
23 #include <media/videobuf2-core.h>
24
25 int v4l2_mc_create_media_graph(struct media_device *mdev)
26
27 {
28 struct media_entity *entity;
29 struct media_entity *if_vid = NULL, *if_aud = NULL;
30 struct media_entity *tuner = NULL, *decoder = NULL;
31 struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL;
32 bool is_webcam = false;
33 u32 flags;
34 int ret;
35
36 if (!mdev)
37 return 0;
38
39 media_device_for_each_entity(entity, mdev) {
40 switch (entity->function) {
41 case MEDIA_ENT_F_IF_VID_DECODER:
42 if_vid = entity;
43 break;
44 case MEDIA_ENT_F_IF_AUD_DECODER:
45 if_aud = entity;
46 break;
47 case MEDIA_ENT_F_TUNER:
48 tuner = entity;
49 break;
50 case MEDIA_ENT_F_ATV_DECODER:
51 decoder = entity;
52 break;
53 case MEDIA_ENT_F_IO_V4L:
54 io_v4l = entity;
55 break;
56 case MEDIA_ENT_F_IO_VBI:
57 io_vbi = entity;
58 break;
59 case MEDIA_ENT_F_IO_SWRADIO:
60 io_swradio = entity;
61 break;
62 case MEDIA_ENT_F_CAM_SENSOR:
63 is_webcam = true;
64 break;
65 }
66 }
67
68 /* It should have at least one I/O entity */
69 if (!io_v4l && !io_vbi && !io_swradio)
70 return -EINVAL;
71
72 /*
73 * Here, webcams are modelled on a very simple way: the sensor is
74 * connected directly to the I/O entity. All dirty details, like
75 * scaler and crop HW are hidden. While such mapping is not enough
76 * for mc-centric hardware, it is enough for v4l2 interface centric
77 * PC-consumer's hardware.
78 */
79 if (is_webcam) {
80 if (!io_v4l)
81 return -EINVAL;
82
83 media_device_for_each_entity(entity, mdev) {
84 if (entity->function != MEDIA_ENT_F_CAM_SENSOR)
85 continue;
86 ret = media_create_pad_link(entity, 0,
87 io_v4l, 0,
88 MEDIA_LNK_FL_ENABLED);
89 if (ret)
90 return ret;
91 }
92 if (!decoder)
93 return 0;
94 }
95
96 /* The device isn't a webcam. So, it should have a decoder */
97 if (!decoder)
98 return -EINVAL;
99
100 /* Link the tuner and IF video output pads */
101 if (tuner) {
102 if (if_vid) {
103 ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
104 if_vid,
105 IF_VID_DEC_PAD_IF_INPUT,
106 MEDIA_LNK_FL_ENABLED);
107 if (ret)
108 return ret;
109 ret = media_create_pad_link(if_vid, IF_VID_DEC_PAD_OUT,
110 decoder, DEMOD_PAD_IF_INPUT,
111 MEDIA_LNK_FL_ENABLED);
112 if (ret)
113 return ret;
114 } else {
115 ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
116 decoder, DEMOD_PAD_IF_INPUT,
117 MEDIA_LNK_FL_ENABLED);
118 if (ret)
119 return ret;
120 }
121
122 if (if_aud) {
123 ret = media_create_pad_link(tuner, TUNER_PAD_AUD_OUT,
124 if_aud,
125 IF_AUD_DEC_PAD_IF_INPUT,
126 MEDIA_LNK_FL_ENABLED);
127 if (ret)
128 return ret;
129 } else {
130 if_aud = tuner;
131 }
132
133 }
134
135 /* Create demod to V4L, VBI and SDR radio links */
136 if (io_v4l) {
137 ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
138 io_v4l, 0,
139 MEDIA_LNK_FL_ENABLED);
140 if (ret)
141 return ret;
142 }
143
144 if (io_swradio) {
145 ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
146 io_swradio, 0,
147 MEDIA_LNK_FL_ENABLED);
148 if (ret)
149 return ret;
150 }
151
152 if (io_vbi) {
153 ret = media_create_pad_link(decoder, DEMOD_PAD_VBI_OUT,
154 io_vbi, 0,
155 MEDIA_LNK_FL_ENABLED);
156 if (ret)
157 return ret;
158 }
159
160 /* Create links for the media connectors */
161 flags = MEDIA_LNK_FL_ENABLED;
162 media_device_for_each_entity(entity, mdev) {
163 switch (entity->function) {
164 case MEDIA_ENT_F_CONN_RF:
165 if (!tuner)
166 continue;
167
168 ret = media_create_pad_link(entity, 0, tuner,
169 TUNER_PAD_RF_INPUT,
170 flags);
171 break;
172 case MEDIA_ENT_F_CONN_SVIDEO:
173 case MEDIA_ENT_F_CONN_COMPOSITE:
174 ret = media_create_pad_link(entity, 0, decoder,
175 DEMOD_PAD_IF_INPUT,
176 flags);
177 break;
178 default:
179 continue;
180 }
181 if (ret)
182 return ret;
183
184 flags = 0;
185 }
186 return 0;
187 }
188 EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
189
190 int v4l_enable_media_source(struct video_device *vdev)
191 {
192 struct media_device *mdev = vdev->entity.graph_obj.mdev;
193 int ret;
194
195 if (!mdev || !mdev->enable_source)
196 return 0;
197 ret = mdev->enable_source(&vdev->entity, &vdev->pipe);
198 if (ret)
199 return -EBUSY;
200 return 0;
201 }
202 EXPORT_SYMBOL_GPL(v4l_enable_media_source);
203
204 void v4l_disable_media_source(struct video_device *vdev)
205 {
206 struct media_device *mdev = vdev->entity.graph_obj.mdev;
207
208 if (mdev && mdev->disable_source)
209 mdev->disable_source(&vdev->entity);
210 }
211 EXPORT_SYMBOL_GPL(v4l_disable_media_source);
212
213 int v4l_vb2q_enable_media_source(struct vb2_queue *q)
214 {
215 struct v4l2_fh *fh = q->owner;
216
217 return v4l_enable_media_source(fh->vdev);
218 }
219 EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
This page took 0.033771 seconds and 4 git commands to generate.