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

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

DEFINITIONS

This source file includes following definitions.
  1. to_snd_cx18_card
  2. p_to_snd_cx18_card
  3. snd_cx18_card_free
  4. snd_cx18_card_private_free
  5. snd_cx18_card_create
  6. snd_cx18_card_set_names
  7. snd_cx18_init
  8. cx18_alsa_load
  9. cx18_alsa_init
  10. snd_cx18_exit
  11. cx18_alsa_exit_callback
  12. cx18_alsa_exit

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

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