Commit 01b65bfb authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarTakashi Iwai <tiwai@suse.de>
parent b37c0096
...@@ -3850,6 +3850,12 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) ...@@ -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)) if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
return audio_idx[type][i]; 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_printk(KERN_WARNING "Too many %s devices\n",
snd_hda_pcm_type_name[type]); snd_hda_pcm_type_name[type]);
return -EAGAIN; return -EAGAIN;
......
...@@ -547,9 +547,6 @@ enum { ...@@ -547,9 +547,6 @@ enum {
/* max. codec address */ /* max. codec address */
#define HDA_MAX_CODEC_ADDRESS 0x0f #define HDA_MAX_CODEC_ADDRESS 0x0f
/* max number of PCM devics per card */
#define HDA_MAX_PCMS 10
/* /*
* generic arrays * generic arrays
*/ */
......
...@@ -407,6 +407,14 @@ struct azx_rb { ...@@ -407,6 +407,14 @@ struct azx_rb {
u32 res[AZX_MAX_CODECS]; /* last read value */ 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 azx {
struct snd_card *card; struct snd_card *card;
struct pci_dev *pci; struct pci_dev *pci;
...@@ -434,7 +442,7 @@ struct azx { ...@@ -434,7 +442,7 @@ struct azx {
struct azx_dev *azx_dev; struct azx_dev *azx_dev;
/* PCM */ /* PCM */
struct snd_pcm *pcm[HDA_MAX_PCMS]; struct list_head pcm_list; /* azx_pcm list */
/* HD codec */ /* HD codec */
unsigned short codec_mask; unsigned short codec_mask;
...@@ -1486,10 +1494,9 @@ static void azx_bus_reset(struct hda_bus *bus) ...@@ -1486,10 +1494,9 @@ static void azx_bus_reset(struct hda_bus *bus)
azx_init_chip(chip, 1); azx_init_chip(chip, 1);
#ifdef CONFIG_PM #ifdef CONFIG_PM
if (chip->initialized) { if (chip->initialized) {
int i; struct azx_pcm *p;
list_for_each_entry(p, &chip->pcm_list, list)
for (i = 0; i < HDA_MAX_PCMS; i++) snd_pcm_suspend_all(p->pcm);
snd_pcm_suspend_all(chip->pcm[i]);
snd_hda_suspend(chip->bus); snd_hda_suspend(chip->bus);
snd_hda_resume(chip->bus); snd_hda_resume(chip->bus);
} }
...@@ -1667,12 +1674,6 @@ static struct snd_pcm_hardware azx_pcm_hw = { ...@@ -1667,12 +1674,6 @@ static struct snd_pcm_hardware azx_pcm_hw = {
.fifo_size = 0, .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) static int azx_pcm_open(struct snd_pcm_substream *substream)
{ {
struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
...@@ -2197,7 +2198,7 @@ static void azx_pcm_free(struct snd_pcm *pcm) ...@@ -2197,7 +2198,7 @@ static void azx_pcm_free(struct snd_pcm *pcm)
{ {
struct azx_pcm *apcm = pcm->private_data; struct azx_pcm *apcm = pcm->private_data;
if (apcm) { if (apcm) {
apcm->chip->pcm[pcm->device] = NULL; list_del(&apcm->list);
kfree(apcm); kfree(apcm);
} }
} }
...@@ -2215,15 +2216,12 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, ...@@ -2215,15 +2216,12 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
unsigned int size; unsigned int size;
int s, err; int s, err;
if (pcm_dev >= HDA_MAX_PCMS) { list_for_each_entry(apcm, &chip->pcm_list, list) {
snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", if (apcm->pcm->device == pcm_dev) {
pcm_dev);
return -EINVAL;
}
if (chip->pcm[pcm_dev]) {
snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev); snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
return -EBUSY; return -EBUSY;
} }
}
err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams, cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
...@@ -2235,12 +2233,13 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, ...@@ -2235,12 +2233,13 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
if (apcm == NULL) if (apcm == NULL)
return -ENOMEM; return -ENOMEM;
apcm->chip = chip; apcm->chip = chip;
apcm->pcm = pcm;
apcm->codec = codec; apcm->codec = codec;
pcm->private_data = apcm; pcm->private_data = apcm;
pcm->private_free = azx_pcm_free; pcm->private_free = azx_pcm_free;
if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
pcm->dev_class = SNDRV_PCM_CLASS_MODEM; pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
chip->pcm[pcm_dev] = pcm; list_add_tail(&apcm->list, &chip->pcm_list);
cpcm->pcm = pcm; cpcm->pcm = pcm;
for (s = 0; s < 2; s++) { for (s = 0; s < 2; s++) {
apcm->hinfo[s] = &cpcm->stream[s]; apcm->hinfo[s] = &cpcm->stream[s];
...@@ -2370,12 +2369,12 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) ...@@ -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 snd_card *card = pci_get_drvdata(pci);
struct azx *chip = card->private_data; struct azx *chip = card->private_data;
int i; struct azx_pcm *p;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
azx_clear_irq_pending(chip); azx_clear_irq_pending(chip);
for (i = 0; i < HDA_MAX_PCMS; i++) list_for_each_entry(p, &chip->pcm_list, list)
snd_pcm_suspend_all(chip->pcm[i]); snd_pcm_suspend_all(p->pcm);
if (chip->initialized) if (chip->initialized)
snd_hda_suspend(chip->bus); snd_hda_suspend(chip->bus);
azx_stop_chip(chip); azx_stop_chip(chip);
...@@ -2672,6 +2671,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, ...@@ -2672,6 +2671,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
check_msi(chip); check_msi(chip);
chip->dev_index = dev; chip->dev_index = dev;
INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
INIT_LIST_HEAD(&chip->pcm_list);
chip->position_fix[0] = chip->position_fix[1] = chip->position_fix[0] = chip->position_fix[1] =
check_position_fix(chip, position_fix[dev]); check_position_fix(chip, position_fix[dev]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment