blob: 643686d405514e51bf92702fe034870e1882ae3a [file] [log] [blame]
Mauro Carvalho Chehab54d0dba2016-02-05 07:02:43 -02001/*
2 * Media Controller ancillary functions
3 *
Mauro Carvalho Chehab41b44e32016-02-22 11:42:04 -03004 * Copyright (c) 2016 Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Shuah Khand0a164f2016-02-11 21:41:25 -02005 * Copyright (C) 2016 Shuah Khan <shuahkh@osg.samsung.com>
Mauro Carvalho Chehab54d0dba2016-02-05 07:02:43 -02006 *
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>
Shuah Khand0a164f2016-02-11 21:41:25 -020020#include <media/media-device.h>
21#include <media/v4l2-fh.h>
Mauro Carvalho Chehab54d0dba2016-02-05 07:02:43 -020022#include <media/v4l2-mc.h>
Shuah Khand0a164f2016-02-11 21:41:25 -020023#include <media/videobuf2-core.h>
Mauro Carvalho Chehab54d0dba2016-02-05 07:02:43 -020024
Mauro Carvalho Chehab54d0dba2016-02-05 07:02:43 -020025int v4l2_mc_create_media_graph(struct media_device *mdev)
26
27{
28 struct media_entity *entity;
Mauro Carvalho Chehab153d41a2016-02-12 08:07:59 -020029 struct media_entity *if_vid = NULL, *if_aud = NULL;
Mauro Carvalho Chehab54d0dba2016-02-05 07:02:43 -020030 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:
Mauro Carvalho Chehab54d0dba2016-02-05 07:02:43 -020063 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:
Mauro Carvalho Chehab54d0dba2016-02-05 07:02:43 -0200174 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}
188EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
Shuah Khand0a164f2016-02-11 21:41:25 -0200189
190int 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}
202EXPORT_SYMBOL_GPL(v4l_enable_media_source);
203
204void 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}
211EXPORT_SYMBOL_GPL(v4l_disable_media_source);
212
213int 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}
219EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);