1 /* 2 * media.c - Media Controller specific ALSA driver code 3 * 4 * Copyright (c) 2016 Shuah Khan <shuahkh@osg.samsung.com> 5 * Copyright (c) 2016 Samsung Electronics Co., Ltd. 6 * 7 * This file is released under the GPLv2. 8 */ 9 10 /* 11 * This file adds Media Controller support to ALSA driver 12 * to use the Media Controller API to share tuner with DVB 13 * and V4L2 drivers that control media device. Media device 14 * is created based on existing quirks framework. Using this 15 * approach, the media controller API usage can be added for 16 * a specific device. 17 */ 18 19 #include <linux/init.h> 20 #include <linux/list.h> 21 #include <linux/mutex.h> 22 #include <linux/slab.h> 23 #include <linux/usb.h> 24 25 #include <sound/pcm.h> 26 #include <sound/core.h> 27 28 #include "usbaudio.h" 29 #include "card.h" 30 #include "mixer.h" 31 #include "media.h" 32 33 static int media_snd_enable_source(struct media_ctl *mctl) 34 { 35 if (mctl && mctl->media_dev->enable_source) 36 return mctl->media_dev->enable_source(&mctl->media_entity, 37 &mctl->media_pipe); 38 return 0; 39 } 40 41 static void media_snd_disable_source(struct media_ctl *mctl) 42 { 43 if (mctl && mctl->media_dev->disable_source) 44 mctl->media_dev->disable_source(&mctl->media_entity); 45 } 46 47 int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm, 48 int stream) 49 { 50 struct media_device *mdev; 51 struct media_ctl *mctl; 52 struct device *pcm_dev = &pcm->streams[stream].dev; 53 u32 intf_type; 54 int ret = 0; 55 u16 mixer_pad; 56 struct media_entity *entity; 57 58 mdev = subs->stream->chip->media_dev; 59 if (!mdev) 60 return -ENODEV; 61 62 if (subs->media_ctl) 63 return 0; 64 65 /* allocate media_ctl */ 66 mctl = kzalloc(sizeof(*mctl), GFP_KERNEL); 67 if (!mctl) 68 return -ENOMEM; 69 70 mctl->media_dev = mdev; 71 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 72 intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK; 73 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK; 74 mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE; 75 mixer_pad = 1; 76 } else { 77 intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE; 78 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE; 79 mctl->media_pad.flags = MEDIA_PAD_FL_SINK; 80 mixer_pad = 2; 81 } 82 mctl->media_entity.name = pcm->name; 83 media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad); 84 ret = media_device_register_entity(mctl->media_dev, 85 &mctl->media_entity); 86 if (ret) 87 goto err1; 88 89 mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0, 90 MAJOR(pcm_dev->devt), 91 MINOR(pcm_dev->devt)); 92 if (!mctl->intf_devnode) { 93 ret = -ENOMEM; 94 goto err2; 95 } 96 mctl->intf_link = media_create_intf_link(&mctl->media_entity, 97 &mctl->intf_devnode->intf, 98 MEDIA_LNK_FL_ENABLED); 99 if (!mctl->intf_link) { 100 ret = -ENOMEM; 101 goto err3; 102 } 103 104 /* create link between mixer and audio */ 105 media_device_for_each_entity(entity, mdev) { 106 switch (entity->function) { 107 case MEDIA_ENT_F_AUDIO_MIXER: 108 ret = media_create_pad_link(entity, mixer_pad, 109 &mctl->media_entity, 0, 110 MEDIA_LNK_FL_ENABLED); 111 if (ret) 112 goto err4; 113 break; 114 } 115 } 116 117 subs->media_ctl = mctl; 118 return 0; 119 120 err4: 121 media_remove_intf_link(mctl->intf_link); 122 err3: 123 media_devnode_remove(mctl->intf_devnode); 124 err2: 125 media_device_unregister_entity(&mctl->media_entity); 126 err1: 127 kfree(mctl); 128 return ret; 129 } 130 131 void media_snd_stream_delete(struct snd_usb_substream *subs) 132 { 133 struct media_ctl *mctl = subs->media_ctl; 134 135 if (mctl && mctl->media_dev) { 136 struct media_device *mdev; 137 138 mdev = subs->stream->chip->media_dev; 139 if (mdev && media_devnode_is_registered(&mdev->devnode)) { 140 media_devnode_remove(mctl->intf_devnode); 141 media_device_unregister_entity(&mctl->media_entity); 142 media_entity_cleanup(&mctl->media_entity); 143 } 144 kfree(mctl); 145 subs->media_ctl = NULL; 146 } 147 } 148 149 int media_snd_start_pipeline(struct snd_usb_substream *subs) 150 { 151 struct media_ctl *mctl = subs->media_ctl; 152 153 if (mctl) 154 return media_snd_enable_source(mctl); 155 return 0; 156 } 157 158 void media_snd_stop_pipeline(struct snd_usb_substream *subs) 159 { 160 struct media_ctl *mctl = subs->media_ctl; 161 162 if (mctl) 163 media_snd_disable_source(mctl); 164 } 165 166 int media_snd_mixer_init(struct snd_usb_audio *chip) 167 { 168 struct device *ctl_dev = &chip->card->ctl_dev; 169 struct media_intf_devnode *ctl_intf; 170 struct usb_mixer_interface *mixer; 171 struct media_device *mdev = chip->media_dev; 172 struct media_mixer_ctl *mctl; 173 u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL; 174 int ret; 175 176 if (!mdev) 177 return -ENODEV; 178 179 ctl_intf = chip->ctl_intf_media_devnode; 180 if (!ctl_intf) { 181 ctl_intf = media_devnode_create(mdev, intf_type, 0, 182 MAJOR(ctl_dev->devt), 183 MINOR(ctl_dev->devt)); 184 if (!ctl_intf) 185 return -ENOMEM; 186 chip->ctl_intf_media_devnode = ctl_intf; 187 } 188 189 list_for_each_entry(mixer, &chip->mixer_list, list) { 190 191 if (mixer->media_mixer_ctl) 192 continue; 193 194 /* allocate media_mixer_ctl */ 195 mctl = kzalloc(sizeof(*mctl), GFP_KERNEL); 196 if (!mctl) 197 return -ENOMEM; 198 199 mctl->media_dev = mdev; 200 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER; 201 mctl->media_entity.name = chip->card->mixername; 202 mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK; 203 mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE; 204 mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE; 205 media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX, 206 mctl->media_pad); 207 ret = media_device_register_entity(mctl->media_dev, 208 &mctl->media_entity); 209 if (ret) { 210 kfree(mctl); 211 return ret; 212 } 213 214 mctl->intf_link = media_create_intf_link(&mctl->media_entity, 215 &ctl_intf->intf, 216 MEDIA_LNK_FL_ENABLED); 217 if (!mctl->intf_link) { 218 media_device_unregister_entity(&mctl->media_entity); 219 media_entity_cleanup(&mctl->media_entity); 220 kfree(mctl); 221 return -ENOMEM; 222 } 223 mctl->intf_devnode = ctl_intf; 224 mixer->media_mixer_ctl = mctl; 225 } 226 return 0; 227 } 228 229 static void media_snd_mixer_delete(struct snd_usb_audio *chip) 230 { 231 struct usb_mixer_interface *mixer; 232 struct media_device *mdev = chip->media_dev; 233 234 if (!mdev) 235 return; 236 237 list_for_each_entry(mixer, &chip->mixer_list, list) { 238 struct media_mixer_ctl *mctl; 239 240 mctl = mixer->media_mixer_ctl; 241 if (!mixer->media_mixer_ctl) 242 continue; 243 244 if (media_devnode_is_registered(&mdev->devnode)) { 245 media_device_unregister_entity(&mctl->media_entity); 246 media_entity_cleanup(&mctl->media_entity); 247 } 248 kfree(mctl); 249 mixer->media_mixer_ctl = NULL; 250 } 251 if (media_devnode_is_registered(&mdev->devnode)) 252 media_devnode_remove(chip->ctl_intf_media_devnode); 253 chip->ctl_intf_media_devnode = NULL; 254 } 255 256 int media_snd_device_create(struct snd_usb_audio *chip, 257 struct usb_interface *iface) 258 { 259 struct media_device *mdev; 260 struct usb_device *usbdev = interface_to_usbdev(iface); 261 int ret; 262 263 mdev = media_device_get_devres(&usbdev->dev); 264 if (!mdev) 265 return -ENOMEM; 266 if (!mdev->dev) { 267 /* register media device */ 268 mdev->dev = &usbdev->dev; 269 if (usbdev->product) 270 strlcpy(mdev->model, usbdev->product, 271 sizeof(mdev->model)); 272 if (usbdev->serial) 273 strlcpy(mdev->serial, usbdev->serial, 274 sizeof(mdev->serial)); 275 strcpy(mdev->bus_info, usbdev->devpath); 276 mdev->hw_revision = le16_to_cpu(usbdev->descriptor.bcdDevice); 277 media_device_init(mdev); 278 } 279 if (!media_devnode_is_registered(&mdev->devnode)) { 280 ret = media_device_register(mdev); 281 if (ret) { 282 dev_err(&usbdev->dev, 283 "Couldn't register media device. Error: %d\n", 284 ret); 285 return ret; 286 } 287 } 288 289 /* save media device - avoid lookups */ 290 chip->media_dev = mdev; 291 292 /* Create media entities for mixer and control dev */ 293 ret = media_snd_mixer_init(chip); 294 if (ret) { 295 dev_err(&usbdev->dev, 296 "Couldn't create media mixer entities. Error: %d\n", 297 ret); 298 299 /* clear saved media_dev */ 300 chip->media_dev = NULL; 301 302 return ret; 303 } 304 return 0; 305 } 306 307 void media_snd_device_delete(struct snd_usb_audio *chip) 308 { 309 struct media_device *mdev = chip->media_dev; 310 311 media_snd_mixer_delete(chip); 312 313 if (mdev) { 314 if (media_devnode_is_registered(&mdev->devnode)) 315 media_device_unregister(mdev); 316 chip->media_dev = NULL; 317 } 318 } 319