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 <linux/usb.h> 20 #include <media/media-entity.h> 21 #include <media/v4l2-mc.h> 22 23 24 struct media_device *v4l2_mc_pci_media_device_init(struct pci_dev *pci_dev, 25 const char *name) 26 { 27 #ifdef CONFIG_PCI 28 struct media_device *mdev; 29 30 mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 31 if (!mdev) 32 return NULL; 33 34 mdev->dev = &pci_dev->dev; 35 36 if (name) 37 strlcpy(mdev->model, name, sizeof(mdev->model)); 38 else 39 strlcpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model)); 40 41 sprintf(mdev->bus_info, "PCI:%s", pci_name(pci_dev)); 42 43 mdev->hw_revision = pci_dev->subsystem_vendor << 16 44 || pci_dev->subsystem_device; 45 46 mdev->driver_version = LINUX_VERSION_CODE; 47 48 media_device_init(mdev); 49 50 return mdev; 51 #else 52 return NULL; 53 #endif 54 } 55 EXPORT_SYMBOL_GPL(v4l2_mc_pci_media_device_init); 56 57 struct media_device *__v4l2_mc_usb_media_device_init(struct usb_device *udev, 58 const char *board_name, 59 const char *driver_name) 60 { 61 #ifdef CONFIG_USB 62 struct media_device *mdev; 63 64 mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 65 if (!mdev) 66 return NULL; 67 68 mdev->dev = &udev->dev; 69 70 if (driver_name) 71 strlcpy(mdev->driver_name, driver_name, 72 sizeof(mdev->driver_name)); 73 74 if (board_name) 75 strlcpy(mdev->model, board_name, sizeof(mdev->model)); 76 else if (udev->product) 77 strlcpy(mdev->model, udev->product, sizeof(mdev->model)); 78 else 79 strlcpy(mdev->model, "unknown model", sizeof(mdev->model)); 80 if (udev->serial) 81 strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial)); 82 usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info)); 83 mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); 84 mdev->driver_version = LINUX_VERSION_CODE; 85 86 media_device_init(mdev); 87 88 return mdev; 89 #else 90 return NULL; 91 #endif 92 } 93 EXPORT_SYMBOL_GPL(__v4l2_mc_usb_media_device_init); 94 95 int v4l2_mc_create_media_graph(struct media_device *mdev) 96 97 { 98 struct media_entity *entity; 99 struct media_entity *if_vid = NULL, *if_aud = NULL; 100 struct media_entity *tuner = NULL, *decoder = NULL; 101 struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL; 102 bool is_webcam = false; 103 u32 flags; 104 int ret; 105 106 if (!mdev) 107 return 0; 108 109 media_device_for_each_entity(entity, mdev) { 110 switch (entity->function) { 111 case MEDIA_ENT_F_IF_VID_DECODER: 112 if_vid = entity; 113 break; 114 case MEDIA_ENT_F_IF_AUD_DECODER: 115 if_aud = entity; 116 break; 117 case MEDIA_ENT_F_TUNER: 118 tuner = entity; 119 break; 120 case MEDIA_ENT_F_ATV_DECODER: 121 decoder = entity; 122 break; 123 case MEDIA_ENT_F_IO_V4L: 124 io_v4l = entity; 125 break; 126 case MEDIA_ENT_F_IO_VBI: 127 io_vbi = entity; 128 break; 129 case MEDIA_ENT_F_IO_SWRADIO: 130 io_swradio = entity; 131 break; 132 case MEDIA_ENT_F_CAM_SENSOR: 133 is_webcam = true; 134 break; 135 } 136 } 137 138 /* It should have at least one I/O entity */ 139 if (!io_v4l && !io_vbi && !io_swradio) 140 return -EINVAL; 141 142 /* 143 * Here, webcams are modelled on a very simple way: the sensor is 144 * connected directly to the I/O entity. All dirty details, like 145 * scaler and crop HW are hidden. While such mapping is not enough 146 * for mc-centric hardware, it is enough for v4l2 interface centric 147 * PC-consumer's hardware. 148 */ 149 if (is_webcam) { 150 if (!io_v4l) 151 return -EINVAL; 152 153 media_device_for_each_entity(entity, mdev) { 154 if (entity->function != MEDIA_ENT_F_CAM_SENSOR) 155 continue; 156 ret = media_create_pad_link(entity, 0, 157 io_v4l, 0, 158 MEDIA_LNK_FL_ENABLED); 159 if (ret) 160 return ret; 161 } 162 if (!decoder) 163 return 0; 164 } 165 166 /* The device isn't a webcam. So, it should have a decoder */ 167 if (!decoder) 168 return -EINVAL; 169 170 /* Link the tuner and IF video output pads */ 171 if (tuner) { 172 if (if_vid) { 173 ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT, 174 if_vid, 175 IF_VID_DEC_PAD_IF_INPUT, 176 MEDIA_LNK_FL_ENABLED); 177 if (ret) 178 return ret; 179 ret = media_create_pad_link(if_vid, IF_VID_DEC_PAD_OUT, 180 decoder, DEMOD_PAD_IF_INPUT, 181 MEDIA_LNK_FL_ENABLED); 182 if (ret) 183 return ret; 184 } else { 185 ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT, 186 decoder, DEMOD_PAD_IF_INPUT, 187 MEDIA_LNK_FL_ENABLED); 188 if (ret) 189 return ret; 190 } 191 192 if (if_aud) { 193 ret = media_create_pad_link(tuner, TUNER_PAD_AUD_OUT, 194 if_aud, 195 IF_AUD_DEC_PAD_IF_INPUT, 196 MEDIA_LNK_FL_ENABLED); 197 if (ret) 198 return ret; 199 } else { 200 if_aud = tuner; 201 } 202 203 } 204 205 /* Create demod to V4L, VBI and SDR radio links */ 206 if (io_v4l) { 207 ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT, 208 io_v4l, 0, 209 MEDIA_LNK_FL_ENABLED); 210 if (ret) 211 return ret; 212 } 213 214 if (io_swradio) { 215 ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT, 216 io_swradio, 0, 217 MEDIA_LNK_FL_ENABLED); 218 if (ret) 219 return ret; 220 } 221 222 if (io_vbi) { 223 ret = media_create_pad_link(decoder, DEMOD_PAD_VBI_OUT, 224 io_vbi, 0, 225 MEDIA_LNK_FL_ENABLED); 226 if (ret) 227 return ret; 228 } 229 230 /* Create links for the media connectors */ 231 flags = MEDIA_LNK_FL_ENABLED; 232 media_device_for_each_entity(entity, mdev) { 233 switch (entity->function) { 234 case MEDIA_ENT_F_CONN_RF: 235 if (!tuner) 236 continue; 237 238 ret = media_create_pad_link(entity, 0, tuner, 239 TUNER_PAD_RF_INPUT, 240 flags); 241 break; 242 case MEDIA_ENT_F_CONN_SVIDEO: 243 case MEDIA_ENT_F_CONN_COMPOSITE: 244 case MEDIA_ENT_F_CONN_TEST: 245 ret = media_create_pad_link(entity, 0, decoder, 246 DEMOD_PAD_IF_INPUT, 247 flags); 248 break; 249 default: 250 continue; 251 } 252 if (ret) 253 return ret; 254 255 flags = 0; 256 } 257 return 0; 258 } 259 EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph); 260