diff -r edd30b308900 pci/hda/hda_codec.c
--- a/pci/hda/hda_codec.c	Mon Jan 07 15:17:43 2008 +0100
+++ b/pci/hda/hda_codec.c	Mon Jan 07 16:00:32 2008 +0100
@@ -2125,6 +2125,26 @@ static int __devinit set_pcm_default_val
 	return 0;
 }
 
+/*
+ * attach a new PCM stream
+ */
+static int __devinit
+snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm, int stream)
+{
+	struct hda_pcm_stream *info;
+	int err;
+
+	info = &pcm->stream[stream];
+	if (!info->substreams)
+		return 0;
+	if (!pcm->name)
+		return -EINVAL;
+	err = set_pcm_default_values(codec, info);
+	if (err < 0)
+		return err;
+	return codec->bus->ops.attach_pcm(codec, pcm, stream);
+}
+
 /**
  * snd_hda_build_pcms - build PCM information
  * @bus: the BUS
@@ -2154,7 +2174,10 @@ int __devinit snd_hda_build_pcms(struct 
 int __devinit snd_hda_build_pcms(struct hda_bus *bus)
 {
 	struct hda_codec *codec;
+	int dev_audio, dev_modem;
 
+	dev_audio = 0;
+	dev_modem = HDA_MAX_AUDIO_PCMS;
 	list_for_each_entry(codec, &bus->codec_list, list) {
 		unsigned int pcm, s;
 		int err;
@@ -2164,12 +2187,13 @@ int __devinit snd_hda_build_pcms(struct 
 		if (err < 0)
 			return err;
 		for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+			struct hda_pcm *cpcm = &codec->pcm_info[pcm];
+			if (cpcm->is_modem)
+				cpcm->device = dev_modem++;
+			else
+				cpcm->device = dev_audio++;
 			for (s = 0; s < 2; s++) {
-				struct hda_pcm_stream *info;
-				info = &codec->pcm_info[pcm].stream[s];
-				if (!info->substreams)
-					continue;
-				err = set_pcm_default_values(codec, info);
+				err = snd_hda_attach_pcm(codec, cpcm, s);
 				if (err < 0)
 					return err;
 			}
diff -r edd30b308900 pci/hda/hda_codec.h
--- a/pci/hda/hda_codec.h	Mon Jan 07 15:17:43 2008 +0100
+++ b/pci/hda/hda_codec.h	Mon Jan 07 16:00:32 2008 +0100
@@ -402,6 +402,12 @@ enum {
 /* max. codec address */
 #define HDA_MAX_CODEC_ADDRESS	0x0f
 
+/* max number of audio and modem PCM streams per bus */
+#define HDA_MAX_AUDIO_PCMS	6
+#define HDA_MAX_MODEM_PCMS	2
+#define HDA_MAX_PCMS		(HDA_MAX_AUDIO_PCMS + HDA_MAX_MODEM_PCMS)
+
+
 /*
  * Structures
  */
@@ -424,6 +430,9 @@ struct hda_bus_ops {
 	unsigned int (*get_response)(struct hda_codec *codec);
 	/* free the private data */
 	void (*private_free)(struct hda_bus *);
+	/* attach a PCM stream */
+	int (*attach_pcm)(struct hda_codec *codec, struct hda_pcm *pcm,
+			  int stream);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	/* notify power-up/down from codec to controller */
 	void (*pm_notify)(struct hda_codec *codec);
@@ -549,6 +558,7 @@ struct hda_pcm {
 	char *name;
 	struct hda_pcm_stream stream[2];
 	unsigned int is_modem;	/* modem codec? */
+	int device;	/* assigned device number */
 };
 
 /* codec information */
@@ -567,6 +577,7 @@ struct hda_codec {
 
 	/* detected preset */
 	const struct hda_codec_preset *preset;
+	const char *name;	/* override the default name */
 
 	/* set by patch */
 	struct hda_codec_ops patch_ops;
diff -r edd30b308900 pci/hda/hda_intel.c
--- a/pci/hda/hda_intel.c	Mon Jan 07 15:17:43 2008 +0100
+++ b/pci/hda/hda_intel.c	Mon Jan 07 16:00:32 2008 +0100
@@ -210,9 +210,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO
 /* 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
@@ -344,7 +342,6 @@ struct azx {
 	struct azx_dev *azx_dev;
 
 	/* PCM */
-	unsigned int pcm_devs;
 	struct snd_pcm *pcm[AZX_MAX_PCMS];
 
 	/* HD codec */
@@ -1022,6 +1019,8 @@ static int azx_setup_controller(struct a
 	return 0;
 }
 
+static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm,
+				 int stream);
 
 /*
  * Codec initialization
@@ -1048,6 +1047,7 @@ static int __devinit azx_codec_create(st
 	bus_temp.pci = chip->pci;
 	bus_temp.ops.command = azx_send_cmd;
 	bus_temp.ops.get_response = azx_get_response;
+	bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	bus_temp.ops.pm_notify = azx_power_notify;
 #endif
@@ -1368,103 +1368,66 @@ static struct snd_pcm_ops azx_pcm_ops = 
 
 static void azx_pcm_free(struct snd_pcm *pcm)
 {
-	kfree(pcm->private_data);
+	struct azx_pcm *apcm = pcm->private_data;
+	if (apcm) {
+		apcm->chip->pcm[pcm->device] = NULL;
+		kfree(apcm);
+	}
 }
 
-static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
-				      struct hda_pcm *cpcm, int pcm_dev)
+static int
+azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm, int stream)
 {
-	int err;
+	struct azx *chip = codec->bus->private_data; 
 	struct snd_pcm *pcm;
 	struct azx_pcm *apcm;
+	struct snd_pcm_substream *substream;
+	int pcm_dev = cpcm->device;
+	int err;
 
-	/* if no substreams are defined for both playback and capture,
-	 * it's just a placeholder.  ignore it.
-	 */
-	if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
-		return 0;
-
-	snd_assert(cpcm->name, return -EINVAL);
-
-	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
-			  cpcm->stream[0].substreams,
-			  cpcm->stream[1].substreams,
-			  &pcm);
-	if (err < 0)
-		return err;
-	strcpy(pcm->name, cpcm->name);
-	apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
-	if (apcm == NULL)
-		return -ENOMEM;
-	apcm->chip = chip;
-	apcm->codec = codec;
-	apcm->hinfo[0] = &cpcm->stream[0];
-	apcm->hinfo[1] = &cpcm->stream[1];
-	pcm->private_data = apcm;
-	pcm->private_free = azx_pcm_free;
-	if (cpcm->stream[0].substreams)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
-	if (cpcm->stream[1].substreams)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
-	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;
-
-	return 0;
-}
-
-static int __devinit azx_pcm_create(struct azx *chip)
-{
-	struct hda_codec *codec;
-	int c, err;
-	int pcm_dev;
-
-	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++;
+	if (pcm_dev >= AZX_MAX_PCMS) {
+		snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
+			   pcm_dev);
+		return -EINVAL;
+	}
+	pcm = chip->pcm[pcm_dev];
+	if (!pcm) {
+		err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, 0, 0, &pcm);
+		if (err < 0)
+			return err;
+		strcpy(pcm->name, cpcm->name);
+		apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+		if (apcm == NULL)
+			return -ENOMEM;
+		apcm->chip = chip;
+		apcm->codec = codec;
+		pcm->private_data = apcm;
+		pcm->private_free = azx_pcm_free;
+		if (cpcm->is_modem)
+			pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
+		chip->pcm[pcm_dev] = pcm;
+	} else {
+		apcm = pcm->private_data;
+		if (apcm->hinfo[stream]) {
+			snd_printk(KERN_ERR SFX "stream %d:%d already exists\n",
+				   pcm_dev, stream);
+			return -EBUSY;
 		}
 	}
 
-	/* create modem PCMs */
-	pcm_dev = AZX_MAX_AUDIO_PCMS;
-	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;
-			}
-			err = create_codec_pcm(chip, codec,
-					       &codec->pcm_info[c], pcm_dev);
-			if (err < 0)
-				return err;
-			chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM;
-			pcm_dev++;
-		}
-	}
-	return 0;
+	err = snd_pcm_new_stream(pcm, stream, cpcm->stream[stream].substreams);
+	if (err < 0)
+		return err;
+	apcm->hinfo[stream] = &cpcm->stream[stream];
+	if (cpcm->stream[stream].substreams)
+		snd_pcm_set_ops(pcm, stream, &azx_pcm_ops);
+	/* buffer pre-allocation */
+	for (substream = pcm->streams[stream].substream; substream;
+	     substream = substream->next)
+		snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci),
+					      1024 * 64, 1024 * 1024);
+ 	return 0;
 }
 
 /*
@@ -1573,7 +1536,7 @@ static int azx_suspend(struct pci_dev *p
 	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);
@@ -1919,7 +1882,7 @@ static int __devinit azx_probe(struct pc
 	}
 
 	/* create PCM streams */
-	err = azx_pcm_create(chip);
+	err = snd_hda_build_pcms(chip->bus);
 	if (err < 0) {
 		snd_card_free(card);
 		return err;
