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