linux/sound/usb/media.c
<<
>>
Prefs
   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
  33int 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
 106remove_intf_link:
 107        media_remove_intf_link(mctl->intf_link);
 108devnode_remove:
 109        media_devnode_remove(mctl->intf_devnode);
 110unregister_entity:
 111        media_device_unregister_entity(&mctl->media_entity);
 112free_mctl:
 113        kfree(mctl);
 114        return ret;
 115}
 116
 117void 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
 135int 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
 151void 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
 164static 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
 227static 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
 254int 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
 278snd_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);
 294create_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
 310void 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}
 328