From 01b65bfb4f8cd45b0d44547c961ef59a0bcf74be Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Nov 2011 14:31:46 +0100 Subject: [PATCH] ALSA: hda - Supports more audio streams 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 --- sound/pci/hda/hda_codec.c | 6 ++++++ sound/pci/hda/hda_codec.h | 3 --- sound/pci/hda/hda_intel.c | 48 +++++++++++++++++++++++------------------------ 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4562e9d..4463f9a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -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; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5644711..17cee4e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -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 */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 096507d..ddd7f3b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -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]); -- 2.7.4