root/sound/usb/media.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_media_stream_init
  2. snd_media_stream_delete
  3. snd_media_start_pipeline
  4. snd_media_stop_pipeline
  5. snd_media_mixer_init
  6. snd_media_mixer_delete
  7. snd_media_device_create
  8. snd_media_device_delete

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * media.c - Media Controller specific ALSA driver code
   4  *
   5  * Copyright (c) 2019 Shuah Khan <shuah@kernel.org>
   6  *
   7  */
   8 
   9 /*
  10  * This file adds Media Controller support to the ALSA driver
  11  * to use the Media Controller API to share the tuner with DVB
  12  * and V4L2 drivers that control the media device.
  13  *
  14  * The media device is created based on the existing quirks framework.
  15  * Using this 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 int snd_media_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm,
  34                           int stream)
  35 {
  36         struct media_device *mdev;
  37         struct media_ctl *mctl;
  38         struct device *pcm_dev = &pcm->streams[stream].dev;
  39         u32 intf_type;
  40         int ret = 0;
  41         u16 mixer_pad;
  42         struct media_entity *entity;
  43 
  44         mdev = subs->stream->chip->media_dev;
  45         if (!mdev)
  46                 return 0;
  47 
  48         if (subs->media_ctl)
  49                 return 0;
  50 
  51         /* allocate media_ctl */
  52         mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
  53         if (!mctl)
  54                 return -ENOMEM;
  55 
  56         mctl->media_dev = mdev;
  57         if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
  58                 intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK;
  59                 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK;
  60                 mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE;
  61                 mixer_pad = 1;
  62         } else {
  63                 intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE;
  64                 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE;
  65                 mctl->media_pad.flags = MEDIA_PAD_FL_SINK;
  66                 mixer_pad = 2;
  67         }
  68         mctl->media_entity.name = pcm->name;
  69         media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad);
  70         ret =  media_device_register_entity(mctl->media_dev,
  71                                             &mctl->media_entity);
  72         if (ret)
  73                 goto free_mctl;
  74 
  75         mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0,
  76                                                   MAJOR(pcm_dev->devt),
  77                                                   MINOR(pcm_dev->devt));
  78         if (!mctl->intf_devnode) {
  79                 ret = -ENOMEM;
  80                 goto unregister_entity;
  81         }
  82         mctl->intf_link = media_create_intf_link(&mctl->media_entity,
  83                                                  &mctl->intf_devnode->intf,
  84                                                  MEDIA_LNK_FL_ENABLED);
  85         if (!mctl->intf_link) {
  86                 ret = -ENOMEM;
  87                 goto devnode_remove;
  88         }
  89 
  90         /* create link between mixer and audio */
  91         media_device_for_each_entity(entity, mdev) {
  92                 switch (entity->function) {
  93                 case MEDIA_ENT_F_AUDIO_MIXER:
  94                         ret = media_create_pad_link(entity, mixer_pad,
  95                                                     &mctl->media_entity, 0,
  96                                                     MEDIA_LNK_FL_ENABLED);
  97                         if (ret)
  98                                 goto remove_intf_link;
  99                         break;
 100                 }
 101         }
 102 
 103         subs->media_ctl = mctl;
 104         return 0;
 105 
 106 remove_intf_link:
 107         media_remove_intf_link(mctl->intf_link);
 108 devnode_remove:
 109         media_devnode_remove(mctl->intf_devnode);
 110 unregister_entity:
 111         media_device_unregister_entity(&mctl->media_entity);
 112 free_mctl:
 113         kfree(mctl);
 114         return ret;
 115 }
 116 
 117 void snd_media_stream_delete(struct snd_usb_substream *subs)
 118 {
 119         struct media_ctl *mctl = subs->media_ctl;
 120 
 121         if (mctl) {
 122                 struct media_device *mdev;
 123 
 124                 mdev = mctl->media_dev;
 125                 if (mdev && media_devnode_is_registered(mdev->devnode)) {
 126                         media_devnode_remove(mctl->intf_devnode);
 127                         media_device_unregister_entity(&mctl->media_entity);
 128                         media_entity_cleanup(&mctl->media_entity);
 129                 }
 130                 kfree(mctl);
 131                 subs->media_ctl = NULL;
 132         }
 133 }
 134 
 135 int snd_media_start_pipeline(struct snd_usb_substream *subs)
 136 {
 137         struct media_ctl *mctl = subs->media_ctl;
 138         int ret = 0;
 139 
 140         if (!mctl)
 141                 return 0;
 142 
 143         mutex_lock(&mctl->media_dev->graph_mutex);
 144         if (mctl->media_dev->enable_source)
 145                 ret = mctl->media_dev->enable_source(&mctl->media_entity,
 146                                                      &mctl->media_pipe);
 147         mutex_unlock(&mctl->media_dev->graph_mutex);
 148         return ret;
 149 }
 150 
 151 void snd_media_stop_pipeline(struct snd_usb_substream *subs)
 152 {
 153         struct media_ctl *mctl = subs->media_ctl;
 154 
 155         if (!mctl)
 156                 return;
 157 
 158         mutex_lock(&mctl->media_dev->graph_mutex);
 159         if (mctl->media_dev->disable_source)
 160                 mctl->media_dev->disable_source(&mctl->media_entity);
 161         mutex_unlock(&mctl->media_dev->graph_mutex);
 162 }
 163 
 164 static int snd_media_mixer_init(struct snd_usb_audio *chip)
 165 {
 166         struct device *ctl_dev = &chip->card->ctl_dev;
 167         struct media_intf_devnode *ctl_intf;
 168         struct usb_mixer_interface *mixer;
 169         struct media_device *mdev = chip->media_dev;
 170         struct media_mixer_ctl *mctl;
 171         u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL;
 172         int ret;
 173 
 174         if (!mdev)
 175                 return -ENODEV;
 176 
 177         ctl_intf = chip->ctl_intf_media_devnode;
 178         if (!ctl_intf) {
 179                 ctl_intf = media_devnode_create(mdev, intf_type, 0,
 180                                                 MAJOR(ctl_dev->devt),
 181                                                 MINOR(ctl_dev->devt));
 182                 if (!ctl_intf)
 183                         return -ENOMEM;
 184                 chip->ctl_intf_media_devnode = ctl_intf;
 185         }
 186 
 187         list_for_each_entry(mixer, &chip->mixer_list, list) {
 188 
 189                 if (mixer->media_mixer_ctl)
 190                         continue;
 191 
 192                 /* allocate media_mixer_ctl */
 193                 mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
 194                 if (!mctl)
 195                         return -ENOMEM;
 196 
 197                 mctl->media_dev = mdev;
 198                 mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER;
 199                 mctl->media_entity.name = chip->card->mixername;
 200                 mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK;
 201                 mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE;
 202                 mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE;
 203                 media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX,
 204                                   mctl->media_pad);
 205                 ret =  media_device_register_entity(mctl->media_dev,
 206                                                     &mctl->media_entity);
 207                 if (ret) {
 208                         kfree(mctl);
 209                         return ret;
 210                 }
 211 
 212                 mctl->intf_link = media_create_intf_link(&mctl->media_entity,
 213                                                          &ctl_intf->intf,
 214                                                          MEDIA_LNK_FL_ENABLED);
 215                 if (!mctl->intf_link) {
 216                         media_device_unregister_entity(&mctl->media_entity);
 217                         media_entity_cleanup(&mctl->media_entity);
 218                         kfree(mctl);
 219                         return -ENOMEM;
 220                 }
 221                 mctl->intf_devnode = ctl_intf;
 222                 mixer->media_mixer_ctl = mctl;
 223         }
 224         return 0;
 225 }
 226 
 227 static void snd_media_mixer_delete(struct snd_usb_audio *chip)
 228 {
 229         struct usb_mixer_interface *mixer;
 230         struct media_device *mdev = chip->media_dev;
 231 
 232         if (!mdev)
 233                 return;
 234 
 235         list_for_each_entry(mixer, &chip->mixer_list, list) {
 236                 struct media_mixer_ctl *mctl;
 237 
 238                 mctl = mixer->media_mixer_ctl;
 239                 if (!mixer->media_mixer_ctl)
 240                         continue;
 241 
 242                 if (media_devnode_is_registered(mdev->devnode)) {
 243                         media_device_unregister_entity(&mctl->media_entity);
 244                         media_entity_cleanup(&mctl->media_entity);
 245                 }
 246                 kfree(mctl);
 247                 mixer->media_mixer_ctl = NULL;
 248         }
 249         if (media_devnode_is_registered(mdev->devnode))
 250                 media_devnode_remove(chip->ctl_intf_media_devnode);
 251         chip->ctl_intf_media_devnode = NULL;
 252 }
 253 
 254 int snd_media_device_create(struct snd_usb_audio *chip,
 255                         struct usb_interface *iface)
 256 {
 257         struct media_device *mdev;
 258         struct usb_device *usbdev = interface_to_usbdev(iface);
 259         int ret = 0;
 260 
 261         /* usb-audio driver is probed for each usb interface, and
 262          * there are multiple interfaces per device. Avoid calling
 263          * media_device_usb_allocate() each time usb_audio_probe()
 264          * is called. Do it only once.
 265          */
 266         if (chip->media_dev) {
 267                 mdev = chip->media_dev;
 268                 goto snd_mixer_init;
 269         }
 270 
 271         mdev = media_device_usb_allocate(usbdev, KBUILD_MODNAME, THIS_MODULE);
 272         if (IS_ERR(mdev))
 273                 return -ENOMEM;
 274 
 275         /* save media device - avoid lookups */
 276         chip->media_dev = mdev;
 277 
 278 snd_mixer_init:
 279         /* Create media entities for mixer and control dev */
 280         ret = snd_media_mixer_init(chip);
 281         /* media_device might be registered, print error and continue */
 282         if (ret)
 283                 dev_err(&usbdev->dev,
 284                         "Couldn't create media mixer entities. Error: %d\n",
 285                         ret);
 286 
 287         if (!media_devnode_is_registered(mdev->devnode)) {
 288                 /* dont'register if snd_media_mixer_init() failed */
 289                 if (ret)
 290                         goto create_fail;
 291 
 292                 /* register media_device */
 293                 ret = media_device_register(mdev);
 294 create_fail:
 295                 if (ret) {
 296                         snd_media_mixer_delete(chip);
 297                         media_device_delete(mdev, KBUILD_MODNAME, THIS_MODULE);
 298                         /* clear saved media_dev */
 299                         chip->media_dev = NULL;
 300                         dev_err(&usbdev->dev,
 301                                 "Couldn't register media device. Error: %d\n",
 302                                 ret);
 303                         return ret;
 304                 }
 305         }
 306 
 307         return ret;
 308 }
 309 
 310 void snd_media_device_delete(struct snd_usb_audio *chip)
 311 {
 312         struct media_device *mdev = chip->media_dev;
 313         struct snd_usb_stream *stream;
 314 
 315         /* release resources */
 316         list_for_each_entry(stream, &chip->pcm_list, list) {
 317                 snd_media_stream_delete(&stream->substream[0]);
 318                 snd_media_stream_delete(&stream->substream[1]);
 319         }
 320 
 321         snd_media_mixer_delete(chip);
 322 
 323         if (mdev) {
 324                 media_device_delete(mdev, KBUILD_MODNAME, THIS_MODULE);
 325                 chip->media_dev = NULL;
 326         }
 327 }

/* [<][>][^][v][top][bottom][index][help] */