root/drivers/media/pci/ivtv/ivtv-alsa-main.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_snd_ivtv_card
  2. p_to_snd_ivtv_card
  3. snd_ivtv_card_free
  4. snd_ivtv_card_private_free
  5. snd_ivtv_card_create
  6. snd_ivtv_card_set_names
  7. snd_ivtv_init
  8. ivtv_alsa_load
  9. ivtv_alsa_init
  10. snd_ivtv_exit
  11. ivtv_alsa_exit_callback
  12. ivtv_alsa_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  ALSA interface to ivtv PCM capture streams
   4  *
   5  *  Copyright (C) 2009,2012  Andy Walls <awalls@md.metrocast.net>
   6  *  Copyright (C) 2009  Devin Heitmueller <dheitmueller@kernellabs.com>
   7  *
   8  *  Portions of this work were sponsored by ONELAN Limited for the cx18 driver
   9  */
  10 
  11 #include "ivtv-driver.h"
  12 #include "ivtv-version.h"
  13 #include "ivtv-alsa.h"
  14 #include "ivtv-alsa-pcm.h"
  15 
  16 #include <sound/core.h>
  17 #include <sound/initval.h>
  18 
  19 int ivtv_alsa_debug;
  20 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  21 
  22 #define IVTV_DEBUG_ALSA_INFO(__fmt, __arg...) \
  23         do { \
  24                 if (ivtv_alsa_debug & 2) \
  25                         printk(KERN_INFO pr_fmt("%s: alsa:" __fmt),     \
  26                                __func__, ##__arg);                      \
  27         } while (0)
  28 
  29 module_param_named(debug, ivtv_alsa_debug, int, 0644);
  30 MODULE_PARM_DESC(debug,
  31                  "Debug level (bitmask). Default: 0\n"
  32                  "\t\t\t  1/0x0001: warning\n"
  33                  "\t\t\t  2/0x0002: info\n");
  34 
  35 module_param_array(index, int, NULL, 0444);
  36 MODULE_PARM_DESC(index,
  37                  "Index value for IVTV ALSA capture interface(s).\n");
  38 
  39 MODULE_AUTHOR("Andy Walls");
  40 MODULE_DESCRIPTION("CX23415/CX23416 ALSA Interface");
  41 MODULE_SUPPORTED_DEVICE("CX23415/CX23416 MPEG2 encoder");
  42 MODULE_LICENSE("GPL");
  43 
  44 MODULE_VERSION(IVTV_VERSION);
  45 
  46 static inline
  47 struct snd_ivtv_card *to_snd_ivtv_card(struct v4l2_device *v4l2_dev)
  48 {
  49         return to_ivtv(v4l2_dev)->alsa;
  50 }
  51 
  52 static inline
  53 struct snd_ivtv_card *p_to_snd_ivtv_card(struct v4l2_device **v4l2_dev)
  54 {
  55         return container_of(v4l2_dev, struct snd_ivtv_card, v4l2_dev);
  56 }
  57 
  58 static void snd_ivtv_card_free(struct snd_ivtv_card *itvsc)
  59 {
  60         if (itvsc == NULL)
  61                 return;
  62 
  63         if (itvsc->v4l2_dev != NULL)
  64                 to_ivtv(itvsc->v4l2_dev)->alsa = NULL;
  65 
  66         /* FIXME - take any other stopping actions needed */
  67 
  68         kfree(itvsc);
  69 }
  70 
  71 static void snd_ivtv_card_private_free(struct snd_card *sc)
  72 {
  73         if (sc == NULL)
  74                 return;
  75         snd_ivtv_card_free(sc->private_data);
  76         sc->private_data = NULL;
  77         sc->private_free = NULL;
  78 }
  79 
  80 static int snd_ivtv_card_create(struct v4l2_device *v4l2_dev,
  81                                        struct snd_card *sc,
  82                                        struct snd_ivtv_card **itvsc)
  83 {
  84         *itvsc = kzalloc(sizeof(struct snd_ivtv_card), GFP_KERNEL);
  85         if (*itvsc == NULL)
  86                 return -ENOMEM;
  87 
  88         (*itvsc)->v4l2_dev = v4l2_dev;
  89         (*itvsc)->sc = sc;
  90 
  91         sc->private_data = *itvsc;
  92         sc->private_free = snd_ivtv_card_private_free;
  93 
  94         return 0;
  95 }
  96 
  97 static int snd_ivtv_card_set_names(struct snd_ivtv_card *itvsc)
  98 {
  99         struct ivtv *itv = to_ivtv(itvsc->v4l2_dev);
 100         struct snd_card *sc = itvsc->sc;
 101 
 102         /* sc->driver is used by alsa-lib's configurator: simple, unique */
 103         strscpy(sc->driver, "CX2341[56]", sizeof(sc->driver));
 104 
 105         /* sc->shortname is a symlink in /proc/asound: IVTV-M -> cardN */
 106         snprintf(sc->shortname,  sizeof(sc->shortname), "IVTV-%d",
 107                  itv->instance);
 108 
 109         /* sc->longname is read from /proc/asound/cards */
 110         snprintf(sc->longname, sizeof(sc->longname),
 111                  "CX2341[56] #%d %s TV/FM Radio/Line-In Capture",
 112                  itv->instance, itv->card_name);
 113 
 114         return 0;
 115 }
 116 
 117 static int snd_ivtv_init(struct v4l2_device *v4l2_dev)
 118 {
 119         struct ivtv *itv = to_ivtv(v4l2_dev);
 120         struct snd_card *sc = NULL;
 121         struct snd_ivtv_card *itvsc;
 122         int ret, idx;
 123 
 124         /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */
 125 
 126         /* (1) Check and increment the device index */
 127         /* This is a no-op for us.  We'll use the itv->instance */
 128 
 129         /* (2) Create a card instance */
 130         /* use first available id if not specified otherwise*/
 131         idx = index[itv->instance] == -1 ? SNDRV_DEFAULT_IDX1 : index[itv->instance];
 132         ret = snd_card_new(&itv->pdev->dev,
 133                            idx,
 134                            SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
 135                            THIS_MODULE, 0, &sc);
 136         if (ret) {
 137                 IVTV_ALSA_ERR("%s: snd_card_new() failed with err %d\n",
 138                               __func__, ret);
 139                 goto err_exit;
 140         }
 141 
 142         /* (3) Create a main component */
 143         ret = snd_ivtv_card_create(v4l2_dev, sc, &itvsc);
 144         if (ret) {
 145                 IVTV_ALSA_ERR("%s: snd_ivtv_card_create() failed with err %d\n",
 146                               __func__, ret);
 147                 goto err_exit_free;
 148         }
 149 
 150         /* (4) Set the driver ID and name strings */
 151         snd_ivtv_card_set_names(itvsc);
 152 
 153         /* (5) Create other components: PCM, & proc files */
 154         ret = snd_ivtv_pcm_create(itvsc);
 155         if (ret) {
 156                 IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n",
 157                               __func__, ret);
 158                 goto err_exit_free;
 159         }
 160         /* FIXME - proc files */
 161 
 162         /* (7) Set the driver data and return 0 */
 163         /* We do this out of normal order for PCI drivers to avoid races */
 164         itv->alsa = itvsc;
 165 
 166         /* (6) Register the card instance */
 167         ret = snd_card_register(sc);
 168         if (ret) {
 169                 itv->alsa = NULL;
 170                 IVTV_ALSA_ERR("%s: snd_card_register() failed with err %d\n",
 171                               __func__, ret);
 172                 goto err_exit_free;
 173         }
 174 
 175         IVTV_ALSA_INFO("%s: Instance %d registered as ALSA card %d\n",
 176                          __func__, itv->instance, sc->number);
 177 
 178         return 0;
 179 
 180 err_exit_free:
 181         if (sc != NULL)
 182                 snd_card_free(sc);
 183         kfree(itvsc);
 184 err_exit:
 185         return ret;
 186 }
 187 
 188 static int ivtv_alsa_load(struct ivtv *itv)
 189 {
 190         struct v4l2_device *v4l2_dev = &itv->v4l2_dev;
 191         struct ivtv_stream *s;
 192 
 193         if (v4l2_dev == NULL) {
 194                 pr_err("ivtv-alsa: %s: struct v4l2_device * is NULL\n",
 195                        __func__);
 196                 return 0;
 197         }
 198 
 199         itv = to_ivtv(v4l2_dev);
 200         if (itv == NULL) {
 201                 pr_err("ivtv-alsa itv is NULL\n");
 202                 return 0;
 203         }
 204 
 205         s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
 206         if (s->vdev.v4l2_dev == NULL) {
 207                 IVTV_DEBUG_ALSA_INFO("PCM stream for card is disabled - skipping\n");
 208                 return 0;
 209         }
 210 
 211         if (itv->alsa != NULL) {
 212                 IVTV_ALSA_ERR("%s: struct snd_ivtv_card * already exists\n",
 213                               __func__);
 214                 return 0;
 215         }
 216 
 217         if (snd_ivtv_init(v4l2_dev)) {
 218                 IVTV_ALSA_ERR("%s: failed to create struct snd_ivtv_card\n",
 219                               __func__);
 220         } else {
 221                 IVTV_DEBUG_ALSA_INFO("created ivtv ALSA interface instance\n");
 222         }
 223         return 0;
 224 }
 225 
 226 static int __init ivtv_alsa_init(void)
 227 {
 228         pr_info("ivtv-alsa: module loading...\n");
 229         ivtv_ext_init = &ivtv_alsa_load;
 230         return 0;
 231 }
 232 
 233 static void __exit snd_ivtv_exit(struct snd_ivtv_card *itvsc)
 234 {
 235         struct ivtv *itv = to_ivtv(itvsc->v4l2_dev);
 236 
 237         /* FIXME - pointer checks & shutdown itvsc */
 238 
 239         snd_card_free(itvsc->sc);
 240         itv->alsa = NULL;
 241 }
 242 
 243 static int __exit ivtv_alsa_exit_callback(struct device *dev, void *data)
 244 {
 245         struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
 246         struct snd_ivtv_card *itvsc;
 247 
 248         if (v4l2_dev == NULL) {
 249                 pr_err("ivtv-alsa: %s: struct v4l2_device * is NULL\n",
 250                        __func__);
 251                 return 0;
 252         }
 253 
 254         itvsc = to_snd_ivtv_card(v4l2_dev);
 255         if (itvsc == NULL) {
 256                 IVTV_ALSA_WARN("%s: struct snd_ivtv_card * is NULL\n",
 257                                __func__);
 258                 return 0;
 259         }
 260 
 261         snd_ivtv_exit(itvsc);
 262         return 0;
 263 }
 264 
 265 static void __exit ivtv_alsa_exit(void)
 266 {
 267         struct device_driver *drv;
 268         int ret;
 269 
 270         pr_info("ivtv-alsa: module unloading...\n");
 271 
 272         drv = driver_find("ivtv", &pci_bus_type);
 273         ret = driver_for_each_device(drv, NULL, NULL, ivtv_alsa_exit_callback);
 274         (void)ret;      /* suppress compiler warning */
 275 
 276         ivtv_ext_init = NULL;
 277         pr_info("ivtv-alsa: module unload complete\n");
 278 }
 279 
 280 module_init(ivtv_alsa_init);
 281 module_exit(ivtv_alsa_exit);

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