[media] v4l2-mc: add an ancillary routine for PCI-based MC
[cascardo/linux.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);