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); 222