ALSA: hda - Supports more audio streams
authorTakashi Iwai <tiwai@suse.de>
Thu, 24 Nov 2011 13:31:46 +0000 (14:31 +0100)
committerTakashi Iwai <tiwai@suse.de>
Sat, 26 Nov 2011 09:19:44 +0000 (10:19 +0100)
So far, the driver supports up to 10 streams.  This is a restriction in
hda_intel.c and hda_codec.c: in the former, the fixed array size limits
the amount, and in the latter, the fixed device-number assignment table
(in get_empty_pcm_device()) limits the possibility.

This patch reduces the restriction by
- using linked list for managing PCM instances in hda_intel.c, and
- assigning non-fixed device numbers for the extra devices

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_intel.c

index 4562e9de6a1ab0dc7015e28d7be14c2eafa5a6b3..4463f9a9619a096771a7c9b143a127c7b5ec1889 100644 (file)
@@ -3850,6 +3850,12 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
                if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
                        return audio_idx[type][i];
 
+       /* non-fixed slots starting from 10 */
+       for (i = 10; i < 32; i++) {
+               if (!test_and_set_bit(i, bus->pcm_dev_bits))
+                       return i;
+       }
+
        snd_printk(KERN_WARNING "Too many %s devices\n",
                snd_hda_pcm_type_name[type]);
        return -EAGAIN;
index 564471169cae72ada50a63e0f2e920964d60d107..17cee4ee8e655b6de62189195160d365a46bcc4f 100644 (file)
@@ -547,9 +547,6 @@ enum {
 /* max. codec address */
 #define HDA_MAX_CODEC_ADDRESS  0x0f
 
-/* max number of PCM devics per card */
-#define HDA_MAX_PCMS           10
-
 /*
  * generic arrays
  */
index 096507d2ca9a7323c8d8e674ff4da7d921e677e4..ddd7f3b21cdc431727e009dde39ec13fbb506cd9 100644 (file)
@@ -407,6 +407,14 @@ struct azx_rb {
        u32 res[AZX_MAX_CODECS];        /* last read value */
 };
 
+struct azx_pcm {
+       struct azx *chip;
+       struct snd_pcm *pcm;
+       struct hda_codec *codec;
+       struct hda_pcm_stream *hinfo[2];
+       struct list_head list;
+};
+
 struct azx {
        struct snd_card *card;
        struct pci_dev *pci;
@@ -434,7 +442,7 @@ struct azx {
        struct azx_dev *azx_dev;
 
        /* PCM */
-       struct snd_pcm *pcm[HDA_MAX_PCMS];
+       struct list_head pcm_list; /* azx_pcm list */
 
        /* HD codec */
        unsigned short codec_mask;
@@ -1486,10 +1494,9 @@ static void azx_bus_reset(struct hda_bus *bus)
        azx_init_chip(chip, 1);
 #ifdef CONFIG_PM
        if (chip->initialized) {
-               int i;
-
-               for (i = 0; i < HDA_MAX_PCMS; i++)
-                       snd_pcm_suspend_all(chip->pcm[i]);
+               struct azx_pcm *p;
+               list_for_each_entry(p, &chip->pcm_list, list)
+                       snd_pcm_suspend_all(p->pcm);
                snd_hda_suspend(chip->bus);
                snd_hda_resume(chip->bus);
        }
@@ -1667,12 +1674,6 @@ static struct snd_pcm_hardware azx_pcm_hw = {
        .fifo_size =            0,
 };
 
-struct azx_pcm {
-       struct azx *chip;
-       struct hda_codec *codec;
-       struct hda_pcm_stream *hinfo[2];
-};
-
 static int azx_pcm_open(struct snd_pcm_substream *substream)
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
@@ -2197,7 +2198,7 @@ static void azx_pcm_free(struct snd_pcm *pcm)
 {
        struct azx_pcm *apcm = pcm->private_data;
        if (apcm) {
-               apcm->chip->pcm[pcm->device] = NULL;
+               list_del(&apcm->list);
                kfree(apcm);
        }
 }
@@ -2215,14 +2216,11 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        unsigned int size;
        int s, err;
 
-       if (pcm_dev >= HDA_MAX_PCMS) {
-               snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
-                          pcm_dev);
-               return -EINVAL;
-       }
-       if (chip->pcm[pcm_dev]) {
-               snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
-               return -EBUSY;
+       list_for_each_entry(apcm, &chip->pcm_list, list) {
+               if (apcm->pcm->device == pcm_dev) {
+                       snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
+                       return -EBUSY;
+               }
        }
        err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
                          cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
@@ -2235,12 +2233,13 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        if (apcm == NULL)
                return -ENOMEM;
        apcm->chip = chip;
+       apcm->pcm = pcm;
        apcm->codec = codec;
        pcm->private_data = apcm;
        pcm->private_free = azx_pcm_free;
        if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
                pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
-       chip->pcm[pcm_dev] = pcm;
+       list_add_tail(&apcm->list, &chip->pcm_list);
        cpcm->pcm = pcm;
        for (s = 0; s < 2; s++) {
                apcm->hinfo[s] = &cpcm->stream[s];
@@ -2370,12 +2369,12 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct azx *chip = card->private_data;
-       int i;
+       struct azx_pcm *p;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        azx_clear_irq_pending(chip);
-       for (i = 0; i < HDA_MAX_PCMS; i++)
-               snd_pcm_suspend_all(chip->pcm[i]);
+       list_for_each_entry(p, &chip->pcm_list, list)
+               snd_pcm_suspend_all(p->pcm);
        if (chip->initialized)
                snd_hda_suspend(chip->bus);
        azx_stop_chip(chip);
@@ -2672,6 +2671,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        check_msi(chip);
        chip->dev_index = dev;
        INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
+       INIT_LIST_HEAD(&chip->pcm_list);
 
        chip->position_fix[0] = chip->position_fix[1] =
                check_position_fix(chip, position_fix[dev]);