linux/drivers/media/pci/cobalt/cobalt-alsa-main.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  ALSA interface to cobalt PCM capture streams
   4 *
   5 *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
   6 *  All rights reserved.
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/slab.h>
  11#include <linux/module.h>
  12#include <linux/kernel.h>
  13#include <linux/device.h>
  14#include <linux/spinlock.h>
  15
  16#include <media/v4l2-device.h>
  17
  18#include <sound/core.h>
  19#include <sound/initval.h>
  20
  21#include "cobalt-driver.h"
  22#include "cobalt-alsa.h"
  23#include "cobalt-alsa-pcm.h"
  24
  25static void snd_cobalt_card_free(struct snd_cobalt_card *cobsc)
  26{
  27        if (cobsc == NULL)
  28                return;
  29
  30        cobsc->s->alsa = NULL;
  31
  32        kfree(cobsc);
  33}
  34
  35static void snd_cobalt_card_private_free(struct snd_card *sc)
  36{
  37        if (sc == NULL)
  38                return;
  39        snd_cobalt_card_free(sc->private_data);
  40        sc->private_data = NULL;
  41        sc->private_free = NULL;
  42}
  43
  44static int snd_cobalt_card_create(struct cobalt_stream *s,
  45                                       struct snd_card *sc,
  46                                       struct snd_cobalt_card **cobsc)
  47{
  48        *cobsc = kzalloc(sizeof(struct snd_cobalt_card), GFP_KERNEL);
  49        if (*cobsc == NULL)
  50                return -ENOMEM;
  51
  52        (*cobsc)->s = s;
  53        (*cobsc)->sc = sc;
  54
  55        sc->private_data = *cobsc;
  56        sc->private_free = snd_cobalt_card_private_free;
  57
  58        return 0;
  59}
  60
  61static int snd_cobalt_card_set_names(struct snd_cobalt_card *cobsc)
  62{
  63        struct cobalt_stream *s = cobsc->s;
  64        struct cobalt *cobalt = s->cobalt;
  65        struct snd_card *sc = cobsc->sc;
  66
  67        /* sc->driver is used by alsa-lib's configurator: simple, unique */
  68        strlcpy(sc->driver, "cobalt", sizeof(sc->driver));
  69
  70        /* sc->shortname is a symlink in /proc/asound: COBALT-M -> cardN */
  71        snprintf(sc->shortname,  sizeof(sc->shortname), "cobalt-%d-%d",
  72                 cobalt->instance, s->video_channel);
  73
  74        /* sc->longname is read from /proc/asound/cards */
  75        snprintf(sc->longname, sizeof(sc->longname),
  76                 "Cobalt %d HDMI %d",
  77                 cobalt->instance, s->video_channel);
  78
  79        return 0;
  80}
  81
  82int cobalt_alsa_init(struct cobalt_stream *s)
  83{
  84        struct cobalt *cobalt = s->cobalt;
  85        struct snd_card *sc = NULL;
  86        struct snd_cobalt_card *cobsc;
  87        int ret;
  88
  89        /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */
  90
  91        /* (1) Check and increment the device index */
  92        /* This is a no-op for us.  We'll use the cobalt->instance */
  93
  94        /* (2) Create a card instance */
  95        ret = snd_card_new(&cobalt->pci_dev->dev, SNDRV_DEFAULT_IDX1,
  96                           SNDRV_DEFAULT_STR1, THIS_MODULE, 0, &sc);
  97        if (ret) {
  98                cobalt_err("snd_card_new() failed with err %d\n", ret);
  99                goto err_exit;
 100        }
 101
 102        /* (3) Create a main component */
 103        ret = snd_cobalt_card_create(s, sc, &cobsc);
 104        if (ret) {
 105                cobalt_err("snd_cobalt_card_create() failed with err %d\n",
 106                           ret);
 107                goto err_exit_free;
 108        }
 109
 110        /* (4) Set the driver ID and name strings */
 111        snd_cobalt_card_set_names(cobsc);
 112
 113        ret = snd_cobalt_pcm_create(cobsc);
 114        if (ret) {
 115                cobalt_err("snd_cobalt_pcm_create() failed with err %d\n",
 116                           ret);
 117                goto err_exit_free;
 118        }
 119        /* FIXME - proc files */
 120
 121        /* (7) Set the driver data and return 0 */
 122        /* We do this out of normal order for PCI drivers to avoid races */
 123        s->alsa = cobsc;
 124
 125        /* (6) Register the card instance */
 126        ret = snd_card_register(sc);
 127        if (ret) {
 128                s->alsa = NULL;
 129                cobalt_err("snd_card_register() failed with err %d\n", ret);
 130                goto err_exit_free;
 131        }
 132
 133        return 0;
 134
 135err_exit_free:
 136        if (sc != NULL)
 137                snd_card_free(sc);
 138        kfree(cobsc);
 139err_exit:
 140        return ret;
 141}
 142
 143void cobalt_alsa_exit(struct cobalt_stream *s)
 144{
 145        struct snd_cobalt_card *cobsc = s->alsa;
 146
 147        if (cobsc)
 148                snd_card_free(cobsc->sc);
 149        s->alsa = NULL;
 150}
 151