staging: most: sound: use static name for ALSA card
[linux-2.6-block.git] / drivers / staging / most / sound / sound.c
index 89b02fc305b8bca2ce4f7d8ba1a0cce58c094acf..c6986310518efd163c2ed124f7b87172f7eecf54 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/printk.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -20,7 +21,6 @@
 
 #define DRIVER_NAME "sound"
 
-static struct list_head dev_list;
 static struct core_component comp;
 
 /**
@@ -56,6 +56,17 @@ struct channel {
        void (*copy_fn)(void *alsa, void *most, unsigned int bytes);
 };
 
+struct sound_adapter {
+       struct list_head dev_list;
+       struct most_interface *iface;
+       struct snd_card *card;
+       struct list_head list;
+       bool registered;
+       int pcm_dev_idx;
+};
+
+static struct list_head adpt_list;
+
 #define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
                       SNDRV_PCM_INFO_MMAP_VALID | \
                       SNDRV_PCM_INFO_BATCH | \
@@ -157,9 +168,10 @@ static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes)
 static struct channel *get_channel(struct most_interface *iface,
                                   int channel_id)
 {
+       struct sound_adapter *adpt = iface->priv;
        struct channel *channel, *tmp;
 
-       list_for_each_entry_safe(channel, tmp, &dev_list, list) {
+       list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) {
                if ((channel->iface == iface) && (channel->id == channel_id))
                        return channel;
        }
@@ -459,14 +471,14 @@ static const struct snd_pcm_ops pcm_ops = {
        .page       = snd_pcm_lib_get_vmalloc_page,
 };
 
-static int split_arg_list(char *buf, char **card_name, u16 *ch_num,
-                         char **sample_res)
+static int split_arg_list(char *buf, char **device_name, u16 *ch_num,
+                         char **sample_res, u8 *create)
 {
        char *num;
        int ret;
 
-       *card_name = strsep(&buf, ".");
-       if (!*card_name) {
+       *device_name = strsep(&buf, ".");
+       if (!*device_name) {
                pr_err("Missing sound card name\n");
                return -EIO;
        }
@@ -479,6 +491,9 @@ static int split_arg_list(char *buf, char **card_name, u16 *ch_num,
        *sample_res = strsep(&buf, ".\n");
        if (!*sample_res)
                goto err;
+
+       if (buf && !strcmp(buf, "create"))
+               *create = 1;
        return 0;
 
 err:
@@ -536,6 +551,20 @@ found:
        return 0;
 }
 
+static void release_adapter(struct sound_adapter *adpt)
+{
+       struct channel *channel, *tmp;
+
+       list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) {
+               list_del(&channel->list);
+               kfree(channel);
+       }
+       if (adpt->card)
+               snd_card_free(adpt->card);
+       list_del(&adpt->list);
+       kfree(adpt);
+}
+
 /**
  * audio_probe_channel - probe function of the driver module
  * @iface: pointer to interface instance
@@ -553,14 +582,15 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id,
                               char *arg_list)
 {
        struct channel *channel;
-       struct snd_card *card;
+       struct sound_adapter *adpt;
        struct snd_pcm *pcm;
        int playback_count = 0;
        int capture_count = 0;
        int ret;
        int direction;
-       char *card_name;
+       char *device_name;
        u16 ch_num;
+       u8 create = 0;
        char *sample_res;
 
        if (!iface)
@@ -571,6 +601,39 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id,
                return -EINVAL;
        }
 
+       ret = split_arg_list(arg_list, &device_name, &ch_num, &sample_res,
+                            &create);
+       if (ret < 0)
+               return ret;
+
+       list_for_each_entry(adpt, &adpt_list, list) {
+               if (adpt->iface != iface)
+                       continue;
+               if (adpt->registered)
+                       return -ENOSPC;
+               adpt->pcm_dev_idx++;
+               goto skip_adpt_alloc;
+       }
+       adpt = kzalloc(sizeof(*adpt), GFP_KERNEL);
+       if (!adpt)
+               return -ENOMEM;
+
+       adpt->iface = iface;
+       INIT_LIST_HEAD(&adpt->dev_list);
+       iface->priv = adpt;
+       list_add_tail(&adpt->list, &adpt_list);
+       ret = snd_card_new(&iface->dev, -1, "INIC", THIS_MODULE,
+                          sizeof(*channel), &adpt->card);
+       if (ret < 0)
+               goto err_free_adpt;
+       snprintf(adpt->card->driver, sizeof(adpt->card->driver),
+                "%s", DRIVER_NAME);
+       snprintf(adpt->card->shortname, sizeof(adpt->card->shortname),
+                "Microchip INIC");
+       snprintf(adpt->card->longname, sizeof(adpt->card->longname),
+                "%s at %s, ch %d", adpt->card->shortname, iface->description,
+                channel_id);
+skip_adpt_alloc:
        if (get_channel(iface, channel_id)) {
                pr_err("channel (%s:%d) is already linked\n",
                       iface->description, channel_id);
@@ -584,53 +647,43 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id,
                capture_count = 1;
                direction = SNDRV_PCM_STREAM_CAPTURE;
        }
-
-       ret = split_arg_list(arg_list, &card_name, &ch_num, &sample_res);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_card_new(&iface->dev, -1, card_name, THIS_MODULE,
-                          sizeof(*channel), &card);
-       if (ret < 0)
-               return ret;
-
-       channel = card->private_data;
-       channel->card = card;
+       channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+       if (!channel) {
+               ret = -ENOMEM;
+               goto err_free_adpt;
+       }
+       channel->card = adpt->card;
        channel->cfg = cfg;
        channel->iface = iface;
        channel->id = channel_id;
        init_waitqueue_head(&channel->playback_waitq);
+       list_add_tail(&channel->list, &adpt->dev_list);
 
        ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res,
                                  cfg);
        if (ret)
-               goto err_free_card;
+               goto err_free_adpt;
 
-       snprintf(card->driver, sizeof(card->driver), "%s", DRIVER_NAME);
-       snprintf(card->shortname, sizeof(card->shortname), "Microchip MOST:%d",
-                card->number);
-       snprintf(card->longname, sizeof(card->longname), "%s at %s, ch %d",
-                card->shortname, iface->description, channel_id);
+       ret = snd_pcm_new(adpt->card, device_name, adpt->pcm_dev_idx,
+                         playback_count, capture_count, &pcm);
 
-       ret = snd_pcm_new(card, card_name, 0, playback_count,
-                         capture_count, &pcm);
        if (ret < 0)
-               goto err_free_card;
+               goto err_free_adpt;
 
        pcm->private_data = channel;
-
+       snprintf(pcm->name, sizeof(pcm->name), device_name);
        snd_pcm_set_ops(pcm, direction, &pcm_ops);
 
-       ret = snd_card_register(card);
-       if (ret < 0)
-               goto err_free_card;
-
-       list_add_tail(&channel->list, &dev_list);
-
+       if (create) {
+               ret = snd_card_register(adpt->card);
+               if (ret < 0)
+                       goto err_free_adpt;
+               adpt->registered = true;
+       }
        return 0;
 
-err_free_card:
-       snd_card_free(card);
+err_free_adpt:
+       release_adapter(adpt);
        return ret;
 }
 
@@ -647,6 +700,7 @@ static int audio_disconnect_channel(struct most_interface *iface,
                                    int channel_id)
 {
        struct channel *channel;
+       struct sound_adapter *adpt = iface->priv;
 
        channel = get_channel(iface, channel_id);
        if (!channel) {
@@ -656,8 +710,10 @@ static int audio_disconnect_channel(struct most_interface *iface,
        }
 
        list_del(&channel->list);
-       snd_card_free(channel->card);
 
+       kfree(channel);
+       if (list_empty(&adpt->dev_list))
+               release_adapter(adpt);
        return 0;
 }
 
@@ -733,22 +789,14 @@ static int __init audio_init(void)
 {
        pr_info("init()\n");
 
-       INIT_LIST_HEAD(&dev_list);
+       INIT_LIST_HEAD(&adpt_list);
 
        return most_register_component(&comp);
 }
 
 static void __exit audio_exit(void)
 {
-       struct channel *channel, *tmp;
-
        pr_info("exit()\n");
-
-       list_for_each_entry_safe(channel, tmp, &dev_list, list) {
-               list_del(&channel->list);
-               snd_card_free(channel->card);
-       }
-
        most_deregister_component(&comp);
 }