Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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;
+0 −3
Original line number Diff line number Diff line
@@ -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
 */
+24 −24
Original line number Diff line number Diff line
@@ -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,15 +2216,12 @@ 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]) {
	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,
			  cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].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]);