From b71f808d551c7d3e3c81e8d270876d886958018c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Mar 2008 17:15:57 -0500 Subject: [PATCH] UBUNTU: Fix audio on laptops with irregular HDA codec numbering OriginalLocation: http://hg-mirror.alsa-project.org/alsa-kernel/raw-rev/c90540c66d2f Bug: 193840 Ignore: no This fix fixes audio on the Inspiron 1525 and likely other machines. Signed-off-by: Mario Limonciello --- ubuntu/sound/alsa-kernel/pci/hda/hda_codec.h | 12 +++- ubuntu/sound/alsa-kernel/pci/hda/hda_intel.c | 89 +++++++++++---------- ubuntu/sound/alsa-kernel/pci/hda/patch_analog.c | 1 + ubuntu/sound/alsa-kernel/pci/hda/patch_atihdmi.c | 1 + ubuntu/sound/alsa-kernel/pci/hda/patch_cmedia.c | 1 + ubuntu/sound/alsa-kernel/pci/hda/patch_conexant.c | 1 + ubuntu/sound/alsa-kernel/pci/hda/patch_realtek.c | 1 + ubuntu/sound/alsa-kernel/pci/hda/patch_si3054.c | 2 +- ubuntu/sound/alsa-kernel/pci/hda/patch_sigmatel.c | 1 + ubuntu/sound/alsa-kernel/pci/hda/patch_via.c | 1 + 10 files changed, 66 insertions(+), 44 deletions(-) diff --git a/ubuntu/sound/alsa-kernel/pci/hda/hda_codec.h b/ubuntu/sound/alsa-kernel/pci/hda/hda_codec.h index f148711..301b522 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/hda_codec.h +++ b/ubuntu/sound/alsa-kernel/pci/hda/hda_codec.h @@ -590,11 +590,21 @@ struct hda_pcm_stream { struct hda_pcm_ops ops; }; +/* PCM types */ +enum { + HDA_PCM_TYPE_AUDIO, + HDA_PCM_TYPE_SPDIF, + HDA_PCM_TYPE_HDMI, + HDA_PCM_TYPE_MODEM, + HDA_PCM_NTYPES +}; + /* for PCM creation */ struct hda_pcm { char *name; struct hda_pcm_stream stream[2]; - unsigned int is_modem; /* modem codec? */ + unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */ + int device; /* assigned device number */ }; /* codec information */ diff --git a/ubuntu/sound/alsa-kernel/pci/hda/hda_intel.c b/ubuntu/sound/alsa-kernel/pci/hda/hda_intel.c index 211e389..d0efbcc 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/hda_intel.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/hda_intel.c @@ -211,9 +211,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* max buffer size - no h/w limit, you can increase as you like */ #define AZX_MAX_BUF_SIZE (1024*1024*1024) /* max number of PCM devics per card */ -#define AZX_MAX_AUDIO_PCMS 6 -#define AZX_MAX_MODEM_PCMS 2 -#define AZX_MAX_PCMS (AZX_MAX_AUDIO_PCMS + AZX_MAX_MODEM_PCMS) +#define AZX_MAX_PCMS 8 /* RIRB int mask: overrun[2], response[0] */ #define RIRB_INT_RESPONSE 0x01 @@ -350,7 +348,6 @@ struct azx { struct azx_dev *azx_dev; /* PCM */ - unsigned int pcm_devs; struct snd_pcm *pcm[AZX_MAX_PCMS]; /* HD codec */ @@ -1386,7 +1383,7 @@ static void azx_pcm_free(struct snd_pcm *pcm) } static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, - struct hda_pcm *cpcm, int pcm_dev) + struct hda_pcm *cpcm) { int err; struct snd_pcm *pcm; @@ -1400,7 +1397,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, snd_assert(cpcm->name, return -EINVAL); - err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, + err = snd_pcm_new(chip->card, cpcm->name, cpcm->device, cpcm->stream[0].substreams, cpcm->stream[1].substreams, &pcm); @@ -1423,59 +1420,67 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 1024 * 64, 1024 * 1024); - chip->pcm[pcm_dev] = pcm; - if (chip->pcm_devs < pcm_dev + 1) - chip->pcm_devs = pcm_dev + 1; - + chip->pcm[cpcm->device] = pcm; return 0; } static int __devinit azx_pcm_create(struct azx *chip) { + static const char *dev_name[HDA_PCM_NTYPES] = { + "Audio", "SPDIF", "HDMI", "Modem" + }; + /* starting device index for each PCM type */ + static int dev_idx[HDA_PCM_NTYPES] = { + [HDA_PCM_TYPE_AUDIO] = 0, + [HDA_PCM_TYPE_SPDIF] = 1, + [HDA_PCM_TYPE_HDMI] = 3, + [HDA_PCM_TYPE_MODEM] = 6 + }; + /* normal audio device indices; not linear to keep compatibility */ + static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; int c, err; - int pcm_dev; + int num_devs[HDA_PCM_NTYPES]; err = snd_hda_build_pcms(chip->bus); if (err < 0) return err; /* create audio PCMs */ - pcm_dev = 0; - list_for_each_entry(codec, &chip->bus->codec_list, list) { - for (c = 0; c < codec->num_pcms; c++) { - if (codec->pcm_info[c].is_modem) - continue; /* create later */ - if (pcm_dev >= AZX_MAX_AUDIO_PCMS) { - snd_printk(KERN_ERR SFX - "Too many audio PCMs\n"); - return -EINVAL; - } - err = create_codec_pcm(chip, codec, - &codec->pcm_info[c], pcm_dev); - if (err < 0) - return err; - pcm_dev++; - } - } - - /* create modem PCMs */ - pcm_dev = AZX_MAX_AUDIO_PCMS; + memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { - if (!codec->pcm_info[c].is_modem) - continue; /* already created */ - if (pcm_dev >= AZX_MAX_PCMS) { - snd_printk(KERN_ERR SFX - "Too many modem PCMs\n"); - return -EINVAL; + struct hda_pcm *cpcm = &codec->pcm_info[c]; + int type = cpcm->pcm_type; + switch (type) { + case HDA_PCM_TYPE_AUDIO: + if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { + snd_printk(KERN_WARNING + "Too many audio devices\n"); + continue; + } + cpcm->device = audio_idx[num_devs[type]]; + break; + case HDA_PCM_TYPE_SPDIF: + case HDA_PCM_TYPE_HDMI: + case HDA_PCM_TYPE_MODEM: + if (num_devs[type]) { + snd_printk(KERN_WARNING + "%s already defined\n", + dev_name[type]); + continue; + } + cpcm->device = dev_idx[type]; + break; + default: + snd_printk(KERN_WARNING + "Invalid PCM type %d\n", type); + continue; } - err = create_codec_pcm(chip, codec, - &codec->pcm_info[c], pcm_dev); + num_devs[type]++; + err = create_codec_pcm(chip, codec, cpcm); if (err < 0) return err; - chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; - pcm_dev++; } } return 0; @@ -1587,7 +1592,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < chip->pcm_devs; i++) + for (i = 0; i < AZX_MAX_PCMS; i++) snd_pcm_suspend_all(chip->pcm[i]); if (chip->initialized) snd_hda_suspend(chip->bus, state); diff --git a/ubuntu/sound/alsa-kernel/pci/hda/patch_analog.c b/ubuntu/sound/alsa-kernel/pci/hda/patch_analog.c index 19f0884..b0e2edc 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/patch_analog.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/patch_analog.c @@ -359,6 +359,7 @@ static int ad198x_build_pcms(struct hda_codec *codec) info++; codec->num_pcms++; info->name = "AD198x Digital"; + info->pcm_type = HDA_PCM_TYPE_SPDIF; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; if (spec->dig_in_nid) { diff --git a/ubuntu/sound/alsa-kernel/pci/hda/patch_atihdmi.c b/ubuntu/sound/alsa-kernel/pci/hda/patch_atihdmi.c index 27d2e00..e0e9ea9 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/patch_atihdmi.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/patch_atihdmi.c @@ -116,6 +116,7 @@ static int atihdmi_build_pcms(struct hda_codec *codec) codec->pcm_info = info; info->name = "ATI HDMI"; + info->pcm_type = HDA_PCM_TYPE_HDMI; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; return 0; diff --git a/ubuntu/sound/alsa-kernel/pci/hda/patch_cmedia.c b/ubuntu/sound/alsa-kernel/pci/hda/patch_cmedia.c index 3d6097b..99ce74b 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/patch_cmedia.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/patch_cmedia.c @@ -571,6 +571,7 @@ static int cmi9880_build_pcms(struct hda_codec *codec) codec->num_pcms++; info++; info->name = "CMI9880 Digital"; + info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->multiout.dig_out_nid) { info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; diff --git a/ubuntu/sound/alsa-kernel/pci/hda/patch_conexant.c b/ubuntu/sound/alsa-kernel/pci/hda/patch_conexant.c index f7cd3a8..b7ed1bf 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/patch_conexant.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/patch_conexant.c @@ -284,6 +284,7 @@ static int conexant_build_pcms(struct hda_codec *codec) info++; codec->num_pcms++; info->name = "Conexant Digital"; + info->pcm_type = HDA_PCM_TYPE_SPDIF; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_digital_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = diff --git a/ubuntu/sound/alsa-kernel/pci/hda/patch_realtek.c b/ubuntu/sound/alsa-kernel/pci/hda/patch_realtek.c index aa54178..8eb29b7 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/patch_realtek.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/patch_realtek.c @@ -2499,6 +2499,7 @@ static int alc_build_pcms(struct hda_codec *codec) codec->num_pcms = 2; info = spec->pcm_rec + 1; info->name = spec->stream_name_digital; + info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->multiout.dig_out_nid && spec->stream_digital_playback) { info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); diff --git a/ubuntu/sound/alsa-kernel/pci/hda/patch_si3054.c b/ubuntu/sound/alsa-kernel/pci/hda/patch_si3054.c index d22f5a6..598ee21 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/patch_si3054.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/patch_si3054.c @@ -206,7 +206,7 @@ static int si3054_build_pcms(struct hda_codec *codec) info->name = "Si3054 Modem"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm; info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm; - info->is_modem = 1; + info->pcm_type = HDA_PCM_TYPE_MODEM; return 0; } diff --git a/ubuntu/sound/alsa-kernel/pci/hda/patch_sigmatel.c b/ubuntu/sound/alsa-kernel/pci/hda/patch_sigmatel.c index dff20ab..873bdfa 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/patch_sigmatel.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/patch_sigmatel.c @@ -1987,6 +1987,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec) codec->num_pcms++; info++; info->name = "STAC92xx Digital"; + info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->multiout.dig_out_nid) { info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; diff --git a/ubuntu/sound/alsa-kernel/pci/hda/patch_via.c b/ubuntu/sound/alsa-kernel/pci/hda/patch_via.c index 4e5dd4c..d9a5c6a 100644 --- a/ubuntu/sound/alsa-kernel/pci/hda/patch_via.c +++ b/ubuntu/sound/alsa-kernel/pci/hda/patch_via.c @@ -523,6 +523,7 @@ static int via_build_pcms(struct hda_codec *codec) codec->num_pcms++; info++; info->name = spec->stream_name_digital; + info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->multiout.dig_out_nid) { info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); -- 1.5.4.3